[Libguestfs] [PATCH v3 4/5] appliance: Added filesystem_walk command

Pino Toscano ptoscano at redhat.com
Tue Apr 5 17:26:56 UTC 2016


"appliance: Added filesystem_walk command"

-> "New API: filesystem_walk"

On Tuesday 05 April 2016 18:47:31 Matteo Cafasso wrote:
> The filesystem_walk command is the appliance's
> counterpart of the daemon's internal_filesystem_walk command.

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.

> 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 <noxdafox at gmail.com>
> ---
>  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'.

Use POD C<..> for the special values 0, -1, 'u'.

> +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 );

Extra space at the end.

> +int deserialise_dirent_list (guestfs_h *, char *, size_t , struct guestfs_tsk_dirent_list *);

deserialise_dirent_list can be static.

> +
> +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);

I think there should be checks for the size of the downloaded file, to
avoid reading too much.

> +  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));

I think this should not be needed at all, the XDR decoding should set
every field in the struct.

> +    ret = xdr_guestfs_int_tsk_dirent(&xdr, (guestfs_int_tsk_dirent *)

Why is "(guestfs_int_tsk_dirent *)" needed?  (Also, missing space.)

Thanks,
-- 
Pino Toscano
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: This is a digitally signed message part.
URL: <http://listman.redhat.com/archives/libguestfs/attachments/20160405/3338e7ac/attachment.sig>


More information about the Libguestfs mailing list