summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--TODO2
-rw-r--r--cat/virt-ls.c175
-rw-r--r--daemon/stat.c2
-rw-r--r--daemon/xattr.c4
-rw-r--r--generator/generator_actions.ml50
-rw-r--r--src/file.c125
6 files changed, 184 insertions, 174 deletions
diff --git a/TODO b/TODO
index 1f84fcc8..1bc16313 100644
--- a/TODO
+++ b/TODO
@@ -565,6 +565,4 @@ 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_lstatlist
- - guestfs_lxattrlist
- guestfs_readlinklist
diff --git a/cat/virt-ls.c b/cat/virt-ls.c
index 771148c3..9e64e240 100644
--- a/cat/virt-ls.c
+++ b/cat/virt-ls.c
@@ -86,9 +86,7 @@ static int is_fifo (int64_t mode);
static int is_lnk (int64_t mode);
static int is_sock (int64_t mode);
-static size_t count_strings (char **);
static void free_strings (char **);
-static char **take_strings (char **, size_t n, char ***);
static inline char *
bad_cast (char const *s)
@@ -467,8 +465,6 @@ do_ls_R (const char *dir)
https://rwmj.wordpress.com/2010/12/15/tip-audit-virtual-machine-for-setuid-files/
*/
static char *full_path (const char *dir, const char *name);
-static struct guestfs_stat_list *lstatlist (const char *dir, char **names);
-static struct guestfs_xattr_list *lxattrlist (const char *dir, char **names);
static int show_file (const char *dir, const char *name, const struct guestfs_stat *stat, const struct guestfs_xattr_list *xattrs);
typedef int (*visitor_function) (const char *dir, const char *name, const struct guestfs_stat *stat, const struct guestfs_xattr_list *xattrs);
@@ -514,11 +510,11 @@ visit (int depth, const char *dir, visitor_function f)
if (names == NULL)
goto out;
- stats = lstatlist (dir, names);
+ stats = guestfs_lstatlist (g, dir, names);
if (stats == NULL)
goto out;
- xattrs = lxattrlist (dir, names);
+ xattrs = guestfs_lxattrlist (g, dir, names);
if (xattrs == NULL)
goto out;
@@ -538,8 +534,12 @@ visit (int depth, const char *dir, visitor_function f)
program_name, dir, names[i]);
goto out;
}
- /* lxattrlist function made sure attrval was \0-terminated, so we can do */
- if (sscanf (xattrs->val[xattrp].attrval, "%zu", &nr_xattrs) != 1) {
+ /* attrval is not \0-terminated. */
+ char attrval[xattrs->val[xattrp].attrval_len+1];
+ memcpy (attrval, xattrs->val[xattrp].attrval,
+ xattrs->val[xattrp].attrval_len);
+ attrval[xattrs->val[xattrp].attrval_len] = '\0';
+ if (sscanf (attrval, "%zu", &nr_xattrs) != 1) {
fprintf (stderr, _("%s: error: cannot parse xattr count for %s %s\n"),
program_name, dir, names[i]);
goto out;
@@ -596,129 +596,6 @@ full_path (const char *dir, const char *name)
return path;
}
-/* This calls guestfs_lstatlist, but it splits the names list up so that we
- * don't overrun the libguestfs protocol limit.
- */
-#define LSTATLIST_MAX 1000
-
-static struct guestfs_stat_list *
-lstatlist (const char *dir, char **names)
-{
- size_t len = count_strings (names);
- char **first;
- size_t old_len;
- struct guestfs_stat_list *ret, *stats;
-
- ret = malloc (sizeof *ret);
- if (ret == NULL) {
- perror ("malloc");
- exit (EXIT_FAILURE);
- }
- ret->len = 0;
- ret->val = NULL;
-
- while (len > 0) {
- first = take_strings (names, LSTATLIST_MAX, &names);
- len = len <= LSTATLIST_MAX ? 0 : len - LSTATLIST_MAX;
-
- stats = guestfs_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) {
- free (ret);
- return NULL;
- }
-
- /* Append stats to ret. */
- old_len = ret->len;
- ret->len += stats->len;
- ret->val = realloc (ret->val, ret->len * sizeof (struct guestfs_stat));
- if (ret->val == NULL) {
- perror ("realloc");
- exit (EXIT_FAILURE);
- }
- memcpy (&ret->val[old_len], stats->val,
- stats->len * sizeof (struct guestfs_stat));
-
- guestfs_free_stat_list (stats);
- }
-
- return ret;
-}
-
-/* Same as above, for lxattrlist. Note the rather peculiar format
- * used to return the list of extended attributes (see
- * guestfs_lxattrlist documentation).
- */
-#define LXATTRLIST_MAX 1000
-
-static struct guestfs_xattr_list *
-lxattrlist (const char *dir, char **names)
-{
- size_t len = count_strings (names);
- char **first;
- size_t i, old_len;
- struct guestfs_xattr_list *ret, *xattrs;
-
- ret = malloc (sizeof *ret);
- if (ret == NULL) {
- perror ("malloc");
- exit (EXIT_FAILURE);
- }
- ret->len = 0;
- ret->val = NULL;
-
- while (len > 0) {
- first = take_strings (names, LXATTRLIST_MAX, &names);
- len = len <= LXATTRLIST_MAX ? 0 : len - LXATTRLIST_MAX;
-
- xattrs = guestfs_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) {
- free (ret);
- return NULL;
- }
-
- /* Append xattrs to ret. */
- old_len = ret->len;
- ret->len += xattrs->len;
- ret->val = realloc (ret->val, ret->len * sizeof (struct guestfs_xattr));
- if (ret->val == NULL) {
- perror ("realloc");
- exit (EXIT_FAILURE);
- }
- for (i = 0; i < xattrs->len; ++i, ++old_len) {
- /* We have to make a deep copy of the attribute name and value.
- * The attrval contains 8 bit data. However make sure also that
- * it is \0-terminated, because that makes the calling code
- * simpler.
- */
- ret->val[old_len].attrname = strdup (xattrs->val[i].attrname);
- ret->val[old_len].attrval = malloc (xattrs->val[i].attrval_len + 1);
- if (ret->val[old_len].attrname == NULL ||
- ret->val[old_len].attrval == NULL) {
- perror ("malloc");
- exit (EXIT_FAILURE);
- }
- 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);
- ret->val[i].attrval[ret->val[i].attrval_len] = '\0';
- }
-
- guestfs_free_xattr_list (xattrs);
- }
-
- return ret;
-}
-
static int
do_ls_lR (const char *dir)
{
@@ -1095,16 +972,6 @@ is_sock (int64_t mode)
}
/* String functions. */
-static size_t
-count_strings (char **names)
-{
- size_t ret = 0;
-
- while (names[ret] != NULL)
- ret++;
- return ret;
-}
-
static void
free_strings (char **names)
{
@@ -1114,29 +981,3 @@ free_strings (char **names)
free (names[i]);
free (names);
}
-
-/* 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 (char **names, size_t n, char ***lastp)
-{
- size_t i;
-
- char **ret = malloc ((n+1) * sizeof (char *));
- if (ret == NULL) {
- perror ("malloc");
- exit (EXIT_FAILURE);
- }
-
- for (i = 0; names[i] != NULL && i < n; ++i)
- ret[i] = names[i];
-
- ret[i] = NULL;
-
- if (lastp)
- *lastp = &names[i];
-
- return ret;
-}
diff --git a/daemon/stat.c b/daemon/stat.c
index f0055518..939fe08e 100644
--- a/daemon/stat.c
+++ b/daemon/stat.c
@@ -125,7 +125,7 @@ do_lstat (const char *path)
}
guestfs_int_stat_list *
-do_lstatlist (const char *path, char *const *names)
+do_internal_lstatlist (const char *path, char *const *names)
{
int path_fd;
guestfs_int_stat_list *ret;
diff --git a/daemon/xattr.c b/daemon/xattr.c
index 71033071..3c0363e4 100644
--- a/daemon/xattr.c
+++ b/daemon/xattr.c
@@ -263,7 +263,7 @@ _removexattr (const char *xattr, const char *path,
}
guestfs_int_xattr_list *
-do_lxattrlist (const char *path, char *const *names)
+do_internal_lxattrlist (const char *path, char *const *names)
{
#if defined(HAVE_LLISTXATTR) && defined(HAVE_LGETXATTR)
/* XXX This would be easier if the kernel had lgetxattrat. In the
@@ -588,7 +588,7 @@ do_lremovexattr (const char *xattr, const char *path)
}
guestfs_int_xattr_list *
-do_lxattrlist (const char *path, char *const *names)
+do_internal_lxattrlist (const char *path, char *const *names)
{
abort ();
}
diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml
index d614e75c..5e776519 100644
--- a/generator/generator_actions.ml
+++ b/generator/generator_actions.ml
@@ -2152,6 +2152,50 @@ C<path> does not exist, then a new file is created.
See also C<guestfs_write>." };
+ { defaults with
+ name = "lstatlist";
+ style = RStructList ("statbufs", "stat"), [Pathname "path"; StringList "names"], [];
+ shortdesc = "lstat on multiple files";
+ longdesc = "\
+This call allows you to perform the C<guestfs_lstat> 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 stat structs, with a one-to-one
+correspondence to the C<names> list. If any name did not exist
+or could not be lstat'd, then the C<ino> field of that structure
+is set to C<-1>.
+
+This call is intended for programs that want to efficiently
+list a directory contents without making many round-trips.
+See also C<guestfs_lxattrlist> for a similarly efficient call
+for getting extended attributes." };
+
+ { defaults with
+ name = "lxattrlist";
+ style = RStructList ("xattrs", "xattr"), [Pathname "path"; StringList "names"], [];
+ optional = Some "linuxxattrs";
+ shortdesc = "lgetxattr on multiple files";
+ longdesc = "\
+This call allows you to get the extended attributes
+of 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 flat list of xattr structs which must be
+interpreted sequentially. The first xattr struct always has a zero-length
+C<attrname>. C<attrval> in this struct is zero-length
+to indicate there was an error doing C<lgetxattr> for this
+file, I<or> is a C string which is a decimal number
+(the number of following attributes for this file, which could
+be C<\"0\">). Then after the first xattr struct are the
+zero or more attributes for the first named file.
+This repeats for the second and subsequent files.
+
+This call is intended for programs that want to efficiently
+list a directory contents without making many round-trips.
+See also C<guestfs_lstatlist> for a similarly efficient call
+for getting standard stats." };
+
]
(* daemon_functions are any functions which cause some action
@@ -6281,9 +6325,10 @@ names, you will need to locate and parse the password file
yourself (Augeas support makes this relatively easy)." };
{ defaults with
- name = "lstatlist";
+ name = "internal_lstatlist";
style = RStructList ("statbufs", "stat"), [Pathname "path"; StringList "names"], [];
proc_nr = Some 204;
+ in_docs = false; in_fish = false;
shortdesc = "lstat on multiple files";
longdesc = "\
This call allows you to perform the C<guestfs_lstat> operation
@@ -6304,9 +6349,10 @@ this call to fail. The caller must split up such requests
into smaller groups of names." };
{ defaults with
- name = "lxattrlist";
+ name = "internal_lxattrlist";
style = RStructList ("xattrs", "xattr"), [Pathname "path"; StringList "names"], [];
proc_nr = Some 205;
+ in_docs = false; in_fish = false;
optional = Some "linuxxattrs";
shortdesc = "lgetxattr on multiple files";
longdesc = "\
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;
+}