1 /**
2 * ntfsresize - Part of the Linux-NTFS project.
3 *
4 * Copyright (c) 2002-2006 Szabolcs Szakacsits
5 * Copyright (c) 2002-2005 Anton Altaparmakov
6 * Copyright (c) 2002-2003 Richard Russon
7 * Copyright (c) 2007 Yura Pakhuchiy
8 * Copyright (c) 2011-2018 Jean-Pierre Andre
9 *
10 * This utility will resize an NTFS volume without data loss.
11 *
12 * WARNING FOR DEVELOPERS!!! Several external tools grep for text messages
13 * to control execution thus if you would like to change any message
14 * then PLEASE think twice before doing so then don't modify it. Thanks!
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program (in the main directory of the Linux-NTFS
28 * distribution in the file COPYING); if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 */
31
32 #include "config.h"
33
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37 #ifdef HAVE_STDLIB_H
38 #include <stdlib.h>
39 #endif
40 #ifdef HAVE_STDIO_H
41 #include <stdio.h>
42 #endif
43 #ifdef HAVE_STDARG_H
44 #include <stdarg.h>
45 #endif
46 #ifdef HAVE_STRING_H
47 #include <string.h>
48 #endif
49 #ifdef HAVE_ERRNO_H
50 #include <errno.h>
51 #endif
52 #ifdef HAVE_LIMITS_H
53 #include <limits.h>
54 #endif
55 #ifdef HAVE_GETOPT_H
56 #include <getopt.h>
57 #endif
58 #ifdef HAVE_FCNTL_H
59 #include <fcntl.h>
60 #endif
61
62 #include "param.h"
63 #include "debug.h"
64 #include "types.h"
65 #include "support.h"
66 #include "endians.h"
67 #include "bootsect.h"
68 #include "device.h"
69 #include "attrib.h"
70 #include "volume.h"
71 #include "mft.h"
72 #include "bitmap.h"
73 #include "inode.h"
74 #include "runlist.h"
75 #include "utils.h"
76 /* #include "version.h" */
77 #include "misc.h"
78
79 #define BAN_NEW_TEXT 1 /* Respect the ban on new messages */
80 #define CLEAN_EXIT 0 /* traditionnally volume is not closed, there must be a reason */
81
82 static const char *EXEC_NAME = "ntfsresize";
83
84 static const char *resize_warning_msg =
85 "WARNING: Every sanity check passed and only the dangerous operations left.\n"
86 "Make sure that important data has been backed up! Power outage or computer\n"
87 "crash may result major data loss!\n";
88
89 static const char *resize_important_msg =
90 "You can go on to shrink the device for example with Linux fdisk.\n"
91 "IMPORTANT: When recreating the partition, make sure that you\n"
92 " 1) create it at the same disk sector (use sector as the unit!)\n"
93 " 2) create it with the same partition type (usually 7, HPFS/NTFS)\n"
94 " 3) do not make it smaller than the new NTFS filesystem size\n"
95 " 4) set the bootable flag for the partition if it existed before\n"
96 "Otherwise you won't be able to access NTFS or can't boot from the disk!\n"
97 "If you make a mistake and don't have a partition table backup then you\n"
98 "can recover the partition table by TestDisk or Parted's rescue mode.\n";
99
100 static const char *invalid_ntfs_msg =
101 "The device '%s' doesn't have a valid NTFS.\n"
102 "Maybe you selected the wrong partition? Or the whole disk instead of a\n"
103 "partition (e.g. /dev/hda, not /dev/hda1)? This error might also occur\n"
104 "if the disk was incorrectly repartitioned (see the ntfsresize FAQ).\n";
105
106 static const char *corrupt_volume_msg =
107 "NTFS is inconsistent. Run chkdsk /f on Windows then reboot it TWICE!\n"
108 "The usage of the /f parameter is very IMPORTANT! No modification was\n"
109 "and will be made to NTFS by this software until it gets repaired.\n";
110
111 static const char *hibernated_volume_msg =
112 "The NTFS partition is hibernated. Windows must be resumed and turned off\n"
113 "properly, so resizing could be done safely.\n";
114
115 static const char *unclean_journal_msg =
116 "The NTFS journal file is unclean. Please shutdown Windows properly before\n"
117 "using this software! Note, if you have run chkdsk previously then boot\n"
118 "Windows again which will automatically initialize the journal correctly.\n";
119
120 static const char *opened_volume_msg =
121 "This software has detected that the NTFS volume is already opened by another\n"
122 "software thus it refuses to progress to preserve data consistency.\n";
123
124 static const char *bad_sectors_warning_msg =
125 "****************************************************************************\n"
126 "* WARNING: The disk has bad sector. This means physical damage on the disk *\n"
127 "* surface caused by deterioration, manufacturing faults or other reason. *\n"
128 "* The reliability of the disk may stay stable or degrade fast. We suggest *\n"
129 "* making a full backup urgently by running 'ntfsclone --rescue ...' then *\n"
130 "* run 'chkdsk /f /r' on Windows and rebooot it TWICE! Then you can resize *\n"
131 "* NTFS safely by additionally using the --bad-sectors option of ntfsresize.*\n"
132 "****************************************************************************\n";
133
134 static const char *many_bad_sectors_msg =
135 "***************************************************************************\n"
136 "* WARNING: The disk has many bad sectors. This means physical damage *\n"
137 "* on the disk surface caused by deterioration, manufacturing faults or *\n"
138 "* other reason. We suggest to get a replacement disk as soon as possible. *\n"
139 "***************************************************************************\n";
140
141 enum mirror_source { MIRR_OLD, MIRR_NEWMFT, MIRR_MFT };
142
143 static struct {
144 int verbose;
145 int debug;
146 int ro_flag;
147 int force;
148 int info;
149 int infombonly;
150 int expand;
151 int reliable_size;
152 int show_progress;
153 int badsectors;
154 int check;
155 s64 bytes;
156 char *volume;
157 } opt;
158
159 struct bitmap {
160 s64 size;
161 u8 *bm;
162 };
163
164 #define NTFS_PROGBAR 0x0001
165 #define NTFS_PROGBAR_SUPPRESS 0x0002
166
167 struct progress_bar {
168 u64 start;
169 u64 stop;
170 int resolution;
171 int flags;
172 float unit;
173 };
174
175 struct llcn_t {
176 s64 lcn; /* last used LCN for a "special" file/attr type */
177 s64 inode; /* inode using it */
178 };
179
180 #define NTFSCK_PROGBAR 0x0001
181
182 /* runlists which have to be processed later */
183 struct DELAYED {
184 struct DELAYED *next;
185 ATTR_TYPES type;
186 MFT_REF mref;
187 VCN lowest_vcn;
188 int name_len;
189 ntfschar *attr_name;
190 runlist_element *rl;
191 runlist *head_rl;
192 } ;
193
194 typedef struct {
195 ntfs_inode *ni; /* inode being processed */
196 ntfs_attr_search_ctx *ctx; /* inode attribute being processed */
197 s64 inuse; /* num of clusters in use */
198 int multi_ref; /* num of clusters referenced many times */
199 int outsider; /* num of clusters outside the volume */
200 int show_outsider; /* controls showing the above information */
201 int flags;
202 struct bitmap lcn_bitmap;
203 } ntfsck_t;
204
205 typedef struct {
206 ntfs_volume *vol;
207 ntfs_inode *ni; /* inode being processed */
208 s64 new_volume_size; /* in clusters; 0 = --info w/o --size */
209 MFT_REF mref; /* mft reference */
210 MFT_RECORD *mrec; /* mft record */
211 ntfs_attr_search_ctx *ctx; /* inode attribute being processed */
212 u64 relocations; /* num of clusters to relocate */
213 s64 inuse; /* num of clusters in use */
214 runlist mftmir_rl; /* $MFTMirr AT_DATA's new position */
215 s64 mftmir_old; /* $MFTMirr AT_DATA's old LCN */
216 int dirty_inode; /* some inode data got relocated */
217 int shrink; /* shrink = 1, enlarge = 0 */
218 s64 badclusters; /* num of physically dead clusters */
219 VCN mft_highest_vcn; /* used for relocating the $MFT */
220 runlist_element *new_mft_start; /* new first run for $MFT:$DATA */
221 struct DELAYED *delayed_runlists; /* runlists to process later */
222 struct progress_bar progress;
223 struct bitmap lcn_bitmap;
224 /* Temporary statistics until all case is supported */
225 struct llcn_t last_mft;
226 struct llcn_t last_mftmir;
227 struct llcn_t last_multi_mft;
228 struct llcn_t last_sparse;
229 struct llcn_t last_compressed;
230 struct llcn_t last_lcn;
231 s64 last_unsupp; /* last unsupported cluster */
232 enum mirror_source mirr_from;
233 } ntfs_resize_t;
234
235 /* FIXME: This, lcn_bitmap and pos from find_free_cluster() will make a cluster
236 allocation related structure, attached to ntfs_resize_t */
237 static s64 max_free_cluster_range = 0;
238
239 #define NTFS_MBYTE (1000 * 1000)
240
241 /* WARNING: don't modify the text, external tools grep for it */
242 #define ERR_PREFIX "ERROR"
243 #define PERR_PREFIX ERR_PREFIX "(%d): "
244 #define NERR_PREFIX ERR_PREFIX ": "
245
246 #define DIRTY_NONE (0)
247 #define DIRTY_INODE (1)
248 #define DIRTY_ATTRIB (2)
249
rounded_up_division(s64 numer,s64 denom)250 static s64 rounded_up_division(s64 numer, s64 denom)
251 {
252 return (numer + (denom - 1)) / denom;
253 }
254
255 /**
256 * perr_printf
257 *
258 * Print an error message.
259 */
260 __attribute__((format(printf, 1, 2)))
perr_printf(const char * fmt,...)261 static void perr_printf(const char *fmt, ...)
262 {
263 va_list ap;
264 int eo = errno;
265
266 fprintf(stdout, PERR_PREFIX, eo);
267 va_start(ap, fmt);
268 vfprintf(stdout, fmt, ap);
269 va_end(ap);
270 fprintf(stdout, ": %s\n", strerror(eo));
271 fflush(stdout);
272 fflush(stderr);
273 }
274
275 __attribute__((format(printf, 1, 2)))
err_printf(const char * fmt,...)276 static void err_printf(const char *fmt, ...)
277 {
278 va_list ap;
279
280 fprintf(stdout, NERR_PREFIX);
281 va_start(ap, fmt);
282 vfprintf(stdout, fmt, ap);
283 va_end(ap);
284 fflush(stdout);
285 fflush(stderr);
286 }
287
288 /**
289 * err_exit
290 *
291 * Print and error message and exit the program.
292 */
293 __attribute__((noreturn))
294 __attribute__((format(printf, 1, 2)))
err_exit(const char * fmt,...)295 static void err_exit(const char *fmt, ...)
296 {
297 va_list ap;
298
299 fprintf(stdout, NERR_PREFIX);
300 va_start(ap, fmt);
301 vfprintf(stdout, fmt, ap);
302 va_end(ap);
303 fflush(stdout);
304 fflush(stderr);
305 exit(1);
306 }
307
308 /**
309 * perr_exit
310 *
311 * Print and error message and exit the program
312 */
313 __attribute__((noreturn))
314 __attribute__((format(printf, 1, 2)))
perr_exit(const char * fmt,...)315 static void perr_exit(const char *fmt, ...)
316 {
317 va_list ap;
318 int eo = errno;
319
320 fprintf(stdout, PERR_PREFIX, eo);
321 va_start(ap, fmt);
322 vfprintf(stdout, fmt, ap);
323 va_end(ap);
324 printf(": %s\n", strerror(eo));
325 fflush(stdout);
326 fflush(stderr);
327 exit(1);
328 }
329
330 /**
331 * usage - Print a list of the parameters to the program
332 *
333 * Print a list of the parameters and options for the program.
334 *
335 * Return: none
336 */
337 __attribute__((noreturn))
usage(int ret)338 static void usage(int ret)
339 {
340
341 printf("\nUsage: %s [OPTIONS] DEVICE\n"
342 " Resize an NTFS volume non-destructively, safely move any data if needed.\n"
343 "\n"
344 " -c, --check Check to ensure that the device is ready for resize\n"
345 " -i, --info Estimate the smallest shrunken size or the smallest\n"
346 " expansion size\n"
347 " -m, --info-mb-only Estimate the smallest shrunken size possible,\n"
348 " output size in MB only\n"
349 " -s, --size SIZE Resize volume to SIZE[k|M|G] bytes\n"
350 " -x, --expand Expand to full partition\n"
351 "\n"
352 " -n, --no-action Do not write to disk\n"
353 " -b, --bad-sectors Support disks having bad sectors\n"
354 " -f, --force Force to progress\n"
355 " -P, --no-progress-bar Don't show progress bar\n"
356 " -v, --verbose More output\n"
357 " -V, --version Display version information\n"
358 " -h, --help Display this help\n"
359 #ifdef DEBUG
360 " -d, --debug Show debug information\n"
361 #endif
362 "\n"
363 " The options -i and -x are exclusive of option -s, and -m is exclusive\n"
364 " of option -x. If options -i, -m, -s and -x are are all omitted\n"
365 " then the NTFS volume will be enlarged to the DEVICE size.\n"
366 "\n", EXEC_NAME);
367 printf("%s%s", ntfs_bugs, ntfs_home);
368 printf("Ntfsresize FAQ: http://linux-ntfs.sourceforge.net/info/ntfsresize.html\n");
369 exit(ret);
370 }
371
372 /**
373 * proceed_question
374 *
375 * Force the user to confirm an action before performing it.
376 * Copy-paste from e2fsprogs
377 */
proceed_question(void)378 static void proceed_question(void)
379 {
380 char buf[256];
381 const char *short_yes = "yY";
382
383 fflush(stdout);
384 fflush(stderr);
385 printf("Are you sure you want to proceed (y/[n])? ");
386 buf[0] = 0;
387 if (fgets(buf, sizeof(buf), stdin)
388 && !strchr(short_yes, buf[0])) {
389 printf("OK quitting. NO CHANGES have been made to your "
390 "NTFS volume.\n");
391 exit(1);
392 }
393 }
394
395 /**
396 * version - Print version information about the program
397 *
398 * Print a copyright statement and a brief description of the program.
399 *
400 * Return: none
401 */
version(void)402 static void version(void)
403 {
404 printf("\nResize an NTFS Volume, without data loss.\n\n");
405 printf("Copyright (c) 2002-2006 Szabolcs Szakacsits\n");
406 printf("Copyright (c) 2002-2005 Anton Altaparmakov\n");
407 printf("Copyright (c) 2002-2003 Richard Russon\n");
408 printf("Copyright (c) 2007 Yura Pakhuchiy\n");
409 printf("Copyright (c) 2011-2018 Jean-Pierre Andre\n");
410 printf("\n%s\n%s%s", ntfs_gpl, ntfs_bugs, ntfs_home);
411 }
412
413 /**
414 * get_new_volume_size
415 *
416 * Convert a user-supplied string into a size. Without any suffix the number
417 * will be assumed to be in bytes. If the number has a suffix of k, M or G it
418 * will be scaled up by 1000, 1000000, or 1000000000.
419 */
get_new_volume_size(char * s)420 static s64 get_new_volume_size(char *s)
421 {
422 s64 size;
423 char *suffix;
424 int prefix_kind = 1000;
425
426 size = strtoll(s, &suffix, 10);
427 if (size <= 0 || errno == ERANGE)
428 err_exit("Illegal new volume size\n");
429
430 if (!*suffix) {
431 opt.reliable_size = 1;
432 return size;
433 }
434
435 if (strlen(suffix) == 2 && suffix[1] == 'i')
436 prefix_kind = 1024;
437 else if (strlen(suffix) > 1)
438 usage(1);
439
440 /* We follow the SI prefixes:
441 http://physics.nist.gov/cuu/Units/prefixes.html
442 http://physics.nist.gov/cuu/Units/binary.html
443 Disk partitioning tools use prefixes as,
444 k M G
445 fdisk 2.11x- 2^10 2^20 10^3*2^20
446 fdisk 2.11y+ 10^3 10^6 10^9
447 cfdisk 10^3 10^6 10^9
448 sfdisk 2^10 2^20
449 parted 2^10 2^20 (may change)
450 fdisk (DOS) 2^10 2^20
451 */
452 /* FIXME: check for overflow */
453 switch (*suffix) {
454 case 'G':
455 size *= prefix_kind;
456 /* FALLTHRU */
457 case 'M':
458 size *= prefix_kind;
459 /* FALLTHRU */
460 case 'k':
461 size *= prefix_kind;
462 break;
463 default:
464 usage(1);
465 }
466
467 return size;
468 }
469
470 /**
471 * parse_options - Read and validate the programs command line
472 *
473 * Read the command line, verify the syntax and parse the options.
474 * This function is very long, but quite simple.
475 *
476 * Return: 1 Success
477 * 0 Error, one or more problems
478 */
parse_options(int argc,char ** argv)479 static int parse_options(int argc, char **argv)
480 {
481 static const char *sopt = "-bcdfhimnPs:vVx";
482 static const struct option lopt[] = {
483 { "bad-sectors",no_argument, NULL, 'b' },
484 { "check", no_argument, NULL, 'c' },
485 #ifdef DEBUG
486 { "debug", no_argument, NULL, 'd' },
487 #endif
488 { "force", no_argument, NULL, 'f' },
489 { "help", no_argument, NULL, 'h' },
490 { "info", no_argument, NULL, 'i' },
491 { "info-mb-only", no_argument, NULL, 'm' },
492 { "no-action", no_argument, NULL, 'n' },
493 { "no-progress-bar", no_argument, NULL, 'P' },
494 { "size", required_argument, NULL, 's' },
495 { "expand", no_argument, NULL, 'x' },
496 { "verbose", no_argument, NULL, 'v' },
497 { "version", no_argument, NULL, 'V' },
498 { NULL, 0, NULL, 0 }
499 };
500
501 int c;
502 int err = 0;
503 int ver = 0;
504 int help = 0;
505
506 memset(&opt, 0, sizeof(opt));
507 opt.show_progress = 1;
508
509 while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
510 switch (c) {
511 case 1: /* A non-option argument */
512 if (!err && !opt.volume)
513 opt.volume = argv[optind-1];
514 else
515 err++;
516 break;
517 case 'b':
518 opt.badsectors++;
519 break;
520 case 'c':
521 opt.check++;
522 break;
523 case 'd':
524 opt.debug++;
525 break;
526 case 'f':
527 opt.force++;
528 break;
529 case 'h':
530 help++;
531 break;
532 case 'i':
533 opt.info++;
534 break;
535 case 'm':
536 opt.infombonly++;
537 break;
538 case 'n':
539 opt.ro_flag = NTFS_MNT_RDONLY;
540 break;
541 case 'P':
542 opt.show_progress = 0;
543 break;
544 case 's':
545 if (!err && (opt.bytes == 0))
546 opt.bytes = get_new_volume_size(optarg);
547 else
548 err++;
549 break;
550 case 'v':
551 opt.verbose++;
552 ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
553 break;
554 case 'V':
555 ver++;
556 break;
557 case 'x':
558 opt.expand++;
559 break;
560 case '?':
561 default:
562 if (optopt == 's') {
563 printf("Option '%s' requires an argument.\n", argv[optind-1]);
564 } else {
565 printf("Unknown option '%s'.\n", argv[optind-1]);
566 }
567 err++;
568 break;
569 }
570 }
571
572 if (!help && !ver) {
573 if (opt.volume == NULL) {
574 if (argc > 1)
575 printf("You must specify exactly one device.\n");
576 err++;
577 }
578 if (opt.info || opt.infombonly) {
579 opt.ro_flag = NTFS_MNT_RDONLY;
580 }
581 if (opt.bytes
582 && (opt.expand || opt.info || opt.infombonly)) {
583 printf(NERR_PREFIX "Options --info(-mb-only) and --expand "
584 "cannot be used with --size.\n");
585 usage(1);
586 }
587 if (opt.expand && opt.infombonly) {
588 printf(NERR_PREFIX "Options --info-mb-only "
589 "cannot be used with --expand.\n");
590 usage(1);
591 }
592 }
593
594 /* Redirect stderr to stdout, note fflush()es are essential! */
595 fflush(stdout);
596 fflush(stderr);
597 if (dup2(STDOUT_FILENO, STDERR_FILENO) == -1)
598 perr_exit("Failed to redirect stderr to stdout");
599 fflush(stdout);
600 fflush(stderr);
601
602 #ifdef DEBUG
603 if (!opt.debug)
604 if (!freopen("/dev/null", "w", stderr))
605 perr_exit("Failed to redirect stderr to /dev/null");
606 #endif
607
608 if (ver)
609 version();
610 if (help || err)
611 usage(err > 0);
612
613 /* tri-state 0 : done, 1 : error, -1 : proceed */
614 return (err ? 1 : (help || ver ? 0 : -1));
615 }
616
print_advise(ntfs_volume * vol,s64 supp_lcn)617 static void print_advise(ntfs_volume *vol, s64 supp_lcn)
618 {
619 s64 old_b, new_b, freed_b, old_mb, new_mb, freed_mb;
620
621 old_b = vol->nr_clusters * vol->cluster_size;
622 old_mb = rounded_up_division(old_b, NTFS_MBYTE);
623
624 /* Take the next supported cluster (free or relocatable)
625 plus reserve a cluster for the backup boot sector */
626 supp_lcn += 2;
627
628 if (supp_lcn > vol->nr_clusters) {
629 err_printf("Very rare fragmentation type detected. "
630 "Sorry, it's not supported yet.\n"
631 "Try to defragment your NTFS, perhaps it helps.\n");
632 exit(1);
633 }
634
635 new_b = supp_lcn * vol->cluster_size;
636 new_mb = rounded_up_division(new_b, NTFS_MBYTE);
637 freed_b = (vol->nr_clusters - supp_lcn + 1) * vol->cluster_size;
638 freed_mb = freed_b / NTFS_MBYTE;
639
640 /* WARNING: don't modify the text, external tools grep for it */
641 if (!opt.infombonly)
642 printf("You might resize at %lld bytes ", (long long)new_b);
643 if ((new_mb * NTFS_MBYTE) < old_b) {
644 if (!opt.infombonly)
645 printf("or %lld MB ", (long long)new_mb);
646 else
647 printf("Minsize (in MB): %lld\n", (long long)new_mb);
648 }
649
650 if (!opt.infombonly) {
651 printf("(freeing ");
652 if (freed_mb && (old_mb - new_mb))
653 printf("%lld MB", (long long)(old_mb - new_mb));
654 else
655 printf("%lld bytes", (long long)freed_b);
656 printf(").\n");
657
658 printf("Please make a test run using both the -n and -s "
659 "options before real resizing!\n");
660 }
661 }
662
rl_set(runlist * rl,VCN vcn,LCN lcn,s64 len)663 static void rl_set(runlist *rl, VCN vcn, LCN lcn, s64 len)
664 {
665 rl->vcn = vcn;
666 rl->lcn = lcn;
667 rl->length = len;
668 }
669
rl_items(runlist * rl)670 static int rl_items(runlist *rl)
671 {
672 int i = 0;
673
674 while (rl[i++].length)
675 ;
676
677 return i;
678 }
679
dump_run(runlist_element * r)680 static void dump_run(runlist_element *r)
681 {
682 ntfs_log_verbose(" %8lld %8lld (0x%08llx) %lld\n", (long long)r->vcn,
683 (long long)r->lcn, (long long)r->lcn,
684 (long long)r->length);
685 }
686
dump_runlist(runlist * rl)687 static void dump_runlist(runlist *rl)
688 {
689 while (rl->length)
690 dump_run(rl++);
691 }
692
693 /**
694 * nr_clusters_to_bitmap_byte_size
695 *
696 * Take the number of clusters in the volume and calculate the size of $Bitmap.
697 * The size must be always a multiple of 8 bytes.
698 */
nr_clusters_to_bitmap_byte_size(s64 nr_clusters)699 static s64 nr_clusters_to_bitmap_byte_size(s64 nr_clusters)
700 {
701 s64 bm_bsize;
702
703 bm_bsize = rounded_up_division(nr_clusters, 8);
704 bm_bsize = (bm_bsize + 7) & ~7;
705
706 return bm_bsize;
707 }
708
collect_resize_constraints(ntfs_resize_t * resize,runlist * rl)709 static void collect_resize_constraints(ntfs_resize_t *resize, runlist *rl)
710 {
711 s64 inode, last_lcn;
712 ATTR_FLAGS flags;
713 ATTR_TYPES atype;
714 struct llcn_t *llcn = NULL;
715 int ret, supported = 0;
716
717 last_lcn = rl->lcn + (rl->length - 1);
718
719 inode = resize->ni->mft_no;
720 flags = resize->ctx->attr->flags;
721 atype = resize->ctx->attr->type;
722
723 if ((ret = ntfs_inode_badclus_bad(inode, resize->ctx->attr)) != 0) {
724 if (ret == -1)
725 perr_exit("Bad sector list check failed");
726 return;
727 }
728
729 if (inode == FILE_Bitmap) {
730 llcn = &resize->last_lcn;
731 if (atype == AT_DATA && NInoAttrList(resize->ni))
732 err_exit("Highly fragmented $Bitmap isn't supported yet.");
733
734 supported = 1;
735
736 } else if (NInoAttrList(resize->ni)) {
737 llcn = &resize->last_multi_mft;
738
739 if (inode != FILE_MFTMirr)
740 supported = 1;
741
742 } else if (flags & ATTR_IS_SPARSE) {
743 llcn = &resize->last_sparse;
744 supported = 1;
745
746 } else if (flags & ATTR_IS_COMPRESSED) {
747 llcn = &resize->last_compressed;
748 supported = 1;
749
750 } else if (inode == FILE_MFTMirr) {
751 llcn = &resize->last_mftmir;
752 supported = 1;
753
754 /* Fragmented $MFTMirr DATA attribute isn't supported yet */
755 if (atype == AT_DATA)
756 if (rl[1].length != 0 || rl->vcn)
757 supported = 0;
758 } else {
759 llcn = &resize->last_lcn;
760 supported = 1;
761 }
762
763 if (llcn->lcn < last_lcn) {
764 llcn->lcn = last_lcn;
765 llcn->inode = inode;
766 }
767
768 if (supported)
769 return;
770
771 if (resize->last_unsupp < last_lcn)
772 resize->last_unsupp = last_lcn;
773 }
774
775
collect_relocation_info(ntfs_resize_t * resize,runlist * rl)776 static void collect_relocation_info(ntfs_resize_t *resize, runlist *rl)
777 {
778 s64 lcn, lcn_length, start, len, inode;
779 s64 new_vol_size; /* (last LCN on the volume) + 1 */
780
781 lcn = rl->lcn;
782 lcn_length = rl->length;
783 inode = resize->ni->mft_no;
784 new_vol_size = resize->new_volume_size;
785
786 if (lcn + lcn_length <= new_vol_size)
787 return;
788
789 if (inode == FILE_Bitmap && resize->ctx->attr->type == AT_DATA)
790 return;
791
792 start = lcn;
793 len = lcn_length;
794
795 if (lcn < new_vol_size) {
796 start = new_vol_size;
797 len = lcn_length - (new_vol_size - lcn);
798
799 if ((!opt.info && !opt.infombonly) && (inode == FILE_MFTMirr)) {
800 err_printf("$MFTMirr can't be split up yet. Please try "
801 "a different size.\n");
802 print_advise(resize->vol, lcn + lcn_length - 1);
803 exit(1);
804 }
805 }
806
807 resize->relocations += len;
808
809 if ((!opt.info && !opt.infombonly) || !resize->new_volume_size)
810 return;
811
812 printf("Relocation needed for inode %8lld attr 0x%x LCN 0x%08llx "
813 "length %6lld\n", (long long)inode,
814 (unsigned int)le32_to_cpu(resize->ctx->attr->type),
815 (unsigned long long)start, (long long)len);
816 }
817
818 /**
819 * build_lcn_usage_bitmap
820 *
821 * lcn_bitmap has one bit for each cluster on the disk. Initially, lcn_bitmap
822 * has no bits set. As each attribute record is read the bits in lcn_bitmap are
823 * checked to ensure that no other file already references that cluster.
824 *
825 * This serves as a rudimentary "chkdsk" operation.
826 */
build_lcn_usage_bitmap(ntfs_volume * vol,ntfsck_t * fsck)827 static void build_lcn_usage_bitmap(ntfs_volume *vol, ntfsck_t *fsck)
828 {
829 s64 inode;
830 ATTR_RECORD *a;
831 runlist *rl;
832 int i, j;
833 struct bitmap *lcn_bitmap = &fsck->lcn_bitmap;
834
835 a = fsck->ctx->attr;
836 inode = fsck->ni->mft_no;
837
838 if (!a->non_resident)
839 return;
840
841 if (!(rl = ntfs_mapping_pairs_decompress(vol, a, NULL))) {
842 int err = errno;
843 perr_printf("ntfs_decompress_mapping_pairs");
844 if (err == EIO)
845 printf("%s", corrupt_volume_msg);
846 exit(1);
847 }
848
849
850 for (i = 0; rl[i].length; i++) {
851 s64 lcn = rl[i].lcn;
852 s64 lcn_length = rl[i].length;
853
854 /* CHECKME: LCN_RL_NOT_MAPPED check isn't needed */
855 if (lcn == LCN_HOLE || lcn == LCN_RL_NOT_MAPPED)
856 continue;
857
858 /* FIXME: ntfs_mapping_pairs_decompress should return error */
859 if (lcn < 0 || lcn_length <= 0)
860 err_exit("Corrupt runlist in inode %lld attr %x LCN "
861 "%llx length %llx\n", (long long)inode,
862 (unsigned int)le32_to_cpu(a->type),
863 (long long)lcn, (long long)lcn_length);
864
865 for (j = 0; j < lcn_length; j++) {
866 u64 k = (u64)lcn + j;
867
868 if (k >= (u64)vol->nr_clusters) {
869 long long outsiders = lcn_length - j;
870
871 fsck->outsider += outsiders;
872
873 if (++fsck->show_outsider <= 10 || opt.verbose)
874 printf("Outside of the volume reference"
875 " for inode %lld at %lld:%lld\n",
876 (long long)inode, (long long)k,
877 (long long)outsiders);
878
879 break;
880 }
881
882 if (ntfs_bit_get_and_set(lcn_bitmap->bm, k, 1)) {
883 if (++fsck->multi_ref <= 10 || opt.verbose)
884 printf("Cluster %lld is referenced "
885 "multiple times!\n",
886 (long long)k);
887 continue;
888 }
889 }
890 fsck->inuse += lcn_length;
891 }
892 free(rl);
893 }
894
895
attr_get_search_ctx(ntfs_inode * ni,MFT_RECORD * mrec)896 static ntfs_attr_search_ctx *attr_get_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec)
897 {
898 ntfs_attr_search_ctx *ret;
899
900 if ((ret = ntfs_attr_get_search_ctx(ni, mrec)) == NULL)
901 perr_printf("ntfs_attr_get_search_ctx");
902
903 return ret;
904 }
905
906 /**
907 * walk_attributes
908 *
909 * For a given MFT Record, iterate through all its attributes. Any non-resident
910 * data runs will be marked in lcn_bitmap.
911 */
walk_attributes(ntfs_volume * vol,ntfsck_t * fsck)912 static int walk_attributes(ntfs_volume *vol, ntfsck_t *fsck)
913 {
914 if (!(fsck->ctx = attr_get_search_ctx(fsck->ni, NULL)))
915 return -1;
916
917 while (!ntfs_attrs_walk(fsck->ctx)) {
918 if (fsck->ctx->attr->type == AT_END)
919 break;
920 build_lcn_usage_bitmap(vol, fsck);
921 }
922
923 ntfs_attr_put_search_ctx(fsck->ctx);
924 return 0;
925 }
926
927 /**
928 * compare_bitmaps
929 *
930 * Compare two bitmaps. In this case, $Bitmap as read from the disk and
931 * lcn_bitmap which we built from the MFT Records.
932 */
compare_bitmaps(ntfs_volume * vol,struct bitmap * a)933 static void compare_bitmaps(ntfs_volume *vol, struct bitmap *a)
934 {
935 s64 i, pos, count;
936 int mismatch = 0;
937 int backup_boot = 0;
938 u8 bm[NTFS_BUF_SIZE];
939
940 if (!opt.infombonly)
941 printf("Accounting clusters ...\n");
942
943 pos = 0;
944 while (1) {
945 count = ntfs_attr_pread(vol->lcnbmp_na, pos, NTFS_BUF_SIZE, bm);
946 if (count == -1)
947 perr_exit("Couldn't get $Bitmap $DATA");
948
949 if (count == 0) {
950 if (a->size > pos)
951 err_exit("$Bitmap size is smaller than expected"
952 " (%lld != %lld)\n",
953 (long long)a->size, (long long)pos);
954 break;
955 }
956
957 for (i = 0; i < count; i++, pos++) {
958 s64 cl; /* current cluster */
959
960 if (a->size <= pos)
961 goto done;
962
963 if (a->bm[pos] == bm[i])
964 continue;
965
966 for (cl = pos * 8; cl < (pos + 1) * 8; cl++) {
967 char bit;
968
969 bit = ntfs_bit_get(a->bm, cl);
970 if (bit == ntfs_bit_get(bm, i * 8 + cl % 8))
971 continue;
972
973 if (!mismatch && !bit && !backup_boot &&
974 cl == vol->nr_clusters / 2) {
975 /* FIXME: call also boot sector check */
976 backup_boot = 1;
977 printf("Found backup boot sector in "
978 "the middle of the volume.\n");
979 continue;
980 }
981
982 if (++mismatch > 10 && !opt.verbose)
983 continue;
984
985 printf("Cluster accounting failed at %lld "
986 "(0x%llx): %s cluster in "
987 "$Bitmap\n", (long long)cl,
988 (unsigned long long)cl,
989 bit ? "missing" : "extra");
990 }
991 }
992 }
993 done:
994 if (mismatch) {
995 printf("Filesystem check failed! Totally %d cluster "
996 "accounting mismatches.\n", mismatch);
997 err_printf("%s", corrupt_volume_msg);
998 exit(1);
999 }
1000 }
1001
1002 /**
1003 * progress_init
1004 *
1005 * Create and scale our progress bar.
1006 */
progress_init(struct progress_bar * p,u64 start,u64 stop,int flags)1007 static void progress_init(struct progress_bar *p, u64 start, u64 stop, int flags)
1008 {
1009 p->start = start;
1010 p->stop = stop;
1011 p->unit = 100.0 / (stop - start);
1012 p->resolution = 100;
1013 p->flags = flags;
1014 }
1015
1016 /**
1017 * progress_update
1018 *
1019 * Update the progress bar and tell the user.
1020 */
progress_update(struct progress_bar * p,u64 current)1021 static void progress_update(struct progress_bar *p, u64 current)
1022 {
1023 float percent;
1024
1025 if (!(p->flags & NTFS_PROGBAR))
1026 return;
1027 if (p->flags & NTFS_PROGBAR_SUPPRESS)
1028 return;
1029
1030 /* WARNING: don't modify the texts, external tools grep for them */
1031 percent = p->unit * current;
1032 if (current != p->stop) {
1033 if ((current - p->start) % p->resolution)
1034 return;
1035 printf("%6.2f percent completed\r", percent);
1036 } else
1037 printf("100.00 percent completed\n");
1038 fflush(stdout);
1039 }
1040
inode_close(ntfs_inode * ni)1041 static int inode_close(ntfs_inode *ni)
1042 {
1043 if (ntfs_inode_close(ni)) {
1044 perr_printf("ntfs_inode_close for inode %llu",
1045 (unsigned long long)ni->mft_no);
1046 return -1;
1047 }
1048 return 0;
1049 }
1050
1051 /**
1052 * walk_inodes
1053 *
1054 * Read each record in the MFT, skipping the unused ones, and build up a bitmap
1055 * from all the non-resident attributes.
1056 */
build_allocation_bitmap(ntfs_volume * vol,ntfsck_t * fsck)1057 static int build_allocation_bitmap(ntfs_volume *vol, ntfsck_t *fsck)
1058 {
1059 s64 nr_mft_records, inode = 0;
1060 ntfs_inode *ni;
1061 struct progress_bar progress;
1062 int pb_flags = 0; /* progress bar flags */
1063
1064 /* WARNING: don't modify the text, external tools grep for it */
1065 if (!opt.infombonly)
1066 printf("Checking filesystem consistency ...\n");
1067
1068 if (fsck->flags & NTFSCK_PROGBAR)
1069 pb_flags |= NTFS_PROGBAR;
1070
1071 nr_mft_records = vol->mft_na->initialized_size >>
1072 vol->mft_record_size_bits;
1073
1074 progress_init(&progress, inode, nr_mft_records - 1, pb_flags);
1075
1076 for (; inode < nr_mft_records; inode++) {
1077 if (!opt.infombonly)
1078 progress_update(&progress, inode);
1079
1080 if ((ni = ntfs_inode_open(vol, (MFT_REF)inode)) == NULL) {
1081 /* FIXME: continue only if it make sense, e.g.
1082 MFT record not in use based on $MFT bitmap */
1083 if (errno == EIO || errno == ENOENT)
1084 continue;
1085 perr_printf("Reading inode %lld failed",
1086 (long long)inode);
1087 return -1;
1088 }
1089
1090 if (ni->mrec->base_mft_record)
1091 goto close_inode;
1092
1093 fsck->ni = ni;
1094 if (walk_attributes(vol, fsck) != 0) {
1095 inode_close(ni);
1096 return -1;
1097 }
1098 close_inode:
1099 if (inode_close(ni) != 0)
1100 return -1;
1101 }
1102 return 0;
1103 }
1104
build_resize_constraints(ntfs_resize_t * resize)1105 static void build_resize_constraints(ntfs_resize_t *resize)
1106 {
1107 s64 i;
1108 runlist *rl;
1109
1110 if (!resize->ctx->attr->non_resident)
1111 return;
1112
1113 if (!(rl = ntfs_mapping_pairs_decompress(resize->vol,
1114 resize->ctx->attr, NULL)))
1115 perr_exit("ntfs_decompress_mapping_pairs");
1116
1117 for (i = 0; rl[i].length; i++) {
1118 /* CHECKME: LCN_RL_NOT_MAPPED check isn't needed */
1119 if (rl[i].lcn == LCN_HOLE || rl[i].lcn == LCN_RL_NOT_MAPPED)
1120 continue;
1121
1122 collect_resize_constraints(resize, rl + i);
1123 if (resize->shrink)
1124 collect_relocation_info(resize, rl + i);
1125 }
1126 free(rl);
1127 }
1128
resize_constraints_by_attributes(ntfs_resize_t * resize)1129 static void resize_constraints_by_attributes(ntfs_resize_t *resize)
1130 {
1131 if (!(resize->ctx = attr_get_search_ctx(resize->ni, NULL)))
1132 exit(1);
1133
1134 while (!ntfs_attrs_walk(resize->ctx)) {
1135 if (resize->ctx->attr->type == AT_END)
1136 break;
1137 build_resize_constraints(resize);
1138 }
1139
1140 ntfs_attr_put_search_ctx(resize->ctx);
1141 }
1142
set_resize_constraints(ntfs_resize_t * resize)1143 static void set_resize_constraints(ntfs_resize_t *resize)
1144 {
1145 s64 nr_mft_records, inode;
1146 ntfs_inode *ni;
1147
1148 if (!opt.infombonly)
1149 printf("Collecting resizing constraints ...\n");
1150
1151 nr_mft_records = resize->vol->mft_na->initialized_size >>
1152 resize->vol->mft_record_size_bits;
1153
1154 for (inode = 0; inode < nr_mft_records; inode++) {
1155
1156 ni = ntfs_inode_open(resize->vol, (MFT_REF)inode);
1157 if (ni == NULL) {
1158 if (errno == EIO || errno == ENOENT)
1159 continue;
1160 perr_exit("Reading inode %lld failed",
1161 (long long)inode);
1162 }
1163
1164 if (ni->mrec->base_mft_record)
1165 goto close_inode;
1166
1167 resize->ni = ni;
1168 resize_constraints_by_attributes(resize);
1169 close_inode:
1170 if (inode_close(ni) != 0)
1171 exit(1);
1172 }
1173 }
1174
rl_fixup(runlist ** rl)1175 static void rl_fixup(runlist **rl)
1176 {
1177 runlist *tmp = *rl;
1178
1179 if (tmp->lcn == LCN_RL_NOT_MAPPED) {
1180 s64 unmapped_len = tmp->length;
1181
1182 ntfs_log_verbose("Skip unmapped run at the beginning ...\n");
1183
1184 if (!tmp->length)
1185 err_exit("Empty unmapped runlist! Please report!\n");
1186 (*rl)++;
1187 for (tmp = *rl; tmp->length; tmp++)
1188 tmp->vcn -= unmapped_len;
1189 }
1190
1191 for (tmp = *rl; tmp->length; tmp++) {
1192 if (tmp->lcn == LCN_RL_NOT_MAPPED) {
1193 ntfs_log_verbose("Skip unmapped run at the end ...\n");
1194
1195 if (tmp[1].length)
1196 err_exit("Unmapped runlist in the middle! "
1197 "Please report!\n");
1198 tmp->lcn = LCN_ENOENT;
1199 tmp->length = 0;
1200 }
1201 }
1202 }
1203
1204 /*
1205 * Plug a replacement (partial) runlist into full runlist
1206 *
1207 * Returns 0 if successful
1208 * -1 if failed
1209 */
1210
replace_runlist(ntfs_attr * na,const runlist_element * reprl,VCN lowest_vcn)1211 static int replace_runlist(ntfs_attr *na, const runlist_element *reprl,
1212 VCN lowest_vcn)
1213 {
1214 const runlist_element *prep;
1215 const runlist_element *pold;
1216 runlist_element *pnew;
1217 runlist_element *newrl;
1218 VCN nextvcn;
1219 s32 oldcnt, newcnt;
1220 s32 newsize;
1221 int r;
1222
1223 r = -1; /* default return */
1224 /* allocate a new runlist able to hold both */
1225 oldcnt = 0;
1226 while (na->rl[oldcnt].length)
1227 oldcnt++;
1228 newcnt = 0;
1229 while (reprl[newcnt].length)
1230 newcnt++;
1231 newsize = ((oldcnt + newcnt)*sizeof(runlist_element) + 4095) & -4096;
1232 newrl = (runlist_element*)malloc(newsize);
1233 if (newrl) {
1234 /* copy old runs until reaching replaced ones */
1235 pnew = newrl;
1236 pold = na->rl;
1237 while (pold->length
1238 && ((pold->vcn + pold->length)
1239 <= (reprl[0].vcn + lowest_vcn))) {
1240 *pnew = *pold;
1241 pnew++;
1242 pold++;
1243 }
1244 /* split a possible old run partially overlapped */
1245 if (pold->length
1246 && (pold->vcn < (reprl[0].vcn + lowest_vcn))) {
1247 pnew->vcn = pold->vcn;
1248 pnew->lcn = pold->lcn;
1249 pnew->length = reprl[0].vcn + lowest_vcn - pold->vcn;
1250 pnew++;
1251 }
1252 /* copy new runs */
1253 prep = reprl;
1254 nextvcn = prep->vcn + lowest_vcn;
1255 while (prep->length) {
1256 pnew->vcn = prep->vcn + lowest_vcn;
1257 pnew->lcn = prep->lcn;
1258 pnew->length = prep->length;
1259 nextvcn = pnew->vcn + pnew->length;
1260 pnew++;
1261 prep++;
1262 }
1263 /* locate the first fully replaced old run */
1264 while (pold->length
1265 && ((pold->vcn + pold->length) <= nextvcn)) {
1266 pold++;
1267 }
1268 /* split a possible old run partially overlapped */
1269 if (pold->length
1270 && (pold->vcn < nextvcn)) {
1271 pnew->vcn = nextvcn;
1272 pnew->lcn = pold->lcn + nextvcn - pold->vcn;
1273 pnew->length = pold->length - nextvcn + pold->vcn;
1274 pnew++;
1275 }
1276 /* copy old runs beyond replaced ones */
1277 while (pold->length) {
1278 *pnew = *pold;
1279 pnew++;
1280 pold++;
1281 }
1282 /* the terminator is same as the old one */
1283 *pnew = *pold;
1284 /* deallocate the old runlist and replace */
1285 free(na->rl);
1286 na->rl = newrl;
1287 r = 0;
1288 }
1289 return (r);
1290 }
1291
1292 /*
1293 * Expand the new runlist in new extent(s)
1294 *
1295 * This implies allocating inode extents and, generally, creating
1296 * an attribute list and allocating clusters for the list, and
1297 * shuffle the existing attributes accordingly.
1298 *
1299 * Sometimes the runlist being reallocated is within an extent,
1300 * so we have a partial runlist to plug into an existing one
1301 * whose other parts have already been processed or will have
1302 * to be processed later, and we must not interfere with the
1303 * processing of these parts.
1304 *
1305 * This cannot be done on the runlist part stored in a single
1306 * extent, it has to be done globally for the file.
1307 *
1308 * We use the standard library functions, so we must wait until
1309 * the new global bitmap and the new MFT bitmap are saved to
1310 * disk and usable for the allocation of a new extent and creation
1311 * of an attribute list.
1312 *
1313 * Aborts if something goes wrong. There should be no data damage,
1314 * because the old runlist is still in use and the bootsector has
1315 * not been updated yet, so the initial clusters can be accessed.
1316 */
1317
expand_attribute_runlist(ntfs_volume * vol,struct DELAYED * delayed)1318 static void expand_attribute_runlist(ntfs_volume *vol, struct DELAYED *delayed)
1319 {
1320 ntfs_inode *ni;
1321 ntfs_attr *na;
1322 ATTR_TYPES type;
1323 MFT_REF mref;
1324 runlist_element *rl;
1325
1326 /* open the inode */
1327 mref = delayed->mref;
1328 #ifndef BAN_NEW_TEXT
1329 ntfs_log_verbose("Processing a delayed update for inode %lld\n",
1330 (long long)mref);
1331 #endif
1332 type = delayed->type;
1333 rl = delayed->rl;
1334
1335 /* The MFT inode is permanently open, do not reopen or close */
1336 if (mref == FILE_MFT)
1337 ni = vol->mft_ni;
1338 else
1339 ni = ntfs_inode_open(vol,mref);
1340 if (ni) {
1341 if (mref == FILE_MFT)
1342 na = (type == AT_DATA ? vol->mft_na : vol->mftbmp_na);
1343 else
1344 na = ntfs_attr_open(ni, type,
1345 delayed->attr_name, delayed->name_len);
1346 if (na) {
1347 /*
1348 * The runlist is first updated in memory, and
1349 * the updated one is used for updating on device
1350 */
1351 if (!ntfs_attr_map_whole_runlist(na)) {
1352 if (replace_runlist(na,rl,delayed->lowest_vcn)
1353 || ntfs_attr_update_mapping_pairs(na,0))
1354 perr_exit("Could not update runlist "
1355 "for attribute 0x%lx in inode %lld",
1356 (long)le32_to_cpu(type),(long long)mref);
1357 } else
1358 perr_exit("Could not map attribute 0x%lx in inode %lld",
1359 (long)le32_to_cpu(type),(long long)mref);
1360 if (mref != FILE_MFT)
1361 ntfs_attr_close(na);
1362 } else
1363 perr_exit("Could not open attribute 0x%lx in inode %lld",
1364 (long)le32_to_cpu(type),(long long)mref);
1365 ntfs_inode_mark_dirty(ni);
1366 if ((mref != FILE_MFT) && ntfs_inode_close(ni))
1367 perr_exit("Failed to close inode %lld through the library",
1368 (long long)mref);
1369 } else
1370 perr_exit("Could not open inode %lld through the library",
1371 (long long)mref);
1372 }
1373
1374 /*
1375 * Reload the MFT before merging delayed updates of runlist
1376 *
1377 * The delayed updates of runlists are those which imply updating
1378 * the runlists which overflow from their original MFT record.
1379 * Such updates must be done in the new location of the MFT and
1380 * the allocations must be recorded in the new location of the
1381 * MFT bitmap.
1382 * The MFT data and MFT bitmap may themselves have delayed parts
1383 * of their runlists, and at this stage, their runlists may have
1384 * been partially updated on disk, and partially to be updated.
1385 * Their in-memory runlists still point at the old location, they
1386 * are obsolete, and we have to read the partially updated runlist
1387 * from the device before merging the delayed updates.
1388 *
1389 * Returns 0 if successful
1390 * -1 otherwise
1391 */
1392
reload_mft(ntfs_resize_t * resize)1393 static int reload_mft(ntfs_resize_t *resize)
1394 {
1395 ntfs_inode *ni;
1396 ntfs_attr *na;
1397 int r;
1398 int xi;
1399
1400 r = 0;
1401 /* get the base inode */
1402 ni = resize->vol->mft_ni;
1403 if (!ntfs_file_record_read(resize->vol, FILE_MFT, &ni->mrec, NULL)) {
1404 for (xi=0; !r && xi<resize->vol->mft_ni->nr_extents; xi++) {
1405 r = ntfs_file_record_read(resize->vol,
1406 ni->extent_nis[xi]->mft_no,
1407 &ni->extent_nis[xi]->mrec, NULL);
1408 }
1409
1410 if (!r) {
1411 /* reopen the MFT bitmap, and swap vol->mftbmp_na */
1412 na = ntfs_attr_open(resize->vol->mft_ni,
1413 AT_BITMAP, NULL, 0);
1414 if (na && !ntfs_attr_map_whole_runlist(na)) {
1415 ntfs_attr_close(resize->vol->mftbmp_na);
1416 resize->vol->mftbmp_na = na;
1417 } else
1418 r = -1;
1419 }
1420
1421 if (!r) {
1422 /* reopen the MFT data, and swap vol->mft_na */
1423 na = ntfs_attr_open(resize->vol->mft_ni,
1424 AT_DATA, NULL, 0);
1425 if (na && !ntfs_attr_map_whole_runlist(na)) {
1426 ntfs_attr_close(resize->vol->mft_na);
1427 resize->vol->mft_na = na;
1428 } else
1429 r = -1;
1430 }
1431 } else
1432 r = -1;
1433 return (r);
1434 }
1435
1436 /*
1437 * Re-record the MFT extents in MFT bitmap
1438 *
1439 * When both MFT data and MFT bitmap have delayed runlists, MFT data
1440 * is updated first, and the extents may be recorded at old location.
1441 */
1442
record_mft_in_bitmap(ntfs_resize_t * resize)1443 static int record_mft_in_bitmap(ntfs_resize_t *resize)
1444 {
1445 ntfs_inode *ni;
1446 int r;
1447 int xi;
1448
1449 r = 0;
1450 /* get the base inode */
1451 ni = resize->vol->mft_ni;
1452 for (xi=0; !r && xi<resize->vol->mft_ni->nr_extents; xi++) {
1453 r = ntfs_bitmap_set_run(resize->vol->mftbmp_na,
1454 ni->extent_nis[xi]->mft_no, 1);
1455 }
1456 return (r);
1457 }
1458
1459 /*
1460 * Process delayed runlist updates
1461 */
1462
delayed_updates(ntfs_resize_t * resize)1463 static void delayed_updates(ntfs_resize_t *resize)
1464 {
1465 struct DELAYED *delayed;
1466 struct DELAYED *delayed_mft_data;
1467 int nr_extents;
1468
1469 if (ntfs_volume_get_free_space(resize->vol))
1470 err_exit("Failed to determine free space\n");
1471
1472 delayed_mft_data = (struct DELAYED*)NULL;
1473 if (resize->delayed_runlists && reload_mft(resize))
1474 err_exit("Failed to reload the MFT for delayed updates\n");
1475
1476 /*
1477 * Important : updates to MFT must come first, so that
1478 * the new location of MFT is used for adding needed extents.
1479 * Now, there are runlists in the MFT bitmap and MFT data.
1480 * Extents to MFT bitmap have to be stored in the new MFT
1481 * data, and extents to MFT data have to be recorded in
1482 * the MFT bitmap.
1483 * So we update MFT data first, and we record the MFT
1484 * extents again in the MFT bitmap if they were recorded
1485 * in the old location.
1486 *
1487 * However, if we are operating in "no action" mode, the
1488 * MFT records to update are not written to their new location
1489 * and the MFT data runlist has to be updated last in order
1490 * to have the entries read from their old location.
1491 * In this situation the MFT bitmap is never written to
1492 * disk, so the same extents are reallocated repeatedly,
1493 * which is not what would be done in a real resizing.
1494 */
1495
1496 if (opt.ro_flag
1497 && resize->delayed_runlists
1498 && (resize->delayed_runlists->mref == FILE_MFT)
1499 && (resize->delayed_runlists->type == AT_DATA)) {
1500 /* Update the MFT data runlist later */
1501 delayed_mft_data = resize->delayed_runlists;
1502 resize->delayed_runlists = resize->delayed_runlists->next;
1503 }
1504
1505 while (resize->delayed_runlists) {
1506 delayed = resize->delayed_runlists;
1507 expand_attribute_runlist(resize->vol, delayed);
1508 if (delayed->mref == FILE_MFT) {
1509 if (delayed->type == AT_BITMAP)
1510 record_mft_in_bitmap(resize);
1511 if (delayed->type == AT_DATA)
1512 resize->mirr_from = MIRR_MFT;
1513 }
1514 resize->delayed_runlists = resize->delayed_runlists->next;
1515 if (delayed->attr_name)
1516 free(delayed->attr_name);
1517 free(delayed->head_rl);
1518 free(delayed);
1519 }
1520 if (opt.ro_flag && delayed_mft_data) {
1521 /* in "no action" mode, check updating the MFT runlist now */
1522 expand_attribute_runlist(resize->vol, delayed_mft_data);
1523 resize->mirr_from = MIRR_MFT;
1524 if (delayed_mft_data->attr_name)
1525 free(delayed_mft_data->attr_name);
1526 free(delayed_mft_data->head_rl);
1527 free(delayed_mft_data);
1528 }
1529 /* Beware of MFT fragmentation when the target size is too small */
1530 nr_extents = resize->vol->mft_ni->nr_extents;
1531 if (nr_extents > 2) {
1532 printf("WARNING: The MFT is now severely fragmented"
1533 " (%d extents)\n", nr_extents);
1534 }
1535 }
1536
1537 /*
1538 * Queue a runlist replacement for later update
1539 *
1540 * Store the attribute identification relative to base inode
1541 */
1542
replace_later(ntfs_resize_t * resize,runlist * rl,runlist * head_rl)1543 static void replace_later(ntfs_resize_t *resize, runlist *rl, runlist *head_rl)
1544 {
1545 struct DELAYED *delayed;
1546 struct DELAYED *previous;
1547 ATTR_RECORD *a;
1548 MFT_REF mref;
1549 leMFT_REF lemref;
1550 int name_len;
1551 ntfschar *attr_name;
1552
1553 /* save the attribute parameters, to be able to find it later */
1554 a = resize->ctx->attr;
1555 name_len = a->name_length;
1556 attr_name = (ntfschar*)NULL;
1557 if (name_len) {
1558 attr_name = (ntfschar*)ntfs_malloc(name_len*sizeof(ntfschar));
1559 if (attr_name)
1560 memcpy(attr_name,(u8*)a + le16_to_cpu(a->name_offset),
1561 name_len*sizeof(ntfschar));
1562 }
1563 delayed = (struct DELAYED*)ntfs_malloc(sizeof(struct DELAYED));
1564 if (delayed && (attr_name || !name_len)) {
1565 lemref = resize->ctx->mrec->base_mft_record;
1566 if (lemref)
1567 mref = le64_to_cpu(lemref);
1568 else
1569 mref = resize->mref;
1570 delayed->mref = MREF(mref);
1571 delayed->type = a->type;
1572 delayed->attr_name = attr_name;
1573 delayed->name_len = name_len;
1574 delayed->lowest_vcn = sle64_to_cpu(a->lowest_vcn);
1575 delayed->rl = rl;
1576 delayed->head_rl = head_rl;
1577 /* Queue ahead of list if this is MFT or head is not MFT */
1578 if ((delayed->mref == FILE_MFT)
1579 || !resize->delayed_runlists
1580 || (resize->delayed_runlists->mref != FILE_MFT)) {
1581 delayed->next = resize->delayed_runlists;
1582 resize->delayed_runlists = delayed;
1583 } else {
1584 /* Queue after all MFTs is this is not MFT */
1585 previous = resize->delayed_runlists;
1586 while (previous->next
1587 && (previous->next->mref == FILE_MFT))
1588 previous = previous->next;
1589 delayed->next = previous->next;
1590 previous->next = delayed;
1591 }
1592 } else
1593 perr_exit("Could not store delayed update data");
1594 }
1595
1596 /*
1597 * Replace the runlist in an attribute
1598 *
1599 * This sometimes requires expanding the runlist into another extent,
1600 * which has to be done globally on the attribute. Is so, the action
1601 * is put in a delay queue, and the caller must not free the runlist.
1602 *
1603 * Returns 0 if the replacement could be done
1604 * 1 when it has been put in the delay queue.
1605 */
1606
replace_attribute_runlist(ntfs_resize_t * resize,runlist * rl)1607 static int replace_attribute_runlist(ntfs_resize_t *resize, runlist *rl)
1608 {
1609 int mp_size, l;
1610 int must_delay;
1611 void *mp;
1612 runlist *head_rl;
1613 ntfs_volume *vol;
1614 ntfs_attr_search_ctx *ctx;
1615 ATTR_RECORD *a;
1616
1617 vol = resize->vol;
1618 ctx = resize->ctx;
1619 a = ctx->attr;
1620 head_rl = rl;
1621 rl_fixup(&rl);
1622
1623 if ((mp_size = ntfs_get_size_for_mapping_pairs(vol, rl, 0, INT_MAX)) == -1)
1624 perr_exit("ntfs_get_size_for_mapping_pairs");
1625
1626 if (a->name_length) {
1627 u16 name_offs = le16_to_cpu(a->name_offset);
1628 u16 mp_offs = le16_to_cpu(a->mapping_pairs_offset);
1629
1630 if (name_offs >= mp_offs)
1631 err_exit("Attribute name is after mapping pairs! "
1632 "Please report!\n");
1633 }
1634
1635 /* CHECKME: don't trust mapping_pairs is always the last item in the
1636 attribute, instead check for the real size/space */
1637 l = (int)le32_to_cpu(a->length) - le16_to_cpu(a->mapping_pairs_offset);
1638 must_delay = 0;
1639 if (mp_size > l) {
1640 s32 remains_size;
1641 char *next_attr;
1642
1643 ntfs_log_verbose("Enlarging attribute header ...\n");
1644
1645 mp_size = (mp_size + 7) & ~7;
1646
1647 ntfs_log_verbose("Old mp size : %d\n", l);
1648 ntfs_log_verbose("New mp size : %d\n", mp_size);
1649 ntfs_log_verbose("Bytes in use : %u\n", (unsigned int)
1650 le32_to_cpu(ctx->mrec->bytes_in_use));
1651
1652 next_attr = (char *)a + le32_to_cpu(a->length);
1653 l = mp_size - l;
1654
1655 ntfs_log_verbose("Bytes in use new : %u\n", l + (unsigned int)
1656 le32_to_cpu(ctx->mrec->bytes_in_use));
1657 ntfs_log_verbose("Bytes allocated : %u\n", (unsigned int)
1658 le32_to_cpu(ctx->mrec->bytes_allocated));
1659
1660 remains_size = le32_to_cpu(ctx->mrec->bytes_in_use);
1661 remains_size -= (next_attr - (char *)ctx->mrec);
1662
1663 ntfs_log_verbose("increase : %d\n", l);
1664 ntfs_log_verbose("shift : %lld\n",
1665 (long long)remains_size);
1666 if (le32_to_cpu(ctx->mrec->bytes_in_use) + l >
1667 le32_to_cpu(ctx->mrec->bytes_allocated)) {
1668 #ifndef BAN_NEW_TEXT
1669 ntfs_log_verbose("Queuing expansion for later processing\n");
1670 #endif
1671 must_delay = 1;
1672 replace_later(resize,rl,head_rl);
1673 } else {
1674 memmove(next_attr + l, next_attr, remains_size);
1675 ctx->mrec->bytes_in_use = cpu_to_le32(l +
1676 le32_to_cpu(ctx->mrec->bytes_in_use));
1677 a->length = cpu_to_le32(le32_to_cpu(a->length) + l);
1678 }
1679 }
1680
1681 if (!must_delay) {
1682 mp = ntfs_calloc(mp_size);
1683 if (!mp)
1684 perr_exit("ntfsc_calloc couldn't get memory");
1685
1686 if (ntfs_mapping_pairs_build(vol, (u8*)mp, mp_size, rl, 0, NULL))
1687 perr_exit("ntfs_mapping_pairs_build");
1688
1689 memmove((u8*)a + le16_to_cpu(a->mapping_pairs_offset), mp, mp_size);
1690
1691 free(mp);
1692 }
1693 return (must_delay);
1694 }
1695
set_bitmap_range(struct bitmap * bm,s64 pos,s64 length,u8 bit)1696 static void set_bitmap_range(struct bitmap *bm, s64 pos, s64 length, u8 bit)
1697 {
1698 while (length--)
1699 ntfs_bit_set(bm->bm, pos++, bit);
1700 }
1701
set_bitmap_clusters(struct bitmap * bm,runlist * rl,u8 bit)1702 static void set_bitmap_clusters(struct bitmap *bm, runlist *rl, u8 bit)
1703 {
1704 for (; rl->length; rl++)
1705 set_bitmap_range(bm, rl->lcn, rl->length, bit);
1706 }
1707
release_bitmap_clusters(struct bitmap * bm,runlist * rl)1708 static void release_bitmap_clusters(struct bitmap *bm, runlist *rl)
1709 {
1710 max_free_cluster_range = 0;
1711 set_bitmap_clusters(bm, rl, 0);
1712 }
1713
set_max_free_zone(s64 length,s64 end,runlist_element * rle)1714 static void set_max_free_zone(s64 length, s64 end, runlist_element *rle)
1715 {
1716 if (length > rle->length) {
1717 rle->lcn = end - length;
1718 rle->length = length;
1719 }
1720 }
1721
find_free_cluster(struct bitmap * bm,runlist_element * rle,s64 nr_vol_clusters,int hint)1722 static int find_free_cluster(struct bitmap *bm,
1723 runlist_element *rle,
1724 s64 nr_vol_clusters,
1725 int hint)
1726 {
1727 /* FIXME: get rid of this 'static' variable */
1728 static s64 pos = 0;
1729 s64 i, items = rle->length;
1730 s64 free_zone = 0;
1731
1732 if (pos >= nr_vol_clusters)
1733 pos = 0;
1734 if (!max_free_cluster_range)
1735 max_free_cluster_range = nr_vol_clusters;
1736 rle->lcn = rle->length = 0;
1737 if (hint)
1738 pos = nr_vol_clusters / 2;
1739 i = pos;
1740
1741 do {
1742 if (!ntfs_bit_get(bm->bm, i)) {
1743 if (++free_zone == items) {
1744 set_max_free_zone(free_zone, i + 1, rle);
1745 break;
1746 }
1747 } else {
1748 set_max_free_zone(free_zone, i, rle);
1749 free_zone = 0;
1750 }
1751 if (++i == nr_vol_clusters) {
1752 set_max_free_zone(free_zone, i, rle);
1753 i = free_zone = 0;
1754 }
1755 if (rle->length == max_free_cluster_range)
1756 break;
1757 } while (i != pos);
1758
1759 if (i)
1760 set_max_free_zone(free_zone, i, rle);
1761
1762 if (!rle->lcn) {
1763 errno = ENOSPC;
1764 return -1;
1765 }
1766 if (rle->length < items && rle->length < max_free_cluster_range) {
1767 max_free_cluster_range = rle->length;
1768 ntfs_log_verbose("Max free range: %7lld \n",
1769 (long long)max_free_cluster_range);
1770 }
1771 pos = rle->lcn + items;
1772 if (pos == nr_vol_clusters)
1773 pos = 0;
1774
1775 set_bitmap_range(bm, rle->lcn, rle->length, 1);
1776 return 0;
1777 }
1778
alloc_cluster(struct bitmap * bm,s64 items,s64 nr_vol_clusters,int hint)1779 static runlist *alloc_cluster(struct bitmap *bm,
1780 s64 items,
1781 s64 nr_vol_clusters,
1782 int hint)
1783 {
1784 runlist_element rle;
1785 runlist *rl = NULL;
1786 int rl_size, runs = 0;
1787 s64 vcn = 0;
1788
1789 if (items <= 0) {
1790 errno = EINVAL;
1791 return NULL;
1792 }
1793
1794 while (items > 0) {
1795
1796 if (runs)
1797 hint = 0;
1798 rle.length = items;
1799 if (find_free_cluster(bm, &rle, nr_vol_clusters, hint) == -1)
1800 return NULL;
1801
1802 rl_size = (runs + 2) * sizeof(runlist_element);
1803 if (!(rl = (runlist *)realloc(rl, rl_size)))
1804 return NULL;
1805
1806 rl_set(rl + runs, vcn, rle.lcn, rle.length);
1807
1808 vcn += rle.length;
1809 items -= rle.length;
1810 runs++;
1811 }
1812
1813 rl_set(rl + runs, vcn, -1LL, 0LL);
1814
1815 if (runs > 1) {
1816 ntfs_log_verbose("Multi-run allocation: \n");
1817 dump_runlist(rl);
1818 }
1819 return rl;
1820 }
1821
read_all(struct ntfs_device * dev,void * buf,int count)1822 static int read_all(struct ntfs_device *dev, void *buf, int count)
1823 {
1824 int i;
1825
1826 while (count > 0) {
1827
1828 i = count;
1829 if (!NDevReadOnly(dev))
1830 i = dev->d_ops->read(dev, buf, count);
1831
1832 if (i < 0) {
1833 if (errno != EAGAIN && errno != EINTR)
1834 return -1;
1835 } else if (i > 0) {
1836 count -= i;
1837 buf = i + (char *)buf;
1838 } else
1839 err_exit("Unexpected end of file!\n");
1840 }
1841 return 0;
1842 }
1843
write_all(struct ntfs_device * dev,void * buf,int count)1844 static int write_all(struct ntfs_device *dev, void *buf, int count)
1845 {
1846 int i;
1847
1848 while (count > 0) {
1849
1850 i = count;
1851 if (!NDevReadOnly(dev))
1852 i = dev->d_ops->write(dev, buf, count);
1853
1854 if (i < 0) {
1855 if (errno != EAGAIN && errno != EINTR)
1856 return -1;
1857 } else {
1858 count -= i;
1859 buf = i + (char *)buf;
1860 }
1861 }
1862 return 0;
1863 }
1864
1865 /**
1866 * write_mft_record
1867 *
1868 * Write an MFT Record back to the disk. If the read-only command line option
1869 * was given, this function will do nothing.
1870 */
write_mft_record(ntfs_volume * v,const MFT_REF mref,MFT_RECORD * buf)1871 static int write_mft_record(ntfs_volume *v, const MFT_REF mref, MFT_RECORD *buf)
1872 {
1873 if (ntfs_mft_record_write(v, mref, buf))
1874 perr_exit("ntfs_mft_record_write");
1875
1876 // if (v->dev->d_ops->sync(v->dev) == -1)
1877 // perr_exit("Failed to sync device");
1878
1879 return 0;
1880 }
1881
lseek_to_cluster(ntfs_volume * vol,s64 lcn)1882 static void lseek_to_cluster(ntfs_volume *vol, s64 lcn)
1883 {
1884 off_t pos;
1885
1886 pos = (off_t)(lcn * vol->cluster_size);
1887
1888 if (vol->dev->d_ops->seek(vol->dev, pos, SEEK_SET) == (off_t)-1)
1889 perr_exit("seek failed to position %lld", (long long)lcn);
1890 }
1891
copy_clusters(ntfs_resize_t * resize,s64 dest,s64 src,s64 len)1892 static void copy_clusters(ntfs_resize_t *resize, s64 dest, s64 src, s64 len)
1893 {
1894 s64 i;
1895 char *buff;
1896 ntfs_volume *vol = resize->vol;
1897
1898 buff = (char*)ntfs_malloc(vol->cluster_size);
1899 if (!buff)
1900 perr_exit("ntfs_malloc");
1901
1902 for (i = 0; i < len; i++) {
1903
1904 lseek_to_cluster(vol, src + i);
1905
1906 if (read_all(vol->dev, buff, vol->cluster_size) == -1) {
1907 perr_printf("Failed to read from the disk");
1908 if (errno == EIO)
1909 printf("%s", bad_sectors_warning_msg);
1910 exit(1);
1911 }
1912
1913 lseek_to_cluster(vol, dest + i);
1914
1915 if (write_all(vol->dev, buff, vol->cluster_size) == -1) {
1916 perr_printf("Failed to write to the disk");
1917 if (errno == EIO)
1918 printf("%s", bad_sectors_warning_msg);
1919 exit(1);
1920 }
1921
1922 resize->relocations++;
1923 progress_update(&resize->progress, resize->relocations);
1924 }
1925 free(buff);
1926 }
1927
relocate_clusters(ntfs_resize_t * r,runlist * dest_rl,s64 src_lcn)1928 static void relocate_clusters(ntfs_resize_t *r, runlist *dest_rl, s64 src_lcn)
1929 {
1930 /* collect_shrink_constraints() ensured $MFTMir DATA is one run */
1931 if (r->mref == FILE_MFTMirr && r->ctx->attr->type == AT_DATA) {
1932 if (!r->mftmir_old) {
1933 r->mftmir_rl.lcn = dest_rl->lcn;
1934 r->mftmir_rl.length = dest_rl->length;
1935 r->mftmir_old = src_lcn;
1936 } else
1937 err_exit("Multi-run $MFTMirr. Please report!\n");
1938 }
1939
1940 for (; dest_rl->length; src_lcn += dest_rl->length, dest_rl++)
1941 copy_clusters(r, dest_rl->lcn, src_lcn, dest_rl->length);
1942 }
1943
rl_split_run(runlist ** rl,int run,s64 pos)1944 static void rl_split_run(runlist **rl, int run, s64 pos)
1945 {
1946 runlist *rl_new, *rle_new, *rle;
1947 int items, new_size, size_head, size_tail;
1948 s64 len_head, len_tail;
1949
1950 items = rl_items(*rl);
1951 new_size = (items + 1) * sizeof(runlist_element);
1952 size_head = run * sizeof(runlist_element);
1953 size_tail = (items - run - 1) * sizeof(runlist_element);
1954
1955 rl_new = ntfs_malloc(new_size);
1956 if (!rl_new)
1957 perr_exit("ntfs_malloc");
1958
1959 rle_new = rl_new + run;
1960 rle = *rl + run;
1961
1962 memmove(rl_new, *rl, size_head);
1963 memmove(rle_new + 2, rle + 1, size_tail);
1964
1965 len_tail = rle->length - (pos - rle->lcn);
1966 len_head = rle->length - len_tail;
1967
1968 rl_set(rle_new, rle->vcn, rle->lcn, len_head);
1969 rl_set(rle_new + 1, rle->vcn + len_head, rle->lcn + len_head, len_tail);
1970
1971 ntfs_log_verbose("Splitting run at cluster %lld:\n", (long long)pos);
1972 dump_run(rle); dump_run(rle_new); dump_run(rle_new + 1);
1973
1974 free(*rl);
1975 *rl = rl_new;
1976 }
1977
rl_insert_at_run(runlist ** rl,int run,runlist * ins)1978 static void rl_insert_at_run(runlist **rl, int run, runlist *ins)
1979 {
1980 int items, ins_items;
1981 int new_size, size_tail;
1982 runlist *rle;
1983 s64 vcn;
1984
1985 items = rl_items(*rl);
1986 ins_items = rl_items(ins) - 1;
1987 new_size = ((items - 1) + ins_items) * sizeof(runlist_element);
1988 size_tail = (items - run - 1) * sizeof(runlist_element);
1989
1990 if (!(*rl = (runlist *)realloc(*rl, new_size)))
1991 perr_exit("realloc");
1992
1993 rle = *rl + run;
1994
1995 memmove(rle + ins_items, rle + 1, size_tail);
1996
1997 for (vcn = rle->vcn; ins->length; rle++, vcn += ins->length, ins++) {
1998 rl_set(rle, vcn, ins->lcn, ins->length);
1999 // dump_run(rle);
2000 }
2001
2002 return;
2003
2004 /* FIXME: fast path if ins_items = 1 */
2005 // (*rl + run)->lcn = ins->lcn;
2006 }
2007
relocate_run(ntfs_resize_t * resize,runlist ** rl,int run)2008 static void relocate_run(ntfs_resize_t *resize, runlist **rl, int run)
2009 {
2010 s64 lcn, lcn_length;
2011 s64 new_vol_size; /* (last LCN on the volume) + 1 */
2012 runlist *relocate_rl; /* relocate runlist to relocate_rl */
2013 int hint;
2014
2015 lcn = (*rl + run)->lcn;
2016 lcn_length = (*rl + run)->length;
2017 new_vol_size = resize->new_volume_size;
2018
2019 if (lcn + lcn_length <= new_vol_size)
2020 return;
2021
2022 if (lcn < new_vol_size) {
2023 rl_split_run(rl, run, new_vol_size);
2024 return;
2025 }
2026
2027 hint = (resize->mref == FILE_MFTMirr) ? 1 : 0;
2028 if ((resize->mref == FILE_MFT)
2029 && (resize->ctx->attr->type == AT_DATA)
2030 && !run
2031 && resize->new_mft_start) {
2032 relocate_rl = resize->new_mft_start;
2033 } else
2034 if (!(relocate_rl = alloc_cluster(&resize->lcn_bitmap,
2035 lcn_length, new_vol_size, hint)))
2036 perr_exit("Cluster allocation failed for %llu:%lld",
2037 (unsigned long long)resize->mref,
2038 (long long)lcn_length);
2039
2040 /* FIXME: check $MFTMirr DATA isn't multi-run (or support it) */
2041 ntfs_log_verbose("Relocate record %7llu:0x%x:%08lld:0x%08llx:0x%08llx "
2042 "--> 0x%08llx\n", (unsigned long long)resize->mref,
2043 (unsigned int)le32_to_cpu(resize->ctx->attr->type),
2044 (long long)lcn_length,
2045 (unsigned long long)(*rl + run)->vcn,
2046 (unsigned long long)lcn,
2047 (unsigned long long)relocate_rl->lcn);
2048
2049 relocate_clusters(resize, relocate_rl, lcn);
2050 rl_insert_at_run(rl, run, relocate_rl);
2051
2052 /* We don't release old clusters in the bitmap, that area isn't
2053 used by the allocator and will be truncated later on */
2054
2055 /* Do not free the relocated MFT start */
2056 if ((resize->mref != FILE_MFT)
2057 || (resize->ctx->attr->type != AT_DATA)
2058 || run
2059 || !resize->new_mft_start)
2060 free(relocate_rl);
2061
2062 resize->dirty_inode = DIRTY_ATTRIB;
2063 }
2064
relocate_attribute(ntfs_resize_t * resize)2065 static void relocate_attribute(ntfs_resize_t *resize)
2066 {
2067 ATTR_RECORD *a;
2068 runlist *rl;
2069 int i;
2070
2071 a = resize->ctx->attr;
2072
2073 if (!a->non_resident)
2074 return;
2075
2076 if (!(rl = ntfs_mapping_pairs_decompress(resize->vol, a, NULL)))
2077 perr_exit("ntfs_decompress_mapping_pairs");
2078
2079 for (i = 0; rl[i].length; i++) {
2080 s64 lcn = rl[i].lcn;
2081 s64 lcn_length = rl[i].length;
2082
2083 if (lcn == LCN_HOLE || lcn == LCN_RL_NOT_MAPPED)
2084 continue;
2085
2086 /* FIXME: ntfs_mapping_pairs_decompress should return error */
2087 if (lcn < 0 || lcn_length <= 0)
2088 err_exit("Corrupt runlist in MTF %llu attr %x LCN "
2089 "%llx length %llx\n",
2090 (unsigned long long)resize->mref,
2091 (unsigned int)le32_to_cpu(a->type),
2092 (long long)lcn, (long long)lcn_length);
2093
2094 relocate_run(resize, &rl, i);
2095 }
2096
2097 if (resize->dirty_inode == DIRTY_ATTRIB) {
2098 if (!replace_attribute_runlist(resize, rl))
2099 free(rl);
2100 resize->dirty_inode = DIRTY_INODE;
2101 } else
2102 free(rl);
2103 }
2104
is_mftdata(ntfs_resize_t * resize)2105 static int is_mftdata(ntfs_resize_t *resize)
2106 {
2107 /*
2108 * We must update the MFT own DATA record at the end of the second
2109 * step, because the old MFT must be kept available for processing
2110 * the other files.
2111 */
2112
2113 if (resize->ctx->attr->type != AT_DATA)
2114 return 0;
2115
2116 if (resize->mref == 0)
2117 return 1;
2118
2119 if (MREF_LE(resize->mrec->base_mft_record) == 0 &&
2120 MSEQNO_LE(resize->mrec->base_mft_record) != 0)
2121 return 1;
2122
2123 return 0;
2124 }
2125
handle_mftdata(ntfs_resize_t * resize,int do_mftdata)2126 static int handle_mftdata(ntfs_resize_t *resize, int do_mftdata)
2127 {
2128 ATTR_RECORD *attr = resize->ctx->attr;
2129 VCN highest_vcn, lowest_vcn;
2130
2131 if (do_mftdata) {
2132
2133 if (!is_mftdata(resize))
2134 return 0;
2135
2136 highest_vcn = sle64_to_cpu(attr->highest_vcn);
2137 lowest_vcn = sle64_to_cpu(attr->lowest_vcn);
2138
2139 if (resize->mft_highest_vcn != highest_vcn)
2140 return 0;
2141
2142 if (lowest_vcn == 0)
2143 resize->mft_highest_vcn = lowest_vcn;
2144 else
2145 resize->mft_highest_vcn = lowest_vcn - 1;
2146
2147 } else if (is_mftdata(resize)) {
2148
2149 highest_vcn = sle64_to_cpu(attr->highest_vcn);
2150
2151 if (resize->mft_highest_vcn < highest_vcn)
2152 resize->mft_highest_vcn = highest_vcn;
2153
2154 return 0;
2155 }
2156
2157 return 1;
2158 }
2159
relocate_attributes(ntfs_resize_t * resize,int do_mftdata)2160 static void relocate_attributes(ntfs_resize_t *resize, int do_mftdata)
2161 {
2162 int ret;
2163 leMFT_REF lemref;
2164 MFT_REF base_mref;
2165
2166 if (!(resize->ctx = attr_get_search_ctx(NULL, resize->mrec)))
2167 exit(1);
2168
2169 lemref = resize->mrec->base_mft_record;
2170 if (lemref)
2171 base_mref = MREF(le64_to_cpu(lemref));
2172 else
2173 base_mref = resize->mref;
2174 while (!ntfs_attrs_walk(resize->ctx)) {
2175 if (resize->ctx->attr->type == AT_END)
2176 break;
2177
2178 if (handle_mftdata(resize, do_mftdata) == 0)
2179 continue;
2180
2181 ret = ntfs_inode_badclus_bad(resize->mref, resize->ctx->attr);
2182 if (ret == -1)
2183 perr_exit("Bad sector list check failed");
2184 else if (ret == 1)
2185 continue;
2186
2187 if (resize->mref == FILE_Bitmap &&
2188 resize->ctx->attr->type == AT_DATA)
2189 continue;
2190
2191 /* Do not relocate bad clusters */
2192 if ((base_mref == FILE_BadClus)
2193 && (resize->ctx->attr->type == AT_DATA))
2194 continue;
2195
2196 relocate_attribute(resize);
2197 }
2198
2199 ntfs_attr_put_search_ctx(resize->ctx);
2200 }
2201
relocate_inode(ntfs_resize_t * resize,MFT_REF mref,int do_mftdata)2202 static void relocate_inode(ntfs_resize_t *resize, MFT_REF mref, int do_mftdata)
2203 {
2204 ntfs_volume *vol = resize->vol;
2205
2206 if (ntfs_file_record_read(vol, mref, &resize->mrec, NULL)) {
2207 /* FIXME: continue only if it make sense, e.g.
2208 MFT record not in use based on $MFT bitmap */
2209 if (errno == EIO || errno == ENOENT)
2210 return;
2211 perr_exit("ntfs_file_record_record");
2212 }
2213
2214 if (!(resize->mrec->flags & MFT_RECORD_IN_USE))
2215 return;
2216
2217 resize->mref = mref;
2218 resize->dirty_inode = DIRTY_NONE;
2219
2220 relocate_attributes(resize, do_mftdata);
2221
2222 // if (vol->dev->d_ops->sync(vol->dev) == -1)
2223 // perr_exit("Failed to sync device");
2224 /* relocate MFT during second step, even if not dirty */
2225 if ((mref == FILE_MFT) && do_mftdata && resize->new_mft_start) {
2226 s64 pos;
2227
2228 /* write the MFT own record at its new location */
2229 pos = (resize->new_mft_start->lcn
2230 << vol->cluster_size_bits)
2231 + (FILE_MFT << vol->mft_record_size_bits);
2232 if (!opt.ro_flag
2233 && (ntfs_mst_pwrite(vol->dev, pos, 1,
2234 vol->mft_record_size, resize->mrec) != 1))
2235 perr_exit("Couldn't update MFT own record");
2236 } else {
2237 if ((resize->dirty_inode == DIRTY_INODE)
2238 && write_mft_record(vol, mref, resize->mrec)) {
2239 perr_exit("Couldn't update record %llu",
2240 (unsigned long long)mref);
2241 }
2242 }
2243 }
2244
relocate_inodes(ntfs_resize_t * resize)2245 static void relocate_inodes(ntfs_resize_t *resize)
2246 {
2247 s64 nr_mft_records;
2248 MFT_REF mref;
2249 VCN highest_vcn;
2250 s64 length;
2251
2252 printf("Relocating needed data ...\n");
2253
2254 progress_init(&resize->progress, 0, resize->relocations, resize->progress.flags);
2255 resize->relocations = 0;
2256
2257 resize->mrec = ntfs_malloc(resize->vol->mft_record_size);
2258 if (!resize->mrec)
2259 perr_exit("ntfs_malloc failed");
2260
2261 nr_mft_records = resize->vol->mft_na->initialized_size >>
2262 resize->vol->mft_record_size_bits;
2263
2264 /*
2265 * If we need to relocate the first run of the MFT DATA,
2266 * do it now, to have a better chance of getting at least
2267 * 16 records in the first chunk. This is mandatory to be
2268 * later able to read an MFT extent in record 15.
2269 * Should this fail, we can stop with no damage, the volume
2270 * is still in its initial state.
2271 */
2272 if (!resize->vol->mft_na->rl)
2273 err_exit("Internal error : no runlist for $MFT\n");
2274
2275 if ((resize->vol->mft_na->rl->lcn + resize->vol->mft_na->rl->length)
2276 >= resize->new_volume_size) {
2277 /*
2278 * The length of the first run is normally found in
2279 * mft_na. However in some rare circumstance, this is
2280 * merged with the first run of an extent of MFT,
2281 * which implies there is a single run in the base record.
2282 * So we have to make sure not to overflow from the
2283 * runs present in the base extent.
2284 */
2285 length = resize->vol->mft_na->rl->length;
2286 if (ntfs_file_record_read(resize->vol, FILE_MFT,
2287 &resize->mrec, NULL)
2288 || !(resize->ctx = attr_get_search_ctx(NULL,
2289 resize->mrec))) {
2290 err_exit("Could not read the base record of MFT\n");
2291 }
2292 while (!ntfs_attrs_walk(resize->ctx)
2293 && (resize->ctx->attr->type != AT_DATA)) { }
2294 if (resize->ctx->attr->type == AT_DATA) {
2295 sle64 high_le;
2296
2297 high_le = resize->ctx->attr->highest_vcn;
2298 if (sle64_to_cpu(high_le) < length)
2299 length = sle64_to_cpu(high_le) + 1;
2300 } else {
2301 err_exit("Could not find the DATA of MFT\n");
2302 }
2303 ntfs_attr_put_search_ctx(resize->ctx);
2304 resize->new_mft_start = alloc_cluster(&resize->lcn_bitmap,
2305 length, resize->new_volume_size, 0);
2306 if (!resize->new_mft_start
2307 || (((resize->new_mft_start->length
2308 << resize->vol->cluster_size_bits)
2309 >> resize->vol->mft_record_size_bits) < 16)) {
2310 err_exit("Could not allocate 16 records in"
2311 " the first MFT chunk\n");
2312 }
2313 resize->mirr_from = MIRR_NEWMFT;
2314 }
2315
2316 for (mref = 0; mref < (MFT_REF)nr_mft_records; mref++)
2317 relocate_inode(resize, mref, 0);
2318
2319 while (1) {
2320 highest_vcn = resize->mft_highest_vcn;
2321 mref = nr_mft_records;
2322 do {
2323 relocate_inode(resize, --mref, 1);
2324 if (resize->mft_highest_vcn == 0)
2325 goto done;
2326 } while (mref);
2327
2328 if (highest_vcn == resize->mft_highest_vcn)
2329 err_exit("Sanity check failed! Highest_vcn = %lld. "
2330 "Please report!\n", (long long)highest_vcn);
2331 }
2332 done:
2333 free(resize->mrec);
2334 }
2335
print_hint(ntfs_volume * vol,const char * s,struct llcn_t llcn)2336 static void print_hint(ntfs_volume *vol, const char *s, struct llcn_t llcn)
2337 {
2338 s64 runs_b, runs_mb;
2339
2340 if (llcn.lcn == 0)
2341 return;
2342
2343 runs_b = llcn.lcn * vol->cluster_size;
2344 runs_mb = rounded_up_division(runs_b, NTFS_MBYTE);
2345 printf("%-19s: %9lld MB %8lld\n", s, (long long)runs_mb,
2346 (long long)llcn.inode);
2347 }
2348
2349 /**
2350 * advise_on_resize
2351 *
2352 * The metadata file $Bitmap has one bit for each cluster on disk. This has
2353 * already been read into lcn_bitmap. By looking for the last used cluster on
2354 * the disk, we can work out by how much we can shrink the volume.
2355 */
advise_on_resize(ntfs_resize_t * resize)2356 static void advise_on_resize(ntfs_resize_t *resize)
2357 {
2358 ntfs_volume *vol = resize->vol;
2359
2360 if (opt.verbose) {
2361 printf("Estimating smallest shrunken size supported ...\n");
2362 printf("File feature Last used at By inode\n");
2363 print_hint(vol, "$MFT", resize->last_mft);
2364 print_hint(vol, "Multi-Record", resize->last_multi_mft);
2365 print_hint(vol, "$MFTMirr", resize->last_mftmir);
2366 print_hint(vol, "Compressed", resize->last_compressed);
2367 print_hint(vol, "Sparse", resize->last_sparse);
2368 print_hint(vol, "Ordinary", resize->last_lcn);
2369 }
2370
2371 print_advise(vol, resize->last_unsupp);
2372 }
2373
2374 /**
2375 * bitmap_file_data_fixup
2376 *
2377 * $Bitmap can overlap the end of the volume. Any bits in this region
2378 * must be set. This region also encompasses the backup boot sector.
2379 */
bitmap_file_data_fixup(s64 cluster,struct bitmap * bm)2380 static void bitmap_file_data_fixup(s64 cluster, struct bitmap *bm)
2381 {
2382 for (; cluster < bm->size << 3; cluster++)
2383 ntfs_bit_set(bm->bm, (u64)cluster, 1);
2384 }
2385
2386 /*
2387 * Open the attribute $BadClust:$Bad and get its runlist
2388 */
2389
open_badclust_bad_attr(ntfs_attr_search_ctx * ctx)2390 static ntfs_attr *open_badclust_bad_attr(ntfs_attr_search_ctx *ctx)
2391 {
2392 ntfs_inode *base_ni;
2393 ntfs_attr *na;
2394 static ntfschar Bad[4] = {
2395 const_cpu_to_le16('$'), const_cpu_to_le16('B'),
2396 const_cpu_to_le16('a'), const_cpu_to_le16('d')
2397 } ;
2398
2399 base_ni = ctx->base_ntfs_ino;
2400 if (!base_ni)
2401 base_ni = ctx->ntfs_ino;
2402
2403 na = ntfs_attr_open(base_ni, AT_DATA, Bad, 4);
2404 if (!na) {
2405 err_printf("Could not access the bad sector list\n");
2406 } else {
2407 if (ntfs_attr_map_whole_runlist(na) || !na->rl) {
2408 err_printf("Could not decode the bad sector list\n");
2409 ntfs_attr_close(na);
2410 ntfs_inode_close(base_ni);
2411 na = (ntfs_attr*)NULL;
2412 }
2413 }
2414 return (na);
2415 }
2416
2417 /**
2418 * truncate_badclust_bad_attr
2419 *
2420 * The metadata file $BadClus needs to be shrunk.
2421 *
2422 * FIXME: this function should go away and instead using a generalized
2423 * "truncate_bitmap_data_attr()"
2424 */
truncate_badclust_bad_attr(ntfs_resize_t * resize)2425 static void truncate_badclust_bad_attr(ntfs_resize_t *resize)
2426 {
2427 ntfs_inode *base_ni;
2428 ntfs_attr *na;
2429 ntfs_attr_search_ctx *ctx;
2430 s64 nr_clusters = resize->new_volume_size;
2431 ntfs_volume *vol = resize->vol;
2432
2433 na = open_badclust_bad_attr(resize->ctx);
2434 if (!na) {
2435 err_printf("Could not access the bad sector list\n");
2436 exit(1);
2437 }
2438 base_ni = na->ni;
2439 if (ntfs_attr_truncate(na,nr_clusters << vol->cluster_size_bits)) {
2440 err_printf("Could not adjust the bad sector list\n");
2441 exit(1);
2442 }
2443 /* Clear the sparse flags, even if there are bad clusters */
2444 na->ni->flags &= ~FILE_ATTR_SPARSE_FILE;
2445 na->data_flags &= ~ATTR_IS_SPARSE;
2446 ctx = resize->ctx;
2447 ctx->attr->data_size = cpu_to_sle64(na->data_size);
2448 ctx->attr->initialized_size = cpu_to_sle64(na->initialized_size);
2449 ctx->attr->flags = na->data_flags;
2450 ctx->attr->compression_unit = 0;
2451 ntfs_inode_mark_dirty(ctx->ntfs_ino);
2452 NInoFileNameSetDirty(na->ni);
2453 NInoFileNameSetDirty(na->ni);
2454
2455 ntfs_attr_close(na);
2456 ntfs_inode_mark_dirty(base_ni);
2457 }
2458
2459 /**
2460 * realloc_bitmap_data_attr
2461 *
2462 * Reallocate the metadata file $Bitmap. It must be large enough for one bit
2463 * per cluster of the shrunken volume. Also it must be a of 8 bytes in size.
2464 */
realloc_bitmap_data_attr(ntfs_resize_t * resize,runlist ** rl,s64 nr_bm_clusters)2465 static void realloc_bitmap_data_attr(ntfs_resize_t *resize,
2466 runlist **rl,
2467 s64 nr_bm_clusters)
2468 {
2469 s64 i;
2470 ntfs_volume *vol = resize->vol;
2471 ATTR_RECORD *a = resize->ctx->attr;
2472 s64 new_size = resize->new_volume_size;
2473 struct bitmap *bm = &resize->lcn_bitmap;
2474
2475 if (!(*rl = ntfs_mapping_pairs_decompress(vol, a, NULL)))
2476 perr_exit("ntfs_mapping_pairs_decompress");
2477
2478 release_bitmap_clusters(bm, *rl);
2479 free(*rl);
2480
2481 for (i = vol->nr_clusters; i < new_size; i++)
2482 ntfs_bit_set(bm->bm, i, 0);
2483
2484 if (!(*rl = alloc_cluster(bm, nr_bm_clusters, new_size, 0)))
2485 perr_exit("Couldn't allocate $Bitmap clusters");
2486 }
2487
realloc_lcn_bitmap(ntfs_resize_t * resize,s64 bm_bsize)2488 static void realloc_lcn_bitmap(ntfs_resize_t *resize, s64 bm_bsize)
2489 {
2490 u8 *tmp;
2491
2492 if (!(tmp = realloc(resize->lcn_bitmap.bm, bm_bsize)))
2493 perr_exit("realloc");
2494
2495 resize->lcn_bitmap.bm = tmp;
2496 resize->lcn_bitmap.size = bm_bsize;
2497 bitmap_file_data_fixup(resize->new_volume_size, &resize->lcn_bitmap);
2498 }
2499
2500 /**
2501 * truncate_bitmap_data_attr
2502 */
truncate_bitmap_data_attr(ntfs_resize_t * resize)2503 static void truncate_bitmap_data_attr(ntfs_resize_t *resize)
2504 {
2505 ATTR_RECORD *a;
2506 runlist *rl;
2507 ntfs_attr *lcnbmp_na;
2508 s64 bm_bsize, size;
2509 s64 nr_bm_clusters;
2510 int truncated;
2511 ntfs_volume *vol = resize->vol;
2512
2513 a = resize->ctx->attr;
2514 if (!a->non_resident)
2515 /* FIXME: handle resident attribute value */
2516 err_exit("Resident attribute in $Bitmap isn't supported!\n");
2517
2518 bm_bsize = nr_clusters_to_bitmap_byte_size(resize->new_volume_size);
2519 nr_bm_clusters = rounded_up_division(bm_bsize, vol->cluster_size);
2520
2521 if (resize->shrink) {
2522 realloc_bitmap_data_attr(resize, &rl, nr_bm_clusters);
2523 realloc_lcn_bitmap(resize, bm_bsize);
2524 } else {
2525 realloc_lcn_bitmap(resize, bm_bsize);
2526 realloc_bitmap_data_attr(resize, &rl, nr_bm_clusters);
2527 }
2528 /*
2529 * Delayed relocations may require cluster allocations
2530 * through the library, to hold added attribute lists,
2531 * be sure they will be within the new limits.
2532 */
2533 lcnbmp_na = resize->vol->lcnbmp_na;
2534 lcnbmp_na->data_size = bm_bsize;
2535 lcnbmp_na->initialized_size = bm_bsize;
2536 lcnbmp_na->allocated_size = nr_bm_clusters << vol->cluster_size_bits;
2537 vol->lcnbmp_ni->data_size = bm_bsize;
2538 vol->lcnbmp_ni->allocated_size = lcnbmp_na->allocated_size;
2539 a->highest_vcn = cpu_to_sle64(nr_bm_clusters - 1LL);
2540 a->allocated_size = cpu_to_sle64(nr_bm_clusters * vol->cluster_size);
2541 a->data_size = cpu_to_sle64(bm_bsize);
2542 a->initialized_size = cpu_to_sle64(bm_bsize);
2543
2544 truncated = !replace_attribute_runlist(resize, rl);
2545
2546 /*
2547 * FIXME: update allocated/data sizes and timestamps in $FILE_NAME
2548 * attribute too, for now chkdsk will do this for us.
2549 */
2550
2551 size = ntfs_rl_pwrite(vol, rl, 0, 0, bm_bsize, resize->lcn_bitmap.bm);
2552 if (bm_bsize != size) {
2553 if (size == -1)
2554 perr_exit("Couldn't write $Bitmap");
2555 err_exit("Couldn't write full $Bitmap file (%lld from %lld)\n",
2556 (long long)size, (long long)bm_bsize);
2557 }
2558
2559 if (truncated) {
2560 /* switch to the new bitmap runlist */
2561 free(lcnbmp_na->rl);
2562 lcnbmp_na->rl = rl;
2563 }
2564 }
2565
2566 /**
2567 * lookup_data_attr
2568 *
2569 * Find the $DATA attribute (with or without a name) for the given MFT reference
2570 * (inode number).
2571 */
lookup_data_attr(ntfs_volume * vol,MFT_REF mref,const char * aname,ntfs_attr_search_ctx ** ctx)2572 static void lookup_data_attr(ntfs_volume *vol,
2573 MFT_REF mref,
2574 const char *aname,
2575 ntfs_attr_search_ctx **ctx)
2576 {
2577 ntfs_inode *ni;
2578 ntfschar *ustr;
2579 int len = 0;
2580
2581 if (!(ni = ntfs_inode_open(vol, mref)))
2582 perr_exit("ntfs_open_inode");
2583
2584 if (!(*ctx = attr_get_search_ctx(ni, NULL)))
2585 exit(1);
2586
2587 if ((ustr = ntfs_str2ucs(aname, &len)) == NULL) {
2588 perr_printf("Couldn't convert '%s' to Unicode", aname);
2589 exit(1);
2590 }
2591
2592 if (ntfs_attr_lookup(AT_DATA, ustr, len, CASE_SENSITIVE,
2593 0, NULL, 0, *ctx))
2594 perr_exit("ntfs_lookup_attr");
2595
2596 ntfs_ucsfree(ustr);
2597 }
2598
close_inode_and_context(ntfs_attr_search_ctx * ctx)2599 static void close_inode_and_context(ntfs_attr_search_ctx *ctx)
2600 {
2601 ntfs_inode *ni;
2602
2603 ni = ctx->base_ntfs_ino;
2604 if (!ni)
2605 ni = ctx->ntfs_ino;
2606 ntfs_attr_put_search_ctx(ctx);
2607 if (ni)
2608 ntfs_inode_close(ni);
2609 }
2610
check_bad_sectors(ntfs_volume * vol)2611 static int check_bad_sectors(ntfs_volume *vol)
2612 {
2613 ntfs_attr_search_ctx *ctx;
2614 ntfs_attr *na;
2615 runlist *rl;
2616 s64 i, badclusters = 0;
2617
2618 ntfs_log_verbose("Checking for bad sectors ...\n");
2619
2620 lookup_data_attr(vol, FILE_BadClus, "$Bad", &ctx);
2621
2622 na = open_badclust_bad_attr(ctx);
2623 if (!na) {
2624 err_printf("Could not access the bad sector list\n");
2625 exit(1);
2626 }
2627 rl = na->rl;
2628 for (i = 0; rl[i].length; i++) {
2629 /* CHECKME: LCN_RL_NOT_MAPPED check isn't needed */
2630 if (rl[i].lcn == LCN_HOLE || rl[i].lcn == LCN_RL_NOT_MAPPED)
2631 continue;
2632
2633 badclusters += rl[i].length;
2634 ntfs_log_verbose("Bad cluster: %#8llx - %#llx (%lld)\n",
2635 (long long)rl[i].lcn,
2636 (long long)rl[i].lcn + rl[i].length - 1,
2637 (long long)rl[i].length);
2638 }
2639
2640 if (badclusters) {
2641 printf("%sThis software has detected that the disk has at least"
2642 " %lld bad sector%s.\n",
2643 !opt.badsectors ? NERR_PREFIX : "WARNING: ",
2644 (long long)badclusters, badclusters - 1 ? "s" : "");
2645 if (!opt.badsectors) {
2646 printf("%s", bad_sectors_warning_msg);
2647 exit(1);
2648 } else
2649 printf("WARNING: Bad sectors can cause reliability "
2650 "problems and massive data loss!!!\n");
2651 }
2652
2653 ntfs_attr_close(na);
2654 #if CLEAN_EXIT
2655 close_inode_and_context(ctx);
2656 #else
2657 ntfs_attr_put_search_ctx(ctx);
2658 #endif
2659
2660 return badclusters;
2661 }
2662
2663 /**
2664 * truncate_badclust_file
2665 *
2666 * Shrink the $BadClus file to match the new volume size.
2667 */
truncate_badclust_file(ntfs_resize_t * resize)2668 static void truncate_badclust_file(ntfs_resize_t *resize)
2669 {
2670 printf("Updating $BadClust file ...\n");
2671
2672 lookup_data_attr(resize->vol, FILE_BadClus, "$Bad", &resize->ctx);
2673 /* FIXME: sanity_check_attr(ctx->attr); */
2674 resize->mref = FILE_BadClus;
2675 truncate_badclust_bad_attr(resize);
2676
2677 close_inode_and_context(resize->ctx);
2678 }
2679
2680 /**
2681 * truncate_bitmap_file
2682 *
2683 * Shrink the $Bitmap file to match the new volume size.
2684 */
truncate_bitmap_file(ntfs_resize_t * resize)2685 static void truncate_bitmap_file(ntfs_resize_t *resize)
2686 {
2687 ntfs_volume *vol = resize->vol;
2688
2689 printf("Updating $Bitmap file ...\n");
2690
2691 lookup_data_attr(resize->vol, FILE_Bitmap, NULL, &resize->ctx);
2692 resize->mref = FILE_Bitmap;
2693 truncate_bitmap_data_attr(resize);
2694
2695 if (resize->new_mft_start) {
2696 s64 pos;
2697
2698 /* write the MFT record at its new location */
2699 pos = (resize->new_mft_start->lcn << vol->cluster_size_bits)
2700 + (FILE_Bitmap << vol->mft_record_size_bits);
2701 if (!opt.ro_flag
2702 && (ntfs_mst_pwrite(vol->dev, pos, 1,
2703 vol->mft_record_size, resize->ctx->mrec) != 1))
2704 perr_exit("Couldn't update $Bitmap at new location");
2705 } else {
2706 if (write_mft_record(vol, resize->ctx->ntfs_ino->mft_no,
2707 resize->ctx->mrec))
2708 perr_exit("Couldn't update $Bitmap");
2709 }
2710
2711 /* If successful, update cache and sync $Bitmap */
2712 memcpy(vol->lcnbmp_ni->mrec,resize->ctx->mrec,vol->mft_record_size);
2713 ntfs_inode_mark_dirty(vol->lcnbmp_ni);
2714 NInoFileNameSetDirty(vol->lcnbmp_ni);
2715 ntfs_inode_sync(vol->lcnbmp_ni);
2716
2717 #if CLEAN_EXIT
2718 close_inode_and_context(resize->ctx);
2719 #else
2720 ntfs_attr_put_search_ctx(resize->ctx);
2721 #endif
2722 }
2723
2724 /**
2725 * setup_lcn_bitmap
2726 *
2727 * Allocate a block of memory with one bit for each cluster of the disk.
2728 * All the bits are set to 0, except those representing the region beyond the
2729 * end of the disk.
2730 */
setup_lcn_bitmap(struct bitmap * bm,s64 nr_clusters)2731 static int setup_lcn_bitmap(struct bitmap *bm, s64 nr_clusters)
2732 {
2733 /* Determine lcn bitmap byte size and allocate it. */
2734 bm->size = rounded_up_division(nr_clusters, 8);
2735
2736 bm->bm = ntfs_calloc(bm->size);
2737 if (!bm->bm)
2738 return -1;
2739
2740 bitmap_file_data_fixup(nr_clusters, bm);
2741 return 0;
2742 }
2743
2744 /**
2745 * update_bootsector
2746 *
2747 * FIXME: should be done using ntfs_* functions
2748 */
update_bootsector(ntfs_resize_t * r)2749 static void update_bootsector(ntfs_resize_t *r)
2750 {
2751 NTFS_BOOT_SECTOR *bs;
2752 ntfs_volume *vol = r->vol;
2753 s64 bs_size = vol->sector_size;
2754
2755 printf("Updating Boot record ...\n");
2756
2757 bs = (NTFS_BOOT_SECTOR*)ntfs_malloc(vol->sector_size);
2758 if (!bs)
2759 perr_exit("ntfs_malloc");
2760
2761 if (vol->dev->d_ops->seek(vol->dev, 0, SEEK_SET) == (off_t)-1)
2762 perr_exit("lseek");
2763
2764 if (vol->dev->d_ops->read(vol->dev, bs, bs_size) == -1)
2765 perr_exit("read() error");
2766
2767 if (bs->bpb.sectors_per_cluster > 128)
2768 bs->number_of_sectors = cpu_to_sle64(r->new_volume_size
2769 << (256 - bs->bpb.sectors_per_cluster));
2770 else
2771 bs->number_of_sectors = cpu_to_sle64(r->new_volume_size *
2772 bs->bpb.sectors_per_cluster);
2773
2774 if (r->mftmir_old || (r->mirr_from == MIRR_MFT)) {
2775 r->progress.flags |= NTFS_PROGBAR_SUPPRESS;
2776 /* Be sure the MFTMirr holds the updated MFT runlist */
2777 switch (r->mirr_from) {
2778 case MIRR_MFT :
2779 /* The late updates of MFT have not been synced */
2780 ntfs_inode_sync(vol->mft_ni);
2781 copy_clusters(r, r->mftmir_rl.lcn,
2782 vol->mft_na->rl->lcn, r->mftmir_rl.length);
2783 break;
2784 case MIRR_NEWMFT :
2785 copy_clusters(r, r->mftmir_rl.lcn,
2786 r->new_mft_start->lcn, r->mftmir_rl.length);
2787 break;
2788 default :
2789 copy_clusters(r, r->mftmir_rl.lcn, r->mftmir_old,
2790 r->mftmir_rl.length);
2791 break;
2792 }
2793 if (r->mftmir_old)
2794 bs->mftmirr_lcn = cpu_to_sle64(r->mftmir_rl.lcn);
2795 r->progress.flags &= ~NTFS_PROGBAR_SUPPRESS;
2796 }
2797 /* Set the start of the relocated MFT */
2798 if (r->new_mft_start) {
2799 bs->mft_lcn = cpu_to_sle64(r->new_mft_start->lcn);
2800 /* no more need for the new MFT start */
2801 free(r->new_mft_start);
2802 r->new_mft_start = (runlist_element*)NULL;
2803 }
2804
2805 if (vol->dev->d_ops->seek(vol->dev, 0, SEEK_SET) == (off_t)-1)
2806 perr_exit("lseek");
2807
2808 if (!opt.ro_flag)
2809 if (vol->dev->d_ops->write(vol->dev, bs, bs_size) == -1)
2810 perr_exit("write() error");
2811 /*
2812 * Set the backup boot sector, if the target size is
2813 * either not defined or is defined with no multiplier
2814 * suffix and is a multiple of the sector size.
2815 * With these conditions we can be confident enough that
2816 * the partition size is already defined or it will be
2817 * later defined with the same exact value.
2818 */
2819 if (!opt.ro_flag && opt.reliable_size
2820 && !(opt.bytes % vol->sector_size)) {
2821 if (vol->dev->d_ops->seek(vol->dev, opt.bytes
2822 - vol->sector_size, SEEK_SET) == (off_t)-1)
2823 perr_exit("lseek");
2824 if (vol->dev->d_ops->write(vol->dev, bs, bs_size) == -1)
2825 perr_exit("write() error");
2826 }
2827 free(bs);
2828 }
2829
2830 /**
2831 * vol_size
2832 */
vol_size(ntfs_volume * v,s64 nr_clusters)2833 static s64 vol_size(ntfs_volume *v, s64 nr_clusters)
2834 {
2835 /* add one sector_size for the backup boot sector */
2836 return nr_clusters * v->cluster_size + v->sector_size;
2837 }
2838
2839 /**
2840 * print_vol_size
2841 *
2842 * Print the volume size in bytes and decimal megabytes.
2843 */
print_vol_size(const char * str,s64 bytes)2844 static void print_vol_size(const char *str, s64 bytes)
2845 {
2846 printf("%s: %lld bytes (%lld MB)\n", str, (long long)bytes,
2847 (long long)rounded_up_division(bytes, NTFS_MBYTE));
2848 }
2849
2850 /**
2851 * print_disk_usage
2852 *
2853 * Display the amount of disk space in use.
2854 */
print_disk_usage(ntfs_volume * vol,s64 nr_used_clusters)2855 static void print_disk_usage(ntfs_volume *vol, s64 nr_used_clusters)
2856 {
2857 s64 total, used;
2858
2859 total = vol->nr_clusters * vol->cluster_size;
2860 used = nr_used_clusters * vol->cluster_size;
2861
2862 /* WARNING: don't modify the text, external tools grep for it */
2863 if (!opt.infombonly) {
2864 printf("Space in use : %lld MB (%.1f%%)\n",
2865 (long long)rounded_up_division(used, NTFS_MBYTE),
2866 100.0 * ((float)used / total));
2867 }
2868 }
2869
print_num_of_relocations(ntfs_resize_t * resize)2870 static void print_num_of_relocations(ntfs_resize_t *resize)
2871 {
2872 s64 relocations = resize->relocations * resize->vol->cluster_size;
2873
2874 printf("Needed relocations : %lld (%lld MB)\n",
2875 (long long)resize->relocations, (long long)
2876 rounded_up_division(relocations, NTFS_MBYTE));
2877 }
2878
check_volume(void)2879 static ntfs_volume *check_volume(void)
2880 {
2881 ntfs_volume *myvol = NULL;
2882
2883 /*
2884 * Pass NTFS_MNT_FORENSIC so that the mount process does not modify the
2885 * volume at all. We will do the logfile emptying and dirty setting
2886 * later if needed.
2887 */
2888 if (!(myvol = ntfs_mount(opt.volume, opt.ro_flag | NTFS_MNT_FORENSIC)))
2889 {
2890 int err = errno;
2891
2892 perr_printf("Opening '%s' as NTFS failed", opt.volume);
2893 switch (err) {
2894 case EINVAL :
2895 printf(invalid_ntfs_msg, opt.volume);
2896 break;
2897 case EIO :
2898 printf("%s", corrupt_volume_msg);
2899 break;
2900 case EPERM :
2901 printf("%s", hibernated_volume_msg);
2902 break;
2903 case EOPNOTSUPP :
2904 printf("%s", unclean_journal_msg);
2905 break;
2906 case EBUSY :
2907 printf("%s", opened_volume_msg);
2908 break;
2909 default :
2910 break;
2911 }
2912 exit(1);
2913 }
2914 return myvol;
2915 }
2916
2917
2918 /**
2919 * mount_volume
2920 *
2921 * First perform some checks to determine if the volume is already mounted, or
2922 * is dirty (Windows wasn't shutdown properly). If everything is OK, then mount
2923 * the volume (load the metadata into memory).
2924 */
mount_volume(void)2925 static ntfs_volume *mount_volume(void)
2926 {
2927 unsigned long mntflag;
2928 ntfs_volume *vol = NULL;
2929
2930 if (ntfs_check_if_mounted(opt.volume, &mntflag)) {
2931 perr_printf("Failed to check '%s' mount state", opt.volume);
2932 printf("Probably /etc/mtab is missing. It's too risky to "
2933 "continue. You might try\nan another Linux distro.\n");
2934 exit(1);
2935 }
2936 if (mntflag & NTFS_MF_MOUNTED) {
2937 if (!(mntflag & NTFS_MF_READONLY))
2938 err_exit("Device '%s' is mounted read-write. "
2939 "You must 'umount' it first.\n", opt.volume);
2940 if (!opt.ro_flag)
2941 err_exit("Device '%s' is mounted. "
2942 "You must 'umount' it first.\n", opt.volume);
2943 }
2944 vol = check_volume();
2945
2946 if (vol->flags & VOLUME_IS_DIRTY)
2947 if (opt.force-- <= 0)
2948 err_exit("Volume is scheduled for check.\nRun chkdsk /f"
2949 " and please try again, or see option -f.\n");
2950
2951 if (NTFS_MAX_CLUSTER_SIZE < vol->cluster_size)
2952 err_exit("Cluster size %u is too large!\n",
2953 (unsigned int)vol->cluster_size);
2954
2955 if (ntfs_volume_get_free_space(vol))
2956 err_exit("Failed to update the free space\n");
2957
2958 if (!opt.infombonly) {
2959 printf("Device name : %s\n", opt.volume);
2960 printf("NTFS volume version: %d.%d\n",
2961 vol->major_ver, vol->minor_ver);
2962 }
2963 if (ntfs_version_is_supported(vol))
2964 perr_exit("Unknown NTFS version");
2965
2966 if (!opt.infombonly) {
2967 printf("Cluster size : %u bytes\n",
2968 (unsigned int)vol->cluster_size);
2969 print_vol_size("Current volume size",
2970 vol_size(vol, vol->nr_clusters));
2971 }
2972
2973 return vol;
2974 }
2975
2976 /**
2977 * prepare_volume_fixup
2978 *
2979 * Set the volume's dirty flag and wipe the filesystem journal. When Windows
2980 * boots it will automatically run chkdsk to check for any problems. If the
2981 * read-only command line option was given, this function will do nothing.
2982 */
prepare_volume_fixup(ntfs_volume * vol)2983 static void prepare_volume_fixup(ntfs_volume *vol)
2984 {
2985 printf("Schedule chkdsk for NTFS consistency check at Windows boot "
2986 "time ...\n");
2987 vol->flags |= VOLUME_IS_DIRTY;
2988 if (ntfs_volume_write_flags(vol, vol->flags))
2989 perr_exit("Failed to set the volume dirty");
2990
2991 /* Porting note: This flag does not exist in libntfs-3g. The dirty flag
2992 * is never modified by libntfs-3g on unmount and we set it above. We
2993 * can safely comment out this statement. */
2994 /* NVolSetWasDirty(vol); */
2995
2996 if (vol->dev->d_ops->sync(vol->dev) == -1)
2997 perr_exit("Failed to sync device");
2998 printf("Resetting $LogFile ... (this might take a while)\n");
2999 if (ntfs_logfile_reset(vol))
3000 perr_exit("Failed to reset $LogFile");
3001 if (vol->dev->d_ops->sync(vol->dev) == -1)
3002 perr_exit("Failed to sync device");
3003 }
3004
set_disk_usage_constraint(ntfs_resize_t * resize)3005 static void set_disk_usage_constraint(ntfs_resize_t *resize)
3006 {
3007 /* last lcn for a filled up volume (no empty space) */
3008 s64 last = resize->inuse - 1;
3009
3010 if (resize->last_unsupp < last)
3011 resize->last_unsupp = last;
3012 }
3013
check_resize_constraints(ntfs_resize_t * resize)3014 static void check_resize_constraints(ntfs_resize_t *resize)
3015 {
3016 s64 new_size = resize->new_volume_size;
3017
3018 /* FIXME: resize.shrink true also if only -i is used */
3019 if (!resize->shrink)
3020 return;
3021
3022 if (resize->inuse == resize->vol->nr_clusters)
3023 err_exit("Volume is full. To shrink it, "
3024 "delete unused files.\n");
3025
3026 if (opt.info || opt.infombonly)
3027 return;
3028
3029 /* FIXME: reserve some extra space so Windows can boot ... */
3030 if (new_size < resize->inuse)
3031 err_exit("New size can't be less than the space already"
3032 " occupied by data.\nYou either need to delete unused"
3033 " files or see the -i option.\n");
3034
3035 if (new_size <= resize->last_unsupp)
3036 err_exit("The fragmentation type, you have, isn't "
3037 "supported yet. Rerun ntfsresize\nwith "
3038 "the -i option to estimate the smallest "
3039 "shrunken volume size supported.\n");
3040
3041 print_num_of_relocations(resize);
3042 }
3043
check_cluster_allocation(ntfs_volume * vol,ntfsck_t * fsck)3044 static void check_cluster_allocation(ntfs_volume *vol, ntfsck_t *fsck)
3045 {
3046 memset(fsck, 0, sizeof(ntfsck_t));
3047
3048 if (opt.show_progress)
3049 fsck->flags |= NTFSCK_PROGBAR;
3050
3051 if (setup_lcn_bitmap(&fsck->lcn_bitmap, vol->nr_clusters) != 0)
3052 perr_exit("Failed to setup allocation bitmap");
3053 if (build_allocation_bitmap(vol, fsck) != 0)
3054 exit(1);
3055 if (fsck->outsider || fsck->multi_ref) {
3056 err_printf("Filesystem check failed!\n");
3057 if (fsck->outsider)
3058 err_printf("%d clusters are referenced outside "
3059 "of the volume.\n", fsck->outsider);
3060 if (fsck->multi_ref)
3061 err_printf("%d clusters are referenced multiple"
3062 " times.\n", fsck->multi_ref);
3063 printf("%s", corrupt_volume_msg);
3064 exit(1);
3065 }
3066
3067 compare_bitmaps(vol, &fsck->lcn_bitmap);
3068 }
3069
3070 /*
3071 * Following are functions to expand an NTFS file system
3072 * to the beginning of a partition. The old metadata can be
3073 * located according to the backup bootsector, provided it can
3074 * still be found at the end of the partition.
3075 *
3076 * The data itself is kept in place, and this is only possible
3077 * if the expanded size is a multiple of cluster size, and big
3078 * enough to hold the new $Boot, $Bitmap and $MFT
3079 *
3080 * The volume cannot be mounted because the layout of data does
3081 * not match the volume parameters. The alignments of MFT entries
3082 * and index blocks may be different in the new volume and the old
3083 * one. The "ntfs_volume" structure is only partially usable,
3084 * "ntfs_inode" and "search_context" cannot be used until the
3085 * metadata has been moved and the volume is opened.
3086 *
3087 * Currently, no part of this new code is called from old code,
3088 * and the only change in old code is the processing of options.
3089 * Deduplication of code should be done later when the code is
3090 * proved safe.
3091 *
3092 */
3093
3094 typedef struct EXPAND {
3095 ntfs_volume *vol;
3096 u64 original_sectors;
3097 u64 new_sectors;
3098 u64 bitmap_allocated;
3099 u64 bitmap_size;
3100 u64 boot_size;
3101 u64 mft_size;
3102 LCN mft_lcn;
3103 s64 byte_increment;
3104 s64 sector_increment;
3105 s64 cluster_increment;
3106 u8 *bitmap;
3107 u8 *mft_bitmap;
3108 char *bootsector;
3109 MFT_RECORD *mrec;
3110 struct progress_bar *progress;
3111 struct DELAYED *delayed_runlists; /* runlists to process later */
3112 } expand_t;
3113
3114 /*
3115 * Locate an attribute in an MFT record
3116 *
3117 * Returns NULL if not found (with no error message)
3118 */
3119
find_attr(MFT_RECORD * mrec,ATTR_TYPES type,ntfschar * name,int namelen)3120 static ATTR_RECORD *find_attr(MFT_RECORD *mrec, ATTR_TYPES type,
3121 ntfschar *name, int namelen)
3122 {
3123 ATTR_RECORD *a;
3124 u32 offset;
3125 ntfschar *attrname;
3126
3127 /* fetch the requested attribute */
3128 offset = le16_to_cpu(mrec->attrs_offset);
3129 a = (ATTR_RECORD*)((char*)mrec + offset);
3130 attrname = (ntfschar*)((char*)a + le16_to_cpu(a->name_offset));
3131 while ((a->type != AT_END)
3132 && ((a->type != type)
3133 || (a->name_length != namelen)
3134 || (namelen && memcmp(attrname,name,2*namelen)))
3135 && (offset < le32_to_cpu(mrec->bytes_in_use))) {
3136 offset += le32_to_cpu(a->length);
3137 a = (ATTR_RECORD*)((char*)mrec + offset);
3138 if (namelen)
3139 attrname = (ntfschar*)((char*)a
3140 + le16_to_cpu(a->name_offset));
3141 }
3142 if ((a->type != type)
3143 || (a->name_length != namelen)
3144 || (namelen && memcmp(attrname,name,2*namelen)))
3145 a = (ATTR_RECORD*)NULL;
3146 return (a);
3147 }
3148
3149 /*
3150 * Read an MFT record and find an unnamed attribute
3151 *
3152 * Returns NULL if fails to read or attribute is not found
3153 */
3154
get_unnamed_attr(expand_t * expand,ATTR_TYPES type,s64 inum)3155 static ATTR_RECORD *get_unnamed_attr(expand_t *expand, ATTR_TYPES type,
3156 s64 inum)
3157 {
3158 ntfs_volume *vol;
3159 ATTR_RECORD *a;
3160 MFT_RECORD *mrec;
3161 s64 pos;
3162 BOOL found;
3163 int got;
3164
3165 found = FALSE;
3166 a = (ATTR_RECORD*)NULL;
3167 mrec = expand->mrec;
3168 vol = expand->vol;
3169 pos = (vol->mft_lcn << vol->cluster_size_bits)
3170 + (inum << vol->mft_record_size_bits)
3171 + expand->byte_increment;
3172 got = ntfs_mst_pread(vol->dev, pos, 1, vol->mft_record_size, mrec);
3173 if ((got == 1) && (mrec->flags & MFT_RECORD_IN_USE)) {
3174 a = find_attr(expand->mrec, type, NULL, 0);
3175 found = a && (a->type == type) && !a->name_length;
3176 }
3177 /* not finding the attribute list is not an error */
3178 if (!found && (type != AT_ATTRIBUTE_LIST)) {
3179 err_printf("Could not find attribute 0x%lx in inode %lld\n",
3180 (long)le32_to_cpu(type), (long long)inum);
3181 a = (ATTR_RECORD*)NULL;
3182 }
3183 return (a);
3184 }
3185
3186 /*
3187 * Read an MFT record and find an unnamed attribute
3188 *
3189 * Returns NULL if fails
3190 */
3191
read_and_get_attr(expand_t * expand,ATTR_TYPES type,s64 inum,ntfschar * name,int namelen)3192 static ATTR_RECORD *read_and_get_attr(expand_t *expand, ATTR_TYPES type,
3193 s64 inum, ntfschar *name, int namelen)
3194 {
3195 ntfs_volume *vol;
3196 ATTR_RECORD *a;
3197 MFT_RECORD *mrec;
3198 s64 pos;
3199 int got;
3200
3201 a = (ATTR_RECORD*)NULL;
3202 mrec = expand->mrec;
3203 vol = expand->vol;
3204 pos = (vol->mft_lcn << vol->cluster_size_bits)
3205 + (inum << vol->mft_record_size_bits)
3206 + expand->byte_increment;
3207 got = ntfs_mst_pread(vol->dev, pos, 1, vol->mft_record_size, mrec);
3208 if ((got == 1) && (mrec->flags & MFT_RECORD_IN_USE)) {
3209 a = find_attr(expand->mrec, type, name, namelen);
3210 }
3211 if (!a) {
3212 err_printf("Could not find attribute 0x%lx in inode %lld\n",
3213 (long)le32_to_cpu(type), (long long)inum);
3214 }
3215 return (a);
3216 }
3217
3218 /*
3219 * Get the size allocated to the unnamed data of some inode
3220 *
3221 * Returns zero if fails.
3222 */
3223
get_data_size(expand_t * expand,s64 inum)3224 static s64 get_data_size(expand_t *expand, s64 inum)
3225 {
3226 ATTR_RECORD *a;
3227 s64 size;
3228
3229 size = 0;
3230 /* get the size of unnamed $DATA */
3231 a = get_unnamed_attr(expand, AT_DATA, inum);
3232 if (a && a->non_resident)
3233 size = sle64_to_cpu(a->allocated_size);
3234 if (!size) {
3235 err_printf("Bad record %lld, could not get its size\n",
3236 (long long)inum);
3237 }
3238 return (size);
3239 }
3240
3241 /*
3242 * Get the MFT bitmap
3243 *
3244 * Returns NULL if fails.
3245 */
3246
get_mft_bitmap(expand_t * expand)3247 static u8 *get_mft_bitmap(expand_t *expand)
3248 {
3249 ATTR_RECORD *a;
3250 ntfs_volume *vol;
3251 runlist_element *rl;
3252 runlist_element *prl;
3253 u32 bitmap_size;
3254 BOOL ok;
3255
3256 expand->mft_bitmap = (u8*)NULL;
3257 vol = expand->vol;
3258 /* get the runlist of unnamed bitmap */
3259 a = get_unnamed_attr(expand, AT_BITMAP, FILE_MFT);
3260 ok = TRUE;
3261 bitmap_size = sle64_to_cpu(a->allocated_size);
3262 if (a
3263 && a->non_resident
3264 && ((bitmap_size << (vol->mft_record_size_bits + 3))
3265 >= expand->mft_size)) {
3266 // rl in extent not implemented
3267 rl = ntfs_mapping_pairs_decompress(expand->vol, a,
3268 (runlist_element*)NULL);
3269 expand->mft_bitmap = (u8*)ntfs_calloc(bitmap_size);
3270 if (rl && expand->mft_bitmap) {
3271 for (prl=rl; prl->length && ok; prl++) {
3272 lseek_to_cluster(vol,
3273 prl->lcn + expand->cluster_increment);
3274 ok = !read_all(vol->dev, expand->mft_bitmap
3275 + (prl->vcn << vol->cluster_size_bits),
3276 prl->length << vol->cluster_size_bits);
3277 }
3278 if (!ok) {
3279 err_printf("Could not read the MFT bitmap\n");
3280 free(expand->mft_bitmap);
3281 expand->mft_bitmap = (u8*)NULL;
3282 }
3283 free(rl);
3284 } else {
3285 err_printf("Could not get the MFT bitmap\n");
3286 }
3287 } else
3288 err_printf("Invalid MFT bitmap\n");
3289 return (expand->mft_bitmap);
3290 }
3291
3292 /*
3293 * Check for bad sectors
3294 *
3295 * Deduplication to be done when proved safe
3296 */
3297
check_expand_bad_sectors(expand_t * expand,ATTR_RECORD * a)3298 static int check_expand_bad_sectors(expand_t *expand, ATTR_RECORD *a)
3299 {
3300 runlist *rl;
3301 int res;
3302 s64 i, badclusters = 0;
3303
3304 res = 0;
3305 ntfs_log_verbose("Checking for bad sectors ...\n");
3306
3307 if (find_attr(expand->mrec, AT_ATTRIBUTE_LIST, NULL, 0)) {
3308 err_printf("Hopelessly many bad sectors have been detected!\n");
3309 err_printf("%s", many_bad_sectors_msg);
3310 res = -1;
3311 } else {
3312
3313 /*
3314 * FIXME: The below would be partial for non-base records in the
3315 * not yet supported multi-record case. Alternatively use audited
3316 * ntfs_attr_truncate after an umount & mount.
3317 */
3318 rl = ntfs_mapping_pairs_decompress(expand->vol, a, NULL);
3319 if (!rl) {
3320 perr_printf("Decompressing $BadClust:"
3321 "$Bad mapping pairs failed");
3322 res = -1;
3323 } else {
3324 for (i = 0; rl[i].length; i++) {
3325 /* CHECKME: LCN_RL_NOT_MAPPED check isn't needed */
3326 if (rl[i].lcn == LCN_HOLE
3327 || rl[i].lcn == LCN_RL_NOT_MAPPED)
3328 continue;
3329
3330 badclusters += rl[i].length;
3331 ntfs_log_verbose("Bad cluster: %#8llx - %#llx"
3332 " (%lld)\n",
3333 (long long)rl[i].lcn,
3334 (long long)rl[i].lcn
3335 + rl[i].length - 1,
3336 (long long)rl[i].length);
3337 }
3338
3339 if (badclusters) {
3340 err_printf("%sThis software has detected that"
3341 " the disk has at least"
3342 " %lld bad sector%s.\n",
3343 !opt.badsectors ? NERR_PREFIX
3344 : "WARNING: ",
3345 (long long)badclusters,
3346 badclusters - 1 ? "s" : "");
3347 if (!opt.badsectors) {
3348 err_printf("%s", bad_sectors_warning_msg);
3349 res = -1;
3350 } else
3351 err_printf("WARNING: Bad sectors can cause"
3352 " reliability problems"
3353 " and massive data loss!!!\n");
3354 }
3355 free(rl);
3356 }
3357 }
3358 return (res);
3359 }
3360
3361 /*
3362 * Check miscellaneous expansion constraints
3363 */
3364
check_expand_constraints(expand_t * expand)3365 static int check_expand_constraints(expand_t *expand)
3366 {
3367 static ntfschar bad[] = {
3368 const_cpu_to_le16('$'), const_cpu_to_le16('B'),
3369 const_cpu_to_le16('a'), const_cpu_to_le16('d')
3370 } ;
3371 ATTR_RECORD *a;
3372 runlist_element *rl;
3373 VOLUME_INFORMATION *volinfo;
3374 VOLUME_FLAGS flags;
3375 int res;
3376
3377 if (opt.verbose)
3378 ntfs_log_verbose("Checking for expansion constraints...\n");
3379 res = 0;
3380 /* extents for $MFT are not supported */
3381 if (get_unnamed_attr(expand, AT_ATTRIBUTE_LIST, FILE_MFT)) {
3382 err_printf("The $MFT is too much fragmented\n");
3383 res = -1;
3384 }
3385 /* fragmented $MFTMirr is not supported */
3386 a = get_unnamed_attr(expand, AT_DATA, FILE_MFTMirr);
3387 if (a) {
3388 rl = ntfs_mapping_pairs_decompress(expand->vol, a, NULL);
3389 if (!rl || !rl[0].length || rl[1].length) {
3390 err_printf("$MFTMirr is bad or fragmented\n");
3391 res = -1;
3392 }
3393 free(rl);
3394 }
3395 /* fragmented $Boot is not supported */
3396 a = get_unnamed_attr(expand, AT_DATA, FILE_Boot);
3397 if (a) {
3398 rl = ntfs_mapping_pairs_decompress(expand->vol, a, NULL);
3399 if (!rl || !rl[0].length || rl[1].length) {
3400 err_printf("$Boot is bad or fragmented\n");
3401 res = -1;
3402 }
3403 free(rl);
3404 }
3405 /* Volume should not be marked dirty */
3406 a = get_unnamed_attr(expand, AT_VOLUME_INFORMATION, FILE_Volume);
3407 if (a) {
3408 volinfo = (VOLUME_INFORMATION*)
3409 (le16_to_cpu(a->value_offset) + (char*)a);
3410 flags = volinfo->flags;
3411 if ((flags & VOLUME_IS_DIRTY) && (opt.force-- <= 0)) {
3412 err_printf("Volume is scheduled for check.\nRun chkdsk /f"
3413 " and please try again, or see option -f.\n");
3414 res = -1;
3415 }
3416 } else {
3417 err_printf("Could not get Volume flags\n");
3418 res = -1;
3419 }
3420
3421 /* There should not be too many bad clusters */
3422 a = read_and_get_attr(expand, AT_DATA, FILE_BadClus, bad, 4);
3423 if (!a || !a->non_resident) {
3424 err_printf("Resident attribute in $BadClust! Please report to "
3425 "%s\n", NTFS_DEV_LIST);
3426 res = -1;
3427 } else
3428 if (check_expand_bad_sectors(expand,a))
3429 res = -1;
3430 return (res);
3431 }
3432
3433 /*
3434 * Compute the new sizes and check whether the NTFS file
3435 * system can be expanded
3436 *
3437 * The partition has to have been expanded,
3438 * the extra space must be able to hold the $MFT, $Boot, and $Bitmap
3439 * the extra space must be a multiple of cluster size
3440 *
3441 * Returns TRUE if the partition can be expanded,
3442 * FALSE if it canno be expanded or option --info was set
3443 */
3444
can_expand(expand_t * expand,ntfs_volume * vol)3445 static BOOL can_expand(expand_t *expand, ntfs_volume *vol)
3446 {
3447 s64 old_sector_count;
3448 s64 sectors_needed;
3449 s64 clusters;
3450 s64 minimum_size;
3451 s64 got;
3452 s64 advice;
3453 s64 bitmap_bits;
3454 BOOL ok;
3455
3456 ok = TRUE;
3457 old_sector_count = vol->nr_clusters
3458 << (vol->cluster_size_bits - vol->sector_size_bits);
3459 /* do not include the space lost near the end */
3460 expand->cluster_increment = (expand->new_sectors
3461 >> (vol->cluster_size_bits - vol->sector_size_bits))
3462 - vol->nr_clusters;
3463 expand->byte_increment = expand->cluster_increment
3464 << vol->cluster_size_bits;
3465 expand->sector_increment = expand->byte_increment
3466 >> vol->sector_size_bits;
3467 printf("Sectors allocated to volume : old %lld current %lld difference %lld\n",
3468 (long long)old_sector_count,
3469 (long long)(old_sector_count + expand->sector_increment),
3470 (long long)expand->sector_increment);
3471 printf("Clusters allocated to volume : old %lld current %lld difference %lld\n",
3472 (long long)vol->nr_clusters,
3473 (long long)(vol->nr_clusters
3474 + expand->cluster_increment),
3475 (long long)expand->cluster_increment);
3476 /* the new size must be bigger */
3477 if ((expand->sector_increment < 0)
3478 || (!expand->sector_increment && !opt.info)) {
3479 err_printf("Cannot expand volume : the partition has not been expanded\n");
3480 ok = FALSE;
3481 }
3482 /* the old bootsector must match the backup */
3483 got = ntfs_pread(expand->vol->dev, expand->byte_increment,
3484 vol->sector_size, expand->mrec);
3485 if ((got != vol->sector_size)
3486 || memcmp(expand->bootsector,expand->mrec,vol->sector_size)) {
3487 err_printf("The backup bootsector does not match the old bootsector\n");
3488 ok = FALSE;
3489 }
3490 if (ok) {
3491 /* read the first MFT record, to get the MFT size */
3492 expand->mft_size = get_data_size(expand, FILE_MFT);
3493 /* read the 6th MFT record, to get the $Boot size */
3494 expand->boot_size = get_data_size(expand, FILE_Boot);
3495 if (!expand->mft_size || !expand->boot_size) {
3496 ok = FALSE;
3497 } else {
3498 /*
3499 * The bitmap is one bit per full cluster,
3500 * accounting for the backup bootsector.
3501 * When evaluating the minimal size, the bitmap
3502 * size must be adapted to the minimal size :
3503 * bits = clusters + ceil(clusters/clustersize)
3504 */
3505 if (opt.info) {
3506 clusters = (((expand->original_sectors + 1)
3507 << vol->sector_size_bits)
3508 + expand->mft_size
3509 + expand->boot_size)
3510 >> vol->cluster_size_bits;
3511 bitmap_bits = ((clusters + 1)
3512 << vol->cluster_size_bits)
3513 / (vol->cluster_size + 1);
3514 } else {
3515 bitmap_bits = (expand->new_sectors + 1)
3516 >> (vol->cluster_size_bits
3517 - vol->sector_size_bits);
3518 }
3519 /* byte size must be a multiple of 8 */
3520 expand->bitmap_size = ((bitmap_bits + 63) >> 3) & -8;
3521 expand->bitmap_allocated = ((expand->bitmap_size - 1)
3522 | (vol->cluster_size - 1)) + 1;
3523 expand->mft_lcn = (expand->boot_size
3524 + expand->bitmap_allocated)
3525 >> vol->cluster_size_bits;
3526 /*
3527 * Check whether $Boot, $Bitmap and $MFT can fit
3528 * into the expanded space.
3529 */
3530 sectors_needed = (expand->boot_size + expand->mft_size
3531 + expand->bitmap_allocated)
3532 >> vol->sector_size_bits;
3533 if (!opt.info
3534 && (sectors_needed >= expand->sector_increment)) {
3535 err_printf("The expanded space cannot hold the new metadata\n");
3536 err_printf(" expanded space %lld sectors\n",
3537 (long long)expand->sector_increment);
3538 err_printf(" needed space %lld sectors\n",
3539 (long long)sectors_needed);
3540 ok = FALSE;
3541 }
3542 }
3543 }
3544 if (ok) {
3545 advice = expand->byte_increment;
3546 /* the increment must be an integral number of clusters */
3547 if (expand->byte_increment & (vol->cluster_size - 1)) {
3548 err_printf("Cannot expand volume without copying the data :\n");
3549 err_printf("There are %d sectors in a cluster,\n",
3550 (int)(vol->cluster_size/vol->sector_size));
3551 err_printf(" and the sector difference is not a multiple of %d\n",
3552 (int)(vol->cluster_size/vol->sector_size));
3553 advice = expand->byte_increment & ~vol->cluster_size;
3554 ok = FALSE;
3555 }
3556 if (!ok)
3557 err_printf("You should increase the beginning of partition by %d sectors\n",
3558 (int)((expand->byte_increment - advice)
3559 >> vol->sector_size_bits));
3560 }
3561 if (ok)
3562 ok = !check_expand_constraints(expand);
3563 if (ok && opt.info) {
3564 minimum_size = (expand->original_sectors
3565 << vol->sector_size_bits)
3566 + expand->boot_size
3567 + expand->mft_size
3568 + expand->bitmap_allocated;
3569
3570 printf("You must expand the partition to at least %lld bytes,\n",
3571 (long long)(minimum_size + vol->sector_size));
3572 printf("and you may add a multiple of %ld bytes to this size.\n",
3573 (long)vol->cluster_size);
3574 printf("The minimum NTFS volume size is %lld bytes\n",
3575 (long long)minimum_size);
3576 ok = FALSE;
3577 }
3578 return (ok);
3579 }
3580
set_bitmap(expand_t * expand,runlist_element * rl)3581 static int set_bitmap(expand_t *expand, runlist_element *rl)
3582 {
3583 int res;
3584 s64 lcn;
3585 s64 lcn_end;
3586 BOOL reallocated;
3587
3588 res = -1;
3589 reallocated = FALSE;
3590 if ((rl->lcn >= 0)
3591 && (rl->length > 0)
3592 && ((rl->lcn + rl->length)
3593 <= (expand->vol->nr_clusters + expand->cluster_increment))) {
3594 lcn = rl->lcn;
3595 lcn_end = lcn + rl->length;
3596 while ((lcn & 7) && (lcn < lcn_end)) {
3597 if (expand->bitmap[lcn >> 3] & 1 << (lcn & 7))
3598 reallocated = TRUE;
3599 expand->bitmap[lcn >> 3] |= 1 << (lcn & 7);
3600 lcn++;
3601 }
3602 while ((lcn_end - lcn) >= 8) {
3603 if (expand->bitmap[lcn >> 3])
3604 reallocated = TRUE;
3605 expand->bitmap[lcn >> 3] = 255;
3606 lcn += 8;
3607 }
3608 while (lcn < lcn_end) {
3609 if (expand->bitmap[lcn >> 3] & 1 << (lcn & 7))
3610 reallocated = TRUE;
3611 expand->bitmap[lcn >> 3] |= 1 << (lcn & 7);
3612 lcn++;
3613 }
3614 if (reallocated)
3615 err_printf("Reallocated cluster found in run"
3616 " lcn 0x%llx length %lld\n",
3617 (long long)rl->lcn,(long long)rl->length);
3618 else
3619 res = 0;
3620 } else {
3621 err_printf("Bad run : lcn 0x%llx length %lld\n",
3622 (long long)rl->lcn,(long long)rl->length);
3623 }
3624 return (res);
3625 }
3626
3627 /*
3628 * Write the backup bootsector
3629 *
3630 * When this has been done, the resizing cannot be done again
3631 */
3632
write_bootsector(expand_t * expand)3633 static int write_bootsector(expand_t *expand)
3634 {
3635 ntfs_volume *vol;
3636 s64 bw;
3637 int res;
3638
3639 res = -1;
3640 vol = expand->vol;
3641 if (opt.verbose)
3642 ntfs_log_verbose("Rewriting the backup bootsector\n");
3643 if (opt.ro_flag)
3644 bw = vol->sector_size;
3645 else
3646 bw = ntfs_pwrite(vol->dev,
3647 expand->new_sectors*vol->sector_size,
3648 vol->sector_size, expand->bootsector);
3649 if (bw == vol->sector_size)
3650 res = 0;
3651 else {
3652 if (bw != -1)
3653 errno = EINVAL;
3654 if (!bw)
3655 err_printf("Failed to rewrite the bootsector (size=0)\n");
3656 else
3657 err_printf("Error rewriting the bootsector");
3658 }
3659 return (res);
3660 }
3661
3662 /*
3663 * Write the new main bitmap
3664 */
3665
write_bitmap(expand_t * expand)3666 static int write_bitmap(expand_t *expand)
3667 {
3668 ntfs_volume *vol;
3669 s64 bw;
3670 u64 cluster;
3671 int res;
3672
3673 res = -1;
3674 vol = expand->vol;
3675 cluster = vol->nr_clusters + expand->cluster_increment;
3676 while (cluster < (expand->bitmap_size << 3)) {
3677 expand->bitmap[cluster >> 3] |= 1 << (cluster & 7);
3678 cluster++;
3679 }
3680 if (opt.verbose)
3681 ntfs_log_verbose("Writing the new bitmap...\n");
3682 /* write the full allocation (to avoid having to read) */
3683 if (opt.ro_flag)
3684 bw = expand->bitmap_allocated;
3685 else
3686 bw = ntfs_pwrite(vol->dev, expand->boot_size,
3687 expand->bitmap_allocated, expand->bitmap);
3688 if (bw == (s64)expand->bitmap_allocated)
3689 res = 0;
3690 else {
3691 if (bw != -1)
3692 errno = EINVAL;
3693 if (!bw)
3694 err_printf("Failed to write the bitmap (size=0)\n");
3695 else
3696 err_printf("Error rewriting the bitmap");
3697 }
3698 return (res);
3699 }
3700
3701 /*
3702 * Copy the $MFT to $MFTMirr
3703 *
3704 * The $MFTMirr is not relocated as it should be kept away from $MFT.
3705 * Apart from the backup bootsector, this is the only part which is
3706 * overwritten. This has no effect on being able to redo the resizing
3707 * if something goes wrong, as the $MFTMirr is never read. However
3708 * this is done near the end of the resizing.
3709 */
3710
copy_mftmirr(expand_t * expand)3711 static int copy_mftmirr(expand_t *expand)
3712 {
3713 ntfs_volume *vol;
3714 s64 pos;
3715 s64 inum;
3716 int res;
3717 u16 usa_ofs;
3718 le16 *pusn;
3719 u16 usn;
3720
3721 if (opt.verbose)
3722 ntfs_log_verbose("Copying $MFT to $MFTMirr...\n");
3723 vol = expand->vol;
3724 res = 0;
3725 for (inum=FILE_MFT; !res && (inum<=FILE_Volume); inum++) {
3726 /* read the new $MFT */
3727 pos = (expand->mft_lcn << vol->cluster_size_bits)
3728 + (inum << vol->mft_record_size_bits);
3729 if (ntfs_mst_pread(vol->dev, pos, 1, vol->mft_record_size,
3730 expand->mrec) == 1) {
3731 /* overwrite the old $MFTMirr */
3732 pos = (vol->mftmirr_lcn << vol->cluster_size_bits)
3733 + (inum << vol->mft_record_size_bits)
3734 + expand->byte_increment;
3735 usa_ofs = le16_to_cpu(expand->mrec->usa_ofs);
3736 pusn = (le16*)((u8*)expand->mrec + usa_ofs);
3737 usn = le16_to_cpu(*pusn) - 1;
3738 if (!usn || (usn == 0xffff))
3739 usn = -2;
3740 *pusn = cpu_to_le16(usn);
3741 if (!opt.ro_flag
3742 && (ntfs_mst_pwrite(vol->dev, pos, 1,
3743 vol->mft_record_size, expand->mrec) != 1)) {
3744 err_printf("Failed to overwrite the old $MFTMirr\n");
3745 res = -1;
3746 }
3747 } else {
3748 err_printf("Failed to write the new $MFT\n");
3749 res = -1;
3750 }
3751 }
3752 return (res);
3753 }
3754
3755 /*
3756 * Copy the $Boot, including the bootsector
3757 *
3758 * When the bootsector has been copied, repair tools are able to
3759 * fix things, but this is dangerous if the other metadata do
3760 * not point to actual user data. So this must be done near the end
3761 * of resizing.
3762 */
3763
copy_boot(expand_t * expand)3764 static int copy_boot(expand_t *expand)
3765 {
3766 NTFS_BOOT_SECTOR *bs;
3767 char *buf;
3768 ntfs_volume *vol;
3769 s64 mftmirr_lcn;
3770 s64 written;
3771 u32 boot_cnt;
3772 u32 hidden_sectors;
3773 le32 hidden_sectors_le;
3774 int res;
3775
3776 if (opt.verbose)
3777 ntfs_log_verbose("Copying $Boot...\n");
3778 vol = expand->vol;
3779 res = 0;
3780 buf = (char*)ntfs_malloc(vol->cluster_size);
3781 if (buf) {
3782 /* set the new volume parameters in the bootsector */
3783 bs = (NTFS_BOOT_SECTOR*)expand->bootsector;
3784 bs->number_of_sectors = cpu_to_sle64(expand->new_sectors);
3785 bs->mft_lcn = cpu_to_sle64(expand->mft_lcn);
3786 mftmirr_lcn = vol->mftmirr_lcn + expand->cluster_increment;
3787 bs->mftmirr_lcn = cpu_to_sle64(mftmirr_lcn);
3788 /* the hidden sectors are needed to boot into windows */
3789 memcpy(&hidden_sectors_le,&bs->bpb.hidden_sectors,4);
3790 /* alignment messed up on the Sparc */
3791 if (hidden_sectors_le) {
3792 hidden_sectors = le32_to_cpu(hidden_sectors_le);
3793 if (hidden_sectors >= expand->sector_increment)
3794 hidden_sectors -= expand->sector_increment;
3795 else
3796 hidden_sectors = 0;
3797 hidden_sectors_le = cpu_to_le32(hidden_sectors);
3798 memcpy(&bs->bpb.hidden_sectors,&hidden_sectors_le,4);
3799 }
3800 written = 0;
3801 boot_cnt = expand->boot_size >> vol->cluster_size_bits;
3802 while (!res && (written < boot_cnt)) {
3803 lseek_to_cluster(vol, expand->cluster_increment + written);
3804 if (!read_all(vol->dev, buf, vol->cluster_size)) {
3805 if (!written)
3806 memcpy(buf, expand->bootsector, vol->sector_size);
3807 lseek_to_cluster(vol, written);
3808 if (!opt.ro_flag
3809 && write_all(vol->dev, buf, vol->cluster_size)) {
3810 err_printf("Failed to write the new $Boot\n");
3811 res = -1;
3812 } else
3813 written++;
3814 } else {
3815 err_printf("Failed to read the old $Boot\n");
3816 res = -1;
3817 }
3818 }
3819 free(buf);
3820 } else {
3821 err_printf("Failed to allocate buffer\n");
3822 res = -1;
3823 }
3824 return (res);
3825 }
3826
3827 /*
3828 * Process delayed runlist updates
3829 *
3830 * This is derived from delayed_updates() and they should
3831 * both be merged when the new code is considered safe.
3832 */
3833
delayed_expand(ntfs_volume * vol,struct DELAYED * delayed,struct progress_bar * progress)3834 static void delayed_expand(ntfs_volume *vol, struct DELAYED *delayed,
3835 struct progress_bar *progress)
3836 {
3837 unsigned long count;
3838 struct DELAYED *current;
3839 int step = 100;
3840
3841 if (delayed) {
3842 if (opt.verbose)
3843 ntfs_log_verbose("Delayed updating of overflowing runlists...\n");
3844 count = 0;
3845 /* count by steps because of inappropriate resolution */
3846 for (current=delayed; current; current=current->next)
3847 count += step;
3848 progress_init(progress, 0, count,
3849 (opt.show_progress ? NTFS_PROGBAR : 0));
3850 current = delayed;
3851 count = 0;
3852 while (current) {
3853 delayed = current;
3854 if (!opt.ro_flag)
3855 expand_attribute_runlist(vol, delayed);
3856 count += step;
3857 progress_update(progress, count);
3858 current = current->next;
3859 if (delayed->attr_name)
3860 free(delayed->attr_name);
3861 free(delayed->head_rl);
3862 free(delayed);
3863 }
3864 }
3865 }
3866
3867 /*
3868 * Expand the sizes in indexes for inodes which were expanded
3869 *
3870 * Only the new $Bitmap sizes are identified as needed to be
3871 * adjusted in index. The $BadClus is only expanded in an
3872 * alternate data stream, whose sizes are not present in the index.
3873 *
3874 * This is modifying the initial data, and can only be done when
3875 * the volume has been reopened after expanding.
3876 */
3877
expand_index_sizes(expand_t * expand)3878 static int expand_index_sizes(expand_t *expand)
3879 {
3880 ntfs_inode *ni;
3881 int res;
3882
3883 res = -1;
3884 ni = ntfs_inode_open(expand->vol, FILE_Bitmap);
3885 if (ni) {
3886 NInoSetDirty(ni);
3887 NInoFileNameSetDirty(ni);
3888 ntfs_inode_close(ni);
3889 res = 0;
3890 }
3891 return (res);
3892 }
3893
3894 /*
3895 * Update a runlist into an attribute
3896 *
3897 * This is derived from replace_attribute_runlist() and they should
3898 * both be merged when the new code is considered safe.
3899 */
3900
update_runlist(expand_t * expand,s64 inum,ATTR_RECORD * a,runlist_element * rl)3901 static int update_runlist(expand_t *expand, s64 inum,
3902 ATTR_RECORD *a, runlist_element *rl)
3903 {
3904 ntfs_resize_t resize;
3905 ntfs_attr_search_ctx ctx;
3906 ntfs_volume *vol;
3907 MFT_RECORD *mrec;
3908 runlist *head_rl;
3909 int mp_size;
3910 int l;
3911 int must_delay;
3912 void *mp;
3913
3914 vol = expand->vol;
3915 mrec = expand->mrec;
3916 head_rl = rl;
3917 rl_fixup(&rl);
3918 if ((mp_size = ntfs_get_size_for_mapping_pairs(vol, rl,
3919 0, INT_MAX)) == -1)
3920 perr_exit("ntfs_get_size_for_mapping_pairs");
3921
3922 if (a->name_length) {
3923 u16 name_offs = le16_to_cpu(a->name_offset);
3924 u16 mp_offs = le16_to_cpu(a->mapping_pairs_offset);
3925
3926 if (name_offs >= mp_offs)
3927 err_exit("Attribute name is after mapping pairs! "
3928 "Please report!\n");
3929 }
3930
3931 /* CHECKME: don't trust mapping_pairs is always the last item in the
3932 attribute, instead check for the real size/space */
3933 l = (int)le32_to_cpu(a->length) - le16_to_cpu(a->mapping_pairs_offset);
3934 must_delay = 0;
3935 if (mp_size > l) {
3936 s32 remains_size;
3937 char *next_attr;
3938
3939 ntfs_log_verbose("Enlarging attribute header ...\n");
3940
3941 mp_size = (mp_size + 7) & ~7;
3942
3943 ntfs_log_verbose("Old mp size : %d\n", l);
3944 ntfs_log_verbose("New mp size : %d\n", mp_size);
3945 ntfs_log_verbose("Bytes in use : %u\n", (unsigned int)
3946 le32_to_cpu(mrec->bytes_in_use));
3947
3948 next_attr = (char *)a + le32_to_cpu(a->length);
3949 l = mp_size - l;
3950
3951 ntfs_log_verbose("Bytes in use new : %u\n", l + (unsigned int)
3952 le32_to_cpu(mrec->bytes_in_use));
3953 ntfs_log_verbose("Bytes allocated : %u\n", (unsigned int)
3954 le32_to_cpu(mrec->bytes_allocated));
3955
3956 remains_size = le32_to_cpu(mrec->bytes_in_use);
3957 remains_size -= (next_attr - (char *)mrec);
3958
3959 ntfs_log_verbose("increase : %d\n", l);
3960 ntfs_log_verbose("shift : %lld\n",
3961 (long long)remains_size);
3962 if (le32_to_cpu(mrec->bytes_in_use) + l >
3963 le32_to_cpu(mrec->bytes_allocated)) {
3964 ntfs_log_verbose("Queuing expansion for later processing\n");
3965 /* hack for reusing unmodified old code ! */
3966 resize.ctx = &ctx;
3967 ctx.attr = a;
3968 ctx.mrec = mrec;
3969 resize.mref = inum;
3970 resize.delayed_runlists = expand->delayed_runlists;
3971 resize.mirr_from = MIRR_OLD;
3972 must_delay = 1;
3973 replace_later(&resize,rl,head_rl);
3974 expand->delayed_runlists = resize.delayed_runlists;
3975 } else {
3976 memmove(next_attr + l, next_attr, remains_size);
3977 mrec->bytes_in_use = cpu_to_le32(l +
3978 le32_to_cpu(mrec->bytes_in_use));
3979 a->length = cpu_to_le32(le32_to_cpu(a->length) + l);
3980 }
3981 }
3982
3983 if (!must_delay) {
3984 mp = ntfs_calloc(mp_size);
3985 if (!mp)
3986 perr_exit("ntfsc_calloc couldn't get memory");
3987
3988 if (ntfs_mapping_pairs_build(vol, (u8*)mp, mp_size, rl, 0, NULL))
3989 perr_exit("ntfs_mapping_pairs_build");
3990
3991 memmove((u8*)a + le16_to_cpu(a->mapping_pairs_offset), mp, mp_size);
3992
3993 free(mp);
3994 }
3995 return (must_delay);
3996 }
3997
3998 /*
3999 * Create a minimal valid MFT record
4000 */
4001
minimal_record(expand_t * expand,MFT_RECORD * mrec)4002 static int minimal_record(expand_t *expand, MFT_RECORD *mrec)
4003 {
4004 int usa_count;
4005 u32 bytes_in_use;
4006
4007 memset(mrec,0,expand->vol->mft_record_size);
4008 mrec->magic = magic_FILE;
4009 mrec->usa_ofs = const_cpu_to_le16(sizeof(MFT_RECORD));
4010 usa_count = expand->vol->mft_record_size / NTFS_BLOCK_SIZE + 1;
4011 mrec->usa_count = cpu_to_le16(usa_count);
4012 bytes_in_use = (sizeof(MFT_RECORD) + 2*usa_count + 7) & -8;
4013 memset(((char*)mrec) + bytes_in_use, 255, 4); /* AT_END */
4014 bytes_in_use += 8;
4015 mrec->bytes_in_use = cpu_to_le32(bytes_in_use);
4016 mrec->bytes_allocated = cpu_to_le32(expand->vol->mft_record_size);
4017 return (0);
4018 }
4019
4020 /*
4021 * Rebase all runlists of an MFT record
4022 *
4023 * Iterate through all its attributes and offset the non resident ones
4024 */
4025
rebase_runlists(expand_t * expand,s64 inum)4026 static int rebase_runlists(expand_t *expand, s64 inum)
4027 {
4028 MFT_RECORD *mrec;
4029 ATTR_RECORD *a;
4030 runlist_element *rl;
4031 runlist_element *prl;
4032 u32 offset;
4033 int res;
4034
4035 res = 0;
4036 mrec = expand->mrec;
4037 offset = le16_to_cpu(mrec->attrs_offset);
4038 a = (ATTR_RECORD*)((char*)mrec + offset);
4039 while (!res && (a->type != AT_END)
4040 && (offset < le32_to_cpu(mrec->bytes_in_use))) {
4041 if (a->non_resident) {
4042 rl = ntfs_mapping_pairs_decompress(expand->vol, a,
4043 (runlist_element*)NULL);
4044 if (rl) {
4045 for (prl=rl; prl->length; prl++)
4046 if (prl->lcn >= 0) {
4047 prl->lcn += expand->cluster_increment;
4048 if (set_bitmap(expand,prl))
4049 res = -1;
4050 }
4051 if (update_runlist(expand,inum,a,rl)) {
4052 ntfs_log_verbose("Runlist updating has to be delayed\n");
4053 } else
4054 free(rl);
4055 } else {
4056 err_printf("Could not get a runlist of inode %lld\n",
4057 (long long)inum);
4058 res = -1;
4059 }
4060 }
4061 offset += le32_to_cpu(a->length);
4062 a = (ATTR_RECORD*)((char*)mrec + offset);
4063 }
4064 return (res);
4065 }
4066
4067 /*
4068 * Rebase the runlists present in records with relocated $DATA
4069 *
4070 * The returned runlist is the old rebased runlist for $DATA,
4071 * which is generally different from the new computed runlist.
4072 */
4073
rebase_runlists_meta(expand_t * expand,s64 inum)4074 static runlist_element *rebase_runlists_meta(expand_t *expand, s64 inum)
4075 {
4076 MFT_RECORD *mrec;
4077 ATTR_RECORD *a;
4078 ntfs_volume *vol;
4079 runlist_element *rl;
4080 runlist_element *old_rl;
4081 runlist_element *prl;
4082 runlist_element new_rl[2];
4083 s64 data_size;
4084 s64 allocated_size;
4085 s64 lcn;
4086 u64 lth;
4087 u32 offset;
4088 BOOL keeprl;
4089 int res;
4090
4091 res = 0;
4092 old_rl = (runlist_element*)NULL;
4093 vol = expand->vol;
4094 mrec = expand->mrec;
4095 switch (inum) {
4096 case FILE_Boot :
4097 lcn = 0;
4098 lth = expand->boot_size >> vol->cluster_size_bits;
4099 data_size = expand->boot_size;
4100 break;
4101 case FILE_Bitmap :
4102 lcn = expand->boot_size >> vol->cluster_size_bits;
4103 lth = expand->bitmap_allocated >> vol->cluster_size_bits;
4104 data_size = expand->bitmap_size;
4105 break;
4106 case FILE_MFT :
4107 lcn = (expand->boot_size + expand->bitmap_allocated)
4108 >> vol->cluster_size_bits;
4109 lth = expand->mft_size >> vol->cluster_size_bits;
4110 data_size = expand->mft_size;
4111 break;
4112 case FILE_BadClus :
4113 lcn = 0; /* not used */
4114 lth = vol->nr_clusters + expand->cluster_increment;
4115 data_size = lth << vol->cluster_size_bits;
4116 break;
4117 default :
4118 lcn = lth = data_size = 0;
4119 res = -1;
4120 }
4121 allocated_size = lth << vol->cluster_size_bits;
4122 offset = le16_to_cpu(mrec->attrs_offset);
4123 a = (ATTR_RECORD*)((char*)mrec + offset);
4124 while (!res && (a->type != AT_END)
4125 && (offset < le32_to_cpu(mrec->bytes_in_use))) {
4126 if (a->non_resident) {
4127 keeprl = FALSE;
4128 rl = ntfs_mapping_pairs_decompress(vol, a,
4129 (runlist_element*)NULL);
4130 if (rl) {
4131 /* rebase the old runlist */
4132 for (prl=rl; prl->length; prl++)
4133 if (prl->lcn >= 0) {
4134 prl->lcn += expand->cluster_increment;
4135 if ((a->type != AT_DATA)
4136 && set_bitmap(expand,prl))
4137 res = -1;
4138 }
4139 /* relocated unnamed data (not $BadClus) */
4140 if ((a->type == AT_DATA)
4141 && !a->name_length
4142 && (inum != FILE_BadClus)) {
4143 old_rl = rl;
4144 rl = new_rl;
4145 keeprl = TRUE;
4146 rl[0].vcn = 0;
4147 rl[0].lcn = lcn;
4148 rl[0].length = lth;
4149 rl[1].vcn = lth;
4150 rl[1].lcn = LCN_ENOENT;
4151 rl[1].length = 0;
4152 if (set_bitmap(expand,rl))
4153 res = -1;
4154 a->data_size = cpu_to_sle64(data_size);
4155 a->initialized_size = a->data_size;
4156 a->allocated_size
4157 = cpu_to_sle64(allocated_size);
4158 a->highest_vcn = cpu_to_sle64(lth - 1);
4159 }
4160 /* expand the named data for $BadClus */
4161 if ((a->type == AT_DATA)
4162 && a->name_length
4163 && (inum == FILE_BadClus)) {
4164 old_rl = rl;
4165 keeprl = TRUE;
4166 prl = rl;
4167 if (prl->length) {
4168 while (prl[1].length)
4169 prl++;
4170 prl->length = lth - prl->vcn;
4171 prl[1].vcn = lth;
4172 } else
4173 prl->vcn = lth;
4174 a->data_size = cpu_to_sle64(data_size);
4175 /* do not change the initialized size */
4176 a->allocated_size
4177 = cpu_to_sle64(allocated_size);
4178 a->highest_vcn = cpu_to_sle64(lth - 1);
4179 }
4180 if (!res && update_runlist(expand,inum,a,rl))
4181 res = -1;
4182 if (!keeprl)
4183 free(rl);
4184 } else {
4185 err_printf("Could not get the data runlist of inode %lld\n",
4186 (long long)inum);
4187 res = -1;
4188 }
4189 }
4190 offset += le32_to_cpu(a->length);
4191 a = (ATTR_RECORD*)((char*)mrec + offset);
4192 }
4193 if (res && old_rl) {
4194 free(old_rl);
4195 old_rl = (runlist_element*)NULL;
4196 }
4197 return (old_rl);
4198 }
4199
4200 /*
4201 * Rebase all runlists in an MFT record
4202 *
4203 * Read from the old $MFT, rebase the runlists,
4204 * and write to the new $MFT
4205 */
4206
rebase_inode(expand_t * expand,const runlist_element * prl,s64 inum,s64 jnum)4207 static int rebase_inode(expand_t *expand, const runlist_element *prl,
4208 s64 inum, s64 jnum)
4209 {
4210 MFT_RECORD *mrec;
4211 runlist_element *rl;
4212 ntfs_volume *vol;
4213 s64 pos;
4214 int res;
4215
4216 res = 0;
4217 vol = expand->vol;
4218 mrec = expand->mrec;
4219 if (expand->mft_bitmap[inum >> 3] & (1 << (inum & 7))) {
4220 pos = (prl->lcn << vol->cluster_size_bits)
4221 + ((inum - jnum) << vol->mft_record_size_bits);
4222 if ((ntfs_mst_pread(vol->dev, pos, 1,
4223 vol->mft_record_size, mrec) == 1)
4224 && (mrec->flags & MFT_RECORD_IN_USE)) {
4225 switch (inum) {
4226 case FILE_Bitmap :
4227 case FILE_Boot :
4228 case FILE_BadClus :
4229 rl = rebase_runlists_meta(expand, inum);
4230 if (rl)
4231 free(rl);
4232 else
4233 res = -1;
4234 break;
4235 default :
4236 res = rebase_runlists(expand, inum);
4237 break;
4238 }
4239 } else {
4240 err_printf("Could not read the $MFT entry %lld\n",
4241 (long long)inum);
4242 res = -1;
4243 }
4244 } else {
4245 /*
4246 * Replace unused records (possibly uninitialized)
4247 * by minimal valid records, not marked in use
4248 */
4249 res = minimal_record(expand,mrec);
4250 }
4251 if (!res) {
4252 pos = (expand->mft_lcn << vol->cluster_size_bits)
4253 + (inum << vol->mft_record_size_bits);
4254 if (opt.verbose)
4255 ntfs_log_verbose("Rebasing inode %lld cluster 0x%llx\n",
4256 (long long)inum,
4257 (long long)(pos >> vol->cluster_size_bits));
4258 if (!opt.ro_flag
4259 && (ntfs_mst_pwrite(vol->dev, pos, 1,
4260 vol->mft_record_size, mrec) != 1)) {
4261 err_printf("Could not write the $MFT entry %lld\n",
4262 (long long)inum);
4263 res = -1;
4264 }
4265 }
4266 return (res);
4267 }
4268
4269 /*
4270 * Rebase all runlists
4271 *
4272 * First get the $MFT and define its location in the expanded space,
4273 * then rebase the other inodes and write them to the new $MFT
4274 */
4275
rebase_all_inodes(expand_t * expand)4276 static int rebase_all_inodes(expand_t *expand)
4277 {
4278 ntfs_volume *vol;
4279 MFT_RECORD *mrec;
4280 s64 inum;
4281 s64 jnum;
4282 s64 inodecnt;
4283 s64 pos;
4284 s64 got;
4285 int res;
4286 runlist_element *mft_rl;
4287 runlist_element *prl;
4288
4289 res = 0;
4290 mft_rl = (runlist_element*)NULL;
4291 vol = expand->vol;
4292 mrec = expand->mrec;
4293 inum = 0;
4294 pos = (vol->mft_lcn + expand->cluster_increment)
4295 << vol->cluster_size_bits;
4296 got = ntfs_mst_pread(vol->dev, pos, 1,
4297 vol->mft_record_size, mrec);
4298 if ((got == 1) && (mrec->flags & MFT_RECORD_IN_USE)) {
4299 pos = expand->mft_lcn << vol->cluster_size_bits;
4300 if (opt.verbose)
4301 ntfs_log_verbose("Rebasing inode %lld cluster 0x%llx\n",
4302 (long long)inum,
4303 (long long)(pos >> vol->cluster_size_bits));
4304 mft_rl = rebase_runlists_meta(expand, FILE_MFT);
4305 if (!mft_rl
4306 || (!opt.ro_flag
4307 && (ntfs_mst_pwrite(vol->dev, pos, 1,
4308 vol->mft_record_size, mrec) != 1)))
4309 res = -1;
4310 else {
4311 for (prl=mft_rl; prl->length; prl++) { }
4312 inodecnt = (prl->vcn << vol->cluster_size_bits)
4313 >> vol->mft_record_size_bits;
4314 progress_init(expand->progress, 0, inodecnt,
4315 (opt.show_progress ? NTFS_PROGBAR : 0));
4316 prl = mft_rl;
4317 jnum = 0;
4318 do {
4319 inum++;
4320 while (prl->length
4321 && ((inum << vol->mft_record_size_bits)
4322 >= ((prl->vcn + prl->length)
4323 << vol->cluster_size_bits))) {
4324 prl++;
4325 jnum = inum;
4326 }
4327 progress_update(expand->progress, inum);
4328 if (prl->length) {
4329 res = rebase_inode(expand,
4330 prl,inum,jnum);
4331 }
4332 } while (!res && prl->length);
4333 free(mft_rl);
4334 }
4335 } else {
4336 err_printf("Could not read the old $MFT\n");
4337 res = -1;
4338 }
4339 return (res);
4340 }
4341
4342
4343
4344 /*
4345 * Get the old volume parameters from the backup bootsector
4346 *
4347 */
4348
get_volume_data(expand_t * expand,struct ntfs_device * dev,s32 sector_size)4349 static ntfs_volume *get_volume_data(expand_t *expand, struct ntfs_device *dev,
4350 s32 sector_size)
4351 {
4352 s64 br;
4353 ntfs_volume *vol;
4354 le16 sector_size_le;
4355 NTFS_BOOT_SECTOR *bs;
4356 BOOL ok;
4357
4358 ok = FALSE;
4359 vol = (ntfs_volume*)ntfs_malloc(sizeof(ntfs_volume));
4360 expand->bootsector = (char*)ntfs_malloc(sector_size);
4361 if (vol && expand->bootsector) {
4362 expand->vol = vol;
4363 vol->dev = dev;
4364 br = ntfs_pread(dev, expand->new_sectors*sector_size,
4365 sector_size, expand->bootsector);
4366 if (br != sector_size) {
4367 if (br != -1)
4368 errno = EINVAL;
4369 if (!br)
4370 err_printf("Failed to read the backup bootsector (size=0)\n");
4371 else
4372 err_printf("Error reading the backup bootsector");
4373 } else {
4374 bs = (NTFS_BOOT_SECTOR*)expand->bootsector;
4375 /* alignment problem on Sparc, even doing memcpy() */
4376 sector_size_le = cpu_to_le16(sector_size);
4377 if (!memcmp(§or_size_le,
4378 &bs->bpb.bytes_per_sector,2)
4379 && ntfs_boot_sector_is_ntfs(bs)
4380 && !ntfs_boot_sector_parse(vol, bs)) {
4381 expand->original_sectors
4382 = sle64_to_cpu(bs->number_of_sectors);
4383 expand->mrec = (MFT_RECORD*)
4384 ntfs_malloc(vol->mft_record_size);
4385 if (expand->mrec
4386 && can_expand(expand,vol)) {
4387 ntfs_log_verbose("Resizing is possible\n");
4388 ok = TRUE;
4389 }
4390 } else
4391 err_printf("Could not get the old volume parameters "
4392 "from the backup bootsector\n");
4393 }
4394 if (!ok) {
4395 free(vol);
4396 free(expand->bootsector);
4397 }
4398 }
4399 return (ok ? vol : (ntfs_volume*)NULL);
4400 }
4401
really_expand(expand_t * expand)4402 static int really_expand(expand_t *expand)
4403 {
4404 ntfs_volume *vol;
4405 struct ntfs_device *dev;
4406 int res;
4407
4408 res = -1;
4409
4410 expand->bitmap = (u8*)ntfs_calloc(expand->bitmap_allocated);
4411 if (expand->bitmap
4412 && get_mft_bitmap(expand)) {
4413 printf("\n*** WARNING ***\n\n");
4414 printf("Expanding a volume is an experimental new feature\n");
4415 if (!opt.ro_flag)
4416 printf("A first check with option -n is recommended\n");
4417 printf("\nShould something go wrong during the actual"
4418 " resizing (power outage, etc.),\n");
4419 printf("just restart the procedure, but DO NOT TRY to repair"
4420 " with chkdsk or similar,\n");
4421 printf("until the resizing is over,"
4422 " you would LOSE YOUR DATA !\n");
4423 printf("\nYou have been warned !\n\n");
4424 if (!opt.ro_flag && (opt.force-- <= 0))
4425 proceed_question();
4426 if (!rebase_all_inodes(expand)
4427 && !write_bitmap(expand)
4428 && !copy_mftmirr(expand)
4429 && !copy_boot(expand)) {
4430 free(expand->vol);
4431 expand->vol = (ntfs_volume*)NULL;
4432 free(expand->mft_bitmap);
4433 expand->mft_bitmap = (u8*)NULL;
4434 if (!opt.ro_flag) {
4435 /* the volume must be dirty, do not check */
4436 opt.force++;
4437 vol = mount_volume();
4438 if (vol) {
4439 dev = vol->dev;
4440 ntfs_log_verbose("Remounting the updated volume\n");
4441 expand->vol = vol;
4442 ntfs_log_verbose("Delayed runlist updatings\n");
4443 delayed_expand(vol, expand->delayed_runlists,
4444 expand->progress);
4445 expand->delayed_runlists
4446 = (struct DELAYED*)NULL;
4447 expand_index_sizes(expand);
4448 /* rewriting the backup bootsector, no return ticket now ! */
4449 res = write_bootsector(expand);
4450 if (dev->d_ops->sync(dev) == -1) {
4451 printf("Could not sync\n");
4452 res = -1;
4453 }
4454 ntfs_umount(vol,0);
4455 if (!res)
4456 printf("\nResizing completed successfully\n");
4457 }
4458 } else {
4459 ntfs_log_verbose("Delayed runlist updatings\n");
4460 delayed_expand(expand->vol,
4461 expand->delayed_runlists,
4462 expand->progress);
4463 expand->delayed_runlists
4464 = (struct DELAYED*)NULL;
4465 printf("\nAll checks have been completed successfully\n");
4466 printf("Cannot check further in no-action mode\n");
4467 }
4468 free(expand->bootsector);
4469 free(expand->mrec);
4470 }
4471 free(expand->bitmap);
4472 } else {
4473 err_printf("Failed to allocate memory\n");
4474 }
4475 return (res);
4476 }
4477
4478 /*
4479 * Expand a volume to beginning of partition
4480 *
4481 * We rely on the backup bootsector to determine the original
4482 * volume size and metadata.
4483 */
4484
expand_to_beginning(void)4485 static int expand_to_beginning(void)
4486 {
4487 expand_t expand;
4488 struct progress_bar progress;
4489 int ret;
4490 ntfs_volume *vol;
4491 struct ntfs_device *dev;
4492 int sector_size;
4493 s64 new_sectors;
4494
4495 ret = -1;
4496 dev = ntfs_device_alloc(opt.volume, 0, &ntfs_device_default_io_ops,
4497 NULL);
4498 if (dev) {
4499 if (!(*dev->d_ops->open)(dev,
4500 (opt.ro_flag ? O_RDONLY : O_RDWR))) {
4501 sector_size = ntfs_device_sector_size_get(dev);
4502 if (sector_size <= 0) {
4503 sector_size = 512;
4504 new_sectors = ntfs_device_size_get(dev,
4505 sector_size);
4506 if (!new_sectors) {
4507 sector_size = 4096;
4508 new_sectors = ntfs_device_size_get(dev,
4509 sector_size);
4510 }
4511 } else
4512 new_sectors = ntfs_device_size_get(dev,
4513 sector_size);
4514 if (new_sectors) {
4515 new_sectors--; /* last sector not counted */
4516 expand.new_sectors = new_sectors;
4517 expand.progress = &progress;
4518 expand.delayed_runlists = (struct DELAYED*)NULL;
4519 vol = get_volume_data(&expand,dev,sector_size);
4520 if (vol) {
4521 expand.vol = vol;
4522 ret = really_expand(&expand);
4523 }
4524 }
4525 (*dev->d_ops->close)(dev);
4526 } else {
4527 err_exit("Couldn't open volume '%s'!\n", opt.volume);
4528 }
4529 ntfs_device_free(dev);
4530 }
4531 return (ret);
4532 }
4533
4534
main(int argc,char ** argv)4535 int main(int argc, char **argv)
4536 {
4537 ntfsck_t fsck;
4538 ntfs_resize_t resize;
4539 s64 new_size = 0; /* in clusters; 0 = --info w/o --size */
4540 s64 device_size; /* in bytes */
4541 ntfs_volume *vol = NULL;
4542 int res;
4543
4544 ntfs_log_set_handler(ntfs_log_handler_outerr);
4545
4546 printf("%s v%s (libntfs-3g)\n", EXEC_NAME, VERSION);
4547
4548 res = parse_options(argc, argv);
4549 if (res >= 0)
4550 return (res);
4551
4552 utils_set_locale();
4553
4554 /*
4555 * If we're just checking the device, we'll do it first,
4556 * and exit out, no matter what we find.
4557 */
4558 if (opt.check) {
4559 vol = check_volume();
4560 #if CLEAN_EXIT
4561 if (vol)
4562 ntfs_umount(vol,0);
4563 #endif
4564 exit(0);
4565 } else {
4566 if (opt.expand) {
4567 /*
4568 * If we are to expand to beginning of partition, do
4569 * not try to mount : when merging two partitions,
4570 * the beginning of the partition would contain an
4571 * old filesystem which is not the one to expand.
4572 */
4573 if (expand_to_beginning() && !opt.info)
4574 exit(1);
4575 return (0);
4576 }
4577 }
4578
4579 if (!(vol = mount_volume()))
4580 err_exit("Couldn't open volume '%s'!\n", opt.volume);
4581
4582 device_size = ntfs_device_size_get(vol->dev, vol->sector_size);
4583 device_size *= vol->sector_size;
4584 if (device_size <= 0)
4585 err_exit("Couldn't get device size (%lld)!\n",
4586 (long long)device_size);
4587
4588 if (!opt.infombonly)
4589 print_vol_size("Current device size", device_size);
4590
4591 if (device_size < vol->nr_clusters * vol->cluster_size)
4592 err_exit("Current NTFS volume size is bigger than the device "
4593 "size!\nCorrupt partition table or incorrect device "
4594 "partitioning?\n");
4595
4596 if (!opt.bytes && !opt.info && !opt.infombonly) {
4597 opt.bytes = device_size;
4598 opt.reliable_size = 1;
4599 }
4600
4601 /* Backup boot sector at the end of device isn't counted in NTFS
4602 volume size thus we have to reserve space for it. */
4603 if (opt.bytes > vol->sector_size)
4604 new_size = (opt.bytes - vol->sector_size) / vol->cluster_size;
4605 else
4606 new_size = 0;
4607
4608 if (!opt.info && !opt.infombonly) {
4609 print_vol_size("New volume size ", vol_size(vol, new_size));
4610 if (device_size < opt.bytes)
4611 err_exit("New size can't be bigger than the device size"
4612 ".\nIf you want to enlarge NTFS then first "
4613 "enlarge the device size by e.g. fdisk.\n");
4614 }
4615
4616 if (!opt.info && !opt.infombonly && (new_size == vol->nr_clusters ||
4617 (opt.bytes == device_size &&
4618 new_size == vol->nr_clusters - 1))) {
4619 printf("Nothing to do: NTFS volume size is already OK.\n");
4620 exit(0);
4621 }
4622
4623 memset(&resize, 0, sizeof(resize));
4624 resize.vol = vol;
4625 resize.new_volume_size = new_size;
4626 /* This is also true if --info was used w/o --size (new_size = 0) */
4627 if (new_size < vol->nr_clusters)
4628 resize.shrink = 1;
4629 if (opt.show_progress)
4630 resize.progress.flags |= NTFS_PROGBAR;
4631 /*
4632 * Checking and __reporting__ of bad sectors must be done before cluster
4633 * allocation check because chkdsk doesn't fix $Bitmap's w/ bad sectors
4634 * thus users would (were) quite confused why chkdsk doesn't work.
4635 */
4636 resize.badclusters = check_bad_sectors(vol);
4637
4638 NVolSetNoFixupWarn(vol);
4639 check_cluster_allocation(vol, &fsck);
4640
4641 print_disk_usage(vol, fsck.inuse);
4642
4643 resize.inuse = fsck.inuse;
4644 resize.lcn_bitmap = fsck.lcn_bitmap;
4645 resize.mirr_from = MIRR_OLD;
4646
4647 set_resize_constraints(&resize);
4648 set_disk_usage_constraint(&resize);
4649 check_resize_constraints(&resize);
4650
4651 if (opt.info || opt.infombonly) {
4652 advise_on_resize(&resize);
4653 exit(0);
4654 }
4655
4656 if (opt.force-- <= 0 && !opt.ro_flag) {
4657 printf("%s", resize_warning_msg);
4658 proceed_question();
4659 }
4660
4661 /* FIXME: performance - relocate logfile here if it's needed */
4662 prepare_volume_fixup(vol);
4663
4664 if (resize.relocations)
4665 relocate_inodes(&resize);
4666
4667 truncate_badclust_file(&resize);
4668 truncate_bitmap_file(&resize);
4669 delayed_updates(&resize);
4670 update_bootsector(&resize);
4671
4672 /* We don't create backup boot sector because we don't know where the
4673 partition will be split. The scheduled chkdsk will fix it */
4674
4675 if (opt.ro_flag) {
4676 printf("The read-only test run ended successfully.\n");
4677 exit(0);
4678 }
4679
4680 /* WARNING: don't modify the texts, external tools grep for them */
4681 printf("Syncing device ...\n");
4682 if (vol->dev->d_ops->sync(vol->dev) == -1)
4683 perr_exit("fsync");
4684
4685 printf("Successfully resized NTFS on device '%s'.\n", vol->dev->d_name);
4686 if (resize.shrink)
4687 printf("%s", resize_important_msg);
4688 if (resize.lcn_bitmap.bm)
4689 free(resize.lcn_bitmap.bm);
4690 if (vol)
4691 ntfs_umount(vol,0);
4692 return 0;
4693 }
4694