mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-22 07:03:38 +00:00
New APIs: ntfsclone-in, ntfsclone-out.
This commit is contained in:
@@ -41,6 +41,7 @@ SUBDIRS += tests/protocol
|
||||
SUBDIRS += tests/lvm
|
||||
SUBDIRS += tests/luks
|
||||
SUBDIRS += tests/md
|
||||
SUBDIRS += tests/ntfsclone
|
||||
SUBDIRS += tests/regressions
|
||||
endif
|
||||
|
||||
|
||||
2
TODO
2
TODO
@@ -385,8 +385,6 @@ ntfslabel: display or change filesystem label (we should unify all
|
||||
set*label APIs into a single set_vfs_label which can deal with any
|
||||
filesystem)
|
||||
|
||||
ntfsclone: clone, image, restore, rescue NTFS
|
||||
|
||||
ntfscluster: display file(s) that occupy a cluster or sector
|
||||
|
||||
ntfsinfo: print various information about NTFS volume and files
|
||||
|
||||
@@ -1146,6 +1146,7 @@ AC_CONFIG_FILES([Makefile
|
||||
tests/luks/Makefile
|
||||
tests/lvm/Makefile
|
||||
tests/md/Makefile
|
||||
tests/ntfsclone/Makefile
|
||||
tests/protocol/Makefile
|
||||
tests/qemu/Makefile
|
||||
tests/regressions/Makefile
|
||||
|
||||
@@ -137,6 +137,7 @@ guestfsd_SOURCES = \
|
||||
mount.c \
|
||||
names.c \
|
||||
ntfs.c \
|
||||
ntfsclone.c \
|
||||
optgroups.c \
|
||||
optgroups.h \
|
||||
parted.c \
|
||||
|
||||
212
daemon/ntfsclone.c
Normal file
212
daemon/ntfsclone.c
Normal file
@@ -0,0 +1,212 @@
|
||||
/* libguestfs - the guestfsd daemon
|
||||
* Copyright (C) 2009-2012 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 <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "read-file.h"
|
||||
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
#include "optgroups.h"
|
||||
|
||||
/* Read the error file. Returns a string that the caller must free. */
|
||||
static char *
|
||||
read_error_file (char *error_file)
|
||||
{
|
||||
size_t len;
|
||||
char *str;
|
||||
|
||||
str = read_file (error_file, &len);
|
||||
if (str == NULL) {
|
||||
str = strdup ("(no error)");
|
||||
if (str == NULL) {
|
||||
perror ("strdup");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
len = strlen (str);
|
||||
}
|
||||
|
||||
/* Remove trailing \n character if any. */
|
||||
if (len > 0 && str[len-1] == '\n')
|
||||
str[--len] = '\0';
|
||||
|
||||
return str; /* caller frees */
|
||||
}
|
||||
|
||||
static int
|
||||
write_cb (void *fd_ptr, const void *buf, size_t len)
|
||||
{
|
||||
int fd = *(int *)fd_ptr;
|
||||
return xwrite (fd, buf, len);
|
||||
}
|
||||
|
||||
/* Has one FileIn parameter. */
|
||||
int
|
||||
do_ntfsclone_in (const char *device)
|
||||
{
|
||||
int err, r;
|
||||
FILE *fp;
|
||||
char *cmd;
|
||||
char error_file[] = "/tmp/ntfscloneXXXXXX";
|
||||
int fd;
|
||||
|
||||
fd = mkstemp (error_file);
|
||||
if (fd == -1) {
|
||||
reply_with_perror ("mkstemp");
|
||||
return -1;
|
||||
}
|
||||
|
||||
close (fd);
|
||||
|
||||
/* Construct the command. */
|
||||
if (asprintf_nowarn (&cmd, "ntfsclone -O %s --restore-image - 2> %s",
|
||||
device, error_file) == -1) {
|
||||
err = errno;
|
||||
r = cancel_receive ();
|
||||
errno = err;
|
||||
reply_with_perror ("asprintf");
|
||||
unlink (error_file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
fprintf (stderr, "%s\n", cmd);
|
||||
|
||||
fp = popen (cmd, "w");
|
||||
if (fp == NULL) {
|
||||
err = errno;
|
||||
r = cancel_receive ();
|
||||
errno = err;
|
||||
reply_with_perror ("%s", cmd);
|
||||
unlink (error_file);
|
||||
free (cmd);
|
||||
return -1;
|
||||
}
|
||||
free (cmd);
|
||||
|
||||
/* The semantics of fwrite are too undefined, so write to the
|
||||
* file descriptor directly instead.
|
||||
*/
|
||||
fd = fileno (fp);
|
||||
|
||||
r = receive_file (write_cb, &fd);
|
||||
if (r == -1) { /* write error */
|
||||
cancel_receive ();
|
||||
char *errstr = read_error_file (error_file);
|
||||
reply_with_error ("write error on device: %s: %s", device, errstr);
|
||||
free (errstr);
|
||||
unlink (error_file);
|
||||
pclose (fp);
|
||||
return -1;
|
||||
}
|
||||
if (r == -2) { /* cancellation from library */
|
||||
/* This error is ignored by the library since it initiated the
|
||||
* cancel. Nevertheless we must send an error reply here.
|
||||
*/
|
||||
reply_with_error ("ntfsclone cancelled");
|
||||
pclose (fp);
|
||||
unlink (error_file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pclose (fp) != 0) {
|
||||
char *errstr = read_error_file (error_file);
|
||||
reply_with_error ("ntfsclone subcommand failed on device: %s: %s",
|
||||
device, errstr);
|
||||
free (errstr);
|
||||
unlink (error_file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
unlink (error_file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Has one FileOut parameter. */
|
||||
/* Takes optional arguments, consult optargs_bitmask. */
|
||||
int
|
||||
do_ntfsclone_out (const char *device,
|
||||
int metadataonly, int rescue, int ignorefscheck,
|
||||
int preservetimestamps, int force)
|
||||
{
|
||||
int r;
|
||||
FILE *fp;
|
||||
char *cmd;
|
||||
char buf[GUESTFS_MAX_CHUNK_SIZE];
|
||||
|
||||
/* Construct the ntfsclone command. */
|
||||
if (asprintf (&cmd, "ntfsclone -o - --save-image%s%s%s%s%s %s",
|
||||
(optargs_bitmask & GUESTFS_NTFSCLONE_OUT_METADATAONLY_BITMASK) && metadataonly ? " --metadata" : "",
|
||||
(optargs_bitmask & GUESTFS_NTFSCLONE_OUT_RESCUE_BITMASK) && rescue ? " --rescue" : "",
|
||||
(optargs_bitmask & GUESTFS_NTFSCLONE_OUT_IGNOREFSCHECK_BITMASK) && ignorefscheck ? " --ignore-fs-check" : "",
|
||||
(optargs_bitmask & GUESTFS_NTFSCLONE_OUT_PRESERVETIMESTAMPS_BITMASK) && preservetimestamps ? " --preserve-timestamps" : "",
|
||||
(optargs_bitmask & GUESTFS_NTFSCLONE_OUT_FORCE_BITMASK) && force ? " --force" : "",
|
||||
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);
|
||||
free (cmd);
|
||||
return -1;
|
||||
}
|
||||
free (cmd);
|
||||
|
||||
/* 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 (buf, 1, sizeof buf, fp)) > 0) {
|
||||
if (send_file_write (buf, r) < 0) {
|
||||
pclose (fp);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ferror (fp)) {
|
||||
perror (device);
|
||||
send_file_end (1); /* Cancel. */
|
||||
pclose (fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pclose (fp) != 0) {
|
||||
perror (device);
|
||||
send_file_end (1); /* Cancel. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (send_file_end (0)) /* Normal end of file. */
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -6682,6 +6682,33 @@ scan the filesystem for inconsistencies.
|
||||
The optional C<clearbadsectors> flag clears the list of bad sectors.
|
||||
This is useful after cloning a disk with bad sectors to a new disk.");
|
||||
|
||||
("ntfsclone_out", (RErr, [Device "device"; FileOut "backupfile"], [OBool "metadataonly"; OBool "rescue"; OBool "ignorefscheck"; OBool "preservetimestamps"; OBool "force"]), 308, [Optional "ntfs3g"; Cancellable],
|
||||
[], (* tested in tests/ntfsclone *)
|
||||
"save NTFS to backup file",
|
||||
"\
|
||||
Stream the NTFS filesystem C<device> to the local file
|
||||
C<backupfile>. The format used for the backup file is a
|
||||
special format used by the L<ntfsclone(8)> tool.
|
||||
|
||||
If the optional C<metadataonly> flag is true, then I<only> the
|
||||
metadata is saved, losing all the user data (this is useful
|
||||
for diagnosing some filesystem problems).
|
||||
|
||||
The optional C<rescue>, C<ignorefscheck>, C<preservetimestamps>
|
||||
and C<force> flags have precise meanings detailed in the
|
||||
L<ntfsclone(8)> man page.
|
||||
|
||||
Use C<guestfs_ntfsclone_in> to restore the file back to a
|
||||
libguestfs device.");
|
||||
|
||||
("ntfsclone_in", (RErr, [FileIn "backupfile"; Device "device"], []), 309, [Optional "ntfs3g"; Cancellable],
|
||||
[], (* tested in tests/ntfsclone *)
|
||||
"restore NTFS from backup file",
|
||||
"\
|
||||
Restore the C<backupfile> (from a previous call to
|
||||
C<guestfs_ntfsclone_out>) to C<device>, overwriting
|
||||
any existing contents of this device.");
|
||||
|
||||
]
|
||||
|
||||
let all_functions = non_daemon_functions @ daemon_functions
|
||||
|
||||
@@ -56,6 +56,7 @@ daemon/modprobe.c
|
||||
daemon/mount.c
|
||||
daemon/names.c
|
||||
daemon/ntfs.c
|
||||
daemon/ntfsclone.c
|
||||
daemon/optgroups.c
|
||||
daemon/parted.c
|
||||
daemon/pingdaemon.c
|
||||
|
||||
@@ -1 +1 @@
|
||||
307
|
||||
309
|
||||
|
||||
30
tests/ntfsclone/Makefile.am
Normal file
30
tests/ntfsclone/Makefile.am
Normal file
@@ -0,0 +1,30 @@
|
||||
# libguestfs
|
||||
# Copyright (C) 2012 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-ntfsclone.sh
|
||||
|
||||
random_val := $(shell awk 'BEGIN{srand(); print 1+int(255*rand())}' < /dev/null)
|
||||
|
||||
TESTS_ENVIRONMENT = \
|
||||
MALLOC_PERTURB_=$(random_val) \
|
||||
$(top_builddir)/run
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(TESTS)
|
||||
54
tests/ntfsclone/test-ntfsclone.sh
Executable file
54
tests/ntfsclone/test-ntfsclone.sh
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/bin/bash -
|
||||
# libguestfs
|
||||
# Copyright (C) 2012 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 ntfsclone-in/-out commands.
|
||||
|
||||
set -e
|
||||
|
||||
rm -f test1.img backup1 backup2
|
||||
|
||||
guestfish=../../fish/guestfish
|
||||
|
||||
# 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 0
|
||||
fi
|
||||
|
||||
# Export the filesystems to the backup file.
|
||||
$guestfish --ro -a ../guests/windows.img <<EOF
|
||||
run
|
||||
ntfsclone-out /dev/sda1 backup1 preservetimestamps:true force:true
|
||||
ntfsclone-out /dev/sda2 backup2 metadataonly:true ignorefscheck:true
|
||||
EOF
|
||||
|
||||
# Restore to another disk image.
|
||||
output=$($guestfish -N part:300M <<EOF
|
||||
ntfsclone-in backup1 /dev/sda1
|
||||
vfs-type /dev/sda1
|
||||
EOF
|
||||
)
|
||||
|
||||
if [ "$output" != "ntfs" ]; then
|
||||
echo "$0: unexpected filesystem type after restore: $output"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#ls -lh backup[12]
|
||||
|
||||
rm -f test1.img backup1 backup2
|
||||
Reference in New Issue
Block a user