diff options
author | Richard W.M. Jones <rjones@redhat.com> | 2012-08-17 09:47:29 +0100 |
---|---|---|
committer | Richard W.M. Jones <rjones@redhat.com> | 2012-08-17 16:08:13 +0100 |
commit | 9d85eba3c3c169478d1edf0dd7ef9495d4be19ce (patch) | |
tree | 7a6bd4b2aeaca63811573fc4befc8f621b24cb09 /src/file.c | |
parent | 294bee38bcdd38542bf26292365ac27aebb06642 (diff) | |
download | libguestfs-9d85eba3c3c169478d1edf0dd7ef9495d4be19ce.tar.gz libguestfs-9d85eba3c3c169478d1edf0dd7ef9495d4be19ce.tar.xz libguestfs-9d85eba3c3c169478d1edf0dd7ef9495d4be19ce.zip |
guestfs_find: Reimplement to avoid protocol limits.
This also reimplements the virt-ls -R option to use the replacement
guestfs_find API, which is simpler (though actually less efficient).
Diffstat (limited to 'src/file.c')
-rw-r--r-- | src/file.c | 117 |
1 files changed, 117 insertions, 0 deletions
@@ -34,6 +34,20 @@ #include "guestfs-internal-actions.h" #include "guestfs_protocol.h" +static int +compare (const void *vp1, const void *vp2) +{ + char * const *p1 = (char * const *) vp1; + char * const *p2 = (char * const *) vp2; + return strcmp (*p1, *p2); +} + +static void +sort_strings (char **argv, size_t len) +{ + qsort (argv, len, sizeof (char *), compare); +} + char * guestfs__cat (guestfs_h *g, const char *path) { @@ -95,3 +109,106 @@ guestfs__cat (guestfs_h *g, const char *path) } return NULL; } + +char ** +guestfs__find (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/find%d", g->tmpdir, ++g->unique); + + if (guestfs_find0 (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), even + * though it is probably impossible. + */ + 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; +} |