http://linux-ntfs.sourceforge.net/snapshots/ntfsprogs-200309071734.tar.bz2
[ntfsprogs.git] / ntfsprogs / ntfsresize.c
1 /**
2  * ntfsresize - Part of the Linux-NTFS project.
3  *
4  * Copyright (c) 2002-2003 Szabolcs Szakacsits
5  * Copyright (c) 2002-2003 Anton Altaparmakov
6  * Copyright (c) 2002-2003 Richard Russon
7  *
8  * This utility will resize 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 #include <unistd.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <stdarg.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <getopt.h>
35
36 #include "debug.h"
37 #include "types.h"
38 #include "support.h"
39 #include "endians.h"
40 #include "bootsect.h"
41 #include "disk_io.h"
42 #include "attrib.h"
43 #include "volume.h"
44 #include "mft.h"
45 #include "bitmap.h"
46 #include "inode.h"
47 #include "runlist.h"
48 #include "utils.h"
49
50 static const char *EXEC_NAME = "ntfsresize";
51
52 static const char *resize_warning_msg =
53 "WARNING: Every sanity check passed and only the DANGEROUS operations left.\n"
54 "Please make sure all your important data had been backed up in case of an\n"
55 "unexpected failure!\n";
56
57 static const char *resize_important_msg =
58 "You can go on to shrink the device e.g. with 'fdisk'.\n"
59 "IMPORTANT: When recreating the partition, make sure you\n"
60 "  1)  create it with the same starting disk cylinder\n"
61 "  2)  create it with the same partition type (usually 7, HPFS/NTFS)\n"
62 "  3)  do not make it smaller than the new NTFS filesystem size\n"
63 "  4)  set the bootable flag for the partition if it existed before\n"
64 "Otherwise you may lose your data or can't boot your computer from the disk!\n";
65
66 static const char *fragmented_volume_msg =
67 "The volume end is fragmented, this case is not yet supported. Defragment it\n"
68 "(Windows 2000, XP and .NET have built in defragmentation tool) and try again.\n";
69
70 struct {
71         int verbose;
72         int quiet;
73         int debug;
74         int ro_flag;
75         int force;
76         int info;
77         s64 bytes;
78         char *volume;
79 } opt;
80
81 struct bitmap {
82         u8 *bm;
83         s64 size;
84 };
85
86 struct progress_bar {
87         u64 start;
88         u64 stop;
89         int resolution;
90         float unit;
91 };
92
93 struct __ntfs_resize_t {
94         s64 new_volume_size;
95         ntfs_inode *ni;                 /* inode being processed */
96         ntfs_attr_search_ctx *ctx;      /* inode attribute being processed */
97         u64 relocations;                /* num of clusters to relocate */
98         u64 inuse;                      /* num of clusters in use */
99         int multi_ref;                  /* num of clusters ref'd many times */
100 };
101
102 typedef struct __ntfs_resize_t ntfs_resize_t;
103
104 ntfs_volume *vol = NULL;
105 struct bitmap lcn_bitmap;
106
107 #define NTFS_MBYTE (1000 * 1000)
108
109 #define ERR_PREFIX   "ERROR"
110 #define PERR_PREFIX  ERR_PREFIX "(%d): "
111 #define NERR_PREFIX  ERR_PREFIX ": "
112
113 #define rounded_up_division(a, b) (((a) + (b - 1)) / (b))
114
115 GEN_PRINTF (Eprintf, stderr, NULL,         FALSE)
116 GEN_PRINTF (Vprintf, stdout, &opt.verbose, TRUE)
117 GEN_PRINTF (Qprintf, stdout, &opt.quiet,   FALSE)
118
119 /**
120  * perr_printf
121  *
122  * Print an error message.
123  */
124 void perr_printf(const char *fmt, ...)
125 {
126         va_list ap;
127         int eo = errno;
128
129         fprintf(stdout, PERR_PREFIX, eo);
130         va_start(ap, fmt);
131         vfprintf(stdout, fmt, ap);
132         va_end(ap);
133         printf(": %s\n", strerror(eo));
134         fflush(stdout);
135         fflush(stderr);
136 }
137
138 /**
139  * err_exit
140  *
141  * Print and error message and exit the program.
142  */
143 int err_exit(const char *fmt, ...)
144 {
145         va_list ap;
146
147         fprintf(stdout, NERR_PREFIX);
148         va_start(ap, fmt);
149         vfprintf(stdout, fmt, ap);
150         va_end(ap);
151         fflush(stdout);
152         fflush(stderr);
153         exit(1);
154 }
155
156 /**
157  * perr_exit
158  *
159  * Print and error message and exit the program
160  */
161 int perr_exit(const char *fmt, ...)
162 {
163         va_list ap;
164         int eo = errno;
165
166         fprintf(stdout, PERR_PREFIX, eo);
167         va_start(ap, fmt);
168         vfprintf(stdout, fmt, ap);
169         va_end(ap);
170         printf(": %s\n", strerror(eo));
171         fflush(stdout);
172         fflush(stderr);
173         exit(1);
174 }
175
176 /**
177  * usage - Print a list of the parameters to the program
178  *
179  * Print a list of the parameters and options for the program.
180  *
181  * Return:  none
182  */
183 void usage()
184 {
185
186         printf ("\nUsage: %s [options] device\n"
187                 "    Resize an NTFS volume non-destructively.\n"
188                 "\n"
189                 "    -i      --info       Calculate the smallest shrunken size supported\n"
190                 "    -s num  --size num   Resize volume to num[k|M|G] bytes\n"
191                 "\n"
192                 "    -n      --no-action  Do not write to disk\n"
193                 "    -f      --force      Force to progress (DANGEROUS)\n"
194         /*      "    -q      --quiet      Less output\n"*/
195         /*      "    -v      --verbose    More output\n"*/
196                 "    -V      --version    Display version information\n"
197                 "    -h      --help       Display this help\n"
198 #ifdef DEBUG
199                 "    -d      --debug      Show debug information\n"
200 #endif
201                 "\n"
202                 "    The options -i and -s are mutually exclusive. If both options are\n"
203                 "    omitted then the NTFS volume will be enlarged to the device size.\n"
204                 "\n", EXEC_NAME);
205         printf ("%s%s\n", ntfs_bugs, ntfs_home);
206         exit(1);
207 }
208
209 /**
210  * proceed_question
211  *
212  * Force the user to confirm an action before performing it.
213  * Copy-paste from e2fsprogs
214  */
215 void proceed_question(void)
216 {
217         char buf[256];
218         const char *short_yes = "yY";
219
220         fflush(stdout);
221         fflush(stderr);
222         printf("Are you sure you want to proceed (y/[n])? ");
223         buf[0] = 0;
224         fgets(buf, sizeof(buf), stdin);
225         if (strchr(short_yes, buf[0]) == 0) {
226                 printf("OK quitting. NO CHANGES have been made to your "
227                                 "NTFS volume.\n");
228                 exit(1);
229         }
230 }
231
232 /**
233  * version - Print version information about the program
234  *
235  * Print a copyright statement and a brief description of the program.
236  *
237  * Return:  none
238  */
239 void version (void)
240 {
241         printf ("\nResize an NTFS Volume, without data loss.\n\n");
242         printf ("Copyright (c)\n");
243         printf ("    2002-2003 Szabolcs Szakacsits\n");
244         printf ("    2002-2003 Anton Altaparmakov\n");
245         printf ("    2002-2003 Richard Russon\n");
246         printf ("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
247 }
248
249 /**
250  * get_new_volume_size
251  *
252  * Convert a user-supplied string into a size.  Without any suffix the number
253  * will be assumed to be in bytes.  If the number has a suffix of k, M or G it
254  * will be scaled up by 1000, 1000000, or 1000000000.
255  */
256 s64 get_new_volume_size(char *s)
257 {
258         s64 size;
259         char *suffix;
260         int prefix_kind = 1000;
261
262         size = strtoll(s, &suffix, 10);
263         if (size <= 0 || errno == ERANGE)
264                 err_exit("Illegal new volume size\n");
265
266         if (!*suffix)
267                 return size;
268
269         if (strlen(suffix) == 2 && suffix[1] == 'i')
270                 prefix_kind = 1024;
271         else if (strlen(suffix) > 1)
272                 usage();
273
274         /* We follow the SI prefixes:
275            http://physics.nist.gov/cuu/Units/prefixes.html
276            http://physics.nist.gov/cuu/Units/binary.html
277            Disk partitioning tools use prefixes as,
278                                k        M          G
279            old fdisk         2^10     2^20      10^3*2^20
280            recent fdisk     10^3     10^6       10^9
281            cfdisk           10^3     10^6       10^9
282            sfdisk            2^10     2^20
283            parted            2^10     2^20  (may change)
284            fdisk (DOS)       2^10     2^20
285         */
286         /* FIXME: check for overflow */
287         switch (*suffix) {
288         case 'G':
289                 size *= prefix_kind;
290         case 'M':
291                 size *= prefix_kind;
292         case 'k':
293                 size *= prefix_kind;
294                 break;
295         default:
296                 usage();
297         }
298
299         return size;
300 }
301
302 /**
303  * parse_options - Read and validate the programs command line
304  *
305  * Read the command line, verify the syntax and parse the options.
306  * This function is very long, but quite simple.
307  *
308  * Return:  1 Success
309  *          0 Error, one or more problems
310  */
311 int parse_options(int argc, char **argv)
312 {
313         static const char *sopt = "-dfhins:vV";
314         static const struct option lopt[] = {
315 #ifdef DEBUG
316                 { "debug",      no_argument,            NULL, 'd' },
317 #endif
318                 { "force",      no_argument,            NULL, 'f' },
319                 { "help",       no_argument,            NULL, 'h' },
320                 { "info",       no_argument,            NULL, 'i' },
321                 { "no-action",  no_argument,            NULL, 'n' },
322         /*      { "quiet",      no_argument,            NULL, 'q' },*/
323                 { "size",       required_argument,      NULL, 's' },
324         /*      { "verbose",    no_argument,            NULL, 'v' },*/
325                 { "version",    no_argument,            NULL, 'V' },
326                 { NULL, 0, NULL, 0 }
327         };
328
329         char c;
330         int err  = 0;
331         int ver  = 0;
332         int help = 0;
333
334         memset(&opt, 0, sizeof(opt));
335
336         while ((c = getopt_long (argc, argv, sopt, lopt, NULL)) != -1) {
337                 switch (c) {
338                 case 1: /* A non-option argument */
339                         if (!err && !opt.volume)
340                                 opt.volume = argv[optind-1];
341                         else
342                                 err++;
343                         break;
344                 case 'd':
345                         opt.debug++;
346                         break;
347                 case 'f':
348                         opt.force++;
349                         break;
350                 case 'h':
351                 case '?':
352                         help++;
353                         break;
354                 case 'i':
355                         opt.info++;
356                         break;
357                 case 'n':
358                         opt.ro_flag = MS_RDONLY;
359                         break;
360                 case 'q':
361                         opt.quiet++;
362                         break;
363                 case 's':
364                         if (!err && (opt.bytes == 0))
365                                 opt.bytes = get_new_volume_size(optarg);
366                         else
367                                 err++;
368                         break;
369                 case 'v':
370                         opt.verbose++;
371                         break;
372                 case 'V':
373                         ver++;
374                         break;
375                 default:
376                         if (optopt == 's') {
377                                 Eprintf ("Option '%s' requires an argument.\n", argv[optind-1]);
378                         } else {
379                                 Eprintf ("Unknown option '%s'.\n", argv[optind-1]);
380                         }
381                         err++;
382                         break;
383                 }
384         }
385
386         if (help || ver) {
387                 opt.quiet = 0;
388         } else {
389                 if (opt.volume == NULL) {
390                         if (argc > 1)
391                                 Eprintf ("You must specify exactly one device.\n");
392                         err++;
393                 }
394
395                 /*
396                 if (opt.quiet && opt.verbose) {
397                         Eprintf ("You may not use --quiet and --verbose at the same time.\n");
398                         err++;
399                 }
400                 */
401
402                 if (opt.info) {
403                         opt.ro_flag = MS_RDONLY;
404                         if (opt.bytes > 0) {
405                                 Eprintf (NERR_PREFIX "Options --info and --size"
406                                         " can't be used together.\n");
407                                 err++;
408                         }
409                 }
410         }
411
412         stderr = stdout;
413
414 #ifdef DEBUG
415         if (!opt.debug)
416                 if (!(stderr = fopen("/dev/null", "rw")))
417                         perr_exit("Couldn't open /dev/null");
418 #endif
419
420         if (ver)
421                 version();
422         if (help || err)
423                 usage();
424
425         return (!err && !help && !ver);
426 }
427
428 /**
429  * runlist_extent_number
430  *
431  * Count the runs in a runlist.
432  */
433 int runlist_extent_number(runlist *rl)
434 {
435         int i;
436
437         for (i = 0; rl[i].length; i++)
438                 ;
439
440         return i;
441 }
442
443 /**
444  * nr_clusters_to_bitmap_byte_size
445  *
446  * Take the number of clusters in the volume and calculate the size of $Bitmap.
447  * The size will always be a multiple of 8 bytes.
448  */
449 s64 nr_clusters_to_bitmap_byte_size(s64 nr_clusters)
450 {
451         s64 bm_bsize;
452
453         bm_bsize = rounded_up_division(nr_clusters, 8);
454
455         bm_bsize = (bm_bsize + 7) & ~7;
456         Dprintf("Bitmap byte size  : %lld (%lld clusters)\n",
457                bm_bsize, rounded_up_division(bm_bsize, vol->cluster_size));
458
459         return bm_bsize;
460 }
461
462 /**
463  * build_lcn_usage_bitmap
464  *
465  * lcn_bitmap has one bit for each cluster on the disk.  Initially, lcn_bitmap
466  * has no bits set.  As each attribute record is read the bits in lcn_bitmap are
467  * checked to ensure that no other file already references that cluster.
468  *
469  * This serves as a rudimentary "chkdsk" operation.
470  */
471 void build_lcn_usage_bitmap(ntfs_resize_t *resize)
472 {
473         s64 new_volume_size, inode;
474         ATTR_RECORD *a;
475         runlist *rl;
476         int i, j;//, runs;
477
478         a = resize->ctx->attr;
479         new_volume_size = resize->new_volume_size;
480         inode = resize->ni->mft_no;
481
482         if (!a->non_resident)
483                 return;
484
485         if (!(rl = ntfs_mapping_pairs_decompress(vol, a, NULL)))
486                 perr_exit("ntfs_decompress_mapping_pairs");
487
488         //runs = runlist_extent_number(rl);
489
490         for (i = 0; rl[i].length; i++) {
491                 s64 lcn = rl[i].lcn;
492                 s64 lcn_length = rl[i].length;
493
494                 if (lcn == LCN_HOLE || lcn == LCN_RL_NOT_MAPPED)
495                         continue;
496
497                 /* FIXME: ntfs_mapping_pairs_decompress should return error */
498                 if (lcn < 0 || lcn_length <= 0)
499                         err_exit("Corrupt runlist in inode %lld attr %x LCN "
500                                  "%llx length %llx\n", inode,
501                                  le32_to_cpu (a->type), lcn, lcn_length);
502
503                 for (j = 0; j < lcn_length; j++) {
504                         u64 k = (u64)lcn + j;
505                         if (ntfs_bit_get_and_set(lcn_bitmap.bm, k, 1)) {
506                                 
507                                 if (++resize->multi_ref > 10)
508                                         continue;
509                                 
510                                 printf("Cluster %Lu (0x%Lx) referenced "
511                                        "multiply times!\n", k, k);
512                         }
513                 }
514
515                 resize->inuse += lcn_length;
516
517                 if (opt.info)
518                         continue;
519
520                 if (lcn + (lcn_length - 1) > new_volume_size) {
521
522                         s64 start = lcn;
523                         s64 len = lcn_length;
524
525                         if (start <= new_volume_size) {
526                                 start = new_volume_size + 1;
527                                 len = lcn_length - (start - lcn);
528                         }
529
530                         resize->relocations += len;
531                 }
532         }
533         free(rl);
534 }
535
536 /**
537  * walk_attributes
538  *
539  * For a given MFT Record, iterate through all its attributes.  Any non-resident
540  * data runs will be marked in lcn_bitmap.
541  */
542 void walk_attributes(ntfs_resize_t *resize)
543 {
544         ntfs_attr_search_ctx *ctx;
545
546         if (!(ctx = ntfs_attr_get_search_ctx(resize->ni, NULL)))
547                 perr_exit("ntfs_get_attr_search_ctx");
548
549         while (!ntfs_attrs_walk(ctx)) {
550                 if (ctx->attr->type == AT_END)
551                         break;
552                 resize->ctx = ctx;
553                 build_lcn_usage_bitmap(resize);
554         }
555
556         ntfs_attr_put_search_ctx(ctx);
557 }
558
559 /**
560  * compare_bitmaps
561  *
562  * Compare two bitmaps.  In this case, $Bitmap as read from the disk and
563  * lcn_bitmap which we built from the MFT Records.
564  */
565 void compare_bitmaps(struct bitmap *a)
566 {
567         s64 i, pos, count;
568         int mismatch = 0;
569         u8 bm[NTFS_BUF_SIZE];
570
571         printf("Accounting clusters ...\n");
572
573         pos = 0;
574         while (1) {
575                 count = ntfs_attr_pread(vol->lcnbmp_na, pos, NTFS_BUF_SIZE, bm);
576                 if (count == -1)
577                         perr_exit("Couldn't get $Bitmap $DATA");
578
579                 if (count == 0) {
580                         if (a->size != pos)
581                                 err_exit("$Bitmap file size doesn't match "
582                                          "calculated size ((%Ld != %Ld)\n",
583                                          a->size, pos);
584                         break;
585                 }
586
587                 for (i = 0; i < count; i++, pos++) {
588                         u64 cl;  /* current cluster */    
589
590                         if (a->bm[pos] == bm[i])
591                                 continue;
592
593                         for (cl = pos * 8; cl < (pos + 1) * 8; cl++) {
594                                 char bit;
595
596                                 bit = ntfs_bit_get(a->bm, cl);
597                                 if (bit == ntfs_bit_get(bm, i * 8 + cl % 8))
598                                         continue;
599
600                                 if (++mismatch > 10)
601                                         continue;
602
603                                 printf("Cluster accounting failed at %Lu "
604                                        "(0x%Lx): %s cluster in $Bitmap\n",
605                                        cl, cl, bit ? "missing" : "extra");
606                         }
607                 }
608         }
609
610         if (mismatch) {
611                 printf("Totally %d cluster accounting mismatches.\n", 
612                        mismatch);
613                 err_exit("Filesystem check failed! Windows wasn't shutdown "
614                          "properly or inconsistent\nfilesystem. Please run "
615                          "chkdsk on Windows.\n");
616         }
617 }
618
619 /**
620  * progress_init
621  *
622  * Create and scale our progress bar.
623  */
624 void progress_init(struct progress_bar *p, u64 start, u64 stop, int res)
625 {
626         p->start = start;
627         p->stop = stop;
628         p->unit = 100.0 / (stop - start);
629         p->resolution = res;
630 }
631
632 /**
633  * progress_update
634  *
635  * Update the progress bar and tell the user.
636  */
637 void progress_update(struct progress_bar *p, u64 current)
638 {
639         float percent = p->unit * current;
640
641         if (current != p->stop) {
642                 if ((current - p->start) % p->resolution)
643                         return;
644                 printf("%6.2f percent completed\r", percent);
645         } else
646                 printf("100.00 percent completed\n");
647         fflush(stdout);
648 }
649
650 /**
651  * walk_inodes
652  *
653  * Read each record in the MFT, skipping the unused ones, and build up a bitmap
654  * from all the non-resident attributes.
655  */
656 void walk_inodes(ntfs_resize_t *resize)
657 {
658         s64 inode = 0;
659         s64 last_mft_rec;
660         ntfs_inode *ni;
661         struct progress_bar progress;
662
663         printf("Checking filesystem consistency ...\n");
664
665         last_mft_rec = vol->nr_mft_records - 1;
666         progress_init(&progress, inode, last_mft_rec, 100);
667
668         for (; inode <= last_mft_rec; inode++) {
669                 progress_update(&progress, inode);
670
671                 if ((ni = ntfs_inode_open(vol, (MFT_REF)inode)) == NULL) {
672                         /* FIXME: continue only if it make sense, e.g.
673                            MFT record not in use based on $MFT bitmap */
674                         if (errno == EIO || errno == ENOENT)
675                                 continue;
676                         perr_exit("Reading inode %lld failed", inode);
677                 }
678
679                 if (!(ni->mrec->flags & MFT_RECORD_IN_USE))
680                         goto close_inode;
681
682                 if ((ni->mrec->base_mft_record) != 0)
683                         goto close_inode;
684
685                 resize->ni = ni;
686                 walk_attributes(resize);
687 close_inode:
688                 if (ntfs_inode_close(ni))
689                         perr_exit("ntfs_inode_close for inode %Ld", inode);
690         }
691 }
692
693 /**
694  * advise_on_resize
695  *
696  * The metadata file $Bitmap has one bit for each cluster on disk.  This has
697  * already been read into lcn_bitmap.  By looking for the last used cluster on
698  * the disk, we can work out by how much we can shrink the volume.
699  */
700 void advise_on_resize()
701 {
702         s64 i, old_b, new_b, g_b, old_mb, new_mb, g_mb;
703         int fragmanted_end;
704
705         printf("Calculating smallest shrunken size supported ...\n");
706
707         for (i = vol->nr_clusters - 1; i > 0 && (i % 8); i--)
708                 if (ntfs_bit_get(lcn_bitmap.bm, i))
709                         goto found_used_cluster;
710
711         if (i > 0) {
712                 if (ntfs_bit_get(lcn_bitmap.bm, i))
713                         goto found_used_cluster;
714         } else
715                 goto found_used_cluster;
716
717         for (i -=  8; i >= 0; i -= 8)
718                 if (lcn_bitmap.bm[i / 8])
719                         break;
720
721         for (i += 7; i > 0; i--)
722                 if (ntfs_bit_get(lcn_bitmap.bm, i))
723                         break;
724
725 found_used_cluster:
726         i += 2; /* first free + we reserve one for the backup boot sector */
727         fragmanted_end = (i >= vol->nr_clusters) ? 1 : 0;
728
729         if (fragmanted_end || !opt.info) {
730                 printf(fragmented_volume_msg);
731                 if (fragmanted_end)
732                         return;
733                 printf("Now ");
734         }
735
736         old_b = vol->nr_clusters * vol->cluster_size;
737         old_mb = rounded_up_division(old_b, NTFS_MBYTE);
738         new_b = i * vol->cluster_size;
739         new_mb = rounded_up_division(new_b, NTFS_MBYTE);
740         g_b = (vol->nr_clusters - i) * vol->cluster_size;
741         g_mb = g_b / NTFS_MBYTE;
742
743         printf("You could resize at %lld bytes ", new_b);
744
745         if ((new_mb * NTFS_MBYTE) < old_b)
746                 printf("or %lld MB ", new_mb);
747
748         printf("(freeing ");
749
750         if (g_mb && (old_mb - new_mb))
751             printf("%lld MB", old_mb - new_mb);
752         else
753             printf("%lld bytes", g_b);
754
755         printf(").\n");
756 }
757
758 /**
759  * look_for_bad_sector
760  *
761  * Read through the metadata file $BadClus looking for bad sectors on the disk.
762  */
763 void look_for_bad_sector(ATTR_RECORD *a)
764 {
765         runlist *rl;
766         int i;
767
768         rl = ntfs_mapping_pairs_decompress(vol, a, NULL);
769         if (!rl)
770                 perr_exit("ntfs_mapping_pairs_decompress");
771
772         for (i = 0; rl[i].length; i++)
773                 if (rl[i].lcn != LCN_HOLE)
774                         err_exit("Device has bad sectors, not supported\n");
775
776         free(rl);
777 }
778
779 /**
780  * rl_set
781  *
782  * Helper to set up a runlist object
783  */
784 void rl_set(runlist *rl, VCN vcn, LCN lcn, s64 len)
785 {
786         rl->vcn = vcn;
787         rl->lcn = lcn;
788         rl->length = len;
789 }
790
791 /**
792  * bitmap_file_data_fixup
793  *
794  * $Bitmap can overlap the end of the volume. Any bits in this region
795  * must be set. This region also encompasses the backup boot sector.
796  */
797 void bitmap_file_data_fixup(s64 cluster, struct bitmap *bm)
798 {
799         for (; cluster < bm->size << 3; cluster++)
800                 ntfs_bit_set(bm->bm, (u64)cluster, 1);
801 }
802
803 /**
804  * truncate_badclust_bad_attr
805  *
806  * The metadata file $BadClus needs to be shrunk.
807  *
808  * FIXME: this function should go away and instead using a generalized
809  * "truncate_bitmap_data_attr()"
810  */
811 void truncate_badclust_bad_attr(ATTR_RECORD *a, s64 nr_clusters)
812 {
813         runlist *rl_bad;
814         int mp_size;
815         char *mp;
816
817         if (!a->non_resident)
818                 /* FIXME: handle resident attribute value */
819                 perr_exit("Resident attribute in $BadClust not supported!");
820
821         if (!(rl_bad = (runlist *)malloc(2 * sizeof(runlist))))
822                 perr_exit("Couldn't get memory");
823
824         rl_set(rl_bad, 0LL, (LCN)LCN_HOLE, nr_clusters);
825         rl_set(rl_bad + 1, nr_clusters, -1LL, 0LL);
826
827         if ((mp_size = ntfs_get_size_for_mapping_pairs(vol, rl_bad)) == -1)
828                 perr_exit("ntfs_get_size_for_mapping_pairs");
829
830         if (mp_size > le32_to_cpu (a->length) -
831                         le16_to_cpu (a->mapping_pairs_offset))
832                 err_exit("Enlarging attribute header isn't supported yet.\n");
833
834         if (!(mp = (char *)calloc(1, mp_size)))
835                 perr_exit("Couldn't get memory");
836
837         if (ntfs_mapping_pairs_build(vol, mp, mp_size, rl_bad))
838                 perr_exit("ntfs_mapping_pairs_build");
839
840         memcpy((char *)a + le16_to_cpu (a->mapping_pairs_offset), mp, mp_size);
841         a->highest_vcn = cpu_to_le64(nr_clusters - 1LL);
842         a->allocated_size = cpu_to_le64(nr_clusters * vol->cluster_size);
843         a->data_size = cpu_to_le64(nr_clusters * vol->cluster_size);
844
845         free(rl_bad);
846         free(mp);
847 }
848
849 /**
850  * shrink_bitmap_data_attr
851  *
852  * Shrink the metadata file $Bitmap.  It must be large enough for one bit per
853  * cluster of the shrunken volume.  Also it must be a of 8 bytes in size.
854  */
855 void shrink_bitmap_data_attr(runlist **rlist, s64 nr_bm_clusters, s64 new_size)
856 {
857         runlist *rl = *rlist;
858         int i, j;
859         u64 k;
860         int trunc_at = -1;      /* FIXME: -1 means unset */
861
862         /* Unallocate truncated clusters in $Bitmap */
863         for (i = 0; rl[i].length; i++) {
864                 if (rl[i].vcn + rl[i].length <= nr_bm_clusters)
865                         continue;
866                 if (trunc_at == -1)
867                         trunc_at = i;
868                 if (rl[i].lcn == LCN_HOLE || rl[i].lcn == LCN_RL_NOT_MAPPED)
869                         continue;
870                 for (j = 0; j < rl[i].length; j++) {
871                         if (rl[i].vcn + j < nr_bm_clusters)
872                                 continue;
873
874                         k = (u64)rl[i].lcn + j;
875                         if (k < new_size) {
876                                 ntfs_bit_set(lcn_bitmap.bm, k, 0);
877                                 Dprintf("Unallocate cluster: "
878                                        "%llu (%llx)\n", k, k);
879                         }
880                 }
881         }
882
883         if (trunc_at != -1) {
884                 /* NOTE: 'i' always > 0 */
885                 i = nr_bm_clusters - rl[trunc_at].vcn;
886                 rl[trunc_at].length = i;
887                 rl_set(rl + trunc_at + 1, nr_bm_clusters, -1LL, 0LL);
888
889                 Dprintf("Runlist truncated at index %d, "
890                                 "new cluster length %d\n", trunc_at, i);
891         }
892 }
893
894 /**
895  * enlarge_bitmap_data_attr
896  *
897  * Enlarge the metadata file $Bitmap.  It must be large enough for one bit per
898  * cluster of the shrunken volume.  Also it must be a of 8 bytes in size.
899  */
900 void enlarge_bitmap_data_attr(runlist **rlist, s64 nr_bm_clusters, s64 new_size)
901 {
902         runlist *rl = *rlist;
903         s64 i, j, free_zone = 0;
904
905         for (i = 0; rl[i].length; i++)
906                 for (j = 0; j < rl[i].length; j++)
907                         ntfs_bit_set(lcn_bitmap.bm, rl[i].lcn + j, 0);
908         free(rl);
909
910         if (!(rl = *rlist = (runlist *)malloc(2 * sizeof(runlist))))
911                 perr_exit("Couldn't get memory");
912
913         for (i = vol->nr_clusters; i < new_size; i++)
914                 ntfs_bit_set(lcn_bitmap.bm, i, 0);
915
916         for (i = 0; i < new_size; i++) {
917                 if (!ntfs_bit_get(lcn_bitmap.bm, i)) {
918                         if (++free_zone == nr_bm_clusters)
919                                 break;
920                 } else
921                         free_zone = 0;
922         }
923
924         if (free_zone != nr_bm_clusters)
925                 err_exit("Couldn't allocate $Bitmap clusters.\n");
926
927         for (; free_zone; free_zone--, i--)
928                 ntfs_bit_set(lcn_bitmap.bm, i, 1);
929
930         rl_set(rl, 0LL, i + 1, nr_bm_clusters);
931         rl_set(rl + 1, nr_bm_clusters, -1LL, 0LL);
932 }
933
934 /**
935  * truncate_bitmap_data_attr
936  */
937 void truncate_bitmap_data_attr(ATTR_RECORD *a, s64 nr_clusters)
938 {
939         runlist *rl;
940         s64 bm_bsize, size;
941         s64 nr_bm_clusters;
942         int mp_size;
943         char *mp;
944         u8 *tmp;
945
946         if (!a->non_resident)
947                 /* FIXME: handle resident attribute value */
948                 perr_exit("Resident data attribute in $Bitmap not supported!");
949
950         bm_bsize = nr_clusters_to_bitmap_byte_size(nr_clusters);
951         nr_bm_clusters = rounded_up_division(bm_bsize, vol->cluster_size);
952
953         if (!(tmp = (u8 *)realloc(lcn_bitmap.bm, bm_bsize)))
954                 perr_exit("realloc");
955         lcn_bitmap.bm = tmp;
956         lcn_bitmap.size = bm_bsize;
957         bitmap_file_data_fixup(nr_clusters, &lcn_bitmap);
958
959         if (!(rl = ntfs_mapping_pairs_decompress(vol, a, NULL)))
960                 perr_exit("ntfs_mapping_pairs_decompress");
961
962         if (nr_clusters < vol->nr_clusters)
963                 shrink_bitmap_data_attr(&rl, nr_bm_clusters, nr_clusters);
964         else
965                 enlarge_bitmap_data_attr(&rl, nr_bm_clusters, nr_clusters);
966
967         if ((mp_size = ntfs_get_size_for_mapping_pairs(vol, rl)) == -1)
968                 perr_exit("ntfs_get_size_for_mapping_pairs");
969
970         if (mp_size > le32_to_cpu (a->length) -
971                         le16_to_cpu (a->mapping_pairs_offset))
972                 err_exit("Enlarging attribute header isn't supported yet.\n");
973
974         if (!(mp = (char *)calloc(1, mp_size)))
975                 perr_exit("Couldn't get memory");
976
977         if (ntfs_mapping_pairs_build(vol, mp, mp_size, rl))
978                 perr_exit("ntfs_mapping_pairs_build");
979
980         memcpy((char *)a + le16_to_cpu (a->mapping_pairs_offset), mp, mp_size);
981         a->highest_vcn = cpu_to_le64(nr_bm_clusters - 1LL);
982         a->allocated_size = cpu_to_le64(nr_bm_clusters * vol->cluster_size);
983         a->data_size = cpu_to_le64(bm_bsize);
984         a->initialized_size = cpu_to_le64(bm_bsize);
985
986         /*
987          * FIXME: update allocated/data sizes and timestamps in $FILE_NAME
988          * attribute too, for now chkdsk will do this for us.
989          */
990
991         size = ntfs_rl_pwrite(vol, rl, 0, bm_bsize, lcn_bitmap.bm);
992         if (bm_bsize != size) {
993                 if (size == -1)
994                         perr_exit("Couldn't write $Bitmap");
995                 printf("Couldn't write full $Bitmap file "
996                        "(%lld from %lld)\n", size, bm_bsize);
997                 exit(1);
998         }
999
1000         free(rl);
1001         free(mp);
1002 }
1003
1004 /**
1005  * lookup_data_attr
1006  *
1007  * Find the $DATA attribute (with or without a name) for the given MFT reference
1008  * (inode number).
1009  */
1010 void lookup_data_attr(MFT_REF mref, char *aname, ntfs_attr_search_ctx **ctx)
1011 {
1012         ntfs_inode *ni;
1013         uchar_t *ustr = NULL;
1014         int len = 0;
1015
1016         if (!(ni = ntfs_inode_open(vol, mref)))
1017                 perr_exit("ntfs_open_inode");
1018
1019         if (NInoAttrList(ni))
1020                 perr_exit("Attribute list attribute not yet supported");
1021
1022         if (!(*ctx = ntfs_attr_get_search_ctx(ni, NULL)))
1023                 perr_exit("ntfs_get_attr_search_ctx");
1024
1025         if (aname && ((len = ntfs_mbstoucs(aname, &ustr, 0)) == -1))
1026                 perr_exit("Unable to convert string to Unicode");
1027
1028         if (!ustr || !len) {
1029                 ustr = AT_UNNAMED;
1030                 len = 0;
1031         }
1032
1033         if (ntfs_attr_lookup(AT_DATA, ustr, len, 0, 0, NULL, 0, *ctx))
1034                 perr_exit("ntfs_lookup_attr");
1035
1036         if (ustr != AT_UNNAMED)
1037                 free(ustr);
1038 }
1039
1040 /**
1041  * write_mft_record
1042  *
1043  * Write an MFT Record back to the disk.  If the read-only command line option
1044  * was given, this function will do nothing.
1045  */
1046 int write_mft_record(ntfs_attr_search_ctx *ctx)
1047 {
1048         if (ntfs_mft_record_write(vol, ctx->ntfs_ino->mft_no, ctx->mrec))
1049                 perr_exit("ntfs_mft_record_write");
1050
1051         if (vol->dev->d_ops->sync(vol->dev) == -1)
1052                 perr_exit("Failed to sync device");
1053
1054         return 0;
1055 }
1056
1057 /**
1058  * truncate_badclust_file
1059  *
1060  * Shrink the $BadClus file to match the new volume size.
1061  */
1062 void truncate_badclust_file(s64 nr_clusters)
1063 {
1064         ntfs_attr_search_ctx *ctx = NULL;
1065
1066         printf("Updating $BadClust file ...\n");
1067
1068         lookup_data_attr((MFT_REF)FILE_BadClus, "$Bad", &ctx);
1069         look_for_bad_sector(ctx->attr);
1070         /* FIXME: sanity_check_attr(ctx->attr); */
1071         truncate_badclust_bad_attr(ctx->attr, nr_clusters);
1072
1073         if (write_mft_record(ctx))
1074                 perr_exit("Couldn't update $BadClust");
1075
1076         ntfs_attr_put_search_ctx(ctx);
1077 }
1078
1079 /**
1080  * truncate_bitmap_file
1081  *
1082  * Shrink the $Bitmap file to match the new volume size.
1083  */
1084 void truncate_bitmap_file(s64 nr_clusters)
1085 {
1086         ntfs_attr_search_ctx *ctx = NULL;
1087
1088         printf("Updating $Bitmap file ...\n");
1089
1090         lookup_data_attr((MFT_REF)FILE_Bitmap, NULL, &ctx);
1091         /* FIXME: sanity_check_attr(ctx->attr); */
1092         truncate_bitmap_data_attr(ctx->attr, nr_clusters);
1093
1094         if (write_mft_record(ctx))
1095                 perr_exit("Couldn't update $Bitmap");
1096
1097         ntfs_attr_put_search_ctx(ctx);
1098 }
1099
1100 /**
1101  * setup_lcn_bitmap
1102  *
1103  * Allocate a block of memory with one bit for each cluster of the disk.
1104  * All the bits are set to 0, except those representing the region beyond the
1105  * end of the disk.
1106  */
1107 void setup_lcn_bitmap()
1108 {
1109         /* Determine lcn bitmap byte size and allocate it. */
1110         lcn_bitmap.size = nr_clusters_to_bitmap_byte_size(vol->nr_clusters);
1111
1112         if (!(lcn_bitmap.bm = (unsigned char *)calloc(1, lcn_bitmap.size)))
1113                 perr_exit("Failed to allocate internal buffer");
1114
1115         bitmap_file_data_fixup(vol->nr_clusters, &lcn_bitmap);
1116 }
1117
1118 /**
1119  * update_bootsector
1120  *
1121  * FIXME: should be done using ntfs_* functions
1122  */
1123 void update_bootsector(s64 nr_clusters)
1124 {
1125         NTFS_BOOT_SECTOR bs;
1126
1127         printf("Updating Boot record ...\n");
1128
1129         if (vol->dev->d_ops->seek(vol->dev, 0, SEEK_SET) == (off_t)-1)
1130                 perr_exit("lseek");
1131
1132         if (vol->dev->d_ops->read(vol->dev, &bs,
1133                         sizeof(NTFS_BOOT_SECTOR)) == -1)
1134                 perr_exit("read() error");
1135
1136         bs.number_of_sectors = nr_clusters * bs.bpb.sectors_per_cluster;
1137         bs.number_of_sectors = cpu_to_le64(bs.number_of_sectors);
1138
1139         if (vol->dev->d_ops->seek(vol->dev, 0, SEEK_SET) == (off_t)-1)
1140                 perr_exit("lseek");
1141
1142         if (!opt.ro_flag)
1143                 if (vol->dev->d_ops->write(vol->dev, &bs,
1144                                 sizeof(NTFS_BOOT_SECTOR)) == -1)
1145                         perr_exit("write() error");
1146 }
1147
1148 /**
1149  * volume_size
1150  */
1151 s64 volume_size(ntfs_volume *vol, s64 nr_clusters)
1152 {
1153         return nr_clusters * vol->cluster_size;
1154 }
1155
1156 /**
1157  * print_volume_size
1158  *
1159  * Print the volume size in bytes and decimal megabytes.
1160  */
1161 void print_volume_size(char *str, s64 bytes)
1162 {
1163         printf("%s: %lld bytes (%lld MB)\n",
1164                str, bytes, rounded_up_division(bytes, NTFS_MBYTE));
1165 }
1166
1167 /**
1168  * print_disk_usage
1169  *
1170  * Display the amount of disk space in use.
1171  */
1172 void print_disk_usage(ntfs_resize_t *resize)
1173 {
1174         s64 total, used, free, relocations;
1175
1176         total = vol->nr_clusters * vol->cluster_size;
1177         used = resize->inuse * vol->cluster_size;
1178         free = total - used;
1179         relocations = resize->relocations * vol->cluster_size;
1180
1181         printf("Space in use       : %lld MB (%.1f%%)   ",
1182                rounded_up_division(used, NTFS_MBYTE),
1183                100.0 * ((float)used / total));
1184
1185         printf("\n");
1186 }
1187
1188 /**
1189  * mount_volume
1190  *
1191  * First perform some checks to determine if the volume is already mounted, or
1192  * is dirty (Windows wasn't shutdown properly).  If everything is OK, then mount
1193  * the volume (load the metadata into memory).
1194  */
1195 void mount_volume()
1196 {
1197         unsigned long mntflag;
1198
1199         if (ntfs_check_if_mounted(opt.volume, &mntflag))
1200                 perr_exit("Failed to check '%s' mount state", opt.volume);
1201
1202         if (mntflag & NTFS_MF_MOUNTED) {
1203                 if (!(mntflag & NTFS_MF_READONLY))
1204                         err_exit("Device %s is mounted read-write. "
1205                                  "You must 'umount' it first.\n", opt.volume);
1206                 if (!opt.ro_flag)
1207                         err_exit("Device %s is mounted. "
1208                                  "You must 'umount' it first.\n", opt.volume);
1209         }
1210
1211         if (!(vol = ntfs_mount(opt.volume, opt.ro_flag))) {
1212
1213                 int err = errno;
1214
1215                 perr_printf("ntfs_mount failed");
1216                 if (err == EINVAL) {
1217                         printf("Apparently device '%s' doesn't have a "
1218                                "valid NTFS. Maybe you selected\nthe whole "
1219                                "disk instead of a partition (e.g. /dev/hda, "
1220                                "not /dev/hda1)?\n", opt.volume);
1221                 }
1222                 exit(1);
1223         }
1224
1225         if (vol->flags & VOLUME_IS_DIRTY)
1226                 if (opt.force-- <= 0)
1227                         err_exit("Volume is dirty. Run chkdsk and "
1228                                  "please try again (or see -f option).\n");
1229
1230         printf("NTFS volume version: %d.%d\n", vol->major_ver, vol->minor_ver);
1231         if (ntfs_version_is_supported(vol))
1232                 perr_exit("Unknown NTFS version");
1233
1234         printf("Cluster size       : %u bytes\n", vol->cluster_size);
1235         print_volume_size("Current volume size",
1236                           volume_size(vol, vol->nr_clusters));
1237 }
1238
1239 /**
1240  * prepare_volume_fixup
1241  *
1242  * Set the volume's dirty flag and wipe the filesystem journal.  When Windows
1243  * boots it will automatically run chkdsk to check for any problems.  If the
1244  * read-only command line option was given, this function will do nothing.
1245  */
1246 void prepare_volume_fixup()
1247 {
1248         u16 flags;
1249
1250         flags = vol->flags | VOLUME_IS_DIRTY;
1251         if (vol->major_ver >= 2)
1252                 flags |= VOLUME_MOUNTED_ON_NT4;
1253
1254         printf("Schedule chkdsk for NTFS consistency check at Windows "
1255                 "boot time ...\n");
1256
1257         if (ntfs_volume_set_flags(vol, flags))
1258                 perr_exit("Failed to set $Volume dirty");
1259
1260         if (vol->dev->d_ops->sync(vol->dev) == -1)
1261                 perr_exit("Failed to sync device");
1262
1263         printf("Resetting $LogFile ... (this might take a while)\n");
1264
1265         if (ntfs_logfile_reset(vol))
1266                 perr_exit("Failed to reset $LogFile");
1267
1268         if (vol->dev->d_ops->sync(vol->dev) == -1)
1269                 perr_exit("Failed to sync device");
1270 }
1271
1272 /**
1273  * main
1274  *
1275  * Start here
1276  */
1277 int main(int argc, char **argv)
1278 {
1279         ntfs_resize_t resize;
1280         s64 new_size = 0;       /* in clusters */
1281         s64 device_size;        /* in bytes */
1282         int i;
1283
1284         printf("%s v%s\n", EXEC_NAME, VERSION);
1285
1286         if (!parse_options (argc, argv))
1287                 return 1;
1288
1289         utils_set_locale();
1290
1291         mount_volume();
1292
1293         device_size = ntfs_device_size_get(vol->dev, vol->sector_size);
1294         device_size *= vol->sector_size;
1295         if (device_size <= 0)
1296                 err_exit("Couldn't get device size (%Ld)!\n", device_size);
1297
1298         print_volume_size("Current device size", device_size);
1299
1300         if (device_size < vol->nr_clusters * vol->cluster_size)
1301                 err_exit("Current NTFS volume size is bigger than the device "
1302                          "size (%Ld)!\nCorrupt partition table or incorrect "
1303                          "device partitioning?\n", device_size);
1304
1305         if (opt.bytes) {
1306                 if (device_size < opt.bytes)
1307                         err_exit("New size can't be bigger than the "
1308                                  "device size (%Ld bytes).\n", device_size);
1309         } else
1310                 opt.bytes = device_size;
1311
1312         /*
1313          * Take the integer part: we don't want to make the volume bigger
1314          * than requested. Later on we will also decrease this value to save
1315          * room for the backup boot sector.
1316          */
1317         new_size = opt.bytes / vol->cluster_size;
1318
1319         if (!opt.info)
1320                 print_volume_size("New volume size    ",
1321                                   volume_size(vol, new_size));
1322
1323         /* Backup boot sector at the end of device isn't counted in NTFS
1324            volume size thus we have to reserve space for. We don't trust
1325            the user does this for us: better to be on the safe side ;) */
1326         if (new_size)
1327                 --new_size;
1328
1329         if (!opt.info && (new_size == vol->nr_clusters ||
1330                           (opt.bytes == device_size &&
1331                            new_size == vol->nr_clusters - 1))) {
1332                 printf("Nothing to do: NTFS volume size is already OK.\n");
1333                 exit(0);
1334         }
1335
1336         setup_lcn_bitmap();
1337
1338         memset(&resize, 0, sizeof(resize));
1339         resize.new_volume_size = new_size;
1340
1341         walk_inodes(&resize);
1342         if (resize.multi_ref) {
1343                 printf("Totally %d clusters referenced multiply times.\n", 
1344                        resize.multi_ref);
1345                 err_exit("Filesystem check failed! Windows wasn't shutdown "
1346                          "properly or inconsistent\nfilesystem. Please run "
1347                          "chkdsk on Windows.\n");
1348         }
1349         compare_bitmaps(&lcn_bitmap);
1350
1351         print_disk_usage(&resize);
1352
1353         if (opt.info) {
1354                 advise_on_resize();
1355                 exit(0);
1356         }
1357
1358         for (i = new_size; i < vol->nr_clusters; i++)
1359                 if (ntfs_bit_get(lcn_bitmap.bm, (u64)i)) {
1360                         /* FIXME: relocate cluster */
1361                         advise_on_resize();
1362                         exit(1);
1363                 }
1364
1365         if (opt.force-- <= 0 && !opt.ro_flag) {
1366                 printf(resize_warning_msg);
1367                 proceed_question();
1368         }
1369
1370         prepare_volume_fixup();
1371
1372         truncate_badclust_file(new_size);
1373         truncate_bitmap_file(new_size);
1374         update_bootsector(new_size);
1375
1376         /* We don't create backup boot sector because we don't know where the
1377            partition will be split. The scheduled chkdsk will fix it anyway */
1378
1379         if (opt.ro_flag) {
1380                 printf("The read-only test run ended successfully.\n");
1381                 exit(0);
1382         }
1383
1384         printf("Syncing device ...\n");
1385         if (vol->dev->d_ops->sync(vol->dev) == -1)
1386                 perr_exit("fsync");
1387
1388         printf("Successfully resized NTFS on device '%s'.\n", vol->dev->d_name);
1389         if (new_size < vol->nr_clusters)
1390                 printf(resize_important_msg);
1391
1392         return 0;
1393 }
1394