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