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