summaryrefslogtreecommitdiffstats
path: root/src/file.c
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2012-08-17 09:47:29 +0100
committerRichard W.M. Jones <rjones@redhat.com>2012-08-17 16:08:13 +0100
commit9d85eba3c3c169478d1edf0dd7ef9495d4be19ce (patch)
tree7a6bd4b2aeaca63811573fc4befc8f621b24cb09 /src/file.c
parent294bee38bcdd38542bf26292365ac27aebb06642 (diff)
downloadlibguestfs-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.c117
1 files changed, 117 insertions, 0 deletions
diff --git a/src/file.c b/src/file.c
index b76900d2..ed157592 100644
--- a/src/file.c
+++ b/src/file.c
@@ -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;
+}