On Tuesday 29 March 2016 20:35:52 Matteo Cafasso wrote: > Signed-off-by: Matteo Cafasso <[email protected]> > ---
See general notes sent as https://www.redhat.com/archives/libguestfs/2016-March/msg00269.html > daemon/Makefile.am | 3 +- > daemon/tsk.c | 186 > +++++++++++++++++++++++++++++++++++++++++++++++++++ > generator/actions.ml | 16 +++++ > m4/guestfs_daemon.m4 | 8 +++ > src/MAX_PROC_NR | 2 +- > 5 files changed, 213 insertions(+), 2 deletions(-) > > diff --git a/daemon/Makefile.am b/daemon/Makefile.am > index 4e2051b..036def9 100644 > --- a/daemon/Makefile.am > +++ b/daemon/Makefile.am > @@ -209,7 +209,8 @@ guestfsd_LDADD = \ > $(LIB_CLOCK_GETTIME) \ > $(LIBINTL) \ > $(SERVENT_LIB) \ > - $(PCRE_LIBS) > + $(PCRE_LIBS) \ > + $(TSK_LIBS) > > guestfsd_CPPFLAGS = \ > -I$(top_srcdir)/gnulib/lib \ > diff --git a/daemon/tsk.c b/daemon/tsk.c > index b84dfae..d72868e 100644 > --- a/daemon/tsk.c > +++ b/daemon/tsk.c > @@ -29,6 +29,26 @@ > #include "actions.h" > #include "optgroups.h" > > +#ifdef HAVE_LIBTSK > + > +#include <tsk/libtsk.h> > +#include <rpc/xdr.h> > +#include <rpc/types.h> > + > +static int > +open_filesystem(const char *device, TSK_IMG_INFO **img, TSK_FS_INFO **fs); > +static TSK_WALK_RET_ENUM > +fswalk_callback(TSK_FS_FILE *fsfile, const char *path, void *data); > +static char *join_path(const char *path, const char *name); > +static int inode_out(guestfs_int_tsk_node *node_info); > +static void reply_with_tsk_error(void); > + > +#else > + > +OPTGROUP_LIBTSK_NOT_AVAILABLE > + > +#endif > + > static int file_out (const char *cmd); > static guestfs_int_tsk_node* parse_ffind (const char *out, int64_t inode); > > @@ -226,3 +246,169 @@ file_out (const char *cmd) > > return 0; > } > + > +#ifdef HAVE_LIBTSK > + > + > +int optgroup_libtsk_available(void) > +{ > + return 1; > +} > + > +int do_filesystem_walk0(const mountable_t *mountable) > +{ > + int ret = 0; > + TSK_FS_INFO *fs = NULL; > + TSK_IMG_INFO *img = NULL; > + int flags = TSK_FS_DIR_WALK_FLAG_ALLOC | TSK_FS_DIR_WALK_FLAG_UNALLOC | > + TSK_FS_DIR_WALK_FLAG_RECURSE | TSK_FS_DIR_WALK_FLAG_NOORPHAN; > + > + if (open_filesystem(mountable->device, &img, &fs) < 0) > + return -1; > + > + reply(NULL, NULL); /* Reply message. */ > + > + if (tsk_fs_dir_walk(fs, fs->root_inum, flags, fswalk_callback, &ret) != 0) > { > + send_file_end(1); /* Cancel file transfer. */ > + reply_with_tsk_error(); > + > + ret = -1; > + } > + else { > + if (send_file_end(0)) /* Normal end of file. */ > + ret = -1; > + > + ret = 0; This ret = 0 will always override the ret = -1 done two lines above. > + } > + > + fs->close(fs); > + img->close(img); > + > + return ret; > +} > + > +/* Inspect the device and initialises the img and fs structures. > + * Return 0 on success, -1 on error. > + */ > +static int > +open_filesystem(const char *device, TSK_IMG_INFO **img, TSK_FS_INFO **fs) > +{ > + const char *images[] = { device }; > + > + if ((*img = tsk_img_open(1, images, TSK_IMG_TYPE_DETECT , 0)) == NULL) { > + reply_with_tsk_error(); > + > + return -1; > + } > + > + if ((*fs = tsk_fs_open_img(*img, 0, TSK_FS_TYPE_DETECT)) == NULL) { > + reply_with_tsk_error(); > + > + (*img)->close(*img); > + > + return -1; > + } > + > + return 0; > +} > + > +/* Filesystem walk callback, it gets called on every FS node. > + * Parse the node, encode it into an XDR structure and send it to the > appliance. > + * Return 0 on success, -1 on error. > + */ > +static TSK_WALK_RET_ENUM > +fswalk_callback(TSK_FS_FILE *fsfile, const char *path, void *data) > +{ > + CLEANUP_FREE char *file_name = NULL; > + struct guestfs_int_tsk_node node_info; > + > + /* Ignore ./ and ../ */ > + if (TSK_FS_ISDOT(fsfile->name->name)) > + return 0; Considering the function returns a TSK_WALK_RET_ENUM, then better use the enum values explicitly (TSK_WALK_CONT, etc), instead of numbers. Other than making it clear what the return value means, it also protects us in the eventual case the API breaks and the enum values are changed. > + > + if ((file_name = join_path(path, fsfile->name->name)) == NULL) > + return -1; The whole join_path seems superfluous, a simple asprintf here does the same. > + node_info.tsk_name = file_name; > + node_info.tsk_inode = fsfile->name->meta_addr; > + if (fsfile->name->flags & TSK_FS_NAME_FLAG_UNALLOC) > + node_info.tsk_allocated = 0; > + else > + node_info.tsk_allocated = 1; Not a real issue, but IMHO node_info.tsk_allocated = fsfile->name->flags & TSK_FS_NAME_FLAG_UNALLOC; would be preferable. YMMV. > + return inode_out(&node_info); inode_out returns -1 on error, which is not a value of the enum TSK_WALK_RET_ENUM. > +} > + > +/* Joins the file name and file path. > + * Return the joined path on success, NULL on failure. > + */ > +static char *join_path(const char *path, const char *name) > +{ > + char *buf; > + size_t len; > + > + path = (path != NULL) ? path : ""; > + len = strlen(path) + strlen(name) + 1; > + > + if (!(buf = malloc(len))) { > + reply_with_perror("malloc"); > + return NULL; > + } > + > + snprintf(buf, len, "%s%s", path, name); > + > + return buf; > +} > + > +/* Serialise node_info into XDR stream and send it to the appliance. > + * Return 0 on success, -1 on error. > + */ > +static int inode_out(guestfs_int_tsk_node *node_info) > +{ > + XDR xdr; > + size_t len; > + CLEANUP_FREE char *buf; > + > + if ((buf = malloc(GUESTFS_MAX_CHUNK_SIZE)) == NULL) { > + reply_with_perror ("malloc"); > + return -1; > + } > + > + /* Serialise tsk_node struct. */ > + len = strlen(node_info->tsk_name) + 1; > + > + xdrmem_create(&xdr, buf, GUESTFS_MAX_CHUNK_SIZE, XDR_ENCODE); > + if (!xdr_u_long(&xdr, &len)) > + return -1; > + if (!xdr_string(&xdr, &node_info->tsk_name, len)) > + return -1; > + if (!xdr_uint64_t(&xdr, &node_info->tsk_inode)) > + return -1; > + if (!xdr_uint32_t(&xdr, &node_info->tsk_allocated)) > + return -1; > + > + /* Resize buffer to actual length. */ > + len = xdr_getpos(&xdr); > + xdr_destroy(&xdr); > + if ((buf = realloc(buf, len)) == NULL) > + return -1; > + > + /* Send serialised tsk_node out. */ > + if (send_file_write(buf, len) < 0) > + return -1; > + > + return 0; > +} > + > +/* Parse TSK error and send it to the appliance. */ > +static void reply_with_tsk_error(void) > +{ > + const char *buf = NULL; > + > + if (tsk_error_get_errno() != 0) { > + buf = tsk_error_get(); > + reply_with_error("TSK error: %s", buf); > + } reply_with_tsk_error is called when some tsk function fails, so it must always report an error; makes sure to send something like "$function failed, unknown errno" or so in case tsk_error_get_errno returns 0. Hint: pass the name of the failed function as parameter to this helper, so the error message shows what failed. > diff --git a/generator/actions.ml b/generator/actions.ml > index 2d291fb..e33655a 100644 > --- a/generator/actions.ml > +++ b/generator/actions.ml > @@ -13015,6 +13015,22 @@ given its inode. > > On some filesystem, it can find deleted files." }; > > + { defaults with > + name = "filesystem_walk0"; added = (1, 33, 16); The next version now is 1.33.17. > + style = RErr, [Mountable "device"; FileOut "filename";], []; > + proc_nr = Some 468; It should be 465... > + optional = Some "libtsk"; > + progress = true; cancellable = true; > + shortdesc = "walks through the filesystem content"; > + longdesc = "\ > +This specialised command is used to 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. > + > +For each file or directory found, the function reports its path, its inode > and whether > +it is allocated or not. > + > +The output is stored in F<filename> on the host encoded in XDR format." }; The XDR encoding of the resulting file is basically meaningless to users of the libguestfs API. Considering this function seems to be only an helper for filesystem_walk, then I'd say it needs to be internal (see internal_feature_available for an example). Thanks, -- Pino Toscano
signature.asc
Description: This is a digitally signed message part.
_______________________________________________ Libguestfs mailing list [email protected] https://www.redhat.com/mailman/listinfo/libguestfs
