From 8ee51907685d6db92031e84d249ea3bb4cdc2d67 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Fri, 17 Aug 2012 13:10:53 +0100 Subject: [PATCH] guestfs_readlinklist: Reimplement to avoid protocol limits. --- TODO | 2 -- daemon/link.c | 2 +- generator/generator_actions.ml | 26 ++++++++++++++++++++- src/file.c | 41 ++++++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 4 deletions(-) diff --git a/TODO b/TODO index 1bc16313d..92621e5c0 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 c4cdfe1d6..4536f0077 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 5e7765192..9c45a6639 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 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 operation +on multiple files, where all files are in the directory C. +C 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 list. Each string is the +value of the symbolic link. + +If the C 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 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 operation diff --git a/src/file.c b/src/file.c index dabd1b211..71b208d3f 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; +}