Adding ntfscat_i command for downloading files based on their inode number. This allows the dowload of files unaccessible otherwise from a NTFS guest disk image. Signed-off-by: Matteo Cafasso <noxdafox@gmail.com> --- daemon/ntfs.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++ generator/actions.ml | 15 +++++++++++++ 2 files changed, 77 insertions(+) diff --git a/daemon/ntfs.c b/daemon/ntfs.c index 568899e..58f62fa 100644 --- a/daemon/ntfs.c +++ b/daemon/ntfs.c @@ -266,3 +266,65 @@ do_ntfsfix (const char *device, int clearbadsectors) return 0; } + +int +do_ntfscat_i (const mountable_t *mountable, int64_t inode) +{ + int r; + FILE *fp; + CLEANUP_FREE char *cmd = NULL; + char buffer[GUESTFS_MAX_CHUNK_SIZE]; + + /* Inode must be greater than 0 */ + if (inode < 0) { + reply_with_error("Inode must be greater than 0"); + return -1; + } + + /* Construct the command. */ + if (asprintf_nowarn (&cmd, "ntfscat -i %ld %s", + inode, mountable->device) == -1) { + reply_with_perror ("asprintf"); + return -1; + } + + if (verbose) + fprintf (stderr, "%s\n", cmd); + + fp = popen (cmd, "r"); + if (fp == NULL) { + reply_with_perror ("%s", cmd); + return -1; + } + + /* Now we must send the reply message, before the file contents. After + * this there is no opportunity in the protocol to send any error + * message back. Instead we can only cancel the transfer. + */ + reply (NULL, NULL); + + while ((r = fread (buffer, 1, sizeof buffer, fp)) > 0) { + if (send_file_write (buffer, r) < 0) { + pclose (fp); + return -1; + } + } + + if (ferror (fp)) { + fprintf (stderr, "fread: %ld: %m\n", inode); + send_file_end (1); /* Cancel. */ + pclose (fp); + return -1; + } + + if (pclose (fp) != 0) { + fprintf (stderr, "pclose: %ld: %m\n", inode); + send_file_end (1); /* Cancel. */ + return -1; + } + + if (send_file_end (0)) /* Normal end of file. */ + return -1; + + return 0; +} diff --git a/generator/actions.ml b/generator/actions.ml index eb45392..18418aa 100644 --- a/generator/actions.ml +++ b/generator/actions.ml @@ -12891,6 +12891,21 @@ This is equivalent to C<sgdisk -e>. See also L<sgdisk(8)>." }; + { defaults with + name = "ntfscat_i"; added = (1, 33, 2); + style = RErr, [Mountable "device"; Int64 "inode"; FileOut "filename"], []; + proc_nr = Some 463; + progress = true; cancellable = true; + shortdesc = "download a file to the local machine given its inode"; + longdesc = "\ +Download a file given its inode from a NTFS filesystem and save it as F<filename> +on the local machine. + +This allows to download some otherwise unaccessible files such as the ones +within the $Extend folder. + +F<filename> can also be a named pipe." }; + ] (* Non-API meta-commands available only in guestfish. -- 2.7.0
Test is based on file signature, it checks whether the extracted file is the $MFT. Signed-off-by: Matteo Cafasso <noxdafox@gmail.com> --- Makefile.am | 1 + configure.ac | 1 + generator/actions.ml | 6 ++++- tests/ntfscat/Makefile.am | 26 +++++++++++++++++++++ tests/ntfscat/test-ntfscat.sh | 53 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 tests/ntfscat/Makefile.am create mode 100755 tests/ntfscat/test-ntfscat.sh diff --git a/Makefile.am b/Makefile.am index ba99feb..1ab85e8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -66,6 +66,7 @@ SUBDIRS += tests/luks SUBDIRS += tests/md SUBDIRS += tests/selinux SUBDIRS += tests/ntfsclone +SUBDIRS += tests/ntfscat SUBDIRS += tests/btrfs SUBDIRS += tests/xfs SUBDIRS += tests/charsets diff --git a/configure.ac b/configure.ac index 29b5092..7598b5f 100644 --- a/configure.ac +++ b/configure.ac @@ -272,6 +272,7 @@ AC_CONFIG_FILES([Makefile tests/nbd/Makefile tests/network/Makefile tests/ntfsclone/Makefile + tests/ntfscat/Makefile tests/parallel/Makefile tests/protocol/Makefile tests/qemu/Makefile diff --git a/generator/actions.ml b/generator/actions.ml index 18418aa..0c71389 100644 --- a/generator/actions.ml +++ b/generator/actions.ml @@ -12892,10 +12892,11 @@ This is equivalent to C<sgdisk -e>. See also L<sgdisk(8)>." }; { defaults with - name = "ntfscat_i"; added = (1, 33, 2); + name = "ntfscat_i"; added = (1, 33, 12); style = RErr, [Mountable "device"; Int64 "inode"; FileOut "filename"], []; proc_nr = Some 463; progress = true; cancellable = true; + test_excuse = "tested in tests/ntfscat"; shortdesc = "download a file to the local machine given its inode"; longdesc = "\ Download a file given its inode from a NTFS filesystem and save it as F<filename> @@ -12904,6 +12905,9 @@ on the local machine. This allows to download some otherwise unaccessible files such as the ones within the $Extend folder. +The filesystem from which to extract the file must be unmounted, +otherwise the call will fail. + F<filename> can also be a named pipe." }; ] diff --git a/tests/ntfscat/Makefile.am b/tests/ntfscat/Makefile.am new file mode 100644 index 0000000..dc64c3d --- /dev/null +++ b/tests/ntfscat/Makefile.am @@ -0,0 +1,26 @@ +# 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. + +include $(top_srcdir)/subdir-rules.mk + +TESTS = \ + test-ntfscat.sh + +TESTS_ENVIRONMENT = $(top_builddir)/run --test + +EXTRA_DIST = \ + $(TESTS) diff --git a/tests/ntfscat/test-ntfscat.sh b/tests/ntfscat/test-ntfscat.sh new file mode 100755 index 0000000..5cfdd95 --- /dev/null +++ b/tests/ntfscat/test-ntfscat.sh @@ -0,0 +1,53 @@ +#!/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 ntfscat-i command. + +set -e + +if [ -n "$SKIP_TEST_NTFSCAT_SH" ]; then + echo "$0: test skipped because environment variable is set." + exit 77 +fi + +rm -f test-mft.bin + +# Skip if ntfs-3g is not supported by the appliance. +if ! guestfish add /dev/null : run : available "ntfs3g"; then + echo "$0: skipped because ntfs-3g is not supported by 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 + +# download Master File Table ($MFT). +guestfish --ro -a ../../test-data/phony-guests/windows.img <<EOF +run +ntfscat-i /dev/sda2 0 test-mft.bin +EOF + +# test extracted file is the Master File Table +if [ `head -c 5 test-mft.bin` != "FILE0" ]; then + echo "$0: wrong file extracted." + exit 1 +fi + +rm -f test-mft.bin -- 2.7.0
Richard W.M. Jones
2016-Mar-01 09:07 UTC
Re: [Libguestfs] [PATCH 2/2] added ntfscat_i tests
Thanks - I have pushed both. Note that I made some minor cleanups to both patches. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com virt-p2v converts physical machines to virtual machines. Boot with a live CD or over the network (PXE) and turn machines into KVM guests. http://libguestfs.org/virt-v2v