blob: cbbbc854a83c4dbb807d08e4c4e9f76c34759adc [file] [log] [blame]
Steve Kondik2111ad72013-07-07 12:07:44 -07001/**
2 * ntfsclone - Part of the Linux-NTFS project.
3 *
4 * Copyright (c) 2003-2006 Szabolcs Szakacsits
5 * Copyright (c) 2004-2006 Anton Altaparmakov
Steve Kondike68cb602016-08-28 00:45:36 -07006 * Copyright (c) 2010-2015 Jean-Pierre Andre
Steve Kondik2111ad72013-07-07 12:07:44 -07007 * Special image format support copyright (c) 2004 Per Olofsson
8 *
9 * Clone NTFS data and/or metadata to a sparse file, image, device or stdout.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 */
16
17#include "config.h"
18
19#ifdef HAVE_UNISTD_H
20#include <unistd.h>
21#endif
22#ifdef HAVE_STDLIB_H
23#include <stdlib.h>
24#endif
25#ifdef HAVE_STDIO_H
26#include <stdio.h>
27#endif
28#ifdef HAVE_SYS_TYPES_H
29#include <sys/types.h>
30#endif
31#ifdef HAVE_SYS_STAT_H
32#include <sys/stat.h>
33#endif
34#ifdef HAVE_TIME_H
35#include <time.h>
36#endif
37#ifdef HAVE_SYS_IOCTL_H
38#include <sys/ioctl.h>
39#endif
40#ifdef HAVE_SYS_VFS_H
41#include <sys/vfs.h>
42#endif
43#ifdef HAVE_SYS_STATVFS_H
44#include <sys/statvfs.h>
45#endif
46#ifdef HAVE_FCNTL_H
47#include <fcntl.h>
48#endif
49#ifdef HAVE_STDARG_H
50#include <stdarg.h>
51#endif
52#ifdef HAVE_STRING_H
53#include <string.h>
54#endif
55#ifdef HAVE_ERRNO_H
56#include <errno.h>
57#endif
58#ifdef HAVE_GETOPT_H
59#include <getopt.h>
60#endif
61#ifdef HAVE_UNISTD_H
62#include <unistd.h>
63#endif
Steve Kondik79165c32015-11-09 19:43:00 -080064#ifdef HAVE_SYS_MOUNT_H
65#include <sys/mount.h>
66#endif
Steve Kondik2111ad72013-07-07 12:07:44 -070067
68/*
69 * FIXME: ntfsclone do bad things about endians handling. Fix it and remove
70 * this note and define.
71 */
72#define NTFS_DO_NOT_CHECK_ENDIANS
73
74#include "debug.h"
75#include "types.h"
76#include "support.h"
77#include "endians.h"
78#include "bootsect.h"
79#include "device.h"
80#include "attrib.h"
81#include "mst.h"
82#include "volume.h"
83#include "mft.h"
84#include "bitmap.h"
85#include "inode.h"
86#include "index.h"
87#include "dir.h"
88#include "runlist.h"
89#include "ntfstime.h"
90#include "utils.h"
91/* #include "version.h" */
92#include "misc.h"
93
94#if defined(linux) && defined(_IO) && !defined(BLKGETSIZE)
95#define BLKGETSIZE _IO(0x12,96) /* Get device size in 512-byte blocks. */
96#endif
97#if defined(linux) && defined(_IOR) && !defined(BLKGETSIZE64)
98#define BLKGETSIZE64 _IOR(0x12,114,size_t) /* Get device size in bytes. */
99#endif
100
Steve Kondik79165c32015-11-09 19:43:00 -0800101#if defined(linux) || defined(__uClinux__) || defined(__sun) \
102 || defined(__APPLE__) || defined(__DARWIN__)
103 /* Make sure the presence of <windows.h> means compiling for Windows */
104#undef HAVE_WINDOWS_H
105#endif
106
107#if defined(__sun) | defined(HAVE_WINDOWS_H)
Steve Kondik2111ad72013-07-07 12:07:44 -0700108#define NO_STATFS 1 /* statfs(2) and f_type are not universal */
109#endif
110
Steve Kondik79165c32015-11-09 19:43:00 -0800111#ifdef HAVE_WINDOWS_H
112/*
113 * Replacements for functions which do not exist on Windows
114 */
115int setmode(int, int); /* from msvcrt.dll */
116
117#define getpid() (0)
118#define srandom(seed) srand(seed)
119#define random() rand()
120#define fsync(fd) (0)
121#define ioctl(fd,code,buf) (-1)
122#define ftruncate(fd, size) ntfs_device_win32_ftruncate(dev_out, size)
123#define BINWMODE "wb"
124#else
125#define BINWMODE "w"
126#endif
127
128#ifndef O_BINARY
129#define O_BINARY 0
130#endif
131
Steve Kondik2111ad72013-07-07 12:07:44 -0700132static const char *EXEC_NAME = "ntfsclone";
133
134static const char *bad_sectors_warning_msg =
135"*************************************************************************\n"
136"* WARNING: The disk has one or more bad sectors. This means that damage *\n"
137"* has occurred on the disk surface, possibly caused by deterioration of *\n"
138"* the physical media, manufacturing faults or other reasons. The *\n"
139"* reliability of the disk may stay stable or degrade fast. *\n"
140"* Use the --rescue option to efficiently save as much data as possible! *\n"
141"*************************************************************************\n";
142
143static const char *dirty_volume_msg =
144"Volume '%s' is scheduled for a check or it was shutdown \n"
145"uncleanly. Please boot Windows or use the --force option to progress.\n";
146
147static struct {
148 int verbose;
149 int quiet;
150 int debug;
151 int force;
152 int overwrite;
153 int std_out;
154 int blkdev_out; /* output file is block device */
155 int metadata; /* metadata only cloning */
Steve Kondik79165c32015-11-09 19:43:00 -0800156 int no_action; /* do not really restore */
Steve Kondik2111ad72013-07-07 12:07:44 -0700157 int ignore_fs_check;
158 int rescue;
159 int save_image;
160 int new_serial;
161 int metadata_image;
162 int preserve_timestamps;
163 int restore_image;
164 char *output;
165 char *volume;
166#ifndef NO_STATFS
167 struct statfs stfs;
168#endif
169} opt;
170
171struct bitmap {
172 s64 size;
173 u8 *bm;
174};
175
176struct progress_bar {
177 u64 start;
178 u64 stop;
179 int resolution;
180 float unit;
181};
182
183typedef struct {
184 ntfs_inode *ni; /* inode being processed */
185 ntfs_attr_search_ctx *ctx; /* inode attribute being processed */
186 s64 inuse; /* number of clusters in use */
Steve Kondik79165c32015-11-09 19:43:00 -0800187 int more_use; /* possibly allocated clusters */
Steve Kondik2111ad72013-07-07 12:07:44 -0700188 LCN current_lcn;
189} ntfs_walk_clusters_ctx;
190
191typedef int (ntfs_walk_op)(ntfs_inode *ni, void *data);
192
193struct ntfs_walk_cluster {
194 ntfs_walk_op *inode_op; /* not implemented yet */
195 ntfs_walk_clusters_ctx *image;
196};
197
198
199static ntfs_volume *vol = NULL;
200static struct bitmap lcn_bitmap;
201
202static int fd_in;
203static int fd_out;
204static FILE *stream_out = (FILE*)NULL;
Steve Kondik79165c32015-11-09 19:43:00 -0800205struct ntfs_device *dev_out = (struct ntfs_device*)NULL;
Steve Kondik2111ad72013-07-07 12:07:44 -0700206static FILE *msg_out = NULL;
207
208static int wipe = 0;
209static unsigned int nr_used_mft_records = 0;
210static unsigned int wiped_unused_mft_data = 0;
211static unsigned int wiped_unused_mft = 0;
212static unsigned int wiped_resident_data = 0;
213static unsigned int wiped_timestamp_data = 0;
214
215static le64 volume_serial_number; /* new random serial number */
216static u64 full_device_size; /* full size, including the backup boot sector */
217
218static BOOL image_is_host_endian = FALSE;
219
220#define IMAGE_MAGIC "\0ntfsclone-image"
221#define IMAGE_MAGIC_SIZE 16
222#define IMAGE_OFFSET_OFFSET 46 /* must be the same for all versions ! */
223#define IMAGE_HDR_ALIGN 8 /* alignment wanted after header */
224
225/* This is the first endianness safe format version. */
226#define NTFSCLONE_IMG_VER_MAJOR_ENDIANNESS_SAFE 10
227#define NTFSCLONE_IMG_VER_MINOR_ENDIANNESS_SAFE 0
228
229/*
230 * Set the version to 10.0 to avoid colisions with old ntfsclone which
231 * stupidly used the volume version as the image version... )-: I hope NTFS
232 * never reaches version 10.0 and if it does one day I hope no-one is using
233 * such an old ntfsclone by then...
234 *
235 * NOTE: Only bump the minor version if the image format and header are still
236 * backwards compatible. Otherwise always bump the major version. If in
237 * doubt, bump the major version.
238 *
239 * Moved to 10.1 : Alternate boot sector now saved. Still compatible.
240 */
241#define NTFSCLONE_IMG_VER_MAJOR 10
242#define NTFSCLONE_IMG_VER_MINOR 1
243
Steve Kondik79165c32015-11-09 19:43:00 -0800244enum { CMD_GAP, CMD_NEXT } ;
245
Steve Kondik2111ad72013-07-07 12:07:44 -0700246/* All values are in little endian. */
247static struct image_hdr {
248 char magic[IMAGE_MAGIC_SIZE];
249 u8 major_ver;
250 u8 minor_ver;
251 /* the following is aligned dangerously (too late...) */
252 le32 cluster_size;
253 le64 device_size;
254 sle64 nr_clusters;
255 le64 inuse;
256 le32 offset_to_image_data; /* From start of image_hdr. */
257} __attribute__((__packed__)) image_hdr;
258
Steve Kondik79165c32015-11-09 19:43:00 -0800259static int compare_bitmaps(struct bitmap *a, BOOL copy);
260
Steve Kondik2111ad72013-07-07 12:07:44 -0700261#define NTFSCLONE_IMG_HEADER_SIZE_OLD \
262 (offsetof(struct image_hdr, offset_to_image_data))
263
264#define NTFS_MBYTE (1000 * 1000)
265
266#define ERR_PREFIX "ERROR"
267#define PERR_PREFIX ERR_PREFIX "(%d): "
268#define NERR_PREFIX ERR_PREFIX ": "
269
270#define LAST_METADATA_INODE 11
271
272#define NTFS_MAX_CLUSTER_SIZE 65536
273#define NTFS_SECTOR_SIZE 512
274
275#define rounded_up_division(a, b) (((a) + (b - 1)) / (b))
276
277#define read_all(f, p, n) io_all((f), (p), (n), 0)
278#define write_all(f, p, n) io_all((f), (p), (n), 1)
279
280__attribute__((format(printf, 1, 2)))
281static void Printf(const char *fmt, ...)
282{
283 va_list ap;
284
285 va_start(ap, fmt);
286 vfprintf(msg_out, fmt, ap);
287 va_end(ap);
288 fflush(msg_out);
289}
290
291__attribute__((format(printf, 1, 2)))
292static void perr_printf(const char *fmt, ...)
293{
294 va_list ap;
295 int eo = errno;
296
297 Printf(PERR_PREFIX, eo);
298 va_start(ap, fmt);
299 vfprintf(msg_out, fmt, ap);
300 va_end(ap);
301 Printf(": %s\n", strerror(eo));
302 fflush(msg_out);
303}
304
305__attribute__((format(printf, 1, 2)))
306static void err_printf(const char *fmt, ...)
307{
308 va_list ap;
309
310 Printf(NERR_PREFIX);
311 va_start(ap, fmt);
312 vfprintf(msg_out, fmt, ap);
313 va_end(ap);
314 fflush(msg_out);
315}
316
317__attribute__((noreturn))
318__attribute__((format(printf, 1, 2)))
319static void err_exit(const char *fmt, ...)
320{
321 va_list ap;
322
323 Printf(NERR_PREFIX);
324 va_start(ap, fmt);
325 vfprintf(msg_out, fmt, ap);
326 va_end(ap);
327 fflush(msg_out);
328 if (vol)
329 ntfs_umount(vol,FALSE);
330 exit(1);
331}
332
333__attribute__((noreturn))
334__attribute__((format(printf, 1, 2)))
335static void perr_exit(const char *fmt, ...)
336{
337 va_list ap;
338 int eo = errno;
339
340 Printf(PERR_PREFIX, eo);
341 va_start(ap, fmt);
342 vfprintf(msg_out, fmt, ap);
343 va_end(ap);
344 Printf(": %s\n", strerror(eo));
345 fflush(msg_out);
346 if (vol)
347 ntfs_umount(vol,FALSE);
348 exit(1);
349}
350
351
352__attribute__((noreturn))
Steve Kondik79165c32015-11-09 19:43:00 -0800353static void usage(int ret)
Steve Kondik2111ad72013-07-07 12:07:44 -0700354{
355 fprintf(stderr, "\nUsage: %s [OPTIONS] SOURCE\n"
356 " Efficiently clone NTFS to a sparse file, image, device or standard output.\n"
357 "\n"
358 " -o, --output FILE Clone NTFS to the non-existent FILE\n"
359 " -O, --overwrite FILE Clone NTFS to FILE, overwriting if exists\n"
360 " -s, --save-image Save to the special image format\n"
361 " -r, --restore-image Restore from the special image format\n"
362 " --rescue Continue after disk read errors\n"
363 " -m, --metadata Clone *only* metadata (for NTFS experts)\n"
Steve Kondik79165c32015-11-09 19:43:00 -0800364 " -n, --no-action Test restoring, without outputting anything\n"
Steve Kondik2111ad72013-07-07 12:07:44 -0700365 " --ignore-fs-check Ignore the filesystem check result\n"
366 " --new-serial Set a new serial number\n"
367 " --new-half-serial Set a partial new serial number\n"
368 " -t, --preserve-timestamps Do not clear the timestamps\n"
369 " -q, --quiet Do not display any progress bars\n"
370 " -f, --force Force to progress (DANGEROUS)\n"
371 " -h, --help Display this help\n"
372#ifdef DEBUG
373 " -d, --debug Show debug information\n"
374#endif
Steve Kondik79165c32015-11-09 19:43:00 -0800375 " -V, --version Display version information\n"
Steve Kondik2111ad72013-07-07 12:07:44 -0700376 "\n"
377 " If FILE is '-' then send the image to the standard output. If SOURCE is '-'\n"
378 " and --restore-image is used then read the image from the standard input.\n"
379 "\n", EXEC_NAME);
380 fprintf(stderr, "%s%s", ntfs_bugs, ntfs_home);
Steve Kondik79165c32015-11-09 19:43:00 -0800381 exit(ret);
382}
383
384/**
385 * version
386 */
387__attribute__((noreturn))
388static void version(void)
389{
390 fprintf(stderr,
391 "Efficiently clone, image, restore or rescue an NTFS Volume.\n\n"
392 "Copyright (c) 2003-2006 Szabolcs Szakacsits\n"
393 "Copyright (c) 2004-2006 Anton Altaparmakov\n"
Steve Kondike68cb602016-08-28 00:45:36 -0700394 "Copyright (c) 2010-2015 Jean-Pierre Andre\n\n");
Steve Kondik79165c32015-11-09 19:43:00 -0800395 fprintf(stderr, "%s\n%s%s", ntfs_gpl, ntfs_bugs, ntfs_home);
396 exit(0);
Steve Kondik2111ad72013-07-07 12:07:44 -0700397}
398
399static void parse_options(int argc, char **argv)
400{
Steve Kondik79165c32015-11-09 19:43:00 -0800401 static const char *sopt = "-dfhmno:O:qrstV";
Steve Kondik2111ad72013-07-07 12:07:44 -0700402 static const struct option lopt[] = {
403#ifdef DEBUG
404 { "debug", no_argument, NULL, 'd' },
405#endif
406 { "quiet", no_argument, NULL, 'q' },
407 { "force", no_argument, NULL, 'f' },
408 { "help", no_argument, NULL, 'h' },
409 { "metadata", no_argument, NULL, 'm' },
Steve Kondik79165c32015-11-09 19:43:00 -0800410 { "no-action", no_argument, NULL, 'n' },
Steve Kondik2111ad72013-07-07 12:07:44 -0700411 { "output", required_argument, NULL, 'o' },
412 { "overwrite", required_argument, NULL, 'O' },
413 { "restore-image", no_argument, NULL, 'r' },
414 { "ignore-fs-check", no_argument, NULL, 'C' },
415 { "rescue", no_argument, NULL, 'R' },
416 { "new-serial", no_argument, NULL, 'I' },
417 { "new-half-serial", no_argument, NULL, 'i' },
418 { "save-image", no_argument, NULL, 's' },
419 { "preserve-timestamps", no_argument, NULL, 't' },
Steve Kondik79165c32015-11-09 19:43:00 -0800420 { "version", no_argument, NULL, 'V' },
Steve Kondik2111ad72013-07-07 12:07:44 -0700421 { NULL, 0, NULL, 0 }
422 };
423
424 int c;
425
426 memset(&opt, 0, sizeof(opt));
427
428 while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
429 switch (c) {
430 case 1: /* A non-option argument */
431 if (opt.volume)
Steve Kondik79165c32015-11-09 19:43:00 -0800432 usage(1);
Steve Kondik2111ad72013-07-07 12:07:44 -0700433 opt.volume = argv[optind-1];
434 break;
435 case 'd':
436 opt.debug++;
437 break;
438 case 'q':
439 opt.quiet++;
440 break;
441 case 'f':
442 opt.force++;
443 break;
444 case 'h':
Steve Kondik79165c32015-11-09 19:43:00 -0800445 usage(0);
Steve Kondik2111ad72013-07-07 12:07:44 -0700446 case '?':
Steve Kondik79165c32015-11-09 19:43:00 -0800447 usage(1);
Steve Kondik2111ad72013-07-07 12:07:44 -0700448 case 'i': /* not proposed as a short option */
449 opt.new_serial |= 1;
450 break;
451 case 'I': /* not proposed as a short option */
452 opt.new_serial |= 2;
453 break;
454 case 'm':
455 opt.metadata++;
456 break;
Steve Kondik79165c32015-11-09 19:43:00 -0800457 case 'n':
458 opt.no_action++;
459 break;
Steve Kondik2111ad72013-07-07 12:07:44 -0700460 case 'O':
461 opt.overwrite++;
462 case 'o':
463 if (opt.output)
Steve Kondik79165c32015-11-09 19:43:00 -0800464 usage(1);
Steve Kondik2111ad72013-07-07 12:07:44 -0700465 opt.output = optarg;
466 break;
467 case 'r':
468 opt.restore_image++;
469 break;
470 case 'C':
471 opt.ignore_fs_check++;
472 break;
473 case 'R':
474 opt.rescue++;
475 break;
476 case 's':
477 opt.save_image++;
478 break;
479 case 't':
480 opt.preserve_timestamps++;
481 break;
Steve Kondik79165c32015-11-09 19:43:00 -0800482 case 'V':
483 version();
484 break;
Steve Kondik2111ad72013-07-07 12:07:44 -0700485 default:
486 err_printf("Unknown option '%s'.\n", argv[optind-1]);
Steve Kondik79165c32015-11-09 19:43:00 -0800487 usage(1);
Steve Kondik2111ad72013-07-07 12:07:44 -0700488 }
489 }
490
Steve Kondik79165c32015-11-09 19:43:00 -0800491 if (!opt.no_action && (opt.output == NULL)) {
Steve Kondik2111ad72013-07-07 12:07:44 -0700492 err_printf("You must specify an output file.\n");
Steve Kondik79165c32015-11-09 19:43:00 -0800493 usage(1);
Steve Kondik2111ad72013-07-07 12:07:44 -0700494 }
495
Steve Kondik79165c32015-11-09 19:43:00 -0800496 if (!opt.no_action && (strcmp(opt.output, "-") == 0))
Steve Kondik2111ad72013-07-07 12:07:44 -0700497 opt.std_out++;
498
499 if (opt.volume == NULL) {
500 err_printf("You must specify a device file.\n");
Steve Kondik79165c32015-11-09 19:43:00 -0800501 usage(1);
502 }
503
504 if (!opt.restore_image && !strcmp(opt.volume, "-")) {
505 err_printf("Only special images can be read from standard input\n");
506 usage(1);
Steve Kondik2111ad72013-07-07 12:07:44 -0700507 }
508
509 if (opt.metadata && opt.save_image) {
510 opt.metadata_image++;
511 opt.save_image = 0;
512 }
513
514 if (opt.metadata && opt.restore_image)
515 err_exit("Restoring only metadata from an image is not "
516 "supported!\n");
517
518 if (opt.metadata && !opt.metadata_image && opt.std_out)
519 err_exit("Cloning only metadata to stdout isn't supported!\n");
520
Steve Kondik79165c32015-11-09 19:43:00 -0800521 if (opt.ignore_fs_check && !opt.metadata && !opt.rescue)
Steve Kondik2111ad72013-07-07 12:07:44 -0700522 err_exit("Filesystem check can be ignored only for metadata "
Steve Kondik79165c32015-11-09 19:43:00 -0800523 "cloning or rescue situations!\n");
Steve Kondik2111ad72013-07-07 12:07:44 -0700524
525 if (opt.save_image && opt.restore_image)
526 err_exit("Saving and restoring an image at the same time "
527 "is not supported!\n");
528
Steve Kondik79165c32015-11-09 19:43:00 -0800529 if (opt.no_action && !opt.restore_image)
530 err_exit("A restoring test requires the restore option!\n");
Steve Kondik2111ad72013-07-07 12:07:44 -0700531
Steve Kondik79165c32015-11-09 19:43:00 -0800532 if (opt.no_action && opt.output)
533 err_exit("A restoring test requires not defining any output!\n");
534
535 if (!opt.no_action && !opt.std_out) {
536 struct stat st;
537#ifdef HAVE_WINDOWS_H
538 BOOL blkdev = opt.output[0] && (opt.output[1] == ':')
539 && !opt.output[2];
540
541 if (!blkdev && (stat(opt.output, &st) == -1)) {
542#else
Steve Kondik2111ad72013-07-07 12:07:44 -0700543 if (stat(opt.output, &st) == -1) {
Steve Kondik79165c32015-11-09 19:43:00 -0800544#endif
Steve Kondik2111ad72013-07-07 12:07:44 -0700545 if (errno != ENOENT)
546 perr_exit("Couldn't access '%s'", opt.output);
547 } else {
548 if (!opt.overwrite)
549 err_exit("Output file '%s' already exists.\n"
550 "Use option --overwrite if you want to"
551 " replace its content.\n", opt.output);
552
Steve Kondik79165c32015-11-09 19:43:00 -0800553#ifdef HAVE_WINDOWS_H
554 if (blkdev) {
555#else
Steve Kondik2111ad72013-07-07 12:07:44 -0700556 if (S_ISBLK(st.st_mode)) {
Steve Kondik79165c32015-11-09 19:43:00 -0800557#endif
Steve Kondik2111ad72013-07-07 12:07:44 -0700558 opt.blkdev_out = 1;
559 if (opt.metadata && !opt.force)
560 err_exit("Cloning only metadata to a "
561 "block device does not usually "
562 "make sense, aborting...\n"
563 "If you were instructed to do "
564 "this by a developer and/or are "
565 "sure that this is what you want "
566 "to do, run this utility again "
567 "but this time add the force "
568 "option, i.e. add '--force' to "
569 "the command line arguments.");
570 }
571 }
572 }
573
Steve Kondik79165c32015-11-09 19:43:00 -0800574 /*
575 * Send messages, debug information and library messages to stdout,
576 * but, if outputing to stdout send them to stderr
577 */
578 if (opt.std_out) {
Steve Kondik2111ad72013-07-07 12:07:44 -0700579 msg_out = stderr;
Steve Kondik79165c32015-11-09 19:43:00 -0800580 ntfs_log_set_handler(ntfs_log_handler_stderr);
Steve Kondik2111ad72013-07-07 12:07:44 -0700581 } else {
Steve Kondik79165c32015-11-09 19:43:00 -0800582 msg_out = stdout;
583 ntfs_log_set_handler(ntfs_log_handler_outerr);
Steve Kondik2111ad72013-07-07 12:07:44 -0700584 }
585}
586
587/*
588 * Initialize the random number generator with the current
589 * time, and generate a 64-bit random number for the serial
590 * number
591 */
592static void generate_serial_number(void) {
593 u64 sn;
594
595 /* different values for parallel processes */
596 srandom(time((time_t*)NULL) ^ (getpid() << 16));
597 sn = ((u64)random() << 32) | ((u64)random() & 0xffffffff);
598 volume_serial_number = cpu_to_le64(sn);
599}
600
601static void progress_init(struct progress_bar *p, u64 start, u64 stop, int res)
602{
603 p->start = start;
604 p->stop = stop;
605 p->unit = 100.0 / (stop - start);
606 p->resolution = res;
607}
608
609
610static void progress_update(struct progress_bar *p, u64 current)
611{
612 float percent = p->unit * current;
613
614 if (opt.quiet)
615 return;
616
617 if (current != p->stop) {
618 if ((current - p->start) % p->resolution)
619 return;
620 Printf("%6.2f percent completed\r", percent);
621 } else
622 Printf("100.00 percent completed\n");
623 fflush(msg_out);
624}
625
626static s64 is_critical_metadata(ntfs_walk_clusters_ctx *image, runlist *rl)
627{
628 s64 inode = image->ni->mft_no;
629
630 if (inode <= LAST_METADATA_INODE) {
631
632 /* Don't save bad sectors (both $Bad and unnamed are ignored */
633 if (inode == FILE_BadClus && image->ctx->attr->type == AT_DATA)
634 return 0;
635
636 if (inode != FILE_LogFile)
637 return rl->length;
638
639 if (image->ctx->attr->type == AT_DATA) {
640
641 /* Save at least the first 16 KiB of FILE_LogFile */
642 s64 s = (s64)16384 - rl->vcn * vol->cluster_size;
643 if (s > 0) {
644 s = rounded_up_division(s, vol->cluster_size);
645 if (rl->length < s)
646 s = rl->length;
647 return s;
648 }
649 return 0;
650 }
651 }
652
653 if (image->ctx->attr->type != AT_DATA)
654 return rl->length;
655
656 return 0;
657}
658
Steve Kondik79165c32015-11-09 19:43:00 -0800659static off_t tellin(int in)
660{
661 return (lseek(in, 0, SEEK_CUR));
662}
Steve Kondik2111ad72013-07-07 12:07:44 -0700663
664static int io_all(void *fd, void *buf, int count, int do_write)
665{
666 int i;
667 struct ntfs_device *dev = fd;
668
669 while (count > 0) {
670 if (do_write) {
Steve Kondik79165c32015-11-09 19:43:00 -0800671 if (opt.no_action) {
672 i = count;
673 } else {
674 if (opt.save_image || opt.metadata_image)
675 i = fwrite(buf, 1, count, stream_out);
676#ifdef HAVE_WINDOWS_H
677 else if (dev_out)
678 i = dev_out->d_ops->write(dev_out,
679 buf, count);
680#endif
681 else
682 i = write(*(int *)fd, buf, count);
683 }
Steve Kondik2111ad72013-07-07 12:07:44 -0700684 } else if (opt.restore_image)
685 i = read(*(int *)fd, buf, count);
686 else
687 i = dev->d_ops->read(dev, buf, count);
688 if (i < 0) {
689 if (errno != EAGAIN && errno != EINTR)
690 return -1;
691 } else if (i == 0 && !do_write && opt.restore_image) {
692 return -1;
693 } else {
694 count -= i;
695 buf = i + (char *) buf;
696 }
697 }
698 return 0;
699}
700
701
Steve Kondik79165c32015-11-09 19:43:00 -0800702static void rescue_sector(void *fd, u32 bytes_per_sector, off_t pos, void *buff)
Steve Kondik2111ad72013-07-07 12:07:44 -0700703{
Steve Kondik79165c32015-11-09 19:43:00 -0800704 const char badsector_magic[] = "BadSectoR";
Steve Kondik2111ad72013-07-07 12:07:44 -0700705 struct ntfs_device *dev = fd;
706
707 if (opt.restore_image) {
Steve Kondik79165c32015-11-09 19:43:00 -0800708 if (!opt.no_action
709 && (lseek(*(int *)fd, pos, SEEK_SET) == (off_t)-1))
Steve Kondik2111ad72013-07-07 12:07:44 -0700710 perr_exit("lseek");
711 } else {
712 if (vol->dev->d_ops->seek(dev, pos, SEEK_SET) == (off_t)-1)
713 perr_exit("seek input");
714 }
715
Steve Kondik79165c32015-11-09 19:43:00 -0800716 if (read_all(fd, buff, bytes_per_sector) == -1) {
Steve Kondik2111ad72013-07-07 12:07:44 -0700717 Printf("WARNING: Can't read sector at %llu, lost data.\n",
718 (unsigned long long)pos);
Steve Kondik79165c32015-11-09 19:43:00 -0800719 memset(buff, '?', bytes_per_sector);
Steve Kondik2111ad72013-07-07 12:07:44 -0700720 memmove(buff, badsector_magic, sizeof(badsector_magic));
721 }
722}
723
724/*
725 * Read a cluster, try to rescue if cannot read
726 */
727
Steve Kondik79165c32015-11-09 19:43:00 -0800728static void read_rescue(void *fd, char *buff, u32 csize, u32 bytes_per_sector,
729 u64 rescue_lcn)
Steve Kondik2111ad72013-07-07 12:07:44 -0700730{
731 off_t rescue_pos;
732
733 if (read_all(fd, buff, csize) == -1) {
734
735 if (errno != EIO)
736 perr_exit("read_all");
737 else if (opt.rescue){
738 u32 i;
739
740 rescue_pos = (off_t)(rescue_lcn * csize);
Steve Kondik79165c32015-11-09 19:43:00 -0800741 for (i = 0; i < csize; i += bytes_per_sector)
742 rescue_sector(fd, bytes_per_sector,
743 rescue_pos + i, buff + i);
Steve Kondik2111ad72013-07-07 12:07:44 -0700744 } else {
745 Printf("%s", bad_sectors_warning_msg);
746 err_exit("Disk is faulty, can't make full backup!");
747 }
748 }
749}
750
751static void copy_cluster(int rescue, u64 rescue_lcn, u64 lcn)
752{
753 char buff[NTFS_MAX_CLUSTER_SIZE]; /* overflow checked at mount time */
754 /* vol is NULL if opt.restore_image is set */
755 s32 csize = le32_to_cpu(image_hdr.cluster_size);
756 BOOL backup_bootsector;
757 void *fd = (void *)&fd_in;
758 off_t rescue_pos;
759 NTFS_BOOT_SECTOR *bs;
760 le64 mask;
Steve Kondik79165c32015-11-09 19:43:00 -0800761 static u16 bytes_per_sector = NTFS_SECTOR_SIZE;
Steve Kondik2111ad72013-07-07 12:07:44 -0700762
763 if (!opt.restore_image) {
764 csize = vol->cluster_size;
Steve Kondik79165c32015-11-09 19:43:00 -0800765 bytes_per_sector = vol->sector_size;
Steve Kondik2111ad72013-07-07 12:07:44 -0700766 fd = vol->dev;
767 }
768
769 rescue_pos = (off_t)(rescue_lcn * csize);
770
771 /* possible partial cluster holding the backup boot sector */
772 backup_bootsector = (lcn + 1)*csize >= full_device_size;
773 if (backup_bootsector) {
774 csize = full_device_size - lcn*csize;
775 if (csize < 0) {
776 err_exit("Corrupted input, copy aborted");
777 }
778 }
779
780// need reading when not about to write ?
781 if (read_all(fd, buff, csize) == -1) {
782
Steve Kondik79165c32015-11-09 19:43:00 -0800783 if (errno != EIO) {
784 if (!errno && opt.restore_image)
785 err_exit("Short image file...\n");
786 else
787 perr_exit("read_all");
788 }
Steve Kondik2111ad72013-07-07 12:07:44 -0700789 else if (rescue){
790 s32 i;
Steve Kondik79165c32015-11-09 19:43:00 -0800791 for (i = 0; i < csize; i += bytes_per_sector)
792 rescue_sector(fd, bytes_per_sector,
793 rescue_pos + i, buff + i);
Steve Kondik2111ad72013-07-07 12:07:44 -0700794 } else {
795 Printf("%s", bad_sectors_warning_msg);
796 err_exit("Disk is faulty, can't make full backup!");
797 }
798 }
799
800 /* Set the new serial number if requested */
801 if (opt.new_serial
802 && !opt.save_image
803 && (!lcn || backup_bootsector)) {
804 /*
805 * For updating the backup boot sector, we need to
806 * know the sector size, but this is not recorded
807 * in the image header, so we collect it on the fly
808 * while reading the first boot sector.
809 */
810 if (!lcn) {
811 bs = (NTFS_BOOT_SECTOR*)buff;
812 bytes_per_sector = le16_to_cpu(bs->bpb.bytes_per_sector);
813 if ((bytes_per_sector > csize)
814 || (bytes_per_sector < NTFS_SECTOR_SIZE))
815 bytes_per_sector = NTFS_SECTOR_SIZE;
816 } else
817 bs = (NTFS_BOOT_SECTOR*)(buff
818 + csize - bytes_per_sector);
819 if (opt.new_serial & 2)
820 bs->volume_serial_number = volume_serial_number;
821 else {
822 mask = const_cpu_to_le64(~0x0ffffffffULL);
823 bs->volume_serial_number
824 = (volume_serial_number & mask)
825 | (bs->volume_serial_number & ~mask);
826 }
827 /* Show the new full serial after merging */
828 if (!lcn)
829 Printf("New serial number : 0x%llx\n",
830 (long long)le64_to_cpu(
831 bs->volume_serial_number));
832 }
833
834 if (opt.save_image || (opt.metadata_image && wipe)) {
Steve Kondik79165c32015-11-09 19:43:00 -0800835 char cmd = CMD_NEXT;
Steve Kondik2111ad72013-07-07 12:07:44 -0700836 if (write_all(&fd_out, &cmd, sizeof(cmd)) == -1)
837 perr_exit("write_all");
838 }
839
840 if ((!opt.metadata_image || wipe)
841 && (write_all(&fd_out, buff, csize) == -1)) {
842#ifndef NO_STATFS
843 int err = errno;
844 perr_printf("Write failed");
845 if (err == EIO && opt.stfs.f_type == 0x517b)
846 Printf("Apparently you tried to clone to a remote "
847 "Windows computer but they don't\nhave "
848 "efficient sparse file handling by default. "
849 "Please try a different method.\n");
850 exit(1);
851#else
852 perr_printf("Write failed");
853#endif
854 }
855}
856
Steve Kondik79165c32015-11-09 19:43:00 -0800857static s64 lseek_out(int fd, s64 pos, int mode)
858{
859 s64 ret;
860
861 if (dev_out)
862 ret = (dev_out->d_ops->seek)(dev_out, pos, mode);
863 else
864 ret = lseek(fd, pos, mode);
865 return (ret);
866}
867
Steve Kondik2111ad72013-07-07 12:07:44 -0700868static void lseek_to_cluster(s64 lcn)
869{
870 off_t pos;
871
872 pos = (off_t)(lcn * vol->cluster_size);
873
874 if (vol->dev->d_ops->seek(vol->dev, pos, SEEK_SET) == (off_t)-1)
875 perr_exit("lseek input");
876
877 if (opt.std_out || opt.save_image || opt.metadata_image)
878 return;
879
Steve Kondik79165c32015-11-09 19:43:00 -0800880 if (lseek_out(fd_out, pos, SEEK_SET) == (off_t)-1)
881 perr_exit("lseek output");
Steve Kondik2111ad72013-07-07 12:07:44 -0700882}
883
884static void gap_to_cluster(s64 gap)
885{
886 sle64 count;
887 char buf[1 + sizeof(count)];
888
889 if (gap) {
890 count = cpu_to_sle64(gap);
Steve Kondik79165c32015-11-09 19:43:00 -0800891 buf[0] = CMD_GAP;
Steve Kondik2111ad72013-07-07 12:07:44 -0700892 memcpy(&buf[1], &count, sizeof(count));
893 if (write_all(&fd_out, buf, sizeof(buf)) == -1)
894 perr_exit("write_all");
895 }
896}
897
898static void image_skip_clusters(s64 count)
899{
900 if (opt.save_image && count > 0) {
Steve Kondike68cb602016-08-28 00:45:36 -0700901 sle64 count_buf;
Steve Kondik2111ad72013-07-07 12:07:44 -0700902 char buff[1 + sizeof(count)];
903
Steve Kondik79165c32015-11-09 19:43:00 -0800904 buff[0] = CMD_GAP;
Steve Kondik2111ad72013-07-07 12:07:44 -0700905 count_buf = cpu_to_sle64(count);
906 memcpy(buff + 1, &count_buf, sizeof(count_buf));
907
908 if (write_all(&fd_out, buff, sizeof(buff)) == -1)
909 perr_exit("write_all");
910 }
911}
912
913static void write_image_hdr(void)
914{
915 char alignment[IMAGE_HDR_ALIGN];
916
917 if (opt.save_image || opt.metadata_image) {
918 int alignsize = le32_to_cpu(image_hdr.offset_to_image_data)
919 - sizeof(image_hdr);
920 memset(alignment,0,IMAGE_HDR_ALIGN);
921 if ((alignsize < 0)
922 || write_all(&fd_out, &image_hdr, sizeof(image_hdr))
923 || write_all(&fd_out, alignment, alignsize))
924 perr_exit("write_all");
925 }
926}
927
Steve Kondik79165c32015-11-09 19:43:00 -0800928static void clone_ntfs(u64 nr_clusters, int more_use)
Steve Kondik2111ad72013-07-07 12:07:44 -0700929{
930 u64 cl, last_cl; /* current and last used cluster */
931 void *buf;
932 u32 csize = vol->cluster_size;
933 u64 p_counter = 0;
934 char alignment[IMAGE_HDR_ALIGN];
935 struct progress_bar progress;
936
937 if (opt.save_image)
938 Printf("Saving NTFS to image ...\n");
939 else
940 Printf("Cloning NTFS ...\n");
941
942 if (opt.new_serial)
943 generate_serial_number();
944
945 buf = ntfs_calloc(csize);
946 if (!buf)
947 perr_exit("clone_ntfs");
948
949 progress_init(&progress, p_counter, nr_clusters, 100);
950
951 if (opt.save_image) {
952 int alignsize = le32_to_cpu(image_hdr.offset_to_image_data)
953 - sizeof(image_hdr);
954 memset(alignment,0,IMAGE_HDR_ALIGN);
955 if ((alignsize < 0)
956 || write_all(&fd_out, &image_hdr, sizeof(image_hdr))
957 || write_all(&fd_out, alignment, alignsize))
958 perr_exit("write_all");
959 }
960
Steve Kondik79165c32015-11-09 19:43:00 -0800961 /* save suspicious clusters if required */
962 if (more_use && opt.ignore_fs_check) {
963 compare_bitmaps(&lcn_bitmap, TRUE);
964 }
Steve Kondik2111ad72013-07-07 12:07:44 -0700965 /* Examine up to the alternate boot sector */
966 for (last_cl = cl = 0; cl <= (u64)vol->nr_clusters; cl++) {
967
968 if (ntfs_bit_get(lcn_bitmap.bm, cl)) {
969 progress_update(&progress, ++p_counter);
970 lseek_to_cluster(cl);
971 image_skip_clusters(cl - last_cl - 1);
972
973 copy_cluster(opt.rescue, cl, cl);
974 last_cl = cl;
975 continue;
976 }
977
978 if (opt.std_out && !opt.save_image) {
979 progress_update(&progress, ++p_counter);
980 if (write_all(&fd_out, buf, csize) == -1)
981 perr_exit("write_all");
982 }
983 }
984 image_skip_clusters(cl - last_cl - 1);
985 free(buf);
986}
987
988static void write_empty_clusters(s32 csize, s64 count,
989 struct progress_bar *progress, u64 *p_counter)
990{
991 s64 i;
992 char buff[NTFS_MAX_CLUSTER_SIZE];
993
994 memset(buff, 0, csize);
995
996 for (i = 0; i < count; i++) {
997 if (write_all(&fd_out, buff, csize) == -1)
998 perr_exit("write_all");
999 progress_update(progress, ++(*p_counter));
1000 }
1001}
1002
1003static void restore_image(void)
1004{
1005 s64 pos = 0, count;
1006 s32 csize = le32_to_cpu(image_hdr.cluster_size);
1007 char cmd;
1008 u64 p_counter = 0;
1009 struct progress_bar progress;
1010
1011 Printf("Restoring NTFS from image ...\n");
1012
1013 progress_init(&progress, p_counter, opt.std_out ?
Steve Kondike68cb602016-08-28 00:45:36 -07001014 (u64)sle64_to_cpu(image_hdr.nr_clusters) + 1 :
1015 le64_to_cpu(image_hdr.inuse) + 1,
Steve Kondik2111ad72013-07-07 12:07:44 -07001016 100);
1017
1018 if (opt.new_serial)
1019 generate_serial_number();
1020
1021 /* Restore up to the alternate boot sector */
1022 while (pos <= sle64_to_cpu(image_hdr.nr_clusters)) {
1023 if (read_all(&fd_in, &cmd, sizeof(cmd)) == -1) {
1024 if (pos == sle64_to_cpu(image_hdr.nr_clusters)) {
1025 /* alternate boot sector no present in old images */
1026 Printf("Warning : no alternate boot"
1027 " sector in image\n");
1028 break;
1029 } else
1030 perr_exit("read_all");
1031 }
1032
Steve Kondik79165c32015-11-09 19:43:00 -08001033 if (cmd == CMD_GAP) {
Steve Kondik2111ad72013-07-07 12:07:44 -07001034 if (!image_is_host_endian) {
Steve Kondike68cb602016-08-28 00:45:36 -07001035 sle64 lecount;
Steve Kondik2111ad72013-07-07 12:07:44 -07001036
1037 /* little endian image, on any computer */
1038 if (read_all(&fd_in, &lecount,
1039 sizeof(lecount)) == -1)
1040 perr_exit("read_all");
1041 count = sle64_to_cpu(lecount);
1042 } else {
1043 /* big endian image on big endian computer */
1044 if (read_all(&fd_in, &count,
1045 sizeof(count)) == -1)
1046 perr_exit("read_all");
1047 }
Steve Kondik79165c32015-11-09 19:43:00 -08001048 if (!count)
1049 err_exit("Bad offset at input location 0x%llx\n",
1050 (long long)tellin(fd_in) - 9);
Steve Kondik2111ad72013-07-07 12:07:44 -07001051 if (opt.std_out) {
1052 if ((!p_counter && count) || (count < 0))
1053 err_exit("Cannot restore a metadata"
1054 " image to stdout\n");
1055 else
1056 write_empty_clusters(csize, count,
1057 &progress, &p_counter);
1058 } else {
1059 if (((pos + count) < 0)
1060 || ((pos + count)
1061 > sle64_to_cpu(image_hdr.nr_clusters)))
Steve Kondik79165c32015-11-09 19:43:00 -08001062 err_exit("restore_image: corrupt image "
1063 "at input offset %lld\n",
1064 (long long)tellin(fd_in) - 9);
1065 else {
1066 if (!opt.no_action
1067 && (lseek_out(fd_out, count * csize,
1068 SEEK_CUR) == (off_t)-1))
Steve Kondik2111ad72013-07-07 12:07:44 -07001069 perr_exit("restore_image: lseek");
Steve Kondik79165c32015-11-09 19:43:00 -08001070 }
Steve Kondik2111ad72013-07-07 12:07:44 -07001071 }
1072 pos += count;
Steve Kondik79165c32015-11-09 19:43:00 -08001073 } else if (cmd == CMD_NEXT) {
Steve Kondik2111ad72013-07-07 12:07:44 -07001074 copy_cluster(0, 0, pos);
1075 pos++;
1076 progress_update(&progress, ++p_counter);
1077 } else
Steve Kondik79165c32015-11-09 19:43:00 -08001078 err_exit("Invalid command code %d at input offset 0x%llx\n",
1079 cmd, (long long)tellin(fd_in) - 1);
Steve Kondik2111ad72013-07-07 12:07:44 -07001080 }
1081}
1082
1083static void wipe_index_entry_timestams(INDEX_ENTRY *e)
1084{
1085 static const struct timespec zero_time = { .tv_sec = 0, .tv_nsec = 0 };
Steve Kondike68cb602016-08-28 00:45:36 -07001086 sle64 timestamp = timespec2ntfs(zero_time);
Steve Kondik2111ad72013-07-07 12:07:44 -07001087
1088 /* FIXME: can fall into infinite loop if corrupted */
1089 while (!(e->ie_flags & INDEX_ENTRY_END)) {
1090
1091 e->key.file_name.creation_time = timestamp;
1092 e->key.file_name.last_data_change_time = timestamp;
1093 e->key.file_name.last_mft_change_time = timestamp;
1094 e->key.file_name.last_access_time = timestamp;
1095
1096 wiped_timestamp_data += 32;
1097
1098 e = (INDEX_ENTRY *)((u8 *)e + le16_to_cpu(e->length));
1099 }
1100}
1101
1102static void wipe_index_allocation_timestamps(ntfs_inode *ni, ATTR_RECORD *attr)
1103{
1104 INDEX_ALLOCATION *indexa, *tmp_indexa;
1105 INDEX_ENTRY *entry;
1106 INDEX_ROOT *indexr;
1107 u8 *bitmap, *byte;
1108 int bit;
1109 ntfs_attr *na;
1110 ntfschar *name;
1111 u32 name_len;
1112
1113 indexr = ntfs_index_root_get(ni, attr);
1114 if (!indexr) {
1115 perr_printf("Failed to read $INDEX_ROOT attribute of inode "
1116 "%lld", (long long)ni->mft_no);
1117 return;
1118 }
1119
1120 if (indexr->type != AT_FILE_NAME)
1121 goto out_indexr;
1122
1123 name = (ntfschar *)((u8 *)attr + le16_to_cpu(attr->name_offset));
1124 name_len = attr->name_length;
1125
1126 byte = bitmap = ntfs_attr_readall(ni, AT_BITMAP, name, name_len,
1127 NULL);
1128 if (!byte) {
1129 perr_printf("Failed to read $BITMAP attribute");
1130 goto out_indexr;
1131 }
1132
1133 na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, name, name_len);
1134 if (!na) {
1135 perr_printf("Failed to open $INDEX_ALLOCATION attribute");
1136 goto out_bitmap;
1137 }
1138
1139 if (!na->data_size)
1140 goto out_na;
1141
1142 tmp_indexa = indexa = ntfs_malloc(na->data_size);
1143 if (!tmp_indexa)
1144 goto out_na;
1145
1146 if (ntfs_attr_pread(na, 0, na->data_size, indexa) != na->data_size) {
1147 perr_printf("Failed to read $INDEX_ALLOCATION attribute");
1148 goto out_indexa;
1149 }
1150
1151 bit = 0;
1152 while ((u8 *)tmp_indexa < (u8 *)indexa + na->data_size) {
1153 if (*byte & (1 << bit)) {
1154 if (ntfs_mst_post_read_fixup((NTFS_RECORD *)tmp_indexa,
1155 le32_to_cpu(
1156 indexr->index_block_size))) {
1157 perr_printf("Damaged INDX record");
1158 goto out_indexa;
1159 }
1160 entry = (INDEX_ENTRY *)((u8 *)tmp_indexa + le32_to_cpu(
1161 tmp_indexa->index.entries_offset) + 0x18);
1162
1163 wipe_index_entry_timestams(entry);
1164
1165 if (ntfs_mft_usn_dec((MFT_RECORD *)tmp_indexa))
1166 perr_exit("ntfs_mft_usn_dec");
1167
1168 if (ntfs_mst_pre_write_fixup((NTFS_RECORD *)tmp_indexa,
1169 le32_to_cpu(
1170 indexr->index_block_size))) {
1171 perr_printf("INDX write fixup failed");
1172 goto out_indexa;
1173 }
1174 }
1175 tmp_indexa = (INDEX_ALLOCATION *)((u8 *)tmp_indexa +
1176 le32_to_cpu(indexr->index_block_size));
1177 bit++;
1178 if (bit > 7) {
1179 bit = 0;
1180 byte++;
1181 }
1182 }
1183 if (ntfs_rl_pwrite(vol, na->rl, 0, 0, na->data_size, indexa) != na->data_size)
1184 perr_printf("ntfs_rl_pwrite failed for inode %lld",
1185 (long long)ni->mft_no);
1186out_indexa:
1187 free(indexa);
1188out_na:
1189 ntfs_attr_close(na);
1190out_bitmap:
1191 free(bitmap);
1192out_indexr:
1193 free(indexr);
1194}
1195
Steve Kondike68cb602016-08-28 00:45:36 -07001196static void wipe_index_root_timestamps(ATTR_RECORD *attr, sle64 timestamp)
Steve Kondik2111ad72013-07-07 12:07:44 -07001197{
1198 INDEX_ENTRY *entry;
1199 INDEX_ROOT *iroot;
1200
1201 iroot = (INDEX_ROOT *)((u8 *)attr + le16_to_cpu(attr->value_offset));
1202 entry = (INDEX_ENTRY *)((u8 *)iroot +
1203 le32_to_cpu(iroot->index.entries_offset) + 0x10);
1204
1205 while (!(entry->ie_flags & INDEX_ENTRY_END)) {
1206
1207 if (iroot->type == AT_FILE_NAME) {
1208
1209 entry->key.file_name.creation_time = timestamp;
1210 entry->key.file_name.last_access_time = timestamp;
1211 entry->key.file_name.last_data_change_time = timestamp;
1212 entry->key.file_name.last_mft_change_time = timestamp;
1213
1214 wiped_timestamp_data += 32;
1215
1216 } else if (ntfs_names_are_equal(NTFS_INDEX_Q,
1217 sizeof(NTFS_INDEX_Q) / 2 - 1,
1218 (ntfschar *)((char *)attr +
1219 le16_to_cpu(attr->name_offset)),
1220 attr->name_length, CASE_SENSITIVE, NULL, 0)) {
1221
1222 QUOTA_CONTROL_ENTRY *quota_q;
1223
1224 quota_q = (QUOTA_CONTROL_ENTRY *)((u8 *)entry +
1225 le16_to_cpu(entry->data_offset));
1226 /*
1227 * FIXME: no guarantee it's indeed /$Extend/$Quota:$Q.
1228 * For now, as a minimal safeguard, we check only for
1229 * quota version 2 ...
1230 */
1231 if (le32_to_cpu(quota_q->version) == 2) {
1232 quota_q->change_time = timestamp;
1233 wiped_timestamp_data += 4;
1234 }
1235 }
1236
1237 entry = (INDEX_ENTRY*)((u8*)entry + le16_to_cpu(entry->length));
1238 }
1239}
1240
1241#define WIPE_TIMESTAMPS(atype, attr, timestamp) \
1242do { \
1243 atype *ats; \
1244 ats = (atype *)((char *)(attr) + le16_to_cpu((attr)->value_offset)); \
1245 \
1246 ats->creation_time = (timestamp); \
1247 ats->last_data_change_time = (timestamp); \
1248 ats->last_mft_change_time= (timestamp); \
1249 ats->last_access_time = (timestamp); \
1250 \
1251 wiped_timestamp_data += 32; \
1252 \
1253} while (0)
1254
1255static void wipe_timestamps(ntfs_walk_clusters_ctx *image)
1256{
1257 static const struct timespec zero_time = { .tv_sec = 0, .tv_nsec = 0 };
1258 ATTR_RECORD *a = image->ctx->attr;
Steve Kondike68cb602016-08-28 00:45:36 -07001259 sle64 timestamp = timespec2ntfs(zero_time);
Steve Kondik2111ad72013-07-07 12:07:44 -07001260
1261 if (a->type == AT_FILE_NAME)
1262 WIPE_TIMESTAMPS(FILE_NAME_ATTR, a, timestamp);
1263
1264 else if (a->type == AT_STANDARD_INFORMATION)
1265 WIPE_TIMESTAMPS(STANDARD_INFORMATION, a, timestamp);
1266
1267 else if (a->type == AT_INDEX_ROOT)
1268 wipe_index_root_timestamps(a, timestamp);
1269}
1270
1271static void wipe_resident_data(ntfs_walk_clusters_ctx *image)
1272{
1273 ATTR_RECORD *a;
1274 u32 i;
1275 int n = 0;
1276 u8 *p;
1277
1278 a = image->ctx->attr;
1279 p = (u8*)a + le16_to_cpu(a->value_offset);
1280
1281 if (image->ni->mft_no <= LAST_METADATA_INODE)
1282 return;
1283
1284 if (a->type != AT_DATA)
1285 return;
1286
1287 for (i = 0; i < le32_to_cpu(a->value_length); i++) {
1288 if (p[i]) {
1289 p[i] = 0;
1290 n++;
1291 }
1292 }
1293
1294 wiped_resident_data += n;
1295}
1296
1297static int wipe_data(char *p, int pos, int len)
1298{
1299 int wiped = 0;
1300
1301 for (p += pos; --len >= 0;) {
1302 if (p[len]) {
1303 p[len] = 0;
1304 wiped++;
1305 }
1306 }
1307
1308 return wiped;
1309}
1310
1311static void wipe_unused_mft_data(ntfs_inode *ni)
1312{
1313 int unused;
1314 MFT_RECORD *m = ni->mrec;
1315
1316 /* FIXME: broken MFTMirr update was fixed in libntfs, check if OK now */
1317 if (ni->mft_no <= LAST_METADATA_INODE)
1318 return;
1319
1320 unused = le32_to_cpu(m->bytes_allocated) - le32_to_cpu(m->bytes_in_use);
1321 wiped_unused_mft_data += wipe_data((char *)m,
1322 le32_to_cpu(m->bytes_in_use), unused);
1323}
1324
1325static void wipe_unused_mft(ntfs_inode *ni)
1326{
1327 int unused;
1328 MFT_RECORD *m = ni->mrec;
1329
1330 /* FIXME: broken MFTMirr update was fixed in libntfs, check if OK now */
1331 if (ni->mft_no <= LAST_METADATA_INODE)
1332 return;
1333
1334 unused = le32_to_cpu(m->bytes_in_use) - sizeof(MFT_RECORD);
1335 wiped_unused_mft += wipe_data((char *)m, sizeof(MFT_RECORD), unused);
1336}
1337
1338static void clone_logfile_parts(ntfs_walk_clusters_ctx *image, runlist *rl)
1339{
1340 s64 offset = 0, lcn, vcn;
1341
1342 while (1) {
1343
1344 vcn = offset / image->ni->vol->cluster_size;
1345 lcn = ntfs_rl_vcn_to_lcn(rl, vcn);
1346 if (lcn < 0)
1347 break;
1348
1349 lseek_to_cluster(lcn);
1350
Steve Kondik79165c32015-11-09 19:43:00 -08001351 if ((lcn + 1) != image->current_lcn) {
1352 /* do not duplicate a cluster */
1353 if (opt.metadata_image && wipe)
1354 gap_to_cluster(lcn - image->current_lcn);
Steve Kondik2111ad72013-07-07 12:07:44 -07001355
Steve Kondik79165c32015-11-09 19:43:00 -08001356 copy_cluster(opt.rescue, lcn, lcn);
1357 }
Steve Kondik2111ad72013-07-07 12:07:44 -07001358 image->current_lcn = lcn + 1;
1359 if (opt.metadata_image && !wipe)
1360 image->inuse++;
1361
1362 if (offset == 0)
1363 offset = NTFS_BLOCK_SIZE >> 1;
1364 else
1365 offset <<= 1;
1366 }
1367}
1368
1369/*
1370 * In-memory wiping of MFT record or MFTMirr record
1371 * (only for metadata images)
1372 *
1373 * The resident data and (optionally) the timestamps are wiped.
1374 */
1375
1376static void wipe_mft(char *mrec, u32 mrecsz, u64 mft_no)
1377{
1378 ntfs_walk_clusters_ctx image;
1379 ntfs_attr_search_ctx *ctx;
1380 ntfs_inode ni;
1381
1382 ni.mft_no = mft_no;
1383 ni.mrec = (MFT_RECORD*)mrec;
1384 ni.vol = vol; /* Hmm */
1385 image.ni = &ni;
1386 ntfs_mst_post_read_fixup_warn((NTFS_RECORD*)mrec,mrecsz,FALSE);
1387 wipe_unused_mft_data(&ni);
1388 if (!(((MFT_RECORD*)mrec)->flags & MFT_RECORD_IN_USE)) {
1389 wipe_unused_mft(&ni);
1390 } else {
1391 /* ctx with no ntfs_inode prevents from searching external attrs */
1392 if (!(ctx = ntfs_attr_get_search_ctx((ntfs_inode*)NULL, (MFT_RECORD*)mrec)))
1393 perr_exit("ntfs_get_attr_search_ctx");
1394
1395 while (!ntfs_attr_lookup(AT_UNUSED, NULL, 0, CASE_SENSITIVE, 0,
1396 NULL, 0, ctx)) {
1397 if (ctx->attr->type == AT_END)
1398 break;
1399
1400 image.ctx = ctx;
1401 if (!ctx->attr->non_resident
1402 && (mft_no > LAST_METADATA_INODE))
1403 wipe_resident_data(&image);
1404 if (!opt.preserve_timestamps)
1405 wipe_timestamps(&image);
1406 }
1407 ntfs_attr_put_search_ctx(ctx);
1408 }
1409 ntfs_mft_usn_dec((MFT_RECORD*)mrec);
1410 ntfs_mst_pre_write_fixup((NTFS_RECORD*)mrec,mrecsz);
1411}
1412
1413/*
1414 * In-memory wiping of a directory record (I30)
1415 * (only for metadata images)
1416 *
1417 * The timestamps are (optionally) wiped
1418 */
1419
1420static void wipe_indx(char *mrec, u32 mrecsz)
1421{
1422 INDEX_ENTRY *entry;
1423 INDEX_ALLOCATION *indexa;
1424
1425 if (ntfs_mst_post_read_fixup((NTFS_RECORD *)mrec, mrecsz)) {
1426 perr_printf("Damaged INDX record");
1427 goto out_indexa;
1428 }
1429 indexa = (INDEX_ALLOCATION*)mrec;
1430 /*
1431 * The index bitmap is not checked, obsoleted records are
1432 * wiped if they pass the safety checks
1433 */
1434 if ((indexa->magic == magic_INDX)
1435 && (le32_to_cpu(indexa->index.entries_offset) >= sizeof(INDEX_HEADER))
1436 && (le32_to_cpu(indexa->index.allocated_size) <= mrecsz)) {
1437 entry = (INDEX_ENTRY *)((u8 *)mrec + le32_to_cpu(
1438 indexa->index.entries_offset) + 0x18);
1439 wipe_index_entry_timestams(entry);
1440 }
1441
1442 if (ntfs_mft_usn_dec((MFT_RECORD *)mrec))
1443 perr_exit("ntfs_mft_usn_dec");
1444
1445 if (ntfs_mst_pre_write_fixup((NTFS_RECORD *)mrec, mrecsz)) {
1446 perr_printf("INDX write fixup failed");
1447 goto out_indexa;
1448 }
1449out_indexa : ;
1450}
1451
1452/*
1453 * Output a set of related clusters (MFT record or index block)
1454 */
1455
1456static void write_set(char *buff, u32 csize, s64 *current_lcn,
1457 runlist_element *rl, u32 wi, u32 wj, u32 cnt)
1458{
1459 u32 k;
1460 s64 target_lcn;
Steve Kondik79165c32015-11-09 19:43:00 -08001461 char cmd = CMD_NEXT;
Steve Kondik2111ad72013-07-07 12:07:44 -07001462
1463 for (k=0; k<cnt; k++) {
1464 target_lcn = rl[wi].lcn + wj;
1465 if (target_lcn != *current_lcn)
1466 gap_to_cluster(target_lcn - *current_lcn);
1467 if ((write_all(&fd_out, &cmd, sizeof(cmd)) == -1)
1468 || (write_all(&fd_out, &buff[k*csize], csize) == -1))
1469 perr_exit("Failed to write_all");
1470 *current_lcn = target_lcn + 1;
1471
1472 if (++wj >= rl[wi].length) {
1473 wj = 0;
1474 wi++;
1475 }
1476 }
1477}
1478
1479/*
1480 * Copy and wipe the full MFT or MFTMirr data.
1481 * (only for metadata images)
1482 *
1483 * Data are read and written by full clusters, but the wiping is done
1484 * per MFT record.
1485 */
1486
1487static void copy_wipe_mft(ntfs_walk_clusters_ctx *image, runlist *rl)
1488{
1489 char buff[NTFS_MAX_CLUSTER_SIZE]; /* overflow checked at mount time */
1490 void *fd;
1491 s64 mft_no;
1492 u32 mft_record_size;
1493 u32 csize;
Steve Kondik79165c32015-11-09 19:43:00 -08001494 u32 bytes_per_sector;
Steve Kondik2111ad72013-07-07 12:07:44 -07001495 u32 records_per_set;
1496 u32 clusters_per_set;
1497 u32 wi,wj; /* indexes for reading */
1498 u32 ri,rj; /* indexes for writing */
1499 u32 k; /* lcn within run */
1500 u32 r; /* mft_record within set */
1501 s64 current_lcn;
1502
1503 current_lcn = image->current_lcn;
1504 mft_record_size = image->ni->vol->mft_record_size;
1505 csize = image->ni->vol->cluster_size;
Steve Kondik79165c32015-11-09 19:43:00 -08001506 bytes_per_sector = image->ni->vol->sector_size;
Steve Kondik2111ad72013-07-07 12:07:44 -07001507 fd = image->ni->vol->dev;
1508 /*
1509 * Depending on the sizes, there may be several records
1510 * per cluster, or several clusters per record.
1511 */
1512 if (csize >= mft_record_size) {
1513 records_per_set = csize/mft_record_size;
1514 clusters_per_set = 1;
1515 } else {
1516 clusters_per_set = mft_record_size/csize;
1517 records_per_set = 1;
1518 }
1519 mft_no = 0;
1520 ri = rj = 0;
1521 wi = wj = 0;
Steve Kondik79165c32015-11-09 19:43:00 -08001522 if (rl[ri].length)
1523 lseek_to_cluster(rl[ri].lcn);
Steve Kondik2111ad72013-07-07 12:07:44 -07001524 while (rl[ri].length) {
1525 for (k=0; (k<clusters_per_set) && rl[ri].length; k++) {
Steve Kondik79165c32015-11-09 19:43:00 -08001526 read_rescue(fd, &buff[k*csize], csize, bytes_per_sector,
1527 rl[ri].lcn + rj);
Steve Kondik2111ad72013-07-07 12:07:44 -07001528 if (++rj >= rl[ri].length) {
1529 rj = 0;
1530 if (rl[++ri].length)
1531 lseek_to_cluster(rl[ri].lcn);
1532 }
1533 }
1534 if (k == clusters_per_set) {
1535 for (r=0; r<records_per_set; r++) {
1536 if (!strncmp(&buff[r*mft_record_size],"FILE",4))
1537 wipe_mft(&buff[r*mft_record_size],
1538 mft_record_size, mft_no);
1539 mft_no++;
1540 }
1541 write_set(buff, csize, &current_lcn,
1542 rl, wi, wj, clusters_per_set);
1543 wj += clusters_per_set;
1544 while (rl[wi].length && (wj >= rl[wi].length))
1545 wj -= rl[wi++].length;
1546 } else {
1547 err_exit("Short last MFT record\n");
1548 }
1549 }
1550 image->current_lcn = current_lcn;
1551}
1552
1553/*
1554 * Copy and wipe the non-resident part of a directory index
1555 * (only for metadata images)
1556 *
1557 * Data are read and written by full clusters, but the wiping is done
1558 * per index record.
1559 */
1560
1561static void copy_wipe_i30(ntfs_walk_clusters_ctx *image, runlist *rl)
1562{
1563 char buff[NTFS_MAX_CLUSTER_SIZE]; /* overflow checked at mount time */
1564 void *fd;
1565 u32 indx_record_size;
1566 u32 csize;
Steve Kondik79165c32015-11-09 19:43:00 -08001567 u32 bytes_per_sector;
Steve Kondik2111ad72013-07-07 12:07:44 -07001568 u32 records_per_set;
1569 u32 clusters_per_set;
1570 u32 wi,wj; /* indexes for reading */
1571 u32 ri,rj; /* indexes for writing */
1572 u32 k; /* lcn within run */
1573 u32 r; /* mft_record within set */
1574 s64 current_lcn;
1575
1576 current_lcn = image->current_lcn;
1577 csize = image->ni->vol->cluster_size;
Steve Kondik79165c32015-11-09 19:43:00 -08001578 bytes_per_sector = image->ni->vol->sector_size;
Steve Kondik2111ad72013-07-07 12:07:44 -07001579 fd = image->ni->vol->dev;
1580 /*
1581 * Depending on the sizes, there may be several records
1582 * per cluster, or several clusters per record.
1583 */
1584 indx_record_size = image->ni->vol->indx_record_size;
1585 if (csize >= indx_record_size) {
1586 records_per_set = csize/indx_record_size;
1587 clusters_per_set = 1;
1588 } else {
1589 clusters_per_set = indx_record_size/csize;
1590 records_per_set = 1;
1591 }
1592 ri = rj = 0;
1593 wi = wj = 0;
Steve Kondik79165c32015-11-09 19:43:00 -08001594 if (rl[ri].length)
1595 lseek_to_cluster(rl[ri].lcn);
Steve Kondik2111ad72013-07-07 12:07:44 -07001596 while (rl[ri].length) {
1597 for (k=0; (k<clusters_per_set) && rl[ri].length; k++) {
Steve Kondik79165c32015-11-09 19:43:00 -08001598 read_rescue(fd, &buff[k*csize], csize, bytes_per_sector,
1599 rl[ri].lcn + rj);
Steve Kondik2111ad72013-07-07 12:07:44 -07001600 if (++rj >= rl[ri].length) {
1601 rj = 0;
1602 if (rl[++ri].length)
1603 lseek_to_cluster(rl[ri].lcn);
1604 }
1605 }
1606 if (k == clusters_per_set) {
1607 /* wipe records_per_set records */
1608 if (!opt.preserve_timestamps)
1609 for (r=0; r<records_per_set; r++) {
1610 if (!strncmp(&buff[r*indx_record_size],"INDX",4))
1611 wipe_indx(&buff[r*indx_record_size],
1612 indx_record_size);
1613 }
1614 write_set(buff, csize, &current_lcn,
1615 rl, wi, wj, clusters_per_set);
1616 wj += clusters_per_set;
1617 while (rl[wi].length && (wj >= rl[wi].length))
1618 wj -= rl[wi++].length;
1619 } else {
1620 err_exit("Short last directory index record\n");
1621 }
1622 }
1623 image->current_lcn = current_lcn;
1624}
1625
1626static void dump_clusters(ntfs_walk_clusters_ctx *image, runlist *rl)
1627{
1628 s64 i, len; /* number of clusters to copy */
1629
1630 if (opt.restore_image)
1631 err_exit("Bug : invalid dump_clusters()\n");
1632
1633 if ((opt.std_out && !opt.metadata_image) || !opt.metadata)
1634 return;
1635 if (!(len = is_critical_metadata(image, rl)))
1636 return;
1637
1638 lseek_to_cluster(rl->lcn);
Steve Kondik2111ad72013-07-07 12:07:44 -07001639 if (opt.metadata_image ? wipe : !wipe) {
Steve Kondik79165c32015-11-09 19:43:00 -08001640 if (opt.metadata_image)
1641 gap_to_cluster(rl->lcn - image->current_lcn);
Steve Kondik2111ad72013-07-07 12:07:44 -07001642 /* FIXME: this could give pretty suboptimal performance */
1643 for (i = 0; i < len; i++)
1644 copy_cluster(opt.rescue, rl->lcn + i, rl->lcn + i);
Steve Kondik79165c32015-11-09 19:43:00 -08001645 if (opt.metadata_image)
1646 image->current_lcn = rl->lcn + len;
Steve Kondik2111ad72013-07-07 12:07:44 -07001647 }
1648}
1649
1650static void walk_runs(struct ntfs_walk_cluster *walk)
1651{
1652 int i, j;
1653 runlist *rl;
1654 ATTR_RECORD *a;
1655 ntfs_attr_search_ctx *ctx;
1656 BOOL mft_data;
1657 BOOL index_i30;
1658
1659 ctx = walk->image->ctx;
1660 a = ctx->attr;
1661
1662 if (!a->non_resident) {
1663 if (wipe) {
1664 wipe_resident_data(walk->image);
1665 if (!opt.preserve_timestamps)
1666 wipe_timestamps(walk->image);
1667 }
1668 return;
1669 }
1670
1671 if (wipe
1672 && !opt.preserve_timestamps
1673 && walk->image->ctx->attr->type == AT_INDEX_ALLOCATION)
1674 wipe_index_allocation_timestamps(walk->image->ni, a);
1675
1676 if (!(rl = ntfs_mapping_pairs_decompress(vol, a, NULL)))
1677 perr_exit("ntfs_decompress_mapping_pairs");
1678
1679 /* special wipings for MFT records and directory indexes */
1680 mft_data = ((walk->image->ni->mft_no == FILE_MFT)
1681 || (walk->image->ni->mft_no == FILE_MFTMirr))
1682 && (a->type == AT_DATA);
1683 index_i30 = (walk->image->ctx->attr->type == AT_INDEX_ALLOCATION)
1684 && (a->name_length == 4)
1685 && !memcmp((char*)a + le16_to_cpu(a->name_offset),
1686 NTFS_INDEX_I30,8);
1687
1688 for (i = 0; rl[i].length; i++) {
1689 s64 lcn = rl[i].lcn;
1690 s64 lcn_length = rl[i].length;
1691
1692 if (lcn == LCN_HOLE || lcn == LCN_RL_NOT_MAPPED)
1693 continue;
1694
1695 /* FIXME: ntfs_mapping_pairs_decompress should return error */
1696 if (lcn < 0 || lcn_length < 0)
1697 err_exit("Corrupt runlist in inode %lld attr %x LCN "
1698 "%llx length %llx\n",
1699 (long long)ctx->ntfs_ino->mft_no,
1700 (unsigned int)le32_to_cpu(a->type),
1701 (long long)lcn, (long long)lcn_length);
1702
1703 if (opt.metadata_image ? wipe && !mft_data && !index_i30 : !wipe)
1704 dump_clusters(walk->image, rl + i);
1705
1706 for (j = 0; j < lcn_length; j++) {
1707 u64 k = (u64)lcn + j;
1708 if (ntfs_bit_get_and_set(lcn_bitmap.bm, k, 1))
1709 err_exit("Cluster %llu referenced twice!\n"
1710 "You didn't shutdown your Windows "
1711 "properly?\n", (unsigned long long)k);
1712 }
1713
1714 if (!opt.metadata_image)
1715 walk->image->inuse += lcn_length;
1716 /*
1717 * For a metadata image, we have to compute the
1718 * number of metadata clusters for the percentages
1719 * to be displayed correctly while restoring.
1720 */
1721 if (!wipe && opt.metadata_image) {
1722 if ((walk->image->ni->mft_no == FILE_LogFile)
1723 && (walk->image->ctx->attr->type == AT_DATA)) {
1724 /* 16 KiB of FILE_LogFile */
1725 walk->image->inuse
1726 += is_critical_metadata(walk->image,rl);
1727 } else {
1728 if ((walk->image->ni->mft_no
1729 <= LAST_METADATA_INODE)
1730 || (walk->image->ctx->attr->type != AT_DATA))
1731 walk->image->inuse += lcn_length;
1732 }
1733 }
1734 }
1735 if (wipe && opt.metadata_image) {
Steve Kondik79165c32015-11-09 19:43:00 -08001736 ntfs_attr *na;
1737 /*
1738 * Non-resident metadata has to be wiped globally,
1739 * because its logical blocks may be larger than
1740 * a cluster and split over two extents.
1741 */
1742 if (mft_data && !a->lowest_vcn) {
1743 na = ntfs_attr_open(walk->image->ni,
1744 AT_DATA, NULL, 0);
1745 if (na) {
1746 na->rl = rl;
1747 rl = (runlist_element*)NULL;
1748 if (!ntfs_attr_map_whole_runlist(na)) {
1749 copy_wipe_mft(walk->image,na->rl);
1750 } else
1751 perr_exit("Failed to map data of inode %lld",
1752 (long long)walk->image->ni->mft_no);
1753 ntfs_attr_close(na);
1754 } else
1755 perr_exit("Failed to open data of inode %lld",
1756 (long long)walk->image->ni->mft_no);
1757 }
1758 if (index_i30 && !a->lowest_vcn) {
1759 na = ntfs_attr_open(walk->image->ni,
1760 AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4);
1761 if (na) {
1762 na->rl = rl;
1763 rl = (runlist_element*)NULL;
1764 if (!ntfs_attr_map_whole_runlist(na)) {
1765 copy_wipe_i30(walk->image,na->rl);
1766 } else
1767 perr_exit("Failed to map index of inode %lld",
1768 (long long)walk->image->ni->mft_no);
1769 ntfs_attr_close(na);
1770 } else
1771 perr_exit("Failed to open index of inode %lld",
1772 (long long)walk->image->ni->mft_no);
1773 }
Steve Kondik2111ad72013-07-07 12:07:44 -07001774 }
1775 if (opt.metadata
1776 && (opt.metadata_image || !wipe)
1777 && (walk->image->ni->mft_no == FILE_LogFile)
1778 && (walk->image->ctx->attr->type == AT_DATA))
1779 clone_logfile_parts(walk->image, rl);
1780
1781 free(rl);
1782}
1783
1784
1785static void walk_attributes(struct ntfs_walk_cluster *walk)
1786{
1787 ntfs_attr_search_ctx *ctx;
1788
1789 if (!(ctx = ntfs_attr_get_search_ctx(walk->image->ni, NULL)))
1790 perr_exit("ntfs_get_attr_search_ctx");
1791
1792 while (!ntfs_attrs_walk(ctx)) {
1793 if (ctx->attr->type == AT_END)
1794 break;
1795
1796 walk->image->ctx = ctx;
1797 walk_runs(walk);
1798 }
1799
1800 ntfs_attr_put_search_ctx(ctx);
1801}
1802
Steve Kondik79165c32015-11-09 19:43:00 -08001803/*
1804 * Compare the actual bitmap to the list of clusters
1805 * allocated to identified files.
1806 *
1807 * Clusters found in use, though not marked in the bitmap are copied
1808 * if the option --ignore-fs-checks is set.
1809 */
Steve Kondik2111ad72013-07-07 12:07:44 -07001810
Steve Kondik79165c32015-11-09 19:43:00 -08001811static int compare_bitmaps(struct bitmap *a, BOOL copy)
Steve Kondik2111ad72013-07-07 12:07:44 -07001812{
1813 s64 i, pos, count;
1814 int mismatch = 0;
Steve Kondik79165c32015-11-09 19:43:00 -08001815 int more_use = 0;
1816 s64 new_cl;
Steve Kondik2111ad72013-07-07 12:07:44 -07001817 u8 bm[NTFS_BUF_SIZE];
1818
1819 Printf("Accounting clusters ...\n");
1820
1821 pos = 0;
Steve Kondik79165c32015-11-09 19:43:00 -08001822 new_cl = 0;
Steve Kondik2111ad72013-07-07 12:07:44 -07001823 while (1) {
1824 count = ntfs_attr_pread(vol->lcnbmp_na, pos, NTFS_BUF_SIZE, bm);
1825 if (count == -1)
1826 perr_exit("Couldn't get $Bitmap $DATA");
1827
1828 if (count == 0) {
1829 /* the backup bootsector need not be accounted for */
1830 if (((vol->nr_clusters + 7) >> 3) > pos)
1831 err_exit("$Bitmap size is smaller than expected"
1832 " (%lld < %lld)\n",
1833 (long long)pos, (long long)a->size);
1834 break;
1835 }
1836
1837 for (i = 0; i < count; i++, pos++) {
1838 s64 cl; /* current cluster */
1839
1840 if (a->size <= pos)
1841 goto done;
1842
1843 if (a->bm[pos] == bm[i])
1844 continue;
1845
1846 for (cl = pos * 8; cl < (pos + 1) * 8; cl++) {
1847 char bit;
1848
1849 bit = ntfs_bit_get(a->bm, cl);
1850 if (bit == ntfs_bit_get(bm, i * 8 + cl % 8))
1851 continue;
1852
Steve Kondik79165c32015-11-09 19:43:00 -08001853 if (!bit)
1854 more_use++;
1855 if (opt.ignore_fs_check && !bit && copy) {
Steve Kondik2111ad72013-07-07 12:07:44 -07001856 lseek_to_cluster(cl);
Steve Kondik79165c32015-11-09 19:43:00 -08001857 if (opt.save_image
1858 || (opt.metadata
1859 && opt.metadata_image)) {
1860 gap_to_cluster(cl - new_cl);
1861 new_cl = cl + 1;
1862 }
Steve Kondik2111ad72013-07-07 12:07:44 -07001863 copy_cluster(opt.rescue, cl, cl);
1864 }
1865
1866 if (++mismatch > 10)
1867 continue;
1868
1869 Printf("Cluster accounting failed at %lld "
1870 "(0x%llx): %s cluster in $Bitmap\n",
1871 (long long)cl, (unsigned long long)cl,
1872 bit ? "missing" : "extra");
1873 }
1874 }
1875 }
1876done:
1877 if (mismatch) {
1878 Printf("Totally %d cluster accounting mismatches.\n", mismatch);
1879 if (opt.ignore_fs_check) {
1880 Printf("WARNING: The NTFS inconsistency was overruled "
1881 "by the --ignore-fs-check option.\n");
Steve Kondik79165c32015-11-09 19:43:00 -08001882 if (new_cl) {
1883 gap_to_cluster(-new_cl);
1884 }
1885 return (more_use);
Steve Kondik2111ad72013-07-07 12:07:44 -07001886 }
1887 err_exit("Filesystem check failed! Windows wasn't shutdown "
1888 "properly or inconsistent\nfilesystem. Please run "
1889 "chkdsk /f on Windows then reboot it TWICE.\n");
1890 }
Steve Kondik79165c32015-11-09 19:43:00 -08001891 return (more_use);
Steve Kondik2111ad72013-07-07 12:07:44 -07001892}
1893
1894
1895static void mft_record_write_with_same_usn(ntfs_volume *volume, ntfs_inode *ni)
1896{
1897 if (ntfs_mft_usn_dec(ni->mrec))
1898 perr_exit("ntfs_mft_usn_dec");
1899
1900 if (ntfs_mft_record_write(volume, ni->mft_no, ni->mrec))
1901 perr_exit("ntfs_mft_record_write");
1902}
1903
1904static void mft_inode_write_with_same_usn(ntfs_volume *volume, ntfs_inode *ni)
1905{
1906 s32 i;
1907
1908 mft_record_write_with_same_usn(volume, ni);
1909
1910 if (ni->nr_extents <= 0)
1911 return;
1912
1913 for (i = 0; i < ni->nr_extents; ++i) {
1914 ntfs_inode *eni = ni->extent_nis[i];
1915 mft_record_write_with_same_usn(volume, eni);
1916 }
1917}
1918
1919static int walk_clusters(ntfs_volume *volume, struct ntfs_walk_cluster *walk)
1920{
1921 s64 inode = 0;
1922 s64 last_mft_rec;
1923 u64 nr_clusters;
1924 ntfs_inode *ni;
1925 struct progress_bar progress;
1926
1927 if (opt.restore_image || (!opt.metadata && wipe))
1928 err_exit("Bug : invalid walk_clusters()\n");
1929 Printf("Scanning volume ...\n");
1930
1931 last_mft_rec = (volume->mft_na->initialized_size >>
1932 volume->mft_record_size_bits) - 1;
1933 walk->image->current_lcn = 0;
1934 progress_init(&progress, inode, last_mft_rec, 100);
1935
1936 NVolSetNoFixupWarn(volume);
1937 for (; inode <= last_mft_rec; inode++) {
1938
1939 int err, deleted_inode;
1940 MFT_REF mref = (MFT_REF)inode;
1941
1942 progress_update(&progress, inode);
1943
1944 /* FIXME: Terrible kludge for libntfs not being able to return
1945 a deleted MFT record as inode */
1946 ni = ntfs_calloc(sizeof(ntfs_inode));
1947 if (!ni)
1948 perr_exit("walk_clusters");
1949
1950 ni->vol = volume;
1951
1952 err = ntfs_file_record_read(volume, mref, &ni->mrec, NULL);
1953 if (err == -1) {
1954 free(ni);
1955 continue;
1956 }
1957
1958 deleted_inode = !(ni->mrec->flags & MFT_RECORD_IN_USE);
1959
1960 if (deleted_inode && !opt.metadata_image) {
1961
1962 ni->mft_no = MREF(mref);
1963 if (wipe) {
1964 wipe_unused_mft(ni);
1965 wipe_unused_mft_data(ni);
1966 mft_record_write_with_same_usn(volume, ni);
1967 }
1968 }
1969
1970 free(ni->mrec);
1971 free(ni);
1972
1973 if (deleted_inode)
1974 continue;
1975
1976 if ((ni = ntfs_inode_open(volume, mref)) == NULL) {
1977 /* FIXME: continue only if it make sense, e.g.
1978 MFT record not in use based on $MFT bitmap */
1979 if (errno == EIO || errno == ENOENT)
1980 continue;
1981 perr_exit("Reading inode %lld failed",
1982 (long long)inode);
1983 }
1984
1985 if (wipe)
1986 nr_used_mft_records++;
1987
1988 if (ni->mrec->base_mft_record)
1989 goto out;
1990
1991 walk->image->ni = ni;
1992 walk_attributes(walk);
1993out:
1994 if (wipe && !opt.metadata_image) {
1995 int i;
1996
1997 wipe_unused_mft_data(ni);
1998 for (i = 0; i < ni->nr_extents; ++i) {
1999 wipe_unused_mft_data(ni->extent_nis[i]);
2000 }
2001 mft_inode_write_with_same_usn(volume, ni);
2002 }
2003
2004 if (ntfs_inode_close(ni))
2005 perr_exit("ntfs_inode_close for inode %lld",
2006 (long long)inode);
2007 }
2008 if (opt.metadata) {
Steve Kondik79165c32015-11-09 19:43:00 -08002009 if (opt.metadata_image && wipe && opt.ignore_fs_check) {
2010 gap_to_cluster(-walk->image->current_lcn);
2011 compare_bitmaps(&lcn_bitmap, TRUE);
2012 walk->image->current_lcn = 0;
2013 }
2014 if (opt.metadata_image ? wipe : !wipe) {
Steve Kondik2111ad72013-07-07 12:07:44 -07002015 /* also get the backup bootsector */
Steve Kondik79165c32015-11-09 19:43:00 -08002016 nr_clusters = vol->nr_clusters;
2017 lseek_to_cluster(nr_clusters);
2018 if (opt.metadata_image && wipe)
2019 gap_to_cluster(nr_clusters
2020 - walk->image->current_lcn);
Steve Kondik2111ad72013-07-07 12:07:44 -07002021 copy_cluster(opt.rescue, nr_clusters, nr_clusters);
Steve Kondik79165c32015-11-09 19:43:00 -08002022 walk->image->current_lcn = nr_clusters;
2023 }
Steve Kondik2111ad72013-07-07 12:07:44 -07002024 /* Not counted, for compatibility with older versions */
2025 if (!opt.metadata_image)
2026 walk->image->inuse++;
2027 }
2028 return 0;
2029}
2030
2031
2032/*
2033 * $Bitmap can overlap the end of the volume. Any bits in this region
2034 * must be set. This region also encompasses the backup boot sector.
2035 */
2036static void bitmap_file_data_fixup(s64 cluster, struct bitmap *bm)
2037{
2038 for (; cluster < bm->size << 3; cluster++)
2039 ntfs_bit_set(bm->bm, (u64)cluster, 1);
2040}
2041
2042
2043/*
2044 * Allocate a block of memory with one bit for each cluster of the disk.
2045 * All the bits are set to 0, except those representing the region beyond the
2046 * end of the disk.
2047 */
2048static void setup_lcn_bitmap(void)
2049{
2050 /* Determine lcn bitmap byte size and allocate it. */
2051 /* include the alternate boot sector in the bitmap count */
2052 lcn_bitmap.size = rounded_up_division(vol->nr_clusters + 1, 8);
2053
2054 lcn_bitmap.bm = ntfs_calloc(lcn_bitmap.size);
2055 if (!lcn_bitmap.bm)
2056 perr_exit("Failed to allocate internal buffer");
2057
2058 bitmap_file_data_fixup(vol->nr_clusters, &lcn_bitmap);
2059}
2060
2061
2062static s64 volume_size(ntfs_volume *volume, s64 nr_clusters)
2063{
2064 return nr_clusters * volume->cluster_size;
2065}
2066
2067
2068static void print_volume_size(const char *str, s64 bytes)
2069{
2070 Printf("%s: %lld bytes (%lld MB)\n", str, (long long)bytes,
2071 (long long)rounded_up_division(bytes, NTFS_MBYTE));
2072}
2073
2074
2075static void print_disk_usage(const char *spacer, u32 cluster_size,
2076 s64 nr_clusters, s64 inuse)
2077{
2078 s64 total, used;
2079
2080 total = nr_clusters * cluster_size;
2081 used = inuse * cluster_size;
2082
2083 Printf("Space in use %s: %lld MB (%.1f%%) ", spacer,
2084 (long long)rounded_up_division(used, NTFS_MBYTE),
2085 100.0 * ((float)used / total));
2086
2087 Printf("\n");
2088}
2089
2090static void print_image_info(void)
2091{
2092 Printf("Ntfsclone image version: %d.%d\n",
2093 image_hdr.major_ver, image_hdr.minor_ver);
2094 Printf("Cluster size : %u bytes\n",
2095 (unsigned)le32_to_cpu(image_hdr.cluster_size));
2096 print_volume_size("Image volume size ",
2097 sle64_to_cpu(image_hdr.nr_clusters) *
2098 le32_to_cpu(image_hdr.cluster_size));
2099 Printf("Image device size : %lld bytes\n",
Steve Kondike68cb602016-08-28 00:45:36 -07002100 (long long)le64_to_cpu(image_hdr.device_size));
Steve Kondik2111ad72013-07-07 12:07:44 -07002101 print_disk_usage(" ", le32_to_cpu(image_hdr.cluster_size),
2102 sle64_to_cpu(image_hdr.nr_clusters),
Steve Kondike68cb602016-08-28 00:45:36 -07002103 le64_to_cpu(image_hdr.inuse));
Steve Kondik2111ad72013-07-07 12:07:44 -07002104 Printf("Offset to image data : %u (0x%x) bytes\n",
2105 (unsigned)le32_to_cpu(image_hdr.offset_to_image_data),
2106 (unsigned)le32_to_cpu(image_hdr.offset_to_image_data));
2107}
2108
2109static void check_if_mounted(const char *device, unsigned long new_mntflag)
2110{
2111 unsigned long mntflag;
2112
2113 if (ntfs_check_if_mounted(device, &mntflag))
2114 perr_exit("Failed to check '%s' mount state", device);
2115
2116 if (mntflag & NTFS_MF_MOUNTED) {
2117 if (!(mntflag & NTFS_MF_READONLY))
2118 err_exit("Device '%s' is mounted read-write. "
2119 "You must 'umount' it first.\n", device);
2120 if (!new_mntflag)
2121 err_exit("Device '%s' is mounted. "
2122 "You must 'umount' it first.\n", device);
2123 }
2124}
2125
2126/**
2127 * mount_volume -
2128 *
2129 * First perform some checks to determine if the volume is already mounted, or
2130 * is dirty (Windows wasn't shutdown properly). If everything is OK, then mount
2131 * the volume (load the metadata into memory).
2132 */
2133static void mount_volume(unsigned long new_mntflag)
2134{
2135 check_if_mounted(opt.volume, new_mntflag);
2136
2137 if (!(vol = ntfs_mount(opt.volume, new_mntflag))) {
2138
2139 int err = errno;
2140
2141 perr_printf("Opening '%s' as NTFS failed", opt.volume);
2142 if (err == EINVAL) {
2143 Printf("Apparently device '%s' doesn't have a "
2144 "valid NTFS. Maybe you selected\nthe whole "
2145 "disk instead of a partition (e.g. /dev/hda, "
2146 "not /dev/hda1)?\n", opt.volume);
2147 }
Steve Kondik79165c32015-11-09 19:43:00 -08002148 /*
2149 * Retry with recovering the log file enabled.
2150 * Normally avoided in order to get the original log file
2151 * data, but needed when remounting the metadata of a
2152 * volume improperly unmounted from Windows.
2153 */
2154 if (!(new_mntflag & (NTFS_MNT_RDONLY | NTFS_MNT_RECOVER))) {
2155 Printf("Trying to recover...\n");
2156 vol = ntfs_mount(opt.volume,
2157 new_mntflag | NTFS_MNT_RECOVER);
2158 Printf("... %s\n",(vol ? "Successful" : "Failed"));
2159 }
2160 if (!vol)
2161 exit(1);
Steve Kondik2111ad72013-07-07 12:07:44 -07002162 }
2163
2164 if (vol->flags & VOLUME_IS_DIRTY)
2165 if (opt.force-- <= 0)
2166 err_exit(dirty_volume_msg, opt.volume);
2167
2168 if (NTFS_MAX_CLUSTER_SIZE < vol->cluster_size)
2169 err_exit("Cluster size %u is too large!\n",
2170 (unsigned int)vol->cluster_size);
2171
2172 Printf("NTFS volume version: %d.%d\n", vol->major_ver, vol->minor_ver);
2173 if (ntfs_version_is_supported(vol))
2174 perr_exit("Unknown NTFS version");
2175
2176 Printf("Cluster size : %u bytes\n",
2177 (unsigned int)vol->cluster_size);
2178 print_volume_size("Current volume size",
2179 volume_size(vol, vol->nr_clusters));
2180}
2181
2182static struct ntfs_walk_cluster backup_clusters = { NULL, NULL };
2183
2184static int device_offset_valid(int fd, s64 ofs)
2185{
2186 char ch;
2187
2188 if (lseek(fd, ofs, SEEK_SET) >= 0 && read(fd, &ch, 1) == 1)
2189 return 0;
2190 return -1;
2191}
2192
2193static s64 device_size_get(int fd)
2194{
2195 s64 high, low;
2196#ifdef BLKGETSIZE64
2197 { u64 size;
2198
2199 if (ioctl(fd, BLKGETSIZE64, &size) >= 0) {
2200 ntfs_log_debug("BLKGETSIZE64 nr bytes = %llu "
2201 "(0x%llx).\n", (unsigned long long)size,
2202 (unsigned long long)size);
2203 return (s64)size;
2204 }
2205 }
2206#endif
2207#ifdef BLKGETSIZE
2208 { unsigned long size;
2209
2210 if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
2211 ntfs_log_debug("BLKGETSIZE nr 512 byte blocks = %lu "
2212 "(0x%lx).\n", size, size);
2213 return (s64)size * 512;
2214 }
2215 }
2216#endif
2217#ifdef FDGETPRM
2218 { struct floppy_struct this_floppy;
2219
2220 if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) {
2221 ntfs_log_debug("FDGETPRM nr 512 byte blocks = %lu "
2222 "(0x%lx).\n", this_floppy.size,
2223 this_floppy.size);
2224 return (s64)this_floppy.size * 512;
2225 }
2226 }
2227#endif
2228 /*
2229 * We couldn't figure it out by using a specialized ioctl,
2230 * so do binary search to find the size of the device.
2231 */
2232 low = 0LL;
2233 for (high = 1024LL; !device_offset_valid(fd, high); high <<= 1)
2234 low = high;
2235 while (low < high - 1LL) {
2236 const s64 mid = (low + high) / 2;
2237
2238 if (!device_offset_valid(fd, mid))
2239 low = mid;
2240 else
2241 high = mid;
2242 }
2243 lseek(fd, 0LL, SEEK_SET);
2244 return (low + 1LL);
2245}
2246
2247static void fsync_clone(int fd)
2248{
2249 Printf("Syncing ...\n");
2250 if (opt.save_image && stream_out && fflush(stream_out))
2251 perr_exit("fflush");
2252 if (fsync(fd) && errno != EINVAL)
2253 perr_exit("fsync");
2254}
2255
2256static void set_filesize(s64 filesize)
2257{
2258#ifndef NO_STATFS
2259 long fs_type = 0; /* Unknown filesystem type */
2260
2261 if (fstatfs(fd_out, &opt.stfs) == -1)
2262 Printf("WARNING: Couldn't get filesystem type: "
2263 "%s\n", strerror(errno));
2264 else
2265 fs_type = opt.stfs.f_type;
2266
2267 if (fs_type == 0x52654973)
2268 Printf("WARNING: You're using ReiserFS, it has very poor "
2269 "performance creating\nlarge sparse files. The next "
2270 "operation might take a very long time!\n"
2271 "Creating sparse output file ...\n");
2272 else if (fs_type == 0x517b)
2273 Printf("WARNING: You're using SMBFS and if the remote share "
2274 "isn't Samba but a Windows\ncomputer then the clone "
2275 "operation will be very inefficient and may fail!\n");
2276#endif
2277
Steve Kondik79165c32015-11-09 19:43:00 -08002278 if (!opt.no_action && (ftruncate(fd_out, filesize) == -1)) {
Steve Kondik2111ad72013-07-07 12:07:44 -07002279 int err = errno;
2280 perr_printf("ftruncate failed for file '%s'", opt.output);
2281#ifndef NO_STATFS
2282 if (fs_type)
2283 Printf("Destination filesystem type is 0x%lx.\n",
2284 (unsigned long)fs_type);
2285#endif
2286 if (err == E2BIG) {
2287 Printf("Your system or the destination filesystem "
2288 "doesn't support large files.\n");
2289#ifndef NO_STATFS
2290 if (fs_type == 0x517b) {
2291 Printf("SMBFS needs minimum Linux kernel "
2292 "version 2.4.25 and\n the 'lfs' option"
2293 "\nfor smbmount to have large "
2294 "file support.\n");
2295 }
2296#endif
2297 } else if (err == EPERM) {
2298 Printf("Apparently the destination filesystem doesn't "
2299 "support sparse files.\nYou can overcome this "
2300 "by using the more efficient --save-image "
2301 "option\nof ntfsclone. Use the --restore-image "
2302 "option to restore the image.\n");
2303 }
2304 exit(1);
2305 }
Steve Kondik79165c32015-11-09 19:43:00 -08002306 /*
2307 * If truncate just created a sparse file, the ability
2308 * to generically store big files has been checked, but no
2309 * space has been reserved and available space has probably
2310 * not been checked. Better reset the file so that we write
2311 * sequentially to the end.
2312 */
2313 if (!opt.no_action) {
2314#ifdef HAVE_WINDOWS_H
2315 if (ftruncate(fd_out, 0))
2316 Printf("Failed to reset the output file.\n");
2317#else
2318 struct stat st;
2319 int s;
2320
2321 s = fstat(fd_out, &st);
2322 if (s || (!st.st_blocks && ftruncate(fd_out, 0)))
2323 Printf("Failed to reset the output file.\n");
2324#endif
2325 /* Proceed even if ftruncate failed */
2326 }
Steve Kondik2111ad72013-07-07 12:07:44 -07002327}
2328
2329static s64 open_image(void)
2330{
2331 if (strcmp(opt.volume, "-") == 0) {
2332 if ((fd_in = fileno(stdin)) == -1)
Steve Kondik79165c32015-11-09 19:43:00 -08002333 perr_exit("fileno for stdin failed");
2334#ifdef HAVE_WINDOWS_H
2335 if (setmode(fd_in,O_BINARY) == -1)
2336 perr_exit("setting binary stdin failed");
2337#endif
Steve Kondik2111ad72013-07-07 12:07:44 -07002338 } else {
Steve Kondik79165c32015-11-09 19:43:00 -08002339 if ((fd_in = open(opt.volume, O_RDONLY | O_BINARY)) == -1)
Steve Kondik2111ad72013-07-07 12:07:44 -07002340 perr_exit("failed to open image");
2341 }
2342 if (read_all(&fd_in, &image_hdr, NTFSCLONE_IMG_HEADER_SIZE_OLD) == -1)
2343 perr_exit("read_all");
2344 if (memcmp(image_hdr.magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE) != 0)
2345 err_exit("Input file is not an image! (invalid magic)\n");
2346 if (image_hdr.major_ver < NTFSCLONE_IMG_VER_MAJOR_ENDIANNESS_SAFE) {
2347 image_hdr.major_ver = NTFSCLONE_IMG_VER_MAJOR;
2348 image_hdr.minor_ver = NTFSCLONE_IMG_VER_MINOR;
2349#if (__BYTE_ORDER == __BIG_ENDIAN)
2350 /*
2351 * old image read on a big endian computer,
2352 * assuming it was created big endian and read cpu-wise,
2353 * so we should translate to little endian
2354 */
2355 Printf("Old image format detected. If the image was created "
2356 "on a little endian architecture it will not "
2357 "work. Use a more recent version of "
2358 "ntfsclone to recreate the image.\n");
2359 image_hdr.cluster_size = cpu_to_le32(image_hdr.cluster_size);
2360 image_hdr.device_size = cpu_to_sle64(image_hdr.device_size);
2361 image_hdr.nr_clusters = cpu_to_sle64(image_hdr.nr_clusters);
2362 image_hdr.inuse = cpu_to_sle64(image_hdr.inuse);
2363#endif
2364 image_hdr.offset_to_image_data =
2365 const_cpu_to_le32((sizeof(image_hdr)
2366 + IMAGE_HDR_ALIGN - 1) & -IMAGE_HDR_ALIGN);
2367 image_is_host_endian = TRUE;
2368 } else {
2369 /* safe image : little endian data */
2370 le32 offset_to_image_data;
2371 int delta;
2372
2373 if (image_hdr.major_ver > NTFSCLONE_IMG_VER_MAJOR)
2374 err_exit("Do not know how to handle image format "
2375 "version %d.%d. Please obtain a "
2376 "newer version of ntfsclone.\n",
2377 image_hdr.major_ver,
2378 image_hdr.minor_ver);
2379 /* Read the image header data offset. */
2380 if (read_all(&fd_in, &offset_to_image_data,
2381 sizeof(offset_to_image_data)) == -1)
2382 perr_exit("read_all");
2383 /* do not translate little endian data */
2384 image_hdr.offset_to_image_data = offset_to_image_data;
2385 /*
2386 * Read any fields from the header that we have not read yet so
2387 * that the input stream is positioned correctly. This means
2388 * we can support future minor versions that just extend the
2389 * header in a backwards compatible way.
2390 */
2391 delta = le32_to_cpu(offset_to_image_data)
2392 - (NTFSCLONE_IMG_HEADER_SIZE_OLD +
2393 sizeof(image_hdr.offset_to_image_data));
2394 if (delta > 0) {
2395 char *dummy_buf;
2396
2397 dummy_buf = malloc(delta);
2398 if (!dummy_buf)
2399 perr_exit("malloc dummy_buffer");
2400 if (read_all(&fd_in, dummy_buf, delta) == -1)
2401 perr_exit("read_all");
2402 free(dummy_buf);
2403 }
2404 }
Steve Kondike68cb602016-08-28 00:45:36 -07002405 return le64_to_cpu(image_hdr.device_size);
Steve Kondik2111ad72013-07-07 12:07:44 -07002406}
2407
2408static s64 open_volume(void)
2409{
2410 s64 device_size;
2411
2412 mount_volume(NTFS_MNT_RDONLY);
2413
2414 device_size = ntfs_device_size_get(vol->dev, 1);
2415 if (device_size <= 0)
2416 err_exit("Couldn't get device size (%lld)!\n",
2417 (long long)device_size);
2418
2419 print_volume_size("Current device size", device_size);
2420
2421 if (device_size < vol->nr_clusters * vol->cluster_size)
2422 err_exit("Current NTFS volume size is bigger than the device "
2423 "size (%lld)!\nCorrupt partition table or incorrect "
2424 "device partitioning?\n", (long long)device_size);
2425
2426 return device_size;
2427}
2428
2429static void initialise_image_hdr(s64 device_size, s64 inuse)
2430{
2431 memcpy(image_hdr.magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE);
2432 image_hdr.major_ver = NTFSCLONE_IMG_VER_MAJOR;
2433 image_hdr.minor_ver = NTFSCLONE_IMG_VER_MINOR;
2434 image_hdr.cluster_size = cpu_to_le32(vol->cluster_size);
Steve Kondike68cb602016-08-28 00:45:36 -07002435 image_hdr.device_size = cpu_to_le64(device_size);
Steve Kondik2111ad72013-07-07 12:07:44 -07002436 image_hdr.nr_clusters = cpu_to_sle64(vol->nr_clusters);
Steve Kondike68cb602016-08-28 00:45:36 -07002437 image_hdr.inuse = cpu_to_le64(inuse);
Steve Kondik2111ad72013-07-07 12:07:44 -07002438 image_hdr.offset_to_image_data = cpu_to_le32((sizeof(image_hdr)
2439 + IMAGE_HDR_ALIGN - 1) & -IMAGE_HDR_ALIGN);
2440}
2441
2442static void check_output_device(s64 input_size)
2443{
2444 if (opt.blkdev_out) {
Steve Kondik79165c32015-11-09 19:43:00 -08002445 s64 dest_size;
2446
2447 if (dev_out)
2448 dest_size = ntfs_device_size_get(dev_out, 1);
2449 else
2450 dest_size = device_size_get(fd_out);
Steve Kondik2111ad72013-07-07 12:07:44 -07002451 if (dest_size < input_size)
2452 err_exit("Output device is too small (%lld) to fit the "
2453 "NTFS image (%lld).\n",
2454 (long long)dest_size, (long long)input_size);
2455
2456 check_if_mounted(opt.output, 0);
2457 } else
2458 set_filesize(input_size);
2459}
2460
Steve Kondik2111ad72013-07-07 12:07:44 -07002461static void ignore_bad_clusters(ntfs_walk_clusters_ctx *image)
2462{
2463 ntfs_inode *ni;
Steve Kondike68cb602016-08-28 00:45:36 -07002464 ntfs_attr *na;
2465 runlist *rl;
Steve Kondik2111ad72013-07-07 12:07:44 -07002466 s64 nr_bad_clusters = 0;
Steve Kondike68cb602016-08-28 00:45:36 -07002467 static le16 Bad[4] = {
2468 const_cpu_to_le16('$'), const_cpu_to_le16('B'),
2469 const_cpu_to_le16('a'), const_cpu_to_le16('d')
2470 } ;
Steve Kondik2111ad72013-07-07 12:07:44 -07002471
2472 if (!(ni = ntfs_inode_open(vol, FILE_BadClus)))
2473 perr_exit("ntfs_open_inode");
2474
Steve Kondike68cb602016-08-28 00:45:36 -07002475 na = ntfs_attr_open(ni, AT_DATA, Bad, 4);
2476 if (!na)
2477 perr_exit("ntfs_attr_open");
2478 if (ntfs_attr_map_whole_runlist(na))
2479 perr_exit("ntfs_attr_map_whole_runlist");
Steve Kondik2111ad72013-07-07 12:07:44 -07002480
Steve Kondike68cb602016-08-28 00:45:36 -07002481 for (rl = na->rl; rl->length; rl++) {
Steve Kondik2111ad72013-07-07 12:07:44 -07002482 s64 lcn = rl->lcn;
2483
2484 if (lcn == LCN_HOLE || lcn < 0)
2485 continue;
2486
2487 for (; lcn < rl->lcn + rl->length; lcn++, nr_bad_clusters++) {
2488 if (ntfs_bit_get_and_set(lcn_bitmap.bm, lcn, 0))
2489 image->inuse--;
2490 }
2491 }
2492 if (nr_bad_clusters)
2493 Printf("WARNING: The disk has %lld or more bad sectors"
2494 " (hardware faults).\n", (long long)nr_bad_clusters);
Steve Kondike68cb602016-08-28 00:45:36 -07002495 ntfs_attr_close(na);
Steve Kondik2111ad72013-07-07 12:07:44 -07002496 if (ntfs_inode_close(ni))
2497 perr_exit("ntfs_inode_close failed for $BadClus");
2498}
2499
2500static void check_dest_free_space(u64 src_bytes)
2501{
Steve Kondik79165c32015-11-09 19:43:00 -08002502#ifndef HAVE_WINDOWS_H
Steve Kondik2111ad72013-07-07 12:07:44 -07002503 u64 dest_bytes;
2504 struct statvfs stvfs;
2505 struct stat st;
2506
2507 if (opt.metadata || opt.blkdev_out || opt.std_out)
2508 return;
2509 /*
2510 * TODO: save_image needs a bit more space than src_bytes
2511 * due to the free space encoding overhead.
2512 */
2513 if (fstatvfs(fd_out, &stvfs) == -1) {
2514 Printf("WARNING: Unknown free space on the destination: %s\n",
2515 strerror(errno));
2516 return;
2517 }
2518
2519 /* If file is a FIFO then there is no point in checking the size. */
2520 if (!fstat(fd_out, &st)) {
2521 if (S_ISFIFO(st.st_mode))
2522 return;
2523 } else
2524 Printf("WARNING: fstat failed: %s\n", strerror(errno));
2525
2526 dest_bytes = (u64)stvfs.f_frsize * stvfs.f_bfree;
2527 if (!dest_bytes)
2528 dest_bytes = (u64)stvfs.f_bsize * stvfs.f_bfree;
2529
2530 if (dest_bytes < src_bytes)
2531 err_exit("Destination doesn't have enough free space: "
2532 "%llu MB < %llu MB\n",
2533 (unsigned long long)rounded_up_division(dest_bytes, NTFS_MBYTE),
2534 (unsigned long long)rounded_up_division(src_bytes, NTFS_MBYTE));
Steve Kondik79165c32015-11-09 19:43:00 -08002535#endif
Steve Kondik2111ad72013-07-07 12:07:44 -07002536}
2537
2538int main(int argc, char **argv)
2539{
2540 ntfs_walk_clusters_ctx image;
2541 s64 device_size; /* input device size in bytes */
2542 s64 ntfs_size;
2543 unsigned int wiped_total = 0;
2544
2545 /* make sure the layout of header is not affected by alignments */
2546 if (offsetof(struct image_hdr, offset_to_image_data)
2547 != IMAGE_OFFSET_OFFSET) {
2548 fprintf(stderr,"ntfsclone is not compiled properly. "
2549 "Please fix\n");
2550 exit(1);
2551 }
2552 /* print to stderr, stdout can be an NTFS image ... */
2553 fprintf(stderr, "%s v%s (libntfs-3g)\n", EXEC_NAME, VERSION);
2554 msg_out = stderr;
2555
2556 parse_options(argc, argv);
2557
2558 utils_set_locale();
2559
2560 if (opt.restore_image) {
2561 device_size = open_image();
2562 ntfs_size = sle64_to_cpu(image_hdr.nr_clusters) *
2563 le32_to_cpu(image_hdr.cluster_size);
2564 } else {
2565 device_size = open_volume();
2566 ntfs_size = vol->nr_clusters * vol->cluster_size;
2567 }
2568 // FIXME: This needs to be the cluster size...
2569 ntfs_size += 512; /* add backup boot sector */
2570 full_device_size = device_size;
2571
2572 if (opt.std_out) {
2573 if ((fd_out = fileno(stdout)) == -1)
2574 perr_exit("fileno for stdout failed");
2575 stream_out = stdout;
Steve Kondik79165c32015-11-09 19:43:00 -08002576#ifdef HAVE_WINDOWS_H
2577 if (setmode(fileno(stdout),O_BINARY) == -1)
2578 perr_exit("setting binary stdout failed");
2579#endif
Steve Kondik2111ad72013-07-07 12:07:44 -07002580 } else {
2581 /* device_size_get() might need to read() */
Steve Kondik79165c32015-11-09 19:43:00 -08002582 int flags = O_RDWR | O_BINARY;
Steve Kondik2111ad72013-07-07 12:07:44 -07002583
Steve Kondik79165c32015-11-09 19:43:00 -08002584 fd_out = 0;
Steve Kondik2111ad72013-07-07 12:07:44 -07002585 if (!opt.blkdev_out) {
2586 flags |= O_CREAT | O_TRUNC;
2587 if (!opt.overwrite)
2588 flags |= O_EXCL;
2589 }
2590
2591 if (opt.save_image || opt.metadata_image) {
Steve Kondik79165c32015-11-09 19:43:00 -08002592 stream_out = fopen(opt.output,BINWMODE);
Steve Kondik2111ad72013-07-07 12:07:44 -07002593 if (!stream_out)
2594 perr_exit("Opening file '%s' failed",
2595 opt.output);
2596 fd_out = fileno(stream_out);
Steve Kondik79165c32015-11-09 19:43:00 -08002597 } else {
2598#ifdef HAVE_WINDOWS_H
2599 if (!opt.no_action) {
2600 dev_out = ntfs_device_alloc(opt.output, 0,
2601 &ntfs_device_default_io_ops, NULL);
2602 if (!dev_out
2603 || (dev_out->d_ops->open)(dev_out, flags))
2604 perr_exit("Opening volume '%s' failed",
2605 opt.output);
2606 }
2607#else
2608 if (!opt.no_action
2609 && ((fd_out = open(opt.output, flags,
2610 S_IRUSR | S_IWUSR)) == -1))
Steve Kondik2111ad72013-07-07 12:07:44 -07002611 perr_exit("Opening file '%s' failed",
2612 opt.output);
Steve Kondik79165c32015-11-09 19:43:00 -08002613#endif
2614 }
Steve Kondik2111ad72013-07-07 12:07:44 -07002615
Steve Kondik79165c32015-11-09 19:43:00 -08002616 if (!opt.save_image && !opt.metadata_image && !opt.no_action)
Steve Kondik2111ad72013-07-07 12:07:44 -07002617 check_output_device(ntfs_size);
2618 }
2619
2620 if (opt.restore_image) {
2621 print_image_info();
2622 restore_image();
Steve Kondik79165c32015-11-09 19:43:00 -08002623 if (!opt.no_action)
2624 fsync_clone(fd_out);
Steve Kondik2111ad72013-07-07 12:07:44 -07002625 exit(0);
2626 }
2627
2628 setup_lcn_bitmap();
2629 memset(&image, 0, sizeof(image));
2630 backup_clusters.image = &image;
2631
2632 walk_clusters(vol, &backup_clusters);
Steve Kondik79165c32015-11-09 19:43:00 -08002633 image.more_use = compare_bitmaps(&lcn_bitmap,
2634 opt.metadata && !opt.metadata_image);
Steve Kondik2111ad72013-07-07 12:07:44 -07002635 print_disk_usage("", vol->cluster_size, vol->nr_clusters, image.inuse);
2636
2637 check_dest_free_space(vol->cluster_size * image.inuse);
2638
2639 ignore_bad_clusters(&image);
2640
2641 if (opt.save_image)
2642 initialise_image_hdr(device_size, image.inuse);
2643
2644 if ((opt.std_out && !opt.metadata_image) || !opt.metadata) {
2645 s64 nr_clusters_to_save = image.inuse;
2646 if (opt.std_out && !opt.save_image)
2647 nr_clusters_to_save = vol->nr_clusters;
2648 nr_clusters_to_save++; /* account for the backup boot sector */
2649
Steve Kondik79165c32015-11-09 19:43:00 -08002650 clone_ntfs(nr_clusters_to_save, image.more_use);
Steve Kondik2111ad72013-07-07 12:07:44 -07002651 fsync_clone(fd_out);
2652 if (opt.save_image)
2653 fclose(stream_out);
2654 ntfs_umount(vol,FALSE);
2655 free(lcn_bitmap.bm);
2656 exit(0);
2657 }
2658
2659 wipe = 1;
2660 if (opt.metadata_image) {
2661 initialise_image_hdr(device_size, image.inuse);
2662 write_image_hdr();
2663 } else {
Steve Kondik79165c32015-11-09 19:43:00 -08002664 if (dev_out) {
2665 (dev_out->d_ops->close)(dev_out);
2666 dev_out = NULL;
2667 } else
2668 fsync_clone(fd_out); /* sync copy before mounting */
Steve Kondik2111ad72013-07-07 12:07:44 -07002669 opt.volume = opt.output;
2670 /* 'force' again mount for dirty volumes (e.g. after resize).
2671 FIXME: use mount flags to avoid potential side-effects in future */
2672 opt.force++;
2673 ntfs_umount(vol,FALSE);
2674 mount_volume(0 /*NTFS_MNT_NOATIME*/);
2675 }
2676
2677 free(lcn_bitmap.bm);
2678 setup_lcn_bitmap();
2679 memset(&image, 0, sizeof(image));
2680 backup_clusters.image = &image;
2681
2682 walk_clusters(vol, &backup_clusters);
2683
2684 Printf("Num of MFT records = %10lld\n",
2685 (long long)vol->mft_na->initialized_size >>
2686 vol->mft_record_size_bits);
2687 Printf("Num of used MFT records = %10u\n", nr_used_mft_records);
2688
2689 Printf("Wiped unused MFT data = %10u\n", wiped_unused_mft_data);
2690 Printf("Wiped deleted MFT data = %10u\n", wiped_unused_mft);
2691 Printf("Wiped resident user data = %10u\n", wiped_resident_data);
2692 Printf("Wiped timestamp data = %10u\n", wiped_timestamp_data);
2693
2694 wiped_total += wiped_unused_mft_data;
2695 wiped_total += wiped_unused_mft;
2696 wiped_total += wiped_resident_data;
2697 wiped_total += wiped_timestamp_data;
2698 Printf("Wiped totally = %10u\n", wiped_total);
2699
2700 if (opt.metadata_image)
2701 fclose(stream_out);
2702 else
2703 fsync_clone(fd_out);
2704 ntfs_umount(vol,FALSE);
2705 free(lcn_bitmap.bm);
2706 return (0);
2707}