From d1df2f342489bbbba086cae2bb95971c8e404cad Mon Sep 17 00:00:00 2001 From: Richard Jones Date: Tue, 19 May 2009 12:05:33 +0100 Subject: [PATCH] Added 'find' command. --- daemon/Makefile.am | 1 + daemon/find.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/generator.ml | 39 ++++++++++++++++ 3 files changed, 169 insertions(+) create mode 100644 daemon/find.c diff --git a/daemon/Makefile.am b/daemon/Makefile.am index ac1f8c5..e0da08c 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -34,6 +34,7 @@ guestfsd_SOURCES = \ dropcaches.c \ ext2.c \ file.c \ + find.c \ fsck.c \ grub.c \ guestfsd.c \ diff --git a/daemon/find.c b/daemon/find.c new file mode 100644 index 0000000..6a7e3e8 --- /dev/null +++ b/daemon/find.c @@ -0,0 +1,129 @@ +/* libguestfs - the guestfsd daemon + * Copyright (C) 2009 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "../src/guestfs_protocol.h" +#include "daemon.h" +#include "actions.h" + +static int +input_to_nul (FILE *fp, char *buf, int maxlen) +{ + int i = 0, c; + + while (i < maxlen) { + c = fgetc (fp); + if (c == EOF) + return 0; + buf[i++] = c; + if (c == '\0') + return i; + } + + reply_with_error ("input_to_nul: input string too long"); + return -1; +} + +char ** +do_find (const char *dir) +{ + struct stat statbuf; + int r, len, sysrootdirlen; + char *cmd; + FILE *fp; + char **res = NULL; + int size = 0, alloc = 0; + char sysrootdir[PATH_MAX]; + char str[PATH_MAX]; + + NEED_ROOT (NULL); + ABS_PATH (dir, NULL); + + snprintf (sysrootdir, sizeof sysrootdir, "/sysroot%s", dir); + + r = stat (sysrootdir, &statbuf); + if (r == -1) { + reply_with_perror ("%s", dir); + return NULL; + } + if (!S_ISDIR (statbuf.st_mode)) { + reply_with_error ("%s: not a directory", dir); + return NULL; + } + + sysrootdirlen = strlen (sysrootdir); + + /* Assemble the external find command. */ + len = 2 * sysrootdirlen + 32; + cmd = malloc (len); + if (!cmd) { + reply_with_perror ("malloc"); + return NULL; + } + + strcpy (cmd, "find "); + shell_quote (cmd+5, len-5, sysrootdir); + strcat (cmd, " -print0"); + + if (verbose) + printf ("%s\n", cmd); + + fp = popen (cmd, "r"); + if (fp == NULL) { + reply_with_perror ("%s", cmd); + free (cmd); + return NULL; + } + free (cmd); + + while ((r = input_to_nul (fp, str, PATH_MAX)) > 0) { + if (verbose) + printf ("find string: %s\n", str); + + len = strlen (str); + if (len <= sysrootdirlen) + continue; + + /* Remove the directory part of the path when adding it. */ + if (add_string (&res, &size, &alloc, str + sysrootdirlen) == -1) { + pclose (fp); + return NULL; + } + } + pclose (fp); + + if (r == -1) { + free_stringslen (res, size); + return NULL; + } + + if (add_string (&res, &size, &alloc, NULL) == -1) + return NULL; + + sort_strings (res, size-1); + + return res; /* caller frees */ +} diff --git a/src/generator.ml b/src/generator.ml index 8ebfafb..01a2309 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -2122,6 +2122,45 @@ is lost."); This resizes an ext2 or ext3 filesystem to match the size of the underlying device."); + ("find", (RStringList "names", [String "directory"]), 107, [], + [InitBasicFS, Always, TestOutputList ( + [["find"; "/"]], ["lost+found"]); + InitBasicFS, Always, TestOutputList ( + [["touch"; "/a"]; + ["mkdir"; "/b"]; + ["touch"; "/b/c"]; + ["find"; "/"]], ["a"; "b"; "b/c"; "lost+found"]); + InitBasicFS, Always, TestOutputList ( + [["mkdir_p"; "/a/b/c"]; + ["touch"; "/a/b/c/d"]; + ["find"; "/a/b/"]], ["c"; "c/d"])], + "find all files and directories", + "\ +This command lists out all files and directories, recursively, +starting at C. It is essentially equivalent to +running the shell command C but some +post-processing happens on the output, described below. + +This returns a list of strings I. Thus +if the directory structure was: + + /tmp/a + /tmp/b + /tmp/c/d + +then the returned list from C C would be +4 elements: + + a + b + c + c/d + +If C is not a directory, then this command returns +an error. + +The returned list is sorted."); + ] let all_functions = non_daemon_functions @ daemon_functions -- 1.8.3.1