v7: - Merge src/tsk.c refactoring patch with #4 of find_block series Matteo Cafasso (4): lib: logic refactoring New API: internal_find_inode New API: find_inode find_inode: added API tests daemon/tsk.c | 52 ++++++++++++++++++++++++++++++++++ generator/actions.ml | 21 ++++++++++++++ src/MAX_PROC_NR | 2 +- src/tsk.c | 52 ++++++++++++++++++++++++++-------- tests/tsk/Makefile.am | 3 +- tests/tsk/test-find-inode.sh | 66 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 182 insertions(+), 14 deletions(-) create mode 100755 tests/tsk/test-find-inode.sh -- 2.9.3
Code changes in preparation for new APIs. Signed-off-by: Matteo Cafasso <noxdafox@gmail.com> --- src/tsk.c | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/src/tsk.c b/src/tsk.c index 90177ab..ecafcb7 100644 --- a/src/tsk.c +++ b/src/tsk.c @@ -34,44 +34,43 @@ #include "guestfs-internal-all.h" #include "guestfs-internal-actions.h" -static struct guestfs_tsk_dirent_list *parse_filesystem_walk (guestfs_h *, FILE *); +static struct guestfs_tsk_dirent_list *parse_dirent_file (guestfs_h *, const char *); static int deserialise_dirent_list (guestfs_h *, FILE *, struct guestfs_tsk_dirent_list *); +static char *make_temp_file (guestfs_h *, const char *); struct guestfs_tsk_dirent_list * guestfs_impl_filesystem_walk (guestfs_h *g, const char *mountable) { int ret = 0; - CLEANUP_FCLOSE FILE *fp = NULL; CLEANUP_UNLINK_FREE char *tmpfile = NULL; - ret = guestfs_int_lazy_make_tmpdir (g); - if (ret < 0) + tmpfile = make_temp_file (g, "filesystem_walk"); + if (tmpfile == NULL) 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; - fp = fopen (tmpfile, "r"); - if (fp == NULL) { - perrorf (g, "fopen: %s", tmpfile); - return NULL; - } - - return parse_filesystem_walk (g, fp); /* caller frees */ + return parse_dirent_file (g, tmpfile); /* caller frees */ } /* Parse the file 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, FILE *fp) +parse_dirent_file (guestfs_h *g, const char *tmpfile) { int ret = 0; + CLEANUP_FCLOSE FILE *fp = NULL; struct guestfs_tsk_dirent_list *dirents = NULL; + fp = fopen (tmpfile, "r"); + if (fp == NULL) { + perrorf (g, "fopen: %s", tmpfile); + return NULL; + } + /* Initialise results array. */ dirents = safe_malloc (g, sizeof (*dirents)); dirents->len = 8; @@ -126,3 +125,15 @@ deserialise_dirent_list (guestfs_h *g, FILE *fp, return ret ? 0 : -1; } + +static char * +make_temp_file (guestfs_h *g, const char *name) +{ + int ret = 0; + + ret = guestfs_int_lazy_make_tmpdir (g); + if (ret < 0) + return NULL; + + return safe_asprintf (g, "%s/%s%d", g->tmpdir, name, ++g->unique); +} -- 2.9.3
Matteo Cafasso
2016-Sep-19 16:42 UTC
[Libguestfs] [PATCH v7 2/4] New API: internal_find_inode
The internal_find_inode command searches all entries referring to the given inode and returns a tsk_dirent structure for each of them. The command is able to retrieve information regarding deleted or unaccessible files where other commands such as stat or find would fail. The gathered list of tsk_dirent structs is serialised into XDR format and written to a file by the appliance. Signed-off-by: Matteo Cafasso <noxdafox@gmail.com> --- daemon/tsk.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ generator/actions.ml | 9 +++++++++ src/MAX_PROC_NR | 2 +- 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/daemon/tsk.c b/daemon/tsk.c index e5669da..af803d7 100644 --- a/daemon/tsk.c +++ b/daemon/tsk.c @@ -44,6 +44,7 @@ enum tsk_dirent_flags { static int open_filesystem (const char *, TSK_IMG_INFO **, TSK_FS_INFO **); static TSK_WALK_RET_ENUM fswalk_callback (TSK_FS_FILE *, const char *, void *); +static TSK_WALK_RET_ENUM findino_callback (TSK_FS_FILE *, const char *, void *); static int send_dirent_info (TSK_FS_FILE *, const char *); static char file_type (TSK_FS_FILE *); static int file_flags (TSK_FS_FILE *fsfile); @@ -79,6 +80,35 @@ do_internal_filesystem_walk (const mountable_t *mountable) return ret; } +int +do_internal_find_inode (const mountable_t *mountable, int64_t inode) +{ + int ret = -1; + TSK_FS_INFO *fs = NULL; + TSK_IMG_INFO *img = NULL; /* Used internally by tsk_fs_dir_walk */ + const 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; + + ret = open_filesystem (mountable->device, &img, &fs); + if (ret < 0) + return ret; + + reply (NULL, NULL); /* Reply message. */ + + ret = tsk_fs_dir_walk (fs, fs->root_inum, flags, + findino_callback, (void *) &inode); + if (ret == 0) + ret = send_file_end (0); /* File transfer end. */ + else + send_file_end (1); /* Cancel file transfer. */ + + 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. */ @@ -120,6 +150,28 @@ fswalk_callback (TSK_FS_FILE *fsfile, const char *path, void *data) return (ret == 0) ? TSK_WALK_CONT : TSK_WALK_ERROR; } +/* Find inode, it gets called on every FS node. + * If the FS node address is the given one, parse it, + * encode it into an XDR structure and send it to the library. + * Return TSK_WALK_CONT on success, TSK_WALK_ERROR on error. + */ +static TSK_WALK_RET_ENUM +findino_callback (TSK_FS_FILE *fsfile, const char *path, void *data) +{ + int ret = 0; + uint64_t *inode = (uint64_t *) data; + + if (*inode != fsfile->name->meta_addr) + return TSK_WALK_CONT; + + if (entry_is_dot (fsfile)) + return TSK_WALK_CONT; + + ret = send_dirent_info (fsfile, path); + + return (ret == 0) ? TSK_WALK_CONT : TSK_WALK_ERROR; +} + /* Extract the information from the entry, serialize and send it out. * Return 0 on success, -1 on error. */ diff --git a/generator/actions.ml b/generator/actions.ml index 68ecee3..4e6627b 100644 --- a/generator/actions.ml +++ b/generator/actions.ml @@ -13232,6 +13232,15 @@ handle C<file>. If C<remove> is true (C<false> by default), then the transformation is removed." }; + { defaults with + name = "internal_find_inode"; added = (1, 35, 6); + style = RErr, [Mountable "device"; Int64 "inode"; FileOut "filename";], []; + proc_nr = Some 470; + visibility = VInternal; + optional = Some "libtsk"; + shortdesc = "search the entries associated to the given inode"; + longdesc = "Internal function for find_inode." }; + ] (* Non-API meta-commands available only in guestfish. diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR index 5ef9d24..5f476b6 100644 --- a/src/MAX_PROC_NR +++ b/src/MAX_PROC_NR @@ -1 +1 @@ -469 +470 -- 2.9.3
Library's counterpart of the daemon's internal_find_inode command. 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_find_inode command. Signed-off-by: Matteo Cafasso <noxdafox@gmail.com> --- generator/actions.ml | 12 ++++++++++++ src/tsk.c | 17 +++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/generator/actions.ml b/generator/actions.ml index 4e6627b..91a1819 100644 --- a/generator/actions.ml +++ b/generator/actions.ml @@ -3717,6 +3717,18 @@ Unknown file type =back" }; + { defaults with + name = "find_inode"; added = (1, 35, 6); + style = RStructList ("dirents", "tsk_dirent"), [Mountable "device"; Int64 "inode";], []; + optional = Some "libtsk"; + progress = true; cancellable = true; + shortdesc = "search the entries associated to the given inode"; + longdesc = "\ +Searches all the entries associated with the given inode. + +For each entry, a C<tsk_dirent> structure is returned. +See C<filesystem_walk> for more information about C<tsk_dirent> structures." }; + ] (* daemon_functions are any functions which cause some action diff --git a/src/tsk.c b/src/tsk.c index ecafcb7..1def9c9 100644 --- a/src/tsk.c +++ b/src/tsk.c @@ -55,6 +55,23 @@ guestfs_impl_filesystem_walk (guestfs_h *g, const char *mountable) return parse_dirent_file (g, tmpfile); /* caller frees */ } +struct guestfs_tsk_dirent_list * +guestfs_impl_find_inode (guestfs_h *g, const char *mountable, int64_t inode) +{ + int ret = 0; + CLEANUP_UNLINK_FREE char *tmpfile = NULL; + + tmpfile = make_temp_file (g, "find_inode"); + if (tmpfile == NULL) + return NULL; + + ret = guestfs_internal_find_inode (g, mountable, inode, tmpfile); + if (ret < 0) + return NULL; + + return parse_dirent_file (g, tmpfile); /* caller frees */ +} + /* Parse the file content and return dirents list. * Return a list of tsk_dirent on success, NULL on error. */ -- 2.9.3
Matteo Cafasso
2016-Sep-19 16:42 UTC
[Libguestfs] [PATCH v7 4/4] find_inode: added API tests
NTFS file system always has the MFT file at inode 0. This reliable information helps testing the API. Signed-off-by: Matteo Cafasso <noxdafox@gmail.com> --- tests/tsk/Makefile.am | 3 +- tests/tsk/test-find-inode.sh | 66 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100755 tests/tsk/test-find-inode.sh diff --git a/tests/tsk/Makefile.am b/tests/tsk/Makefile.am index 0b50839..07c74f9 100644 --- a/tests/tsk/Makefile.am +++ b/tests/tsk/Makefile.am @@ -20,7 +20,8 @@ include $(top_srcdir)/subdir-rules.mk TESTS = \ test-download-inode.sh \ test-download-blocks.sh \ - test-filesystem-walk.sh + test-filesystem-walk.sh \ + test-find-inode.sh TESTS_ENVIRONMENT = $(top_builddir)/run --test diff --git a/tests/tsk/test-find-inode.sh b/tests/tsk/test-find-inode.sh new file mode 100755 index 0000000..f69fcf6 --- /dev/null +++ b/tests/tsk/test-find-inode.sh @@ -0,0 +1,66 @@ +#!/bin/bash - +# libguestfs +# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +# Test the find-inode command. + +if [ -n "$SKIP_TEST_FIND_INODE_SH" ]; then + echo "$0: test skipped because environment variable is set." + exit 77 +fi + +# Skip if TSK is not supported by the appliance. +if ! guestfish add /dev/null : run : available "libtsk"; then + echo "$0: skipped because TSK is not available in the appliance" + exit 77 +fi + +if [ ! -s ../../test-data/phony-guests/windows.img ]; then + echo "$0: skipped because windows.img is zero-sized" + exit 77 +fi + +output=$( +guestfish --ro -a ../../test-data/phony-guests/windows.img <<EOF +run +find-inode /dev/sda2 0 +EOF +) + +# test $MFT is in the list +echo $output | grep -zq '{ tsk_inode: 0 +tsk_type: r +tsk_size: .* +tsk_name: \$MFT +tsk_flags: 1 +tsk_atime_sec: .* +tsk_atime_nsec: .* +tsk_mtime_sec: .* +tsk_mtime_nsec: .* +tsk_ctime_sec: .* +tsk_ctime_nsec: .* +tsk_crtime_sec: .* +tsk_crtime_nsec: .* +tsk_nlink: 1 +tsk_link: +tsk_spare1: 0 }' +if [ $? != 0 ]; then + echo "$0: \$MFT not found in files list." + echo "File list:" + echo $output + exit 1 +fi -- 2.9.3
On Monday, 19 September 2016 19:42:48 CEST Matteo Cafasso wrote:> v7: > > - Merge src/tsk.c refactoring patch with #4 of find_block series > > Matteo Cafasso (4): > lib: logic refactoring > New API: internal_find_inode > New API: find_inode > find_inode: added API testsLGTM, pushed. Thanks for the work, and all the patience to polish it! -- Pino Toscano