From e6eae9fa16abf3a27b29c269953d63213612b0be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Sat, 9 Feb 2013 12:54:44 +0100 Subject: [PATCH] Ported ntfsclone to Windows This mainly means using the functions in win32_io.c instead of the standard msvcrt.dll ones in order to be able to truncate files and create sparse ones. --- ntfsprogs/ntfsclone.c | 110 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 98 insertions(+), 12 deletions(-) diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index 260e9903..d020586b 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -95,10 +95,37 @@ #define BLKGETSIZE64 _IOR(0x12,114,size_t) /* Get device size in bytes. */ #endif -#ifdef __sun +#if defined(linux) || defined(__uClinux__) || defined(__sun) \ + || defined(__APPLE__) || defined(__DARWIN__) + /* Make sure the presence of means compiling for Windows */ +#undef HAVE_WINDOWS_H +#endif + +#if defined(__sun) | defined(HAVE_WINDOWS_H) #define NO_STATFS 1 /* statfs(2) and f_type are not universal */ #endif +#ifdef HAVE_WINDOWS_H +/* + * Replacements for functions which do not exist on Windows + */ +int setmode(int, int); /* from msvcrt.dll */ + +#define getpid() (0) +#define srandom(seed) srand(seed) +#define random() rand() +#define fsync(fd) (0) +#define ioctl(fd,code,buf) (0) +#define ftruncate(fd, size) ntfs_device_win32_ftruncate(dev_out, size) +#define BINWMODE "wb" +#else +#define BINWMODE "w" +#endif + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + static const char *EXEC_NAME = "ntfsclone"; static const char *bad_sectors_warning_msg = @@ -172,6 +199,7 @@ static struct bitmap lcn_bitmap; static int fd_in; static int fd_out; static FILE *stream_out = (FILE*)NULL; +struct ntfs_device *dev_out = (struct ntfs_device*)NULL; static FILE *msg_out = NULL; static int wipe = 0; @@ -477,8 +505,14 @@ static void parse_options(int argc, char **argv) if (!opt.no_action && !opt.std_out) { struct stat st; +#ifdef HAVE_WINDOWS_H + BOOL blkdev = opt.output[0] && (opt.output[1] == ':') + && !opt.output[2]; + if (!blkdev && (stat(opt.output, &st) == -1)) { +#else if (stat(opt.output, &st) == -1) { +#endif if (errno != ENOENT) perr_exit("Couldn't access '%s'", opt.output); } else { @@ -487,7 +521,11 @@ static void parse_options(int argc, char **argv) "Use option --overwrite if you want to" " replace its content.\n", opt.output); +#ifdef HAVE_WINDOWS_H + if (blkdev) { +#else if (S_ISBLK(st.st_mode)) { +#endif opt.blkdev_out = 1; if (opt.metadata && !opt.force) err_exit("Cloning only metadata to a " @@ -606,6 +644,11 @@ static int io_all(void *fd, void *buf, int count, int do_write) } else { if (opt.save_image || opt.metadata_image) i = fwrite(buf, 1, count, stream_out); +#ifdef HAVE_WINDOWS_H + else if (dev_out) + i = dev_out->d_ops->write(dev_out, + buf, count); +#endif else i = write(*(int *)fd, buf, count); } @@ -778,6 +821,17 @@ static void copy_cluster(int rescue, u64 rescue_lcn, u64 lcn) } } +static s64 lseek_out(int fd, s64 pos, int mode) +{ + s64 ret; + + if (dev_out) + ret = (dev_out->d_ops->seek)(dev_out, pos, mode); + else + ret = lseek(fd, pos, mode); + return (ret); +} + static void lseek_to_cluster(s64 lcn) { off_t pos; @@ -790,8 +844,8 @@ static void lseek_to_cluster(s64 lcn) if (opt.std_out || opt.save_image || opt.metadata_image) return; - if (lseek(fd_out, pos, SEEK_SET) == (off_t)-1) - perr_exit("lseek output"); + if (lseek_out(fd_out, pos, SEEK_SET) == (off_t)-1) + perr_exit("lseek output"); } static void gap_to_cluster(s64 gap) @@ -975,11 +1029,12 @@ static void restore_image(void) err_exit("restore_image: corrupt image " "at input offset %lld\n", (long long)tellin(fd_in) - 9); - else + else { if (!opt.no_action - && (lseek(fd_out, count * csize, + && (lseek_out(fd_out, count * csize, SEEK_CUR) == (off_t)-1)) perr_exit("restore_image: lseek"); + } } pos += count; } else if (cmd == CMD_NEXT) { @@ -2215,9 +2270,13 @@ static s64 open_image(void) { if (strcmp(opt.volume, "-") == 0) { if ((fd_in = fileno(stdin)) == -1) - perr_exit("fileno for stdout failed"); + perr_exit("fileno for stdin failed"); +#ifdef HAVE_WINDOWS_H + if (setmode(fd_in,O_BINARY) == -1) + perr_exit("setting binary stdin failed"); +#endif } else { - if ((fd_in = open(opt.volume, O_RDONLY)) == -1) + if ((fd_in = open(opt.volume, O_RDONLY | O_BINARY)) == -1) perr_exit("failed to open image"); } if (read_all(&fd_in, &image_hdr, NTFSCLONE_IMG_HEADER_SIZE_OLD) == -1) @@ -2323,7 +2382,12 @@ static void initialise_image_hdr(s64 device_size, s64 inuse) static void check_output_device(s64 input_size) { if (opt.blkdev_out) { - s64 dest_size = device_size_get(fd_out); + s64 dest_size; + + if (dev_out) + dest_size = ntfs_device_size_get(dev_out, 1); + else + dest_size = device_size_get(fd_out); if (dest_size < input_size) err_exit("Output device is too small (%lld) to fit the " "NTFS image (%lld).\n", @@ -2414,6 +2478,7 @@ static void ignore_bad_clusters(ntfs_walk_clusters_ctx *image) static void check_dest_free_space(u64 src_bytes) { +#ifndef HAVE_WINDOWS_H u64 dest_bytes; struct statvfs stvfs; struct stat st; @@ -2446,6 +2511,7 @@ static void check_dest_free_space(u64 src_bytes) "%llu MB < %llu MB\n", (unsigned long long)rounded_up_division(dest_bytes, NTFS_MBYTE), (unsigned long long)rounded_up_division(src_bytes, NTFS_MBYTE)); +#endif } int main(int argc, char **argv) @@ -2486,9 +2552,13 @@ int main(int argc, char **argv) if ((fd_out = fileno(stdout)) == -1) perr_exit("fileno for stdout failed"); stream_out = stdout; +#ifdef HAVE_WINDOWS_H + if (setmode(fileno(stdout),O_BINARY) == -1) + perr_exit("setting binary stdout failed"); +#endif } else { /* device_size_get() might need to read() */ - int flags = O_RDWR; + int flags = O_RDWR | O_BINARY; fd_out = 0; if (!opt.blkdev_out) { @@ -2498,17 +2568,29 @@ int main(int argc, char **argv) } if (opt.save_image || opt.metadata_image) { - stream_out = fopen(opt.output,"w"); + stream_out = fopen(opt.output,BINWMODE); if (!stream_out) perr_exit("Opening file '%s' failed", opt.output); fd_out = fileno(stream_out); - } else + } else { +#ifdef HAVE_WINDOWS_H + if (!opt.no_action) { + dev_out = ntfs_device_alloc(opt.output, 0, + &ntfs_device_default_io_ops, NULL); + if (!dev_out + || (dev_out->d_ops->open)(dev_out, flags)) + perr_exit("Opening volume '%s' failed", + opt.output); + } +#else if (!opt.no_action && ((fd_out = open(opt.output, flags, S_IRUSR | S_IWUSR)) == -1)) perr_exit("Opening file '%s' failed", opt.output); +#endif + } if (!opt.save_image && !opt.metadata_image && !opt.no_action) check_output_device(ntfs_size); @@ -2558,7 +2640,11 @@ int main(int argc, char **argv) initialise_image_hdr(device_size, image.inuse); write_image_hdr(); } else { - fsync_clone(fd_out); /* sync copy before mounting */ + if (dev_out) { + (dev_out->d_ops->close)(dev_out); + dev_out = NULL; + } else + fsync_clone(fd_out); /* sync copy before mounting */ opt.volume = opt.output; /* 'force' again mount for dirty volumes (e.g. after resize). FIXME: use mount flags to avoid potential side-effects in future */