• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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