<html>
  <head>
    <meta content="text/html; charset=windows-1252"
      http-equiv="Content-Type">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    On 05/04/16 20:26, Pino Toscano wrote:<br>
    <blockquote
      cite="mid:3065226.eebAnzoKex@pendragon.usersys.redhat.com"
      type="cite">
      <pre wrap="">"appliance: Added filesystem_walk command"

-> "New API: filesystem_walk"

On Tuesday 05 April 2016 18:47:31 Matteo Cafasso wrote:
</pre>
      <blockquote type="cite">
        <pre wrap="">The filesystem_walk command is the appliance's
counterpart of the daemon's internal_filesystem_walk command.
</pre>
      </blockquote>
      <pre wrap="">
It is not the counterpart in the appliance, but in the library.
The appliance is the small VM used to do all the operations with the
disk images, and the guestfsd daemon runs there.

This non-daemon API exists only in the library, hence in userspace.

</pre>
      <blockquote type="cite">
        <pre wrap="">It writes the daemon's command output on a temporary file and parses it,
deserialising the XDR formatted tsk_dirent structs.

It returns to the caller the list of tsk_dirent structs generated by the
internal_filesystem_walk command.

Signed-off-by: Matteo Cafasso <a class="moz-txt-link-rfc2396E" href="mailto:noxdafox@gmail.com"><noxdafox@gmail.com></a>
---
 generator/actions.ml |  69 +++++++++++++++++++++++++++++
 src/Makefile.am      |   1 +
 src/tsk.c            | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 193 insertions(+)
 create mode 100644 src/tsk.c

diff --git a/generator/actions.ml b/generator/actions.ml
index 8073370..afff402 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -3546,6 +3546,75 @@ The environment variable C<XDG_RUNTIME_DIR> controls the default
 value: If C<XDG_RUNTIME_DIR> is set, then that is the default.
 Else F</tmp> is the default." };

