summaryrefslogtreecommitdiffstats
path: root/src/file.c
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2012-08-17 12:21:37 +0100
committerRichard W.M. Jones <rjones@redhat.com>2012-08-17 16:08:13 +0100
commitdc66dd32c214db99467341caea0be517d2dd736f (patch)
tree82de6e3d7b60aa78095892d7152bc8e38acadab4 /src/file.c
parent118932fbeac606919f8b96c81184f4f3e0910508 (diff)
downloadlibguestfs-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.c125
1 files changed, 125 insertions, 0 deletions
diff --git a/src/file.c b/src/file.c
index cd2ea516..dabd1b21 100644
--- a/src/file.c
+++ b/src/file.c
@@ -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;
+}