diff options
author | Richard W.M. Jones <rjones@redhat.com> | 2012-08-17 12:21:37 +0100 |
---|---|---|
committer | Richard W.M. Jones <rjones@redhat.com> | 2012-08-17 16:08:13 +0100 |
commit | dc66dd32c214db99467341caea0be517d2dd736f (patch) | |
tree | 82de6e3d7b60aa78095892d7152bc8e38acadab4 /src/file.c | |
parent | 118932fbeac606919f8b96c81184f4f3e0910508 (diff) | |
download | libguestfs-dc66dd32c214db99467341caea0be517d2dd736f.tar.gz libguestfs-dc66dd32c214db99467341caea0be517d2dd736f.tar.xz libguestfs-dc66dd32c214db99467341caea0be517d2dd736f.zip |
guestfs_lstatlist, guestfs_lxattrlist: Reimplement to avoid protocol limits.
Note that the code to do this was already in virt-ls, so this is
change is mostly just moving the code into the core library.
Diffstat (limited to 'src/file.c')
-rw-r--r-- | src/file.c | 125 |
1 files changed, 125 insertions, 0 deletions
@@ -49,6 +49,38 @@ sort_strings (char **argv, size_t len) qsort (argv, len, sizeof (char *), compare); } +/* Take the first 'n' names, returning a newly allocated list. The + * strings themselves are not duplicated. If 'lastp' is not NULL, + * then it is updated with the pointer to the list of remaining names. + */ +static char ** +take_strings (guestfs_h *g, char *const *names, size_t n, char *const **lastp) +{ + size_t i; + + char **ret = safe_malloc (g, (n+1) * sizeof (char *)); + + for (i = 0; names[i] != NULL && i < n; ++i) + ret[i] = names[i]; + + ret[i] = NULL; + + if (lastp) + *lastp = &names[i]; + + return ret; +} + +static size_t +count_strings (char * const*names) +{ + size_t ret = 0; + + while (names[ret] != NULL) + ret++; + return ret; +} + char * guestfs__cat (guestfs_h *g, const char *path) { @@ -369,3 +401,96 @@ guestfs__write_append (guestfs_h *g, const char *path, { return write_or_append (g, path, content, size, 1); } + +#define LSTATLIST_MAX 1000 + +struct guestfs_stat_list * +guestfs__lstatlist (guestfs_h *g, const char *dir, char * const*names) +{ + size_t len = count_strings (names); + char **first; + size_t old_len; + struct guestfs_stat_list *ret, *stats; + + ret = safe_malloc (g, sizeof *ret); + ret->len = 0; + ret->val = NULL; + + while (len > 0) { + first = take_strings (g, names, LSTATLIST_MAX, &names); + len = len <= LSTATLIST_MAX ? 0 : len - LSTATLIST_MAX; + + stats = guestfs_internal_lstatlist (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 (stats == NULL) { + guestfs_free_stat_list (stats); + return NULL; + } + + /* Append stats to ret. */ + old_len = ret->len; + ret->len += stats->len; + ret->val = safe_realloc (g, ret->val, + ret->len * sizeof (struct guestfs_stat)); + memcpy (&ret->val[old_len], stats->val, + stats->len * sizeof (struct guestfs_stat)); + + guestfs_free_stat_list (stats); + } + + return ret; +} + +#define LXATTRLIST_MAX 1000 + +struct guestfs_xattr_list * +guestfs__lxattrlist (guestfs_h *g, const char *dir, char *const *names) +{ + size_t len = count_strings (names); + char **first; + size_t i, old_len; + struct guestfs_xattr_list *ret, *xattrs; + + ret = safe_malloc (g, sizeof *ret); + ret->len = 0; + ret->val = NULL; + + while (len > 0) { + first = take_strings (g, names, LXATTRLIST_MAX, &names); + len = len <= LXATTRLIST_MAX ? 0 : len - LXATTRLIST_MAX; + + xattrs = guestfs_internal_lxattrlist (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 (xattrs == NULL) { + guestfs_free_xattr_list (ret); + return NULL; + } + + /* Append xattrs to ret. */ + old_len = ret->len; + ret->len += xattrs->len; + ret->val = safe_realloc (g, ret->val, + ret->len * sizeof (struct guestfs_xattr)); + for (i = 0; i < xattrs->len; ++i, ++old_len) { + /* We have to make a deep copy of the attribute name and value. + */ + ret->val[old_len].attrname = safe_strdup (g, xattrs->val[i].attrname); + ret->val[old_len].attrval = safe_malloc (g, xattrs->val[i].attrval_len); + ret->val[old_len].attrval_len = xattrs->val[i].attrval_len; + memcpy (ret->val[old_len].attrval, xattrs->val[i].attrval, + xattrs->val[i].attrval_len); + } + + guestfs_free_xattr_list (xattrs); + } + + return ret; +} |