#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 <windows.h> 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 =
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;
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 {
"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 "
} 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);
}
}
}
+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;
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)
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) {
{
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)
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",
static void check_dest_free_space(u64 src_bytes)
{
+#ifndef HAVE_WINDOWS_H
u64 dest_bytes;
struct statvfs stvfs;
struct stat st;
"%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)
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) {
}
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);
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 */