diff options
-rw-r--r-- | daemon/ls.c | 43 | ||||
-rw-r--r-- | generator/generator_actions.ml | 38 | ||||
-rw-r--r-- | src/file.c | 102 |
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; @@ -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; +} |