summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2012-08-17 14:11:21 +0100
committerRichard W.M. Jones <rjones@redhat.com>2012-08-17 16:08:13 +0100
commita69f44f56f20beab7793be428df22104f79500e7 (patch)
tree76d6d082290fbc7b429b7be8c7781881249f51f0
parent1b4d8e2cca7819b4c6e14bb052f40a9fc40205d3 (diff)
downloadlibguestfs-a69f44f56f20beab7793be428df22104f79500e7.tar.gz
libguestfs-a69f44f56f20beab7793be428df22104f79500e7.tar.xz
libguestfs-a69f44f56f20beab7793be428df22104f79500e7.zip
guestfs_ls: Reimplement to avoid protocol limits.
-rw-r--r--daemon/ls.c43
-rw-r--r--generator/generator_actions.ml38
-rw-r--r--src/file.c102
3 files changed, 119 insertions, 64 deletions
diff --git a/daemon/ls.c b/daemon/ls.c
index 0f60a4ea..5adf5ef3 100644
--- a/daemon/ls.c
+++ b/daemon/ls.c
@@ -93,49 +93,6 @@ do_ls0 (const char *path)
return 0;
}
-char **
-do_ls (const char *path)
-{
- DECLARE_STRINGSBUF (ret);
- DIR *dir;
- struct dirent *d;
-
- CHROOT_IN;
- dir = opendir (path);
- CHROOT_OUT;
-
- if (!dir) {
- reply_with_perror ("opendir: %s", path);
- return NULL;
- }
-
- while ((d = readdir (dir)) != NULL) {
- if (STREQ (d->d_name, ".") || STREQ (d->d_name, ".."))
- continue;
-
- if (add_string (&ret, d->d_name) == -1) {
- closedir (dir);
- return NULL;
- }
- }
-
- if (ret.size > 0)
- sort_strings (ret.argv, ret.size);
-
- if (end_stringsbuf (&ret) == -1) {
- closedir (dir);
- return NULL;
- }
-
- if (closedir (dir) == -1) {
- reply_with_perror ("closedir: %s", path);
- free_stringslen (ret.argv, ret.size);
- return NULL;
- }
-
- return ret.argv;
-}
-
/* Because we can't chroot and run the ls command (since 'ls' won't
* necessarily exist in the chroot), this command can be used to escape
* from the sysroot (eg. 'll /..'). This command is not meant for
diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml
index be2db82a..66eb54f6 100644
--- a/generator/generator_actions.ml
+++ b/generator/generator_actions.ml
@@ -2219,6 +2219,23 @@ 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." };
+ { defaults with
+ name = "ls";
+ style = RStringList "listing", [Pathname "directory"], [];
+ tests = [
+ InitScratchFS, Always, TestOutputList (
+ [["mkdir"; "/ls"];
+ ["touch"; "/ls/new"];
+ ["touch"; "/ls/newer"];
+ ["touch"; "/ls/newest"];
+ ["ls"; "/ls"]], ["new"; "newer"; "newest"])
+ ];
+ shortdesc = "list the files in a directory";
+ longdesc = "\
+List the files in C<directory> (relative to the root directory,
+there is no cwd). The '.' and '..' entries are not returned, but
+hidden files are shown." };
+
]
(* daemon_functions are any functions which cause some action
@@ -2310,27 +2327,6 @@ This command is mostly useful for interactive sessions. It
is I<not> intended that you try to parse the output string." };
{ defaults with
- name = "ls";
- style = RStringList "listing", [Pathname "directory"], [];
- proc_nr = Some 6;
- tests = [
- InitScratchFS, Always, TestOutputList (
- [["mkdir"; "/ls"];
- ["touch"; "/ls/new"];
- ["touch"; "/ls/newer"];
- ["touch"; "/ls/newest"];
- ["ls"; "/ls"]], ["new"; "newer"; "newest"])
- ];
- shortdesc = "list the files in a directory";
- longdesc = "\
-List the files in C<directory> (relative to the root directory,
-there is no cwd). The '.' and '..' entries are not returned, but
-hidden files are shown.
-
-This command is mostly useful for interactive sessions. Programs
-should probably use C<guestfs_readdir> instead." };
-
- { defaults with
name = "list_devices";
style = RStringList "devices", [], [];
proc_nr = Some 7;
diff --git a/src/file.c b/src/file.c
index 71b208d3..9257b857 100644
--- a/src/file.c
+++ b/src/file.c
@@ -535,3 +535,105 @@ guestfs__readlinklist (guestfs_h *g, const char *dir, char *const *names)
return ret;
}
+
+char **
+guestfs__ls (guestfs_h *g, const char *directory)
+{
+ int fd = -1;
+ struct stat statbuf;
+ char *tmpfile = NULL, *buf = NULL;
+ char **ret = NULL;
+ size_t i, count, size;
+
+ tmpfile = safe_asprintf (g, "%s/ls%d", g->tmpdir, ++g->unique);
+
+ if (guestfs_ls0 (g, directory, tmpfile) == -1)
+ goto err;
+
+ fd = open (tmpfile, O_RDONLY|O_CLOEXEC);
+ if (fd == -1) {
+ perrorf (g, "open: %s", tmpfile);
+ goto err;
+ }
+
+ unlink (tmpfile);
+ free (tmpfile);
+ tmpfile = NULL;
+
+ /* Read the whole file into memory. */
+ if (fstat (fd, &statbuf) == -1) {
+ perrorf (g, "stat: %s", tmpfile);
+ goto err;
+ }
+
+ /* Don't use safe_malloc, because we want to return an errno to the caller. */
+ size = statbuf.st_size;
+ buf = malloc (size);
+ if (!buf) {
+ perrorf (g, "malloc: %zu bytes", size);
+ goto err;
+ }
+
+ if (full_read (fd, buf, size) != size) {
+ perrorf (g, "full-read: %s: %zu bytes", tmpfile, size);
+ goto err;
+ }
+
+ if (close (fd) == -1) {
+ perrorf (g, "close: %s", tmpfile);
+ goto err;
+ }
+ fd = -1;
+
+ /* 'buf' contains the list of strings, separated (and terminated) by
+ * '\0' characters. Convert this to a list of lines. Note we
+ * handle the case where buf is completely empty (size == 0).
+ */
+ count = 0;
+ for (i = 0; i < size; ++i)
+ if (buf[i] == '\0')
+ count++;
+
+ ret = malloc ((count + 1) * sizeof (char *));
+ if (!ret) {
+ perrorf (g, "malloc");
+ goto err;
+ }
+
+ count = 0;
+ ret[count++] = buf;
+ for (i = 0; i < size; ++i) {
+ if (buf[i] == '\0')
+ ret[count++] = &buf[i+1];
+ }
+ ret[--count] = NULL;
+
+ /* Finally we have to duplicate and sort the strings, since that's
+ * what the caller is expecting.
+ */
+ for (i = 0; ret[i] != NULL; ++i) {
+ ret[i] = strdup (ret[i]);
+ if (ret[i] == NULL) {
+ perrorf (g, "strdup");
+ while (i > 0)
+ free (ret[--i]);
+ goto err;
+ }
+ }
+ free (buf);
+
+ sort_strings (ret, count);
+
+ return ret; /* caller frees */
+
+ err:
+ free (buf);
+ free (ret);
+ if (fd >= 0)
+ close (fd);
+ if (tmpfile) {
+ unlink (tmpfile);
+ free (tmpfile);
+ }
+ return NULL;
+}