+  { defaults with
+    name = "filesystem_walk"; added = (1, 33, 18);
+    style = RStructList ("dirents", "tsk_dirent"), [Mountable "device";], [];
+    optional = Some "libtsk";
+    progress = true; cancellable = true;
+    shortdesc = "walk through the filesystem content";
+    longdesc = "\
+Walk through the internal structures of a disk partition
+(eg. F</dev/sda1>) in order to return a list of all the files
+and directories stored within.
+
+It is not necessary to mount the disk partition to run this command.
+
+All entries in the filesystem are returned, excluding C<.> and
+C<..>. This function can list deleted or unaccessible files.
+The entries are I<not> sorted.
+
+If the entry is not allocated (ex: it has been deleted),
+its inode, type or size might not be recovered correctly.
+In such case, the inode might be 0, the size might be -1 and the type
+might be unidentified 'u'.
</pre>
      </blockquote>
      <pre wrap="">
Use POD C<..> for the special values 0, -1, 'u'.

</pre>
      <blockquote type="cite">
        <pre wrap="">+This call returns as well basic file type information about each
+file.  The C<tsk_type> field will contain one of the following characters:
+
+=over 4
+
+=item 'b'
+
+Block special
+
+=item 'c'
+
+Char special
+
+=item 'd'
+
+Directory
+
+=item 'f'
+
+FIFO (named pipe)
+
+=item 'l'
+
+Symbolic link
+
+=item 'r'
+
+Regular file
+
+=item 's'
+
+Socket
+
+=item 'h'
+
+Shadow inode (Solaris)
+
+=item 'w'
+
+Whiteout inode (BSD)
+
+=item 'u'
+
+Unknown file type
+
+=back" };
+
 ]

 (* daemon_functions are any functions which cause some action
diff --git a/src/Makefile.am b/src/Makefile.am
index 3b4cd10..9f8af4c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -130,6 +130,7 @@ libguestfs_la_SOURCES = \
        structs-copy.c \
        structs-free.c \
        tmpdirs.c \
+       tsk.c \
        whole-file.c \
        libguestfs.syms

diff --git a/src/tsk.c b/src/tsk.c
new file mode 100644
index 0000000..4d7fd7c
--- /dev/null
+++ b/src/tsk.c
@@ -0,0 +1,123 @@
+/* libguestfs
+ * Copyright (C) 2016 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <rpc/xdr.h>
+#include <rpc/types.h>
+
+#include "full-read.h"
+
+#include "guestfs.h"
+#include "guestfs_protocol.h"
+#include "guestfs-internal.h"
+#include "guestfs-internal-all.h"
+#include "guestfs-internal-actions.h"
+
+static struct guestfs_tsk_dirent_list *parse_filesystem_walk (guestfs_h *, char *, size_t );
</pre>
      </blockquote>
      <pre wrap="">
Extra space at the end.

</pre>
      <blockquote type="cite">
        <pre wrap="">+int deserialise_dirent_list (guestfs_h *, char *, size_t , struct guestfs_tsk_dirent_list *);
</pre>
      </blockquote>
      <pre wrap="">
deserialise_dirent_list can be static.

</pre>
      <blockquote type="cite">
        <pre wrap="">+
+struct guestfs_tsk_dirent_list *
+guestfs_impl_filesystem_walk (guestfs_h *g, const char *mountable)
+{
+  int ret = 0;
+  size_t size = 0;
+  CLEANUP_FREE char *buf = NULL;
+  CLEANUP_UNLINK_FREE char *tmpfile = NULL;
+
+  ret = guestfs_int_lazy_make_tmpdir (g);
+  if (ret < 0)
+    return NULL;
+
+  tmpfile = safe_asprintf (g, "%s/filesystem_walk%d", g->tmpdir, ++g->unique);
+
+  ret = guestfs_internal_filesystem_walk (g, mountable, tmpfile);
+  if (ret < 0)
+    return NULL;
+
+  ret = guestfs_int_read_whole_file (g, tmpfile, &buf, &size);
</pre>
      </blockquote>
      <pre wrap="">
I think there should be checks for the size of the downloaded file, to
avoid reading too much.

</pre>
      <blockquote type="cite">
        <pre wrap="">+  if (ret < 0)
+    return NULL;
+
+  return parse_filesystem_walk (g, buf, size);  /* caller frees */
+}
+
+/* Parse buf content and return dirents list.
+ * Return a list of tsk_dirent on success, NULL on error.
+ */
+static struct guestfs_tsk_dirent_list *
+parse_filesystem_walk (guestfs_h *g, char *buf, size_t bufsize)
+{
+  int ret = 0;
+  struct guestfs_tsk_dirent_list *dirents = NULL;
+
+  /* Initialise results array. */
+  dirents = safe_malloc (g, sizeof (*dirents));
+  dirents->len = 8;
+  dirents->val = safe_malloc (g, dirents->len * sizeof (*dirents->val));
+
+  /* Deserialise buffer into dirent list. */
+  ret = deserialise_dirent_list (g, buf, bufsize, dirents);
+  if (ret < 0) {
+    guestfs_free_tsk_dirent_list (dirents);
+    return NULL;
+  }
+
+  return dirents;
+}
+
+/* Deserialise buf content and populate the dirent list.
+ * Return the number of deserialised dirents, -1 on error.
+ */
+int
+deserialise_dirent_list (guestfs_h *g, char *buf, size_t bufsize,
+                         struct guestfs_tsk_dirent_list *dirents)
+{
+  XDR xdr;
+  bool_t ret = 0;
+  uint32_t index = 0;
+
+  xdrmem_create (&xdr, buf, bufsize, XDR_DECODE);
+
+  for (index = 0; xdr_getpos (&xdr) < bufsize; index++) {
+    if (index == dirents->len) {
+      dirents->len = 2 * dirents->len;
+      dirents->val = safe_realloc (g, dirents->val,
+                                   dirents->len *
+                                   sizeof (*dirents->val));
+    }
+
+    memset(&dirents->val[index], 0, sizeof (*dirents->val));
</pre>
      </blockquote>
      <pre wrap="">
I think this should not be needed at all, the XDR decoding should set
every field in the struct.</pre>
    </blockquote>
    This is indeed needed as the initialized memory won't be zeroed thus
    confusing the inner 'xdr_string' function (very bad API IMHO). <br>
    <blockquote
      cite="mid:3065226.eebAnzoKex@pendragon.usersys.redhat.com"
      type="cite">
      <pre wrap="">

</pre>
      <blockquote type="cite">
        <pre wrap="">+    ret = xdr_guestfs_int_tsk_dirent(&xdr, (guestfs_int_tsk_dirent *)
</pre>
      </blockquote>
      <pre wrap="">
Why is "(guestfs_int_tsk_dirent *)" needed?  (Also, missing space.)</pre>
    </blockquote>
    The struct is guestfs_tsk_dirent, the function parameter is of type
    guestfs_int_tsk_dirent.<br>
    <blockquote
      cite="mid:3065226.eebAnzoKex@pendragon.usersys.redhat.com"
      type="cite">
      <pre wrap="">

Thanks,
</pre>
      <br>
      <fieldset class="mimeAttachmentHeader"></fieldset>
      <br>
      <pre wrap="">_______________________________________________
Libguestfs mailing list
<a class="moz-txt-link-abbreviated" href="mailto:Libguestfs@redhat.com">Libguestfs@redhat.com</a>
<a class="moz-txt-link-freetext" href="https://www.redhat.com/mailman/listinfo/libguestfs">https://www.redhat.com/mailman/listinfo/libguestfs</a></pre>
    </blockquote>
    <br>
  </body>
</html>