mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-22 07:03:38 +00:00
guestfs_ls: Reimplement to avoid protocol limits.
This commit is contained in:
43
daemon/ls.c
43
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
|
||||
|
||||
@@ -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
|
||||
@@ -2309,27 +2326,6 @@ there is no cwd) in the format of 'ls -la'.
|
||||
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", [], [];
|
||||
|
||||
102
src/file.c
102
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user