2 * ntfswipe - Part of the Linux-NTFS project.
4 * Copyright (c) 2002-2003 Richard Russon
6 * This utility will overwrite usused space on an NTFS volume.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program (in the main directory of the Linux-NTFS
20 * distribution in the file COPYING); if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
40 static const char *EXEC_NAME = "ntfswipe";
41 static struct options opts;
43 GEN_PRINTF (Eprintf, stderr, NULL, FALSE)
44 GEN_PRINTF (Vprintf, stdout, &opts.verbose, TRUE)
45 GEN_PRINTF (Qprintf, stdout, &opts.quiet, FALSE)
48 * version - Print version information about the program
50 * Print a copyright statement and a brief description of the program.
56 printf ("\n%s v%s - Overwrite the unused space on an NTFS Volume.\n\n",
58 printf ("Copyright (c)\n");
59 printf (" 2002-2003 Richard Russon\n");
60 printf ("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
64 * usage - Print a list of the parameters to the program
66 * Print a list of the parameters and options for the program.
72 printf ("\nUsage: %s [options] device\n"
73 " -i --info Show volume information (default)\n"
75 " -d --directory Wipe directory indexes\n"
76 " -l --logfile Wipe the logfile (journal)\n"
77 " -m --mft Wipe mft space\n"
78 " -p --pagefile Wipe pagefile (swap space)\n"
79 " -t --tails Wipe file tails\n"
80 " -u --unused Wipe unused clusters\n"
82 " -a --all Wipe all unused space\n"
84 " -c num --count num Number of times to write (default = 1)\n"
85 " -b list --bytes list List of values to write (default = 0)\n"
87 " -n --no-action Do not write to disk\n"
88 " -f --force Use less caution\n"
89 " -q --quiet Less output\n"
90 " -v --verbose More output\n"
91 " -V --version Version information\n"
92 " -h --help Print this help\n\n",
94 printf ("%s%s\n", ntfs_bugs, ntfs_home);
98 * parse_list - Read a comma-separated list of numbers
99 * @list: The comma-separated list of numbers
100 * @result: Store the parsed list here (must be freed by caller)
102 * Read a comma-separated list of numbers and allocate an array of ints to store
103 * them in. The numbers can be in decimal, octal or hex.
105 * N.B. The caller must free the memory returned in @result.
106 * N.B. If the function fails, @result is not changed.
108 * Return: 0 Error, invalid string
109 * n Success, the count of numbers parsed
111 int parse_list (const char *list, int **result)
119 if (!list || !result)
122 for (count = 0, ptr = list; ptr; ptr = strchr (ptr+1, ','))
125 mem = malloc ((count+1) * sizeof (int));
127 Eprintf ("Couldn't allocate memory in parse_list().\n");
131 memset (mem, 0xFF, (count+1) * sizeof (int));
133 for (ptr = list, i = 0; i < count; i++) {
136 mem[i] = strtol (ptr, &end, 0);
138 if (!end || (end == ptr) || ((*end != ',') && (*end != 0))) {
139 Eprintf ("Invalid list '%s'\n", list);
144 if ((mem[i] < 0) || (mem[i] > 255)) {
145 Eprintf ("Bytes must be in range 0-255.\n");
153 Dprintf ("Parsing list '%s' - ", list);
154 for (i = 0; i <= count; i++)
155 Dprintf ("0x%02x ", mem[i]);
163 * parse_options - Read and validate the programs command line
165 * Read the command line, verify the syntax and parse the options.
166 * This function is very long, but quite simple.
169 * 0 Error, one or more problems
171 int parse_options (int argc, char *argv[])
173 static const char *sopt = "-ab:c:dfh?ilmnpqtuvV";
174 static const struct option lopt[] = {
175 { "all", no_argument, NULL, 'a' },
176 { "bytes", required_argument, NULL, 'b' },
177 { "count", required_argument, NULL, 'c' },
178 { "directory", no_argument, NULL, 'd' },
179 { "force", no_argument, NULL, 'f' },
180 { "help", no_argument, NULL, 'h' },
181 { "info", no_argument, NULL, 'i' },
182 { "logfile", no_argument, NULL, 'l' },
183 { "mft", no_argument, NULL, 'm' },
184 { "no-action", no_argument, NULL, 'n' },
185 { "pagefile", no_argument, NULL, 'p' },
186 { "quiet", no_argument, NULL, 'q' },
187 { "tails", no_argument, NULL, 't' },
188 { "unused", no_argument, NULL, 'u' },
189 { "verbose", no_argument, NULL, 'v' },
190 { "version", no_argument, NULL, 'V' },
200 opterr = 0; /* We'll handle the errors, thank you. */
204 while ((c = getopt_long (argc, argv, sopt, lopt, NULL)) != -1) {
206 case 1: /* A non-option argument */
208 opts.device = argv[optind-1];
216 opts.info++; /* and fall through */
227 if (!parse_list (argv[optind-1], &opts.bytes))
234 if (opts.count == 1) {
236 opts.count = strtol (optarg, &end, 0);
281 if ((optopt == 'b') || (optopt == 'c')) {
282 Eprintf ("Option '%s' requires an argument.\n", argv[optind-1]);
284 Eprintf ("Unknown option '%s'.\n", argv[optind-1]);
294 if (opts.device == NULL) {
296 Eprintf ("You must specify exactly one device.\n");
300 if (opts.quiet && opts.verbose) {
301 Eprintf ("You may not use --quiet and --verbose at the same time.\n");
306 if (opts.info && (opts.unused || opts.tails || opts.mft || opts.directory)) {
307 Eprintf ("You may not use any other options with --info.\n");
312 if ((opts.count < 1) || (opts.count > 100)) {
313 Eprintf ("The iteration count must be between 1 and 100.\n");
317 /* Create a default list */
319 opts.bytes = malloc (2 * sizeof (int));
324 Eprintf ("Couldn't allocate memory for byte list.\n");
329 if (!opts.directory && !opts.logfile && !opts.mft &&
330 !opts.pagefile && !opts.tails && !opts.unused) {
340 return (!err && !help && !ver);
345 * wipe_unused - Wipe unused clusters
346 * @vol: An ntfs volume obtained from ntfs_mount
347 * @byte: Overwrite with this value
349 * Read $Bitmap and wipe any clusters that are marked as not in use.
351 * Return: 1 Success, the clusters were wiped
352 * 0 Error, something went wrong
354 int wipe_unused (ntfs_volume *vol, int byte, enum action act)
356 if (!vol || (byte < 0))
359 Qprintf ("wipe_unused 0x%02x\n", byte);
364 * wipe_tails - Wipe the file tails
365 * @vol: An ntfs volume obtained from ntfs_mount
366 * @byte: Overwrite with this value
368 * Disk space is allocated in clusters. If a file isn't an exact multiple of
369 * the cluster size, there is some slack space at the end. Wipe this space.
371 * Return: 1 Success, the clusters were wiped
372 * 0 Error, something went wrong
374 int wipe_tails (ntfs_volume *vol, int byte, enum action act)
376 if (!vol || (byte < 0))
379 Qprintf ("wipe_tails 0x%02x\n", byte);
384 * wipe_mft - Wipe the MFT slack space
385 * @vol: An ntfs volume obtained from ntfs_mount
386 * @byte: Overwrite with this value
388 * MFT Records are 1024 bytes long, but some of this space isn't used. Wipe any
389 * unused space at the end of the record and wipe any unused records.
391 * Return: 1 Success, the clusters were wiped
392 * 0 Error, something went wrong
394 int wipe_mft (ntfs_volume *vol, int byte, enum action act)
396 if (!vol || (byte < 0))
399 Qprintf ("wipe_mft 0x%02x\n", byte);
404 * wipe_directory - Wipe the directory indexes
405 * @vol: An ntfs volume obtained from ntfs_mount
406 * @byte: Overwrite with this value
408 * Directories are kept in sorted B+ Trees. Index blocks may not be full. Wipe
409 * the unused space at the ends of these blocks.
411 * Return: 1 Success, the clusters were wiped
412 * 0 Error, something went wrong
414 int wipe_directory (ntfs_volume *vol, int byte, enum action act)
416 if (!vol || (byte < 0))
419 Qprintf ("wipe_directory 0x%02x\n", byte);
424 * wipe_logfile - Wipe the logfile (journal)
425 * @vol: An ntfs volume obtained from ntfs_mount
426 * @byte: Overwrite with this value
428 * The logfile journals the metadata to give the volume fault-tolerance. If the
429 * volume is in a consistant state, then this information can be erased.
431 * Return: 1 Success, the clusters were wiped
432 * 0 Error, something went wrong
434 int wipe_logfile (ntfs_volume *vol, int byte, enum action act)
436 if (!vol || (byte < 0))
439 Qprintf ("wipe_logfile 0x%02x\n", byte);
444 * wipe_pagefile - Wipe the pagefile (swap space)
445 * @vol: An ntfs volume obtained from ntfs_mount
446 * @byte: Overwrite with this value
448 * pagefile.sys is used by Windows as extra virtual memory (swap space).
449 * Windows recreates the file at bootup, so it can be wiped without harm.
451 * Return: 1 Success, the clusters were wiped
452 * 0 Error, something went wrong
454 int wipe_pagefile (ntfs_volume *vol, int byte, enum action act)
456 if (!vol || (byte < 0))
459 Qprintf ("wipe_pagefile 0x%02x\n", byte);
465 * ntfs_info - Display information about the NTFS Volume
466 * @vol: An ntfs volume obtained from ntfs_mount
468 * Tell the user how much could be cleaned up. List the number of free
469 * clusters, MFT records, etc.
471 * Return: 1 Success, displayed some info
472 * 0 Error, something went wrong
474 int ntfs_info (ntfs_volume *vol)
481 Qprintf ("ntfs_info\n");
485 Qprintf ("Cluster size = %u\n", vol->cluster_size);
486 Qprintf ("Volume size = %lld clusters\n", vol->nr_clusters);
487 Qprintf ("Volume size = %lld bytes\n", vol->nr_clusters * vol->cluster_size);
488 Qprintf ("Volume size = %lld MiB\n", vol->nr_clusters * vol->cluster_size / (1024*1024)); /* round up? */
493 buffer = malloc (vol->mft_record_size);
497 Qprintf ("cluster\n");
498 //Qprintf ("allocated_size = %lld\n", vol->lcnbmp_na->allocated_size);
499 Qprintf ("data_size = %lld\n", vol->lcnbmp_na->data_size);
500 //Qprintf ("initialized_size = %lld\n", vol->lcnbmp_na->initialized_size);
504 u64 size = vol->lcnbmp_na->allocated_size;
505 int bufsize = vol->mft_record_size;
510 for (offset = 0; offset < size; offset += bufsize) {
512 if ((offset + bufsize) > size)
513 bufsize = size - offset;
515 if (ntfs_attr_pread (vol->lcnbmp_na, offset, bufsize, buffer) < bufsize) {
520 for (i = 0; i < bufsize; i++) {
521 for (j = 0; j < 8; j++) {
522 if ((((offset+i)*8) + j) >= vol->nr_clusters)
524 if (buffer[i] & (1 << j)) {
536 Qprintf ("cluster use %lld, not %lld, total %lld\n", use, not, use+not);
544 u64 bmpsize = vol->mftbmp_na->data_size;
545 int bmpbufsize = 512;
547 u64 use = 0, not = 0;
549 bitmap = malloc (bmpbufsize);
553 printf ("mft has %lld records\n", vol->nr_mft_records);
555 //Qprintf ("allocated_size = %lld\n", vol->mftbmp_na->allocated_size);
556 Qprintf ("data_size = %lld\n", vol->mftbmp_na->data_size);
557 //Qprintf ("initialized_size = %lld\n", vol->mftbmp_na->initialized_size);
559 printf ("bmpsize = %lld\n", bmpsize);
560 for (bmpoff = 0; bmpoff < bmpsize; bmpoff += bmpbufsize) {
561 if ((bmpoff + bmpbufsize) > bmpsize)
562 bmpbufsize = bmpsize - bmpoff;
564 //printf ("bmpbufsize = %d\n", bmpbufsize);
566 if (ntfs_attr_pread (vol->mftbmp_na, bmpoff, bmpbufsize, bitmap) < bmpbufsize) {
571 for (i = 0; i < bmpbufsize; i++) {
572 for (j = 0; j < 8; j++) {
573 if ((((bmpoff+i)*8) + j) >= vol->nr_mft_records)
575 if (bitmap[i] & (1 << j)) {
588 printf ("use %lld, not %lld, total %lld\n", use, not, use+not);
595 * wipe_unused - volume = n clusters, u unused (%age & MB)
599 * wipe_tails - volume = n files, total tail slack space
603 * wipe_mft - volume = n mft records, u unused, s total slack space
607 * wipe_directory - volume has d dirs, t total slack space
608 * $MFT, $INDEX_ROOT, $INDEX_ALLOC, $BITMAP
610 * wipe_logfile - logfile is <size>
613 * wipe_pagefile - pagefile is <size>
622 inode = ntfs_inode_open (vol, 6); /* $Bitmap */
626 attr = ntfs_attr_open (inode, AT_DATA, NULL, 0);
632 ntfs_attr_close (attr);
633 ntfs_inode_close (inode);
641 * print_summary - Tell the user what we are about to do
643 * List the operations about to be performed. The output will be silenced by
644 * the --quiet option.
648 void print_summary (void)
653 Qprintf ("%s is in 'no-action' mode, it will NOT write to disk."
656 Qprintf ("%s is about to wipe:\n", EXEC_NAME);
658 Qprintf ("\tunused disk space\n");
660 Qprintf ("\tfile tails\n");
662 Qprintf ("\tunused mft areas\n");
664 Qprintf ("\tunused directory index space\n");
666 Qprintf ("\tthe logfile (journal)\n");
668 Qprintf ("\tthe pagefile (swap space)\n");
670 Qprintf ("\n%s will overwrite these areas with: ", EXEC_NAME);
672 for (i = 0; opts.bytes[i] >= 0; i++)
673 Qprintf ("0x%02x ", opts.bytes[i]);
678 Qprintf ("%s will repeat these operations %d times.\n", EXEC_NAME, opts.count);
687 * Return: 0 Success, the program worked
688 * 1 Error, something went wrong
690 int main (int argc, char *argv[])
696 enum action act = act_info;
698 if (!parse_options (argc, argv))
706 if (opts.info || opts.noaction)
709 vol = utils_mount_volume (opts.device, flags, opts.force);
713 if (vol->flags & VOLUME_IS_DIRTY) {
714 Qprintf ("Volume is dirty.\n");
716 Eprintf ("Run chkdsk and try again, or use the --force option.\n");
719 Qprintf ("Forced to continue.\n");
725 } else if (opts.noaction) {
731 /* Even if the output it quieted, you still get 5 seconds to abort. */
732 if ((act == act_wipe) && !opts.force) {
733 Qprintf ("\n%s will begin in 5 seconds, press CTRL-C to abort.\n", EXEC_NAME);
740 runlist_element *rl = vol->mft_na->rl;
741 printf ("________________________________________________________________________________\n\n");
742 for (; rl->length > 0; rl++, i++) {
743 printf ("%4d %lld,%lld,%lld\n", i, rl->vcn, rl->lcn, rl->length);
745 printf ("%4d %lld,%lld,%lld\n", i, rl->vcn, rl->lcn, rl->length);
750 for (i = 0; i < opts.count; i++) {
755 for (j = 0; byte = opts.bytes[j], byte >= 0; j++) {
757 if (opts.directory) {
758 wiped = wipe_directory (vol, byte, act);
766 wiped = wipe_tails (vol, byte, act);
774 wiped = wipe_logfile (vol, byte, act);
782 wiped = wipe_mft (vol, byte, act);
790 wiped = wipe_pagefile (vol, byte, act);
798 wiped = wipe_unused (vol, byte, act);
812 ntfs_umount (vol, FALSE);