1 /**
2 * ntfswipe - Part of the Linux-NTFS project.
3 *
4 * Copyright (c) 2005 Anton Altaparmakov
5 * Copyright (c) 2002-2005 Richard Russon
6 * Copyright (c) 2004 Yura Pakhuchiy
7 *
8 * This utility will overwrite unused space on an NTFS volume.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program (in the main directory of the Linux-NTFS
22 * distribution in the file COPYING); if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26 #include "config.h"
27
28 #ifdef HAVE_STDIO_H
29 #include <stdio.h>
30 #endif
31 #ifdef HAVE_ERRNO_H
32 #include <errno.h>
33 #endif
34 #ifdef HAVE_STDARG_H
35 #include <stdarg.h>
36 #endif
37 #ifdef HAVE_GETOPT_H
38 #include <getopt.h>
39 #endif
40 #ifdef HAVE_STRING_H
41 #include <string.h>
42 #endif
43 #ifdef HAVE_STDLIB_H
44 #include <stdlib.h>
45 #else
46 #ifdef HAVE_MALLOC_H
47 #include <malloc.h>
48 #endif
49 #endif
50 #ifdef HAVE_UNISTD_H
51 #include <unistd.h>
52 #endif
53 #ifdef HAVE_TIME_H
54 #include <time.h>
55 #endif
56 #ifdef HAVE_LIMITS_H
57 #include <limits.h>
58 #endif
59
60 #include "ntfswipe.h"
61 #include "types.h"
62 #include "volume.h"
63 #include "utils.h"
64 #include "debug.h"
65 #include "dir.h"
66 #include "mst.h"
67 /* #include "version.h" */
68 #include "logging.h"
69 #include "list.h"
70 #include "mft.h"
71
72 static const char *EXEC_NAME = "ntfswipe";
73 static struct options opts;
74 static unsigned long int npasses = 0;
75
76 struct filename {
77 char *parent_name;
78 struct ntfs_list_head list; /* Previous/Next links */
79 ntfschar *uname; /* Filename in unicode */
80 int uname_len; /* and its length */
81 /* Allocated size (multiple of cluster size) */
82 s64 size_alloc;
83 s64 size_data; /* Actual size of data */
84 long long parent_mref;
85 FILE_ATTR_FLAGS flags;
86 time_t date_c; /* Time created */
87 time_t date_a; /* altered */
88 time_t date_m; /* mft record changed */
89 time_t date_r; /* read */
90 char *name; /* Filename in current locale */
91 FILE_NAME_TYPE_FLAGS name_space;
92 char padding[7]; /* Unused: padding to 64 bit. */
93 };
94
95 struct data {
96 struct ntfs_list_head list; /* Previous/Next links */
97 char *name; /* Stream name in current locale */
98 ntfschar *uname; /* Unicode stream name */
99 int uname_len; /* and its length */
100 int resident; /* Stream is resident */
101 int compressed; /* Stream is compressed */
102 int encrypted; /* Stream is encrypted */
103 /* Allocated size (multiple of cluster size) */
104 s64 size_alloc;
105 s64 size_data; /* Actual size of data */
106 /* Initialised size, may be less than data size */
107 s64 size_init;
108 VCN size_vcn; /* Highest VCN in the data runs */
109 runlist_element *runlist; /* Decoded data runs */
110 int percent; /* Amount potentially recoverable */
111 void *data; /* If resident, a pointer to the data */
112 char padding[4]; /* Unused: padding to 64 bit. */
113 };
114
115 struct ufile {
116 s64 inode; /* MFT record number */
117 time_t date; /* Last modification date/time */
118 struct ntfs_list_head name; /* A list of filenames */
119 struct ntfs_list_head data; /* A list of data streams */
120 char *pref_name; /* Preferred filename */
121 char *pref_pname; /* parent filename */
122 s64 max_size; /* Largest size we find */
123 int attr_list; /* MFT record may be one of many */
124 int directory; /* MFT record represents a directory */
125 MFT_RECORD *mft; /* Raw MFT record */
126 char padding[4]; /* Unused: padding to 64 bit. */
127 };
128
129 #define NPAT 22
130
131 /* Taken from `shred' source */
132 static const unsigned int patterns[NPAT] = {
133 0x000, 0xFFF, /* 1-bit */
134 0x555, 0xAAA, /* 2-bit */
135 0x249, 0x492, 0x6DB, 0x924, 0xB6D, 0xDB6, /* 3-bit */
136 0x111, 0x222, 0x333, 0x444, 0x666, 0x777,
137 0x888, 0x999, 0xBBB, 0xCCC, 0xDDD, 0xEEE /* 4-bit */
138 };
139
140
141 /**
142 * version - Print version information about the program
143 *
144 * Print a copyright statement and a brief description of the program.
145 *
146 * Return: none
147 */
version(void)148 static void version(void)
149 {
150 ntfs_log_info("\n%s v%s (libntfs-3g) - Overwrite the unused space on an NTFS "
151 "Volume.\n\n", EXEC_NAME, VERSION);
152 ntfs_log_info("Copyright (c) 2002-2005 Richard Russon\n");
153 ntfs_log_info("Copyright (c) 2004 Yura Pakhuchiy\n");
154 ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
155 }
156
157 /**
158 * usage - Print a list of the parameters to the program
159 *
160 * Print a list of the parameters and options for the program.
161 *
162 * Return: none
163 */
usage(void)164 static void usage(void)
165 {
166 ntfs_log_info("\nUsage: %s [options] device\n"
167 " -i --info Show volume information (default)\n"
168 "\n"
169 " -d --directory Wipe directory indexes\n"
170 " -l --logfile Wipe the logfile (journal)\n"
171 " -m --mft Wipe mft space\n"
172 " -p --pagefile Wipe pagefile (swap space)\n"
173 " -t --tails Wipe file tails\n"
174 " -u --unused Wipe unused clusters\n"
175 " -U --unused-fast Wipe unused clusters (fast)\n"
176 " -s --undel Wipe undelete data\n"
177 "\n"
178 " -a --all Wipe all unused space\n"
179 "\n"
180 " -c num --count num Number of times to write(default = 1)\n"
181 " -b list --bytes list List of values to write(default = 0)\n"
182 "\n"
183 " -n --no-action Do not write to disk\n"
184 " -f --force Use less caution\n"
185 " -q --quiet Less output\n"
186 " -v --verbose More output\n"
187 " -V --version Version information\n"
188 " -h --help Print this help\n\n",
189 EXEC_NAME);
190 ntfs_log_info("%s%s\n", ntfs_bugs, ntfs_home);
191 }
192
193 /**
194 * parse_list - Read a comma-separated list of numbers
195 * @list: The comma-separated list of numbers
196 * @result: Store the parsed list here (must be freed by caller)
197 *
198 * Read a comma-separated list of numbers and allocate an array of ints to store
199 * them in. The numbers can be in decimal, octal or hex.
200 *
201 * N.B. The caller must free the memory returned in @result.
202 * N.B. If the function fails, @result is not changed.
203 *
204 * Return: 0 Error, invalid string
205 * n Success, the count of numbers parsed
206 */
parse_list(char * list,int ** result)207 static int parse_list(char *list, int **result)
208 {
209 char *ptr;
210 char *end;
211 int i;
212 int count;
213 int *mem = NULL;
214
215 if (!list || !result)
216 return 0;
217
218 for (count = 0, ptr = list; ptr; ptr = strchr(ptr+1, ','))
219 count++;
220
221 mem = malloc((count+1) * sizeof(int));
222 if (!mem) {
223 ntfs_log_error("Couldn't allocate memory in parse_list().\n");
224 return 0;
225 }
226
227 memset(mem, 0xFF, (count+1) * sizeof(int));
228
229 for (ptr = list, i = 0; i < count; i++) {
230
231 end = NULL;
232 mem[i] = strtol(ptr, &end, 0);
233
234 if (!end || (end == ptr) || ((*end != ',') && (*end != 0))) {
235 ntfs_log_error("Invalid list '%s'\n", list);
236 free(mem);
237 return 0;
238 }
239
240 if ((mem[i] < 0) || (mem[i] > 255)) {
241 ntfs_log_error("Bytes must be in range 0-255.\n");
242 free(mem);
243 return 0;
244 }
245
246 ptr = end + 1;
247 }
248
249 ntfs_log_debug("Parsing list '%s' - ", list);
250 for (i = 0; i <= count; i++)
251 ntfs_log_debug("0x%02x ", mem[i]);
252 ntfs_log_debug("\n");
253
254 *result = mem;
255 return count;
256 }
257
258 /**
259 * parse_options - Read and validate the programs command line
260 *
261 * Read the command line, verify the syntax and parse the options.
262 * This function is very long, but quite simple.
263 *
264 * Return: 1 Success
265 * 0 Error, one or more problems
266 */
parse_options(int argc,char * argv[])267 static int parse_options(int argc, char *argv[])
268 {
269 static const char *sopt = "-ab:c:dfh?ilmnpqtuUvVs";
270 static struct option lopt[] = {
271 { "all", no_argument, NULL, 'a' },
272 { "bytes", required_argument, NULL, 'b' },
273 { "count", required_argument, NULL, 'c' },
274 { "directory", no_argument, NULL, 'd' },
275 { "force", no_argument, NULL, 'f' },
276 { "help", no_argument, NULL, 'h' },
277 { "info", no_argument, NULL, 'i' },
278 { "logfile", no_argument, NULL, 'l' },
279 { "mft", no_argument, NULL, 'm' },
280 { "no-action", no_argument, NULL, 'n' },
281 //{ "no-wait", no_argument, NULL, 0 },
282 { "pagefile", no_argument, NULL, 'p' },
283 { "quiet", no_argument, NULL, 'q' },
284 { "tails", no_argument, NULL, 't' },
285 { "unused", no_argument, NULL, 'u' },
286 { "unused-fast",no_argument, NULL, 'U' },
287 { "undel", no_argument, NULL, 's' },
288 { "verbose", no_argument, NULL, 'v' },
289 { "version", no_argument, NULL, 'V' },
290 { NULL, 0, NULL, 0 }
291 };
292
293 int c = -1;
294 char *end;
295 int err = 0;
296 int ver = 0;
297 int help = 0;
298 int levels = 0;
299
300 opterr = 0; /* We'll handle the errors, thank you. */
301
302 opts.count = 1;
303
304 while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
305 switch (c) {
306 case 1: /* A non-option argument */
307 if (!opts.device) {
308 opts.device = argv[optind-1];
309 } else {
310 opts.device = NULL;
311 err++;
312 }
313 break;
314
315 case 'i':
316 opts.info++; /* and fall through */
317 /* FALLTHRU */
318 case 'a':
319 opts.directory++;
320 opts.logfile++;
321 opts.mft++;
322 opts.pagefile++;
323 opts.tails++;
324 opts.unused++;
325 opts.undel++;
326 break;
327 case 'b':
328 if (!opts.bytes) {
329 if (!parse_list(optarg, &opts.bytes))
330 err++;
331 } else {
332 err++;
333 }
334 break;
335 case 'c':
336 if (opts.count == 1) {
337 end = NULL;
338 opts.count = strtol(optarg, &end, 0);
339 if (end && *end)
340 err++;
341 } else {
342 err++;
343 }
344 break;
345 case 'd':
346 opts.directory++;
347 break;
348 case 'f':
349 opts.force++;
350 break;
351 case 'h':
352 help++;
353 break;
354 case 'l':
355 opts.logfile++;
356 break;
357 case 'm':
358 opts.mft++;
359 break;
360 case 'n':
361 opts.noaction++;
362 break;
363 case 'p':
364 opts.pagefile++;
365 break;
366 case 'q':
367 opts.quiet++;
368 ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET);
369 break;
370 case 's':
371 opts.undel++;
372 break;
373 case 't':
374 opts.tails++;
375 break;
376 case 'u':
377 opts.unused++;
378 break;
379 case 'U':
380 opts.unused_fast++;
381 break;
382 case 'v':
383 opts.verbose++;
384 ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
385 break;
386 case 'V':
387 ver++;
388 break;
389 case '?':
390 if (strncmp (argv[optind-1], "--log-", 6) == 0) {
391 if (!ntfs_log_parse_option (argv[optind-1]))
392 err++;
393 break;
394 }
395 /* fall through */
396 default:
397 if ((optopt == 'b') || (optopt == 'c')) {
398 ntfs_log_error("Option '%s' requires an argument.\n", argv[optind-1]);
399 } else {
400 ntfs_log_error("Unknown option '%s'.\n", argv[optind-1]);
401 }
402 err++;
403 break;
404 }
405 }
406
407 if (opts.bytes && opts.undel) {
408 ntfs_log_error("Options --bytes and --undel are not compatible.\n");
409 err++;
410 }
411 /* Make sure we're in sync with the log levels */
412 levels = ntfs_log_get_levels();
413 if (levels & NTFS_LOG_LEVEL_VERBOSE)
414 opts.verbose++;
415 if (!(levels & NTFS_LOG_LEVEL_QUIET))
416 opts.quiet++;
417
418 if (help || ver) {
419 opts.quiet = 0;
420 } else {
421 if (opts.device == NULL) {
422 if (argc > 1)
423 ntfs_log_error("You must specify exactly one device.\n");
424 err++;
425 }
426
427 if (opts.quiet && opts.verbose) {
428 ntfs_log_error("You may not use --quiet and --verbose at the same time.\n");
429 err++;
430 }
431
432 /*
433 if (opts.info && (opts.unused || opts.tails || opts.mft || opts.directory)) {
434 ntfs_log_error("You may not use any other options with --info.\n");
435 err++;
436 }
437 */
438
439 if ((opts.count < 1) || (opts.count > 100)) {
440 ntfs_log_error("The iteration count must be between 1 and 100.\n");
441 err++;
442 }
443
444 /* Create a default list */
445 if (!opts.bytes) {
446 opts.bytes = malloc(2 * sizeof(int));
447 if (opts.bytes) {
448 opts.bytes[0] = 0;
449 opts.bytes[1] = -1;
450 } else {
451 ntfs_log_error("Couldn't allocate memory for byte list.\n");
452 err++;
453 }
454 }
455
456 if (!opts.directory && !opts.logfile && !opts.mft &&
457 !opts.pagefile && !opts.tails && !opts.unused &&
458 !opts.unused_fast && !opts.undel) {
459 opts.info = 1;
460 }
461 }
462
463 if (ver)
464 version();
465 if (help || err)
466 usage();
467
468 /* tri-state 0 : done, 1 : error, -1 : proceed */
469 return (err ? 1 : (help || ver ? 0 : -1));
470 }
471
472 /**
473 * wipe_unused - Wipe unused clusters
474 * @vol: An ntfs volume obtained from ntfs_mount
475 * @byte: Overwrite with this value
476 * @act: Wipe, test or info
477 *
478 * Read $Bitmap and wipe any clusters that are marked as not in use.
479 *
480 * Return: >0 Success, the attribute was wiped
481 * 0 Nothing to wipe
482 * -1 Error, something went wrong
483 */
wipe_unused(ntfs_volume * vol,int byte,enum action act)484 static s64 wipe_unused(ntfs_volume *vol, int byte, enum action act)
485 {
486 s64 i;
487 s64 total = 0;
488 s64 result = 0;
489 u8 *buffer = NULL;
490
491 if (!vol || (byte < 0))
492 return -1;
493
494 if (act != act_info) {
495 buffer = malloc(vol->cluster_size);
496 if (!buffer) {
497 ntfs_log_error("malloc failed\n");
498 return -1;
499 }
500 memset(buffer, byte, vol->cluster_size);
501 }
502
503 for (i = 0; i < vol->nr_clusters; i++) {
504 if (utils_cluster_in_use(vol, i)) {
505 //ntfs_log_verbose("cluster %lld is in use\n", i);
506 continue;
507 }
508
509 if (act == act_wipe) {
510 //ntfs_log_verbose("cluster %lld is not in use\n", i);
511 result = ntfs_pwrite(vol->dev, vol->cluster_size * i, vol->cluster_size, buffer);
512 if (result != vol->cluster_size) {
513 ntfs_log_error("write failed\n");
514 goto free;
515 }
516 }
517
518 total += vol->cluster_size;
519 }
520
521 ntfs_log_quiet("wipe_unused 0x%02x, %lld bytes\n", byte, (long long)total);
522 free:
523 free(buffer);
524 return total;
525 }
526
527 /**
528 * wipe_unused_fast - Faster wipe unused clusters
529 * @vol: An ntfs volume obtained from ntfs_mount
530 * @byte: Overwrite with this value
531 * @act: Wipe, test or info
532 *
533 * Read $Bitmap and wipe any clusters that are marked as not in use.
534 *
535 * - read/write on a block basis (64 clusters, arbitrary)
536 * - skip of fully used block
537 * - skip non-used block already wiped
538 *
539 * Return: >0 Success, the attribute was wiped
540 * 0 Nothing to wipe
541 * -1 Error, something went wrong
542 */
wipe_unused_fast(ntfs_volume * vol,int byte,enum action act)543 static s64 wipe_unused_fast(ntfs_volume *vol, int byte, enum action act)
544 {
545 s64 i;
546 s64 total = 0;
547 s64 unused = 0;
548 s64 result;
549 u8 *buffer;
550 u8 *big_buffer;
551 u32 *u32_buffer;
552 u32 u32_bytes;
553 unsigned int blksize;
554 unsigned int j,k;
555 BOOL wipe_needed;
556
557 if (!vol || (byte < 0))
558 return -1;
559
560 big_buffer = (u8*)malloc(vol->cluster_size*64);
561 if (!big_buffer) {
562 ntfs_log_error("malloc failed\n");
563 return -1;
564 }
565
566 for (i = 0; i < vol->nr_clusters; i+=64) {
567 blksize = vol->nr_clusters - i;
568 if (blksize > 64)
569 blksize = 64;
570 /* if all clusters in this block are used, ignore the block */
571 result = 0;
572 for (j = 0; j < blksize; j++) {
573 if (utils_cluster_in_use(vol, i+j))
574 result++;
575 }
576 unused += (blksize - result) * vol->cluster_size;
577
578 if (result == blksize) {
579 continue;
580 }
581 /*
582 * if all unused clusters in this block are already wiped,
583 * ignore the block
584 */
585 if (ntfs_pread(vol->dev, vol->cluster_size * i,
586 vol->cluster_size * blksize, big_buffer)
587 != vol->cluster_size * blksize) {
588 ntfs_log_error("Read failed at cluster %lld\n",
589 (long long)i);
590 goto free;
591 }
592
593 result = 0;
594 wipe_needed = FALSE;
595 u32_bytes = (byte & 255)*0x01010101;
596 buffer = big_buffer;
597 for (j = 0; (j < blksize) && !wipe_needed; j++) {
598 u32_buffer = (u32*)buffer;
599 if (!utils_cluster_in_use(vol, i+j)) {
600 for (k = 0; (k < vol->cluster_size)
601 && (*u32_buffer++ == u32_bytes); k+=4) {
602 }
603 if (k < vol->cluster_size)
604 wipe_needed = TRUE;
605 }
606 buffer += vol->cluster_size;
607 }
608
609 if (!wipe_needed) {
610 continue;
611 }
612 /* else wipe unused clusters in the block */
613 buffer = big_buffer;
614
615 for (j = 0; j < blksize; j++) {
616 if (!utils_cluster_in_use(vol, i+j)) {
617 memset(buffer, byte, vol->cluster_size);
618 total += vol->cluster_size;
619 }
620 buffer += vol->cluster_size;
621 }
622
623 if ((act == act_wipe)
624 && (ntfs_pwrite(vol->dev, vol->cluster_size * i,
625 vol->cluster_size * blksize, big_buffer)
626 != vol->cluster_size * blksize)) {
627 ntfs_log_error("Write failed at cluster %lld\n",
628 (long long)i);
629 goto free;
630 }
631 }
632
633 ntfs_log_quiet("wipe_unused_fast 0x%02x, %lld bytes"
634 " already wiped, %lld more bytes wiped\n",
635 byte, (long long)(unused - total), (long long)total);
636 free:
637 free(big_buffer);
638 return total;
639 }
640
641 /**
642 * wipe_compressed_attribute - Wipe compressed $DATA attribute
643 * @vol: An ntfs volume obtained from ntfs_mount
644 * @byte: Overwrite with this value
645 * @act: Wipe, test or info
646 * @na: Opened ntfs attribute
647 *
648 * Return: >0 Success, the attribute was wiped
649 * 0 Nothing to wipe
650 * -1 Error, something went wrong
651 */
wipe_compressed_attribute(ntfs_volume * vol,int byte,enum action act,ntfs_attr * na)652 static s64 wipe_compressed_attribute(ntfs_volume *vol, int byte,
653 enum action act, ntfs_attr *na)
654 {
655 unsigned char *buf;
656 s64 size, offset, ret, wiped = 0;
657 le16 block_size_le;
658 u16 block_size;
659 VCN cur_vcn = 0;
660 runlist_element *rlc = na->rl;
661 s64 cu_mask = na->compression_block_clusters - 1;
662 runlist_element *restart = na->rl;
663
664 while (rlc->length) {
665 cur_vcn += rlc->length;
666 if ((cur_vcn & cu_mask) ||
667 (((rlc + 1)->length) && (rlc->lcn != LCN_HOLE))) {
668 rlc++;
669 continue;
670 }
671
672 if (rlc->lcn == LCN_HOLE) {
673 runlist_element *rlt;
674
675 offset = cur_vcn - rlc->length;
676 if (offset == (offset & (~cu_mask))) {
677 restart = rlc + 1;
678 rlc++;
679 continue;
680 }
681 offset = (offset & (~cu_mask))
682 << vol->cluster_size_bits;
683 rlt = rlc;
684 while ((rlt - 1)->lcn == LCN_HOLE) rlt--;
685 while (1) {
686 ret = ntfs_rl_pread(vol, restart,
687 offset - (restart->vcn
688 << vol->cluster_size_bits),
689 2, &block_size_le);
690 block_size = le16_to_cpu(block_size_le);
691 if (ret != 2) {
692 ntfs_log_verbose("Internal error\n");
693 ntfs_log_error("ntfs_rl_pread failed");
694 return -1;
695 }
696 if (block_size == 0) {
697 offset += 2;
698 break;
699 }
700 block_size &= 0x0FFF;
701 block_size += 3;
702 offset += block_size;
703 if (offset >= (((rlt->vcn) <<
704 vol->cluster_size_bits) - 2))
705 goto next;
706 }
707 size = (rlt->vcn << vol->cluster_size_bits) - offset;
708 } else {
709 size = na->allocated_size - na->data_size;
710 offset = (cur_vcn << vol->cluster_size_bits) - size;
711 }
712
713 if (size < 0) {
714 ntfs_log_verbose("Internal error\n");
715 ntfs_log_error("bug or damaged fs: we want "
716 "allocate buffer size %lld bytes",
717 (long long)size);
718 return -1;
719 }
720
721 if ((act == act_info) || (!size)) {
722 wiped += size;
723 if (rlc->lcn == LCN_HOLE)
724 restart = rlc + 1;
725 rlc++;
726 continue;
727 }
728
729 buf = malloc(size);
730 if (!buf) {
731 ntfs_log_verbose("Not enough memory\n");
732 ntfs_log_error("Not enough memory to allocate "
733 "%lld bytes",
734 (long long)size);
735 return -1;
736 }
737 memset(buf, byte, size);
738
739 ret = ntfs_rl_pwrite(vol, restart,
740 restart->vcn << vol->cluster_size_bits,
741 offset, size, buf);
742 free(buf);
743 if (ret != size) {
744 ntfs_log_verbose("Internal error\n");
745 ntfs_log_error("ntfs_rl_pwrite failed, offset %llu, "
746 "size %lld, vcn %lld",
747 (unsigned long long)offset,
748 (long long)size, (long long)rlc->vcn);
749 return -1;
750 }
751 wiped += ret;
752 next:
753 if (rlc->lcn == LCN_HOLE)
754 restart = rlc + 1;
755 rlc++;
756 }
757
758 return wiped;
759 }
760
761 /**
762 * wipe_attribute - Wipe not compressed $DATA attribute
763 * @vol: An ntfs volume obtained from ntfs_mount
764 * @byte: Overwrite with this value
765 * @act: Wipe, test or info
766 * @na: Opened ntfs attribute
767 *
768 * Return: >0 Success, the attribute was wiped
769 * 0 Nothing to wipe
770 * -1 Error, something went wrong
771 */
wipe_attribute(ntfs_volume * vol,int byte,enum action act,ntfs_attr * na)772 static s64 wipe_attribute(ntfs_volume *vol, int byte, enum action act,
773 ntfs_attr *na)
774 {
775 unsigned char *buf;
776 s64 wiped;
777 s64 size;
778 u64 offset = na->data_size;
779
780 if (!offset)
781 return 0;
782 if (na->data_flags & ATTR_IS_ENCRYPTED)
783 offset = (((offset - 1) >> 10) + 1) << 10;
784 size = (vol->cluster_size - offset) % vol->cluster_size;
785
786 if (act == act_info)
787 return size;
788
789 buf = malloc(size);
790 if (!buf) {
791 ntfs_log_verbose("Not enough memory\n");
792 ntfs_log_error("Not enough memory to allocate %lld bytes",
793 (long long)size);
794 return -1;
795 }
796 memset(buf, byte, size);
797
798 wiped = ntfs_rl_pwrite(vol, na->rl, 0, offset, size, buf);
799 if (wiped == -1) {
800 ntfs_log_verbose("Internal error\n");
801 ntfs_log_error("Couldn't wipe tail");
802 }
803
804 free(buf);
805 return wiped;
806 }
807
808 /*
809 * Wipe a data attribute tail
810 *
811 * Return: >0 Success, the clusters were wiped
812 * 0 Nothing to wipe
813 * -1 Error, something went wrong
814 */
815
wipe_attr_tail(ntfs_inode * ni,ntfschar * name,int namelen,int byte,enum action act)816 static s64 wipe_attr_tail(ntfs_inode *ni, ntfschar *name, int namelen,
817 int byte, enum action act)
818 {
819 ntfs_attr *na;
820 ntfs_volume *vol = ni->vol;
821 s64 wiped;
822
823 wiped = -1;
824 na = ntfs_attr_open(ni, AT_DATA, name, namelen);
825 if (!na) {
826 ntfs_log_error("Couldn't open $DATA attribute\n");
827 goto close_attr;
828 }
829
830 if (!NAttrNonResident(na)) {
831 ntfs_log_verbose("Resident $DATA attribute. Skipping.\n");
832 goto close_attr;
833 }
834
835 if (ntfs_attr_map_whole_runlist(na)) {
836 ntfs_log_verbose("Internal error\n");
837 ntfs_log_error("Can't map runlist (inode %lld)\n",
838 (long long)ni->mft_no);
839 goto close_attr;
840 }
841
842 if (na->data_flags & ATTR_COMPRESSION_MASK)
843 wiped = wipe_compressed_attribute(vol, byte, act, na);
844 else
845 wiped = wipe_attribute(vol, byte, act, na);
846
847 if (wiped == -1) {
848 ntfs_log_error(" (inode %lld)\n", (long long)ni->mft_no);
849 }
850
851 close_attr:
852 ntfs_attr_close(na);
853 return (wiped);
854 }
855
856 /**
857 * wipe_tails - Wipe the file tails in all its data attributes
858 * @vol: An ntfs volume obtained from ntfs_mount
859 * @byte: Overwrite with this value
860 * @act: Wipe, test or info
861 *
862 * Disk space is allocated in clusters. If a file isn't an exact multiple of
863 * the cluster size, there is some slack space at the end. Wipe this space.
864 *
865 * Return: >0 Success, the clusters were wiped
866 * 0 Nothing to wipe
867 * -1 Error, something went wrong
868 */
wipe_tails(ntfs_volume * vol,int byte,enum action act)869 static s64 wipe_tails(ntfs_volume *vol, int byte, enum action act)
870 {
871 s64 total = 0;
872 s64 nr_mft_records, inode_num;
873 ntfs_attr_search_ctx *ctx;
874 ntfs_inode *ni;
875 ATTR_RECORD *a;
876 ntfschar *name;
877
878 if (!vol || (byte < 0))
879 return -1;
880
881 nr_mft_records = vol->mft_na->initialized_size >>
882 vol->mft_record_size_bits;
883
884 /* Avoid getting fixup warnings on unitialized inodes */
885 NVolSetNoFixupWarn(vol);
886
887 for (inode_num = FILE_first_user; inode_num < nr_mft_records;
888 inode_num++) {
889 s64 attr_wiped;
890 s64 wiped = 0;
891
892 ntfs_log_verbose("Inode %lld - ", (long long)inode_num);
893 ni = ntfs_inode_open(vol, inode_num);
894 if (!ni) {
895 if (opts.verbose)
896 ntfs_log_verbose("Could not open inode\n");
897 else
898 ntfs_log_verbose("\r");
899 continue;
900 }
901
902 if (ni->mrec->base_mft_record) {
903 ntfs_log_verbose("Not base mft record. Skipping\n");
904 goto close_inode;
905 }
906
907 ctx = ntfs_attr_get_search_ctx(ni, (MFT_RECORD*)NULL);
908 if (!ctx) {
909 ntfs_log_error("Can't get a context, aborting\n");
910 ntfs_inode_close(ni);
911 goto close_abort;
912 }
913 while (!ntfs_attr_lookup(AT_DATA, NULL, 0, CASE_SENSITIVE, 0,
914 NULL, 0, ctx)) {
915 a = ctx->attr;
916
917 if (!ctx->al_entry || !ctx->al_entry->lowest_vcn) {
918 name = (ntfschar*)((u8*)a
919 + le16_to_cpu(a->name_offset));
920 attr_wiped = wipe_attr_tail(ni, name,
921 a->name_length, byte, act);
922 if (attr_wiped > 0)
923 wiped += attr_wiped;
924 }
925 }
926 ntfs_attr_put_search_ctx(ctx);
927 if (wiped) {
928 ntfs_log_verbose("Wiped %llu bytes\n",
929 (unsigned long long)wiped);
930 total += wiped;
931 } else
932 ntfs_log_verbose("Nothing to wipe\n");
933 close_inode:
934 ntfs_inode_close(ni);
935 }
936 close_abort :
937 NVolClearNoFixupWarn(vol);
938 ntfs_log_quiet("wipe_tails 0x%02x, %lld bytes\n", byte,
939 (long long)total);
940 return total;
941 }
942
943 /**
944 * wipe_mft - Wipe the MFT slack space
945 * @vol: An ntfs volume obtained from ntfs_mount
946 * @byte: Overwrite with this value
947 * @act: Wipe, test or info
948 *
949 * MFT Records are 1024 bytes long, but some of this space isn't used. Wipe any
950 * unused space at the end of the record and wipe any unused records.
951 *
952 * Return: >0 Success, the clusters were wiped
953 * 0 Nothing to wipe
954 * -1 Error, something went wrong
955 */
wipe_mft(ntfs_volume * vol,int byte,enum action act)956 static s64 wipe_mft(ntfs_volume *vol, int byte, enum action act)
957 {
958 // by considering the individual attributes we might be able to
959 // wipe a few more bytes at the attr's tail.
960 s64 nr_mft_records, i;
961 s64 total = 0;
962 s64 result = 0;
963 int size = 0;
964 MFT_RECORD *rec = NULL;
965
966 if (!vol || (byte < 0))
967 return -1;
968
969 rec = (MFT_RECORD*)malloc(vol->mft_record_size);
970 if (!rec) {
971 ntfs_log_error("malloc failed\n");
972 return -1;
973 }
974
975 nr_mft_records = vol->mft_na->initialized_size >>
976 vol->mft_record_size_bits;
977
978 for (i = 0; i < nr_mft_records; i++) {
979 if (utils_mftrec_in_use(vol, i)) {
980 result = ntfs_attr_mst_pread(vol->mft_na, vol->mft_record_size * i,
981 1, vol->mft_record_size, rec);
982 if (result != 1) {
983 ntfs_log_error("error attr mst read %lld\n",
984 (long long)i);
985 total = -1; // XXX just negate result?
986 goto free;
987 }
988
989 // We know that the end marker will only take 4 bytes
990 size = le32_to_cpu(rec->bytes_in_use) - 4;
991
992 if ((size <= 0) || (size > (int)vol->mft_record_size)) {
993 ntfs_log_error("Bad mft record %lld\n",
994 (long long)i);
995 total = -1;
996 goto free;
997 }
998 if (act == act_info) {
999 //ntfs_log_info("mft %d\n", size);
1000 total += size;
1001 continue;
1002 }
1003
1004 memset(((u8*) rec) + size, byte, vol->mft_record_size - size);
1005 } else {
1006 const u16 usa_offset =
1007 (vol->major_ver == 3) ? 0x0030 : 0x002A;
1008 const u32 usa_size = 1 +
1009 (vol->mft_record_size >> NTFS_BLOCK_SIZE_BITS);
1010 const u16 attrs_offset =
1011 ((usa_offset + usa_size) + 7) & ~((u16) 7);
1012 const u32 bytes_in_use = attrs_offset + 8;
1013
1014 if(usa_size > 0xFFFF || (usa_offset + usa_size) >
1015 (NTFS_BLOCK_SIZE - sizeof(u16)))
1016 {
1017 ntfs_log_error("%d: usa_size out of bounds "
1018 "(%u)\n", __LINE__, usa_size);
1019 total = -1;
1020 goto free;
1021 }
1022
1023 if (act == act_info) {
1024 total += vol->mft_record_size;
1025 continue;
1026 }
1027
1028 // Build the record from scratch
1029 memset(rec, 0, vol->mft_record_size);
1030
1031 // Common values
1032 rec->magic = magic_FILE;
1033 rec->usa_ofs = cpu_to_le16(usa_offset);
1034 rec->usa_count = cpu_to_le16((u16) usa_size);
1035 rec->sequence_number = const_cpu_to_le16(0x0001);
1036 rec->attrs_offset = cpu_to_le16(attrs_offset);
1037 rec->bytes_in_use = cpu_to_le32(bytes_in_use);
1038 rec->bytes_allocated = cpu_to_le32(vol->mft_record_size);
1039 rec->next_attr_instance = const_cpu_to_le16(0x0001);
1040
1041 // End marker.
1042 *((le32*) (((u8*) rec) + attrs_offset)) = const_cpu_to_le32(0xFFFFFFFF);
1043 }
1044
1045 result = ntfs_attr_mst_pwrite(vol->mft_na, vol->mft_record_size * i,
1046 1, vol->mft_record_size, rec);
1047 if (result != 1) {
1048 ntfs_log_error("error attr mst write %lld\n",
1049 (long long)i);
1050 total = -1;
1051 goto free;
1052 }
1053
1054 if ((vol->mft_record_size * (i+1)) <= vol->mftmirr_na->allocated_size)
1055 {
1056 // We have to reduce the update sequence number, or else...
1057 u16 offset;
1058 le16 *usnp;
1059 offset = le16_to_cpu(rec->usa_ofs);
1060 usnp = (le16*) (((u8*) rec) + offset);
1061 *usnp = cpu_to_le16(le16_to_cpu(*usnp) - 1);
1062
1063 result = ntfs_attr_mst_pwrite(vol->mftmirr_na, vol->mft_record_size * i,
1064 1, vol->mft_record_size, rec);
1065 if (result != 1) {
1066 ntfs_log_error("error attr mst write %lld\n",
1067 (long long)i);
1068 total = -1;
1069 goto free;
1070 }
1071 }
1072
1073 total += vol->mft_record_size;
1074 }
1075
1076 ntfs_log_quiet("wipe_mft 0x%02x, %lld bytes\n", byte, (long long)total);
1077 free:
1078 free(rec);
1079 return total;
1080 }
1081
1082 /**
1083 * wipe_index_allocation - Wipe $INDEX_ALLOCATION attribute
1084 * @vol: An ntfs volume obtained from ntfs_mount
1085 * @byte: Overwrite with this value
1086 * @act: Wipe, test or info
1087 * @naa: Opened ntfs $INDEX_ALLOCATION attribute
1088 * @nab: Opened ntfs $BITMAP attribute
1089 * @indx_record_size: Size of INDX record
1090 *
1091 * Return: >0 Success, the clusters were wiped
1092 * 0 Nothing to wipe
1093 * -1 Error, something went wrong
1094 */
wipe_index_allocation(ntfs_volume * vol,int byte,enum action act,ntfs_attr * naa,ntfs_attr * nab,u32 indx_record_size)1095 static s64 wipe_index_allocation(ntfs_volume *vol, int byte, enum action act
1096 __attribute__((unused)), ntfs_attr *naa, ntfs_attr *nab,
1097 u32 indx_record_size)
1098 {
1099 s64 total = 0;
1100 s64 wiped = 0;
1101 s64 offset = 0;
1102 s64 obyte = 0;
1103 u64 wipe_offset;
1104 s64 wipe_size;
1105 u8 obit = 0;
1106 u8 mask;
1107 u8 *bitmap;
1108 u8 *buf;
1109
1110 bitmap = malloc(nab->data_size);
1111 if (!bitmap) {
1112 ntfs_log_verbose("malloc failed\n");
1113 ntfs_log_error("Couldn't allocate %lld bytes",
1114 (long long)nab->data_size);
1115 return -1;
1116 }
1117
1118 if (ntfs_attr_pread(nab, 0, nab->data_size, bitmap)
1119 != nab->data_size) {
1120 ntfs_log_verbose("Internal error\n");
1121 ntfs_log_error("Couldn't read $BITMAP");
1122 total = -1;
1123 goto free_bitmap;
1124 }
1125
1126 buf = malloc(indx_record_size);
1127 if (!buf) {
1128 ntfs_log_verbose("malloc failed\n");
1129 ntfs_log_error("Couldn't allocate %u bytes",
1130 (unsigned int)indx_record_size);
1131 total = -1;
1132 goto free_bitmap;
1133 }
1134
1135 while (offset < naa->allocated_size) {
1136 mask = 1 << obit;
1137 if (bitmap[obyte] & mask) {
1138 INDEX_ALLOCATION *indx;
1139
1140 s64 ret = ntfs_rl_pread(vol, naa->rl,
1141 offset, indx_record_size, buf);
1142 if (ret != indx_record_size) {
1143 ntfs_log_verbose("ntfs_rl_pread failed\n");
1144 ntfs_log_error("Couldn't read INDX record");
1145 total = -1;
1146 goto free_buf;
1147 }
1148
1149 indx = (INDEX_ALLOCATION *) buf;
1150 if (ntfs_mst_post_read_fixup((NTFS_RECORD *)buf,
1151 indx_record_size))
1152 ntfs_log_error("damaged fs: mst_post_read_fixup failed");
1153
1154 if ((le32_to_cpu(indx->index.allocated_size) + 0x18) !=
1155 indx_record_size) {
1156 ntfs_log_verbose("Internal error\n");
1157 ntfs_log_error("INDX record should be %u bytes",
1158 (unsigned int)indx_record_size);
1159 total = -1;
1160 goto free_buf;
1161 }
1162
1163 wipe_offset = le32_to_cpu(indx->index.index_length) + 0x18;
1164 wipe_size = indx_record_size - wipe_offset;
1165 memset(buf + wipe_offset, byte, wipe_size);
1166 if (ntfs_mst_pre_write_fixup((NTFS_RECORD *)indx,
1167 indx_record_size))
1168 ntfs_log_error("damaged fs: mst_pre_write_protect failed");
1169 if (opts.verbose > 1)
1170 ntfs_log_verbose("+");
1171 } else {
1172 wipe_size = indx_record_size;
1173 memset(buf, byte, wipe_size);
1174 if (opts.verbose > 1)
1175 ntfs_log_verbose("x");
1176 }
1177
1178 wiped = ntfs_rl_pwrite(vol, naa->rl, 0, offset, indx_record_size, buf);
1179 if (wiped != indx_record_size) {
1180 ntfs_log_verbose("ntfs_rl_pwrite failed\n");
1181 ntfs_log_error("Couldn't wipe tail of INDX record");
1182 total = -1;
1183 goto free_buf;
1184 }
1185 total += wipe_size;
1186
1187 offset += indx_record_size;
1188 obit++;
1189 if (obit > 7) {
1190 obit = 0;
1191 obyte++;
1192 }
1193 }
1194 if ((opts.verbose > 1) && (wiped != -1))
1195 ntfs_log_verbose("\n\t");
1196 free_buf:
1197 free(buf);
1198 free_bitmap:
1199 free(bitmap);
1200 return total;
1201 }
1202
1203 /**
1204 * get_indx_record_size - determine size of INDX record from $INDEX_ROOT
1205 * @nar: Opened ntfs $INDEX_ROOT attribute
1206 *
1207 * Return: >0 Success, return INDX record size
1208 * 0 Error, something went wrong
1209 */
get_indx_record_size(ntfs_attr * nar)1210 static u32 get_indx_record_size(ntfs_attr *nar)
1211 {
1212 u32 indx_record_size;
1213 le32 indx_record_size_le;
1214
1215 if (ntfs_attr_pread(nar, 8, 4, &indx_record_size_le) != 4) {
1216 ntfs_log_verbose("Couldn't determine size of INDX record\n");
1217 ntfs_log_error("ntfs_attr_pread failed");
1218 return 0;
1219 }
1220
1221 indx_record_size = le32_to_cpu(indx_record_size_le);
1222 if (!indx_record_size) {
1223 ntfs_log_verbose("Internal error\n");
1224 ntfs_log_error("INDX record should be 0");
1225 }
1226 return indx_record_size;
1227 }
1228
1229 /**
1230 * wipe_directory - Wipe the directory indexes
1231 * @vol: An ntfs volume obtained from ntfs_mount
1232 * @byte: Overwrite with this value
1233 * @act: Wipe, test or info
1234 *
1235 * Directories are kept in sorted B+ Trees. Index blocks may not be full. Wipe
1236 * the unused space at the ends of these blocks.
1237 *
1238 * Return: >0 Success, the clusters were wiped
1239 * 0 Nothing to wipe
1240 * -1 Error, something went wrong
1241 */
wipe_directory(ntfs_volume * vol,int byte,enum action act)1242 static s64 wipe_directory(ntfs_volume *vol, int byte, enum action act)
1243 {
1244 s64 total = 0;
1245 s64 nr_mft_records, inode_num;
1246 ntfs_inode *ni;
1247 ntfs_attr *naa;
1248 ntfs_attr *nab;
1249 ntfs_attr *nar;
1250
1251 if (!vol || (byte < 0))
1252 return -1;
1253
1254 nr_mft_records = vol->mft_na->initialized_size >>
1255 vol->mft_record_size_bits;
1256
1257 /* Avoid getting fixup warnings on unitialized inodes */
1258 NVolSetNoFixupWarn(vol);
1259
1260 for (inode_num = 5; inode_num < nr_mft_records; inode_num++) {
1261 u32 indx_record_size;
1262 s64 wiped;
1263
1264 ntfs_log_verbose("Inode %lld - ", (long long)inode_num);
1265 ni = ntfs_inode_open(vol, inode_num);
1266 if (!ni) {
1267 if (opts.verbose > 2)
1268 ntfs_log_verbose("Could not open inode\n");
1269 else
1270 ntfs_log_verbose("\r");
1271 continue;
1272 }
1273
1274 if (ni->mrec->base_mft_record) {
1275 if (opts.verbose > 2)
1276 ntfs_log_verbose("Not base mft record. Skipping\n");
1277 else
1278 ntfs_log_verbose("\r");
1279 goto close_inode;
1280 }
1281
1282 naa = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4);
1283 if (!naa) {
1284 if (opts.verbose > 2)
1285 ntfs_log_verbose("Couldn't open $INDEX_ALLOCATION\n");
1286 else
1287 ntfs_log_verbose("\r");
1288 goto close_inode;
1289 }
1290
1291 if (!NAttrNonResident(naa)) {
1292 ntfs_log_verbose("Resident $INDEX_ALLOCATION\n");
1293 ntfs_log_error("damaged fs: Resident $INDEX_ALLOCATION "
1294 "(inode %lld)\n", (long long)inode_num);
1295 goto close_attr_allocation;
1296 }
1297
1298 if (ntfs_attr_map_whole_runlist(naa)) {
1299 ntfs_log_verbose("Internal error\n");
1300 ntfs_log_error("Can't map runlist for $INDEX_ALLOCATION "
1301 "(inode %lld)\n", (long long)inode_num);
1302 goto close_attr_allocation;
1303 }
1304
1305 nab = ntfs_attr_open(ni, AT_BITMAP, NTFS_INDEX_I30, 4);
1306 if (!nab) {
1307 ntfs_log_verbose("Couldn't open $BITMAP\n");
1308 ntfs_log_error("damaged fs: $INDEX_ALLOCATION is present, "
1309 "but we can't open $BITMAP with same "
1310 "name (inode %lld)\n", (long long)inode_num);
1311 goto close_attr_allocation;
1312 }
1313
1314 nar = ntfs_attr_open(ni, AT_INDEX_ROOT, NTFS_INDEX_I30, 4);
1315 if (!nar) {
1316 ntfs_log_verbose("Couldn't open $INDEX_ROOT\n");
1317 ntfs_log_error("damaged fs: $INDEX_ALLOCATION is present, but "
1318 "we can't open $INDEX_ROOT with same name"
1319 " (inode %lld)\n", (long long)inode_num);
1320 goto close_attr_bitmap;
1321 }
1322
1323 if (NAttrNonResident(nar)) {
1324 ntfs_log_verbose("Not resident $INDEX_ROOT\n");
1325 ntfs_log_error("damaged fs: Not resident $INDEX_ROOT "
1326 "(inode %lld)\n", (long long)inode_num);
1327 goto close_attr_root;
1328 }
1329
1330 indx_record_size = get_indx_record_size(nar);
1331 if (!indx_record_size) {
1332 ntfs_log_error(" (inode %lld)\n", (long long)inode_num);
1333 goto close_attr_root;
1334 }
1335
1336 wiped = wipe_index_allocation(vol, byte, act,
1337 naa, nab, indx_record_size);
1338 if (wiped == -1) {
1339 ntfs_log_error(" (inode %lld)\n",
1340 (long long)inode_num);
1341 goto close_attr_root;
1342 }
1343
1344 if (wiped) {
1345 ntfs_log_verbose("Wiped %llu bytes\n",
1346 (unsigned long long)wiped);
1347 total += wiped;
1348 } else
1349 ntfs_log_verbose("Nothing to wipe\n");
1350 close_attr_root:
1351 ntfs_attr_close(nar);
1352 close_attr_bitmap:
1353 ntfs_attr_close(nab);
1354 close_attr_allocation:
1355 ntfs_attr_close(naa);
1356 close_inode:
1357 ntfs_inode_close(ni);
1358 }
1359
1360 NVolClearNoFixupWarn(vol);
1361 ntfs_log_quiet("wipe_directory 0x%02x, %lld bytes\n", byte,
1362 (long long)total);
1363 return total;
1364 }
1365
1366 /**
1367 * wipe_logfile - Wipe the logfile (journal)
1368 * @vol: An ntfs volume obtained from ntfs_mount
1369 * @byte: Overwrite with this value
1370 * @act: Wipe, test or info
1371 *
1372 * The logfile journals the metadata to give the volume fault-tolerance. If the
1373 * volume is in a consistent state, then this information can be erased.
1374 *
1375 * Return: >0 Success, the clusters were wiped
1376 * 0 Nothing to wipe
1377 * -1 Error, something went wrong
1378 */
wipe_logfile(ntfs_volume * vol,int byte,enum action act)1379 static s64 wipe_logfile(ntfs_volume *vol, int byte, enum action act
1380 __attribute__((unused)))
1381 {
1382 const int NTFS_BUF_SIZE2 = 8192;
1383 //FIXME(?): We might need to zero the LSN field of every single mft
1384 //record as well. (But, first try without doing that and see what
1385 //happens, since chkdsk might pickup the pieces and do it for us...)
1386 ntfs_inode *ni;
1387 ntfs_attr *na;
1388 s64 len, pos, count;
1389 char buf[NTFS_BUF_SIZE2];
1390 int eo;
1391
1392 /* We can wipe logfile only with 0xff. */
1393 byte = 0xff;
1394
1395 if (!vol || (byte < 0))
1396 return -1;
1397
1398 //ntfs_log_quiet("wipe_logfile(not implemented) 0x%02x\n", byte);
1399
1400 if ((ni = ntfs_inode_open(vol, FILE_LogFile)) == NULL) {
1401 ntfs_log_debug("Failed to open inode FILE_LogFile.\n");
1402 return -1;
1403 }
1404
1405 if ((na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0)) == NULL) {
1406 ntfs_log_debug("Failed to open $FILE_LogFile/$DATA.\n");
1407 goto error_exit;
1408 }
1409
1410 /* The $DATA attribute of the $LogFile has to be non-resident. */
1411 if (!NAttrNonResident(na)) {
1412 ntfs_log_debug("$LogFile $DATA attribute is resident!?!\n");
1413 errno = EIO;
1414 goto io_error_exit;
1415 }
1416
1417 /* Get length of $LogFile contents. */
1418 len = na->data_size;
1419 if (!len) {
1420 ntfs_log_debug("$LogFile has zero length, no disk write "
1421 "needed.\n");
1422 return 0;
1423 }
1424
1425 /* Read $LogFile until its end. We do this as a check for correct
1426 length thus making sure we are decompressing the mapping pairs
1427 array correctly and hence writing below is safe as well. */
1428 pos = 0;
1429 while ((count = ntfs_attr_pread(na, pos, NTFS_BUF_SIZE2, buf)) > 0)
1430 pos += count;
1431
1432 if (count == -1 || pos != len) {
1433 ntfs_log_debug("Amount of $LogFile data read does not "
1434 "correspond to expected length!\n");
1435 if (count != -1)
1436 errno = EIO;
1437 goto io_error_exit;
1438 }
1439
1440 /* Fill the buffer with @byte's. */
1441 memset(buf, byte, NTFS_BUF_SIZE2);
1442
1443 /* Set the $DATA attribute. */
1444 pos = 0;
1445 while ((count = len - pos) > 0) {
1446 if (count > NTFS_BUF_SIZE2)
1447 count = NTFS_BUF_SIZE2;
1448
1449 if ((count = ntfs_attr_pwrite(na, pos, count, buf)) <= 0) {
1450 ntfs_log_debug("Failed to set the $LogFile attribute "
1451 "value.\n");
1452 if (count != -1)
1453 errno = EIO;
1454 goto io_error_exit;
1455 }
1456
1457 pos += count;
1458 }
1459
1460 ntfs_attr_close(na);
1461 ntfs_inode_close(ni);
1462 ntfs_log_quiet("wipe_logfile 0x%02x, %lld bytes\n", byte,
1463 (long long)pos);
1464 return pos;
1465
1466 io_error_exit:
1467 eo = errno;
1468 ntfs_attr_close(na);
1469 errno = eo;
1470 error_exit:
1471 eo = errno;
1472 ntfs_inode_close(ni);
1473 errno = eo;
1474 return -1;
1475 }
1476
1477 /**
1478 * wipe_pagefile - Wipe the pagefile (swap space)
1479 * @vol: An ntfs volume obtained from ntfs_mount
1480 * @byte: Overwrite with this value
1481 * @act: Wipe, test or info
1482 *
1483 * pagefile.sys is used by Windows as extra virtual memory (swap space).
1484 * Windows recreates the file at bootup, so it can be wiped without harm.
1485 *
1486 * Return: >0 Success, the clusters were wiped
1487 * 0 Nothing to wipe
1488 * -1 Error, something went wrong
1489 */
wipe_pagefile(ntfs_volume * vol,int byte,enum action act)1490 static s64 wipe_pagefile(ntfs_volume *vol, int byte, enum action act
1491 __attribute__((unused)))
1492 {
1493 // wipe completely, chkdsk doesn't do anything, booting writes header
1494 const int NTFS_BUF_SIZE2 = 4096;
1495 ntfs_inode *ni;
1496 ntfs_attr *na;
1497 s64 len, pos, count;
1498 char buf[NTFS_BUF_SIZE2];
1499 int eo;
1500
1501 if (!vol || (byte < 0))
1502 return -1;
1503
1504 //ntfs_log_quiet("wipe_pagefile(not implemented) 0x%02x\n", byte);
1505
1506 ni = ntfs_pathname_to_inode(vol, NULL, "pagefile.sys");
1507 if (!ni) {
1508 ntfs_log_debug("Failed to open inode of pagefile.sys.\n");
1509 return 0;
1510 }
1511
1512 if ((na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0)) == NULL) {
1513 ntfs_log_debug("Failed to open pagefile.sys/$DATA.\n");
1514 goto error_exit;
1515 }
1516
1517 /* The $DATA attribute of the pagefile.sys has to be non-resident. */
1518 if (!NAttrNonResident(na)) {
1519 ntfs_log_debug("pagefile.sys $DATA attribute is resident!?!\n");
1520 errno = EIO;
1521 goto io_error_exit;
1522 }
1523
1524 /* Get length of pagefile.sys contents. */
1525 len = na->data_size;
1526 if (!len) {
1527 ntfs_log_debug("pagefile.sys has zero length, no disk write "
1528 "needed.\n");
1529 return 0;
1530 }
1531
1532 memset(buf, byte, NTFS_BUF_SIZE2);
1533
1534 /* Set the $DATA attribute. */
1535 pos = 0;
1536 while ((count = len - pos) > 0) {
1537 if (count > NTFS_BUF_SIZE2)
1538 count = NTFS_BUF_SIZE2;
1539
1540 if ((count = ntfs_attr_pwrite(na, pos, count, buf)) <= 0) {
1541 ntfs_log_debug("Failed to set the pagefile.sys "
1542 "attribute value.\n");
1543 if (count != -1)
1544 errno = EIO;
1545 goto io_error_exit;
1546 }
1547
1548 pos += count;
1549 }
1550
1551 ntfs_attr_close(na);
1552 ntfs_inode_close(ni);
1553 ntfs_log_quiet("wipe_pagefile 0x%02x, %lld bytes\n", byte,
1554 (long long)pos);
1555 return pos;
1556
1557 io_error_exit:
1558 eo = errno;
1559 ntfs_attr_close(na);
1560 errno = eo;
1561 error_exit:
1562 eo = errno;
1563 ntfs_inode_close(ni);
1564 errno = eo;
1565 return -1;
1566 }
1567
1568 /**
1569 * Part of ntfsprogs.
1570 * Modified: removed logging, signal handling, removed data.
1571 *
1572 * free_file - Release the resources used by a file object
1573 * \param file The unwanted file object
1574 *
1575 * This will free up the memory used by a file object and iterate through the
1576 * object's children, freeing their resources too.
1577 *
1578 * \return none
1579 */
free_file(struct ufile * file)1580 static void free_file (struct ufile *file)
1581 {
1582 struct ntfs_list_head *item = NULL, *tmp = NULL;
1583 struct filename *f = NULL;
1584 struct data *d = NULL;
1585
1586 if (file == NULL)
1587 return;
1588
1589 ntfs_list_for_each_safe(item, tmp, &(file->name)) {
1590 /* List of filenames */
1591
1592 f = ntfs_list_entry(item, struct filename, list);
1593 if (f->name != NULL)
1594 free(f->name);
1595 if (f->parent_name != NULL) {
1596 free(f->parent_name);
1597 }
1598 free(f);
1599 }
1600
1601 ntfs_list_for_each_safe(item, tmp, &(file->data)) {
1602 /* List of data streams */
1603
1604 d = ntfs_list_entry(item, struct data, list);
1605 if (d->name != NULL)
1606 free(d->name);
1607 if (d->runlist != NULL)
1608 free(d->runlist);
1609 free(d);
1610 }
1611
1612
1613 free(file->mft);
1614 free(file);
1615 }
1616
1617 /**
1618 * Fills the given buffer with one of predefined patterns.
1619 * \param pat_no Pass number.
1620 * \param buffer Buffer to be filled.
1621 * \param buflen Length of the buffer.
1622 */
fill_buffer(unsigned long int pat_no,unsigned char * const buffer,const size_t buflen,int * const selected)1623 static void fill_buffer (
1624 unsigned long int pat_no,
1625 unsigned char * const buffer,
1626 const size_t buflen,
1627 int * const selected )
1628 /*@requires notnull buffer @*/ /*@sets *buffer @*/
1629 {
1630
1631 size_t i;
1632 #if (!defined HAVE_MEMCPY) && (!defined HAVE_STRING_H)
1633 size_t j;
1634 #endif
1635 unsigned int bits;
1636
1637 if ((buffer == NULL) || (buflen == 0))
1638 return;
1639
1640 /* De-select all patterns once every npasses calls. */
1641 if (pat_no % npasses == 0) {
1642 for (i = 0; i < NPAT; i++) {
1643 selected[i] = 0;
1644 }
1645 }
1646 pat_no %= npasses;
1647 /* double check for npasses >= NPAT + 3: */
1648 for (i = 0; i < NPAT; i++) {
1649 if (selected[i] == 0)
1650 break;
1651 }
1652 if (i >= NPAT) {
1653 for (i = 0; i < NPAT; i++) {
1654 selected[i] = 0;
1655 }
1656 }
1657
1658 /* The first, last and middle passess will be using a random pattern */
1659 if ((pat_no == 0) || (pat_no == npasses-1) || (pat_no == npasses/2)) {
1660 #if (!defined __STRICT_ANSI__) && (defined HAVE_RANDOM)
1661 bits = (unsigned int)(random() & 0xFFF);
1662 #else
1663 bits = (unsigned int)(rand() & 0xFFF);
1664 #endif
1665 } else {
1666 /* For other passes, one of the fixed patterns is selected. */
1667 do {
1668 #if (!defined __STRICT_ANSI__) && (defined HAVE_RANDOM)
1669 i = (size_t)random() % NPAT;
1670 #else
1671 i = (size_t)rand() % NPAT;
1672 #endif
1673 } while (selected[i] == 1);
1674 bits = patterns[i];
1675 selected[i] = 1;
1676 }
1677
1678 buffer[0] = (unsigned char) bits;
1679 buffer[1] = (unsigned char) bits;
1680 buffer[2] = (unsigned char) bits;
1681 for (i = 3; i < buflen / 2; i *= 2) {
1682 #ifdef HAVE_MEMCPY
1683 memcpy(buffer + i, buffer, i);
1684 #elif defined HAVE_STRING_H
1685 strncpy((char *)(buffer + i), (char *)buffer, i);
1686 #else
1687 for (j = 0; j < i; j++) {
1688 buffer[i+j] = buffer[j];
1689 }
1690 #endif
1691 }
1692 if (i < buflen) {
1693 #ifdef HAVE_MEMCPY
1694 memcpy(buffer + i, buffer, buflen - i);
1695 #elif defined HAVE_STRING_H
1696 strncpy((char *)(buffer + i), (char *)buffer, buflen - i);
1697 #else
1698 for (j=0; j<buflen - i; j++) {
1699 buffer[i+j] = buffer[j];
1700 }
1701 #endif
1702 }
1703 }
1704
1705 /**
1706 * Destroys the specified record's filenames and data.
1707 *
1708 * \param nv The filesystem.
1709 * \param record The record (i-node number), which filenames & data
1710 * to destroy.
1711 * \return 0 in case of no errors, other values otherwise.
1712 */
destroy_record(ntfs_volume * nv,const s64 record,unsigned char * const buf)1713 static int destroy_record(ntfs_volume *nv, const s64 record,
1714 unsigned char * const buf)
1715 {
1716 struct ufile *file = NULL;
1717 runlist_element *rl = NULL;
1718 ntfs_attr *mft = NULL;
1719
1720 ntfs_attr_search_ctx *ctx = NULL;
1721 int ret_wfs = 0;
1722 unsigned long int pass, i;
1723 s64 j;
1724 unsigned char * a_offset;
1725 int selected[NPAT];
1726
1727 file = (struct ufile *) malloc(sizeof(struct ufile));
1728 if (file == NULL) {
1729 return -1;
1730 }
1731
1732 NTFS_INIT_LIST_HEAD(&(file->name));
1733 NTFS_INIT_LIST_HEAD(&(file->data));
1734 file->inode = record;
1735
1736 file->mft = (MFT_RECORD*)malloc(nv->mft_record_size);
1737 if (file->mft == NULL) {
1738 free_file (file);
1739 return -1;
1740 }
1741
1742 mft = ntfs_attr_open(nv->mft_ni, AT_DATA, AT_UNNAMED, 0);
1743 if (mft == NULL) {
1744 free_file(file);
1745 return -2;
1746 }
1747
1748 /* Avoid getting fixup warnings on unitialized inodes */
1749 NVolSetNoFixupWarn(nv);
1750 /* Read the MFT reocrd of the i-node */
1751 if (ntfs_attr_mst_pread(mft, nv->mft_record_size * record, 1LL,
1752 nv->mft_record_size, file->mft) < 1) {
1753
1754 NVolClearNoFixupWarn(nv);
1755 ntfs_attr_close(mft);
1756 free_file(file);
1757 return -3;
1758 }
1759 NVolClearNoFixupWarn(nv);
1760 ntfs_attr_close(mft);
1761 mft = NULL;
1762
1763 ctx = ntfs_attr_get_search_ctx(NULL, file->mft);
1764 if (ctx == NULL) {
1765 free_file(file);
1766 return -4;
1767 }
1768
1769 /* Wiping file names */
1770 while (1 == 1) {
1771
1772 if (ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, CASE_SENSITIVE,
1773 0LL, NULL, 0, ctx) != 0) {
1774 break; /* None / no more of that type */
1775 }
1776 if (ctx->attr == NULL)
1777 break;
1778
1779 /* We know this will always be resident.
1780 Find the offset of the data, including the MFT record. */
1781 a_offset = ((unsigned char *) ctx->attr
1782 + le16_to_cpu(ctx->attr->value_offset));
1783
1784 for (pass = 0; pass < npasses; pass++) {
1785 fill_buffer(pass, a_offset,
1786 le32_to_cpu(ctx->attr->value_length),
1787 selected);
1788
1789 if ( !opts.noaction ) {
1790 if (ntfs_mft_records_write(nv,
1791 MK_MREF(record, 0), 1LL,
1792 ctx->mrec) != 0) {
1793 ret_wfs = -5;
1794 break;
1795 }
1796 /* Flush after each writing, if more than
1797 1 overwriting needs to be done. Allow I/O
1798 bufferring (efficiency), if just one
1799 pass is needed. */
1800 if (npasses > 1) {
1801 nv->dev->d_ops->sync(nv->dev);
1802 }
1803 }
1804
1805 }
1806
1807 /* Wiping file name length */
1808 for (pass = 0; pass < npasses; pass++) {
1809
1810 fill_buffer (pass, (unsigned char *)
1811 &(ctx->attr->value_length), sizeof(u32),
1812 selected);
1813
1814 if (!opts.noaction) {
1815 if (ntfs_mft_records_write(nv,
1816 MK_MREF(record, 0),
1817 1LL, ctx->mrec) != 0) {
1818 ret_wfs = -5;
1819 break;
1820 }
1821
1822 if (npasses > 1) {
1823 nv->dev->d_ops->sync(nv->dev);
1824 }
1825 }
1826 }
1827 ctx->attr->value_length = const_cpu_to_le32(0);
1828 if (!opts.noaction) {
1829 if (ntfs_mft_records_write(nv, MK_MREF(record, 0),
1830 1LL, ctx->mrec) != 0) {
1831 ret_wfs = -5;
1832 break;
1833 }
1834 }
1835 }
1836
1837 ntfs_attr_reinit_search_ctx(ctx);
1838
1839 /* Wiping file data */
1840 while (1 == 1) {
1841 if (ntfs_attr_lookup(AT_DATA, NULL, 0, CASE_SENSITIVE, 0LL,
1842 NULL, 0, ctx) != 0) {
1843 break; /* None / no more of that type */
1844 }
1845 if (ctx->attr == NULL)
1846 break;
1847
1848 if (ctx->attr->non_resident == 0) {
1849 /* attribute is resident (part of MFT record) */
1850 /* find the offset of the data, including the MFT record */
1851 a_offset = ((unsigned char *) ctx->attr
1852 + le16_to_cpu(ctx->attr->value_offset));
1853
1854 /* Wiping the data itself */
1855 for (pass = 0; pass < npasses; pass++) {
1856
1857 fill_buffer (pass, a_offset,
1858 le32_to_cpu(ctx->attr->value_length),
1859 selected);
1860
1861 if (!opts.noaction) {
1862 if (ntfs_mft_records_write(nv,
1863 MK_MREF(record, 0),
1864 1LL, ctx->mrec) != 0) {
1865 ret_wfs = -5;
1866 break;
1867 }
1868
1869 if (npasses > 1) {
1870 nv->dev->d_ops->sync(nv->dev);
1871 }
1872 }
1873 }
1874
1875 /* Wiping data length */
1876 for (pass = 0; pass < npasses; pass++) {
1877
1878 fill_buffer(pass, (unsigned char *)
1879 &(ctx->attr->value_length),
1880 sizeof(u32), selected);
1881
1882 if (!opts.noaction) {
1883 if (ntfs_mft_records_write(nv,
1884 MK_MREF(record, 0),
1885 1LL, ctx->mrec) != 0) {
1886 ret_wfs = -5;
1887 break;
1888 }
1889
1890 if (npasses > 1) {
1891 nv->dev->d_ops->sync(nv->dev);
1892 }
1893 }
1894 }
1895 ctx->attr->value_length = const_cpu_to_le32(0);
1896 if ( !opts.noaction ) {
1897 if (ntfs_mft_records_write(nv,
1898 MK_MREF(record, 0),
1899 1LL, ctx->mrec) != 0) {
1900 ret_wfs = -5;
1901 break;
1902 }
1903 }
1904 } else {
1905 /* Non-resident here */
1906
1907 rl = ntfs_mapping_pairs_decompress(nv,
1908 ctx->attr, NULL);
1909 if (rl == NULL) {
1910 continue;
1911 }
1912
1913 if (rl[0].length <= 0) {
1914 continue;
1915 }
1916
1917 for (i = 0; (rl[i].length > 0) && (ret_wfs == 0); i++) {
1918 if (rl[i].lcn == -1) {
1919 continue;
1920 }
1921 for (j = rl[i].lcn;
1922 (j < rl[i].lcn + rl[i].length)
1923 && (ret_wfs == 0); j++) {
1924
1925 if (utils_cluster_in_use(nv, j) != 0)
1926 continue;
1927 for (pass = 0;
1928 pass < npasses;
1929 pass++) {
1930
1931 fill_buffer(pass, buf,
1932 (size_t) nv->cluster_size,
1933 selected);
1934 if (!opts.noaction) {
1935 if (ntfs_cluster_write(
1936 nv, j, 1LL,
1937 buf) < 1) {
1938 ret_wfs = -5;
1939 break;
1940 }
1941
1942 if (npasses > 1) {
1943 nv->dev->d_ops->sync
1944 (nv->dev);
1945 }
1946 }
1947 }
1948 }
1949 }
1950
1951 /* Wipe the data length here */
1952 for (pass = 0; pass < npasses; pass++) {
1953 fill_buffer(pass, (unsigned char *)
1954 &(ctx->attr->lowest_vcn),
1955 sizeof(VCN), selected);
1956 fill_buffer(pass, (unsigned char *)
1957 &(ctx->attr->highest_vcn),
1958 sizeof(VCN), selected);
1959 fill_buffer(pass, (unsigned char *)
1960 &(ctx->attr->allocated_size),
1961 sizeof(s64), selected);
1962 fill_buffer(pass, (unsigned char *)
1963 &(ctx->attr->data_size),
1964 sizeof(s64), selected);
1965 fill_buffer(pass, (unsigned char *)
1966 &(ctx->attr->initialized_size),
1967 sizeof(s64), selected);
1968 fill_buffer(pass, (unsigned char *)
1969 &(ctx->attr->compressed_size),
1970 sizeof(s64), selected);
1971
1972 if ( !opts.noaction ) {
1973 if (ntfs_mft_records_write(nv,
1974 MK_MREF (record, 0),
1975 1LL, ctx->mrec) != 0) {
1976 ret_wfs = -5;
1977 break;
1978 }
1979
1980 if (npasses > 1) {
1981 nv->dev->d_ops->sync(nv->dev);
1982 }
1983 }
1984 }
1985 ctx->attr->lowest_vcn = const_cpu_to_sle64(0);
1986 ctx->attr->highest_vcn = const_cpu_to_sle64(0);
1987 ctx->attr->allocated_size = const_cpu_to_sle64(0);
1988 ctx->attr->data_size = const_cpu_to_sle64(0);
1989 ctx->attr->initialized_size = const_cpu_to_sle64(0);
1990 ctx->attr->compressed_size = const_cpu_to_sle64(0);
1991 if (!opts.noaction) {
1992 if (ntfs_mft_records_write(nv,
1993 MK_MREF (record, 0),
1994 1LL, ctx->mrec) != 0) {
1995 ret_wfs = -5;
1996 break;
1997 }
1998 }
1999 } /* end of resident check */
2000 } /* end of 'wiping file data' loop */
2001
2002 ntfs_attr_put_search_ctx(ctx);
2003 free_file(file);
2004
2005 return ret_wfs;
2006 }
2007
2008 /**
2009 * Starts search for deleted inodes and undelete data on the given
2010 * NTFS filesystem.
2011 * \param FS The filesystem.
2012 * \return 0 in case of no errors, other values otherwise.
2013 */
wipe_unrm(ntfs_volume * nv)2014 static int wipe_unrm(ntfs_volume *nv)
2015 {
2016 int ret_wfs = 0, ret;
2017 ntfs_attr *bitmapattr = NULL;
2018 s64 bmpsize, size, nr_mft_records, i, j, k;
2019 unsigned char b;
2020 unsigned char * buf = NULL;
2021
2022 #define MYBUF_SIZE 8192
2023 unsigned char *mybuf;
2024 #define MINIM(x, y) ( ((x)<(y))?(x):(y) )
2025
2026 mybuf = (unsigned char *) malloc(MYBUF_SIZE);
2027 if (mybuf == NULL) {
2028 return -1;
2029 }
2030
2031 buf = (unsigned char *) malloc(nv->cluster_size);
2032 if (buf == NULL) {
2033 free (mybuf);
2034 return -1;
2035 }
2036
2037 bitmapattr = ntfs_attr_open(nv->mft_ni, AT_BITMAP, AT_UNNAMED, 0);
2038 if (bitmapattr == NULL) {
2039 free (buf);
2040 free (mybuf);
2041 return -2;
2042 }
2043 bmpsize = bitmapattr->initialized_size;
2044
2045 nr_mft_records = nv->mft_na->initialized_size
2046 >> nv->mft_record_size_bits;
2047
2048 /* just like ntfsundelete; detects i-node numbers fine */
2049 for (i = 0; (i < bmpsize) && (ret_wfs==0); i += MYBUF_SIZE) {
2050
2051 /* read a part of the file bitmap */
2052 size = ntfs_attr_pread(bitmapattr, i,
2053 MINIM((bmpsize - i), MYBUF_SIZE), mybuf);
2054 if (size < 0)
2055 break;
2056
2057 /* parse each byte of the just-read part of the bitmap */
2058 for (j = 0; (j < size) && (ret_wfs==0); j++) {
2059 b = mybuf[j];
2060 /* parse each bit of the byte Bit 1 means 'in use'. */
2061 for (k = 0; (k < CHAR_BIT) && (ret_wfs==0);
2062 k++, b>>=1) {
2063 /* (i+j)*8+k is the i-node bit number */
2064 if (((i+j)*CHAR_BIT+k) >= nr_mft_records) {
2065 goto done;
2066 }
2067 if ((b & 1) != 0) {
2068 /* i-node is in use, skip it */
2069 continue;
2070 }
2071 /* wiping the i-node here: */
2072 ret = destroy_record (nv,
2073 (i+j)*CHAR_BIT+k, buf);
2074 if (ret != 0) {
2075 ret_wfs = ret;
2076 }
2077 }
2078 }
2079 }
2080 done:
2081 ntfs_attr_close(bitmapattr);
2082 free(buf);
2083 free(mybuf);
2084
2085 ntfs_log_quiet("wipe_undelete\n");
2086 return ret_wfs;
2087 }
2088
2089
2090
2091 /**
2092 * print_summary - Tell the user what we are about to do
2093 *
2094 * List the operations about to be performed. The output will be silenced by
2095 * the --quiet option.
2096 *
2097 * Return: none
2098 */
print_summary(void)2099 static void print_summary(void)
2100 {
2101 int i;
2102
2103 if (opts.noaction)
2104 ntfs_log_quiet("%s is in 'no-action' mode, it will NOT write to disk."
2105 "\n\n", EXEC_NAME);
2106
2107 ntfs_log_quiet("%s is about to wipe:\n", EXEC_NAME);
2108 if (opts.unused)
2109 ntfs_log_quiet("\tunused disk space\n");
2110 if (opts.unused_fast)
2111 ntfs_log_quiet("\tunused disk space (fast)\n");
2112 if (opts.tails)
2113 ntfs_log_quiet("\tfile tails\n");
2114 if (opts.mft)
2115 ntfs_log_quiet("\tunused mft areas\n");
2116 if (opts.directory)
2117 ntfs_log_quiet("\tunused directory index space\n");
2118 if (opts.logfile)
2119 ntfs_log_quiet("\tthe logfile (journal)\n");
2120 if (opts.pagefile)
2121 ntfs_log_quiet("\tthe pagefile (swap space)\n");
2122 if (opts.undel)
2123 ntfs_log_quiet("\tundelete data\n");
2124
2125 ntfs_log_quiet("\n%s will overwrite these areas with: ", EXEC_NAME);
2126 if (opts.bytes) {
2127 for (i = 0; opts.bytes[i] >= 0; i++)
2128 ntfs_log_quiet("0x%02x ", opts.bytes[i]);
2129 }
2130 ntfs_log_quiet("\n");
2131 if (opts.undel)
2132 ntfs_log_quiet("(however undelete data will be overwritten"
2133 " by random values)\n");
2134
2135 if (opts.count > 1)
2136 ntfs_log_quiet("%s will repeat these operations %d times.\n", EXEC_NAME, opts.count);
2137 ntfs_log_quiet("\n");
2138 }
2139
2140 /**
2141 * main - Begin here
2142 *
2143 * Start from here.
2144 *
2145 * Return: 0 Success, the program worked
2146 * 1 Error, something went wrong
2147 */
main(int argc,char * argv[])2148 int main(int argc, char *argv[])
2149 {
2150 ntfs_volume *vol;
2151 int result = 1;
2152 int flags = 0;
2153 int res;
2154 int i, j;
2155 enum action act = act_info;
2156
2157 ntfs_log_set_handler(ntfs_log_handler_outerr);
2158
2159 res = parse_options(argc, argv);
2160 if (res >= 0)
2161 return (res);
2162
2163 utils_set_locale();
2164
2165 if (!opts.info)
2166 print_summary();
2167
2168 if (opts.info || opts.noaction)
2169 flags = NTFS_MNT_RDONLY;
2170 if (opts.force)
2171 flags |= NTFS_MNT_RECOVER;
2172
2173 vol = utils_mount_volume(opts.device, flags);
2174 if (!vol)
2175 goto free;
2176
2177 if ((vol->flags & VOLUME_IS_DIRTY) && !opts.force)
2178 goto umount;
2179
2180 if (opts.info) {
2181 act = act_info;
2182 opts.count = 1;
2183 } else if (opts.noaction) {
2184 act = act_test;
2185 } else {
2186 act = act_wipe;
2187 }
2188
2189 /* Even if the output it quieted, you still get 5 seconds to abort. */
2190 if ((act == act_wipe) && !opts.force) {
2191 ntfs_log_quiet("\n%s will begin in 5 seconds, press CTRL-C to abort.\n", EXEC_NAME);
2192 sleep(5);
2193 }
2194
2195 for (i = 0; opts.bytes[i] >= 0; i++) {
2196 npasses = i+1;
2197 }
2198 if (npasses == 0) {
2199 npasses = opts.count;
2200 }
2201 #ifdef HAVE_TIME_H
2202 srandom(time(NULL));
2203 #else
2204 /* use a pointer as a pseudorandom value */
2205 srandom((int)vol + npasses);
2206 #endif
2207 ntfs_log_info("\n");
2208 for (i = 0; i < opts.count; i++) {
2209 int byte;
2210 s64 total = 0;
2211 s64 wiped = 0;
2212
2213 for (j = 0; byte = opts.bytes[j], byte >= 0; j++) {
2214
2215 if (opts.directory) {
2216 wiped = wipe_directory(vol, byte, act);
2217 if (wiped < 0)
2218 goto umount;
2219 else
2220 total += wiped;
2221 }
2222
2223 if (opts.tails) {
2224 wiped = wipe_tails(vol, byte, act);
2225 if (wiped < 0)
2226 goto umount;
2227 else
2228 total += wiped;
2229 }
2230
2231 if (opts.logfile) {
2232 wiped = wipe_logfile(vol, byte, act);
2233 if (wiped < 0)
2234 goto umount;
2235 else
2236 total += wiped;
2237 }
2238
2239 if (opts.mft) {
2240 wiped = wipe_mft(vol, byte, act);
2241 if (wiped < 0)
2242 goto umount;
2243 else
2244 total += wiped;
2245 }
2246
2247 if (opts.pagefile) {
2248 wiped = wipe_pagefile(vol, byte, act);
2249 if (wiped < 0)
2250 goto umount;
2251 else
2252 total += wiped;
2253 }
2254
2255 if (opts.unused || opts.unused_fast) {
2256 if (opts.unused_fast)
2257 wiped = wipe_unused_fast(vol, byte,
2258 act);
2259 else
2260 wiped = wipe_unused(vol, byte, act);
2261 if (wiped < 0)
2262 goto umount;
2263 else
2264 total += wiped;
2265 }
2266
2267 if (opts.undel) {
2268 wiped = wipe_unrm(vol);
2269 if (wiped != 0)
2270 goto umount;
2271 /*
2272 else
2273 total += wiped;
2274 */
2275 }
2276
2277 if (act == act_info)
2278 break;
2279 }
2280
2281 if (opts.noaction || opts.info)
2282 ntfs_log_info("%lld bytes would be wiped"
2283 " (excluding undelete data)\n",
2284 (long long)total);
2285 else
2286 ntfs_log_info("%lld bytes were wiped"
2287 " (excluding undelete data)\n",
2288 (long long)total);
2289 }
2290 result = 0;
2291 umount:
2292 ntfs_umount(vol, FALSE);
2293 free:
2294 if (opts.bytes)
2295 free(opts.bytes);
2296 return result;
2297 }
2298