summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--TODO2
-rw-r--r--daemon/link.c2
-rw-r--r--generator/generator_actions.ml26
-rw-r--r--src/file.c41
4 files changed, 67 insertions, 4 deletions
diff --git a/TODO b/TODO
index 1bc16313..92621e5c 100644
--- a/TODO
+++ b/TODO
@@ -564,5 +564,3 @@ These would be changed from daemon_functions to non_daemon_functions,
with the non-daemon versions implemented using guestfs_upload and
guestfs_download (and others). This change should be transparent from
the p.o.v of the API and ABI.
-
- - guestfs_readlinklist
diff --git a/daemon/link.c b/daemon/link.c
index c4cdfe1d..4536f007 100644
--- a/daemon/link.c
+++ b/daemon/link.c
@@ -53,7 +53,7 @@ do_readlink (const char *path)
}
char **
-do_readlinklist (const char *path, char *const *names)
+do_internal_readlinklist (const char *path, char *const *names)
{
int fd_cwd;
size_t i;
diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml
index 5e776519..9c45a663 100644
--- a/generator/generator_actions.ml
+++ b/generator/generator_actions.ml
@@ -2196,6 +2196,29 @@ list a directory contents without making many round-trips.
See also C<guestfs_lstatlist> for a similarly efficient call
for getting standard stats." };
+ { defaults with
+ name = "readlinklist";
+ style = RStringList "links", [Pathname "path"; StringList "names"], [];
+ shortdesc = "readlink on multiple files";
+ longdesc = "\
+This call allows you to do a C<readlink> operation
+on multiple files, where all files are in the directory C<path>.
+C<names> is the list of files from this directory.
+
+On return you get a list of strings, with a one-to-one
+correspondence to the C<names> list. Each string is the
+value of the symbolic link.
+
+If the C<readlink(2)> operation fails on any name, then
+the corresponding result string is the empty string C<\"\">.
+However the whole operation is completed even if there
+were C<readlink(2)> errors, and so you can call this
+function with names where you don't know if they are
+symbolic links already (albeit slightly less efficient).
+
+This call is intended for programs that want to efficiently
+list a directory contents without making many round-trips." };
+
]
(* daemon_functions are any functions which cause some action
@@ -6379,9 +6402,10 @@ this call to fail. The caller must split up such requests
into smaller groups of names." };
{ defaults with
- name = "readlinklist";
+ name = "internal_readlinklist";
style = RStringList "links", [Pathname "path"; StringList "names"], [];
proc_nr = Some 206;
+ in_docs = false; in_fish = false;
shortdesc = "readlink on multiple files";
longdesc = "\
This call allows you to do a C<readlink> operation
diff --git a/src/file.c b/src/file.c
index dabd1b21..71b208d3 100644
--- a/src/file.c
+++ b/src/file.c
@@ -494,3 +494,44 @@ guestfs__lxattrlist (guestfs_h *g, const char *dir, char *const *names)
return ret;
}
+
+#define READLINK_MAX 1000
+
+char **
+guestfs__readlinklist (guestfs_h *g, const char *dir, char *const *names)
+{
+ size_t len = count_strings (names);
+ char **first;
+ size_t old_len, ret_len = 0;
+ char **ret = NULL, **links;
+
+ while (len > 0) {
+ first = take_strings (g, names, READLINK_MAX, &names);
+ len = len <= READLINK_MAX ? 0 : len - READLINK_MAX;
+
+ links = guestfs_internal_readlinklist (g, dir, first);
+ /* Note we don't need to free up the strings because take_strings
+ * does not do a deep copy.
+ */
+ free (first);
+
+ if (links == NULL) {
+ guestfs___free_string_list (ret);
+ return NULL;
+ }
+
+ /* Append links to ret. */
+ old_len = ret_len;
+ ret_len += count_strings (links);
+ ret = safe_realloc (g, ret, ret_len * sizeof (char *));
+ memcpy (&ret[old_len], links, (ret_len-old_len) * sizeof (char *));
+
+ free (links);
+ }
+
+ /* NULL-terminate the list. */
+ ret = safe_realloc (g, ret, (ret_len+1) * sizeof (char *));
+ ret[ret_len] = NULL;
+
+ return ret;
+}