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 * 9 * This utility will resize an NTFS volume without data loss. 10 * 11 * WARNING FOR DEVELOPERS!!! Several external tools grep for text messages 12 * to control execution thus if you would like to change any message 13 * then PLEASE think twice before doing so then don't modify it. Thanks! 14 * 15 * This program is free software; you can redistribute it and/or modify 16 * it under the terms of the GNU General Public License as published by 17 * the Free Software Foundation; either version 2 of the License, or 18 * (at your option) any later version. 19 * 20 * This program is distributed in the hope that it will be useful, 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * GNU General Public License for more details. 24 * 25 * You should have received a copy of the GNU General Public License 26 * along with this program (in the main directory of the Linux-NTFS 27 * distribution in the file COPYING); if not, write to the Free Software 28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 29 */ 30 31 #include "config.h" 32 33 #ifdef HAVE_UNISTD_H 34 #include <unistd.h> 35 #endif 36 #ifdef HAVE_STDLIB_H 37 #include <stdlib.h> 38 #endif 39 #ifdef HAVE_STDIO_H 40 #include <stdio.h> 41 #endif 42 #ifdef HAVE_STDARG_H 43 #include <stdarg.h> 44 #endif 45 #ifdef HAVE_STRING_H 46 #include <string.h> 47 #endif 48 #ifdef HAVE_ERRNO_H 49 #include <errno.h> 50 #endif 51 #ifdef HAVE_GETOPT_H 52 #include <getopt.h> 53 #endif 54 55 #include "compat.h" 56 #include "debug.h" 57 #include "types.h" 58 #include "support.h" 59 #include "endians.h" 60 #include "bootsect.h" 61 #include "device.h" 62 #include "attrib.h" 63 #include "volume.h" 64 #include "mft.h" 65 #include "bitmap.h" 66 #include "inode.h" 67 #include "runlist.h" 68 #include "utils.h" 69 #include "version.h" 70 71 static const char *EXEC_NAME = "ntfsresize"; 72 73 static const char *resize_warning_msg = 74 "WARNING: Every sanity check passed and only the dangerous operations left.\n" 75 "Make sure that important data has been backed up! Power outage or computer\n" 76 "crash may result major data loss!\n"; 77 78 static const char *resize_important_msg = 79 #ifdef __sun 80 "When booted, Windows will check the file system and may reboot.\n" 81 "If you are running this from inside parted, STOP reading now.\n" 82 "Otherwise, you can go on to shrink the device with fdisk or parted.\n" 83 #else 84 "You can go on to shrink the device for example with Linux fdisk.\n" 85 #endif 86 "IMPORTANT: When recreating the partition, make sure that you\n" 87 " 1) create it at the same disk sector (use sector as the unit!)\n" 88 " 2) create it with the same partition type (usually 7, HPFS/NTFS)\n" 89 " 3) do not make it smaller than the new NTFS filesystem size\n" 90 " 4) set the bootable flag for the partition if it existed before\n" 91 "Otherwise you won't be able to access NTFS or can't boot from the disk!\n" 92 "If you make a mistake and don't have a partition table backup then you\n" 93 "can recover the partition table by TestDisk or Parted's rescue mode.\n"; 94 95 static const char *invalid_ntfs_msg = 96 "The device '%s' doesn't have a valid NTFS.\n" 97 "Maybe you selected the wrong partition? Or the whole disk instead of a\n" 98 "partition (e.g. /dev/hda, not /dev/hda1)? This error might also occur\n" 99 "if the disk was incorrectly repartitioned (see the ntfsresize FAQ).\n"; 100 101 static const char *corrupt_volume_msg = 102 "NTFS is inconsistent. Run chkdsk /f on Windows then reboot it TWICE!\n" 103 "The usage of the /f parameter is very IMPORTANT! No modification was\n" 104 "and will be made to NTFS by this software until it gets repaired.\n"; 105 106 static const char *hibernated_volume_msg = 107 "The NTFS partition is hibernated. Windows must be resumed and turned off\n" 108 "properly, so resizing could be done safely.\n"; 109 110 static const char *unclean_journal_msg = 111 "The NTFS journal file is unclean. Please shutdown Windows properly before\n" 112 "using this software! Note, if you have run chkdsk previously then boot\n" 113 "Windows again which will automatically initialize the journal correctly.\n"; 114 115 static const char *opened_volume_msg = 116 "This software has detected that the NTFS volume is already opened by another\n" 117 "software thus it refuses to progress to preserve data consistency.\n"; 118 119 static const char *bad_sectors_warning_msg = 120 "****************************************************************************\n" 121 "* WARNING: The disk has bad sector. This means physical damage on the disk *\n" 122 "* surface caused by deterioration, manufacturing faults or other reason. *\n" 123 "* The reliability of the disk may stay stable or degrade fast. We suggest *\n" 124 "* making a full backup urgently by running 'ntfsclone --rescue ...' then *\n" 125 "* run 'chkdsk /f /r' on Windows and rebooot it TWICE! Then you can resize *\n" 126 "* NTFS safely by additionally using the --bad-sectors option of ntfsresize.*\n" 127 "****************************************************************************\n"; 128 129 static const char *many_bad_sectors_msg = 130 "***************************************************************************\n" 131 "* WARNING: The disk has many bad sectors. This means physical damage *\n" 132 "* on the disk surface caused by deterioration, manufacturing faults or *\n" 133 "* other reason. We suggest to get a replacement disk as soon as possible. *\n" 134 "***************************************************************************\n"; 135 136 static struct { 137 int verbose; 138 int debug; 139 int ro_flag; 140 int force; 141 int info; 142 int show_progress; 143 int badsectors; 144 s64 bytes; 145 char *volume; 146 } opt; 147 148 struct bitmap { 149 s64 size; 150 u8 *bm; 151 }; 152 153 #define NTFS_PROGBAR 0x0001 154 #define NTFS_PROGBAR_SUPPRESS 0x0002 155 156 struct progress_bar { 157 u64 start; 158 u64 stop; 159 int resolution; 160 int flags; 161 float unit; 162 }; 163 164 struct llcn_t { 165 s64 lcn; /* last used LCN for a "special" file/attr type */ 166 s64 inode; /* inode using it */ 167 }; 168 169 #define NTFSCK_PROGBAR 0x0001 170 171 typedef struct { 172 ntfs_inode *ni; /* inode being processed */ 173 ntfs_attr_search_ctx *ctx; /* inode attribute being processed */ 174 s64 inuse; /* num of clusters in use */ 175 int multi_ref; /* num of clusters referenced many times */ 176 int outsider; /* num of clusters outside the volume */ 177 int show_outsider; /* controls showing the above information */ 178 int flags; 179 struct bitmap lcn_bitmap; 180 } ntfsck_t; 181 182 typedef struct { 183 ntfs_volume *vol; 184 ntfs_inode *ni; /* inode being processed */ 185 s64 new_volume_size; /* in clusters; 0 = --info w/o --size */ 186 MFT_REF mref; /* mft reference */ 187 MFT_RECORD *mrec; /* mft record */ 188 ntfs_attr_search_ctx *ctx; /* inode attribute being processed */ 189 u64 relocations; /* num of clusters to relocate */ 190 s64 inuse; /* num of clusters in use */ 191 runlist mftmir_rl; /* $MFTMirr AT_DATA's new position */ 192 s64 mftmir_old; /* $MFTMirr AT_DATA's old LCN */ 193 int dirty_inode; /* some inode data got relocated */ 194 int shrink; /* shrink = 1, enlarge = 0 */ 195 s64 badclusters; /* num of physically dead clusters */ 196 VCN mft_highest_vcn; /* used for relocating the $MFT */ 197 struct progress_bar progress; 198 struct bitmap lcn_bitmap; 199 /* Temporary statistics until all case is supported */ 200 struct llcn_t last_mft; 201 struct llcn_t last_mftmir; 202 struct llcn_t last_multi_mft; 203 struct llcn_t last_sparse; 204 struct llcn_t last_compressed; 205 struct llcn_t last_lcn; 206 s64 last_unsupp; /* last unsupported cluster */ 207 } ntfs_resize_t; 208 209 /* FIXME: This, lcn_bitmap and pos from find_free_cluster() will make a cluster 210 allocation related structure, attached to ntfs_resize_t */ 211 static s64 max_free_cluster_range = 0; 212 213 #define NTFS_MBYTE (1000 * 1000) 214 215 /* WARNING: don't modify the text, external tools grep for it */ 216 #define ERR_PREFIX "ERROR" 217 #define PERR_PREFIX ERR_PREFIX "(%d): " 218 #define NERR_PREFIX ERR_PREFIX ": " 219 220 #define DIRTY_NONE (0) 221 #define DIRTY_INODE (1) 222 #define DIRTY_ATTRIB (2) 223 224 #define NTFS_MAX_CLUSTER_SIZE (65536) 225 226 static s64 rounded_up_division(s64 numer, s64 denom) 227 { 228 return (numer + (denom - 1)) / denom; 229 } 230 231 /** 232 * perr_printf 233 * 234 * Print an error message. 235 */ 236 __attribute__((format(printf, 1, 2))) 237 static void perr_printf(const char *fmt, ...) 238 { 239 va_list ap; 240 int eo = errno; 241 242 fprintf(stdout, PERR_PREFIX, eo); 243 va_start(ap, fmt); 244 vfprintf(stdout, fmt, ap); 245 va_end(ap); 246 fprintf(stdout, ": %s\n", strerror(eo)); 247 fflush(stdout); 248 fflush(stderr); 249 } 250 251 __attribute__((format(printf, 1, 2))) 252 static void err_printf(const char *fmt, ...) 253 { 254 va_list ap; 255 256 fprintf(stdout, NERR_PREFIX); 257 va_start(ap, fmt); 258 vfprintf(stdout, fmt, ap); 259 va_end(ap); 260 fflush(stdout); 261 fflush(stderr); 262 } 263 264 /** 265 * err_exit 266 * 267 * Print and error message and exit the program. 268 */ 269 __attribute__((noreturn)) 270 __attribute__((format(printf, 1, 2))) 271 static int err_exit(const char *fmt, ...) 272 { 273 va_list ap; 274 275 fprintf(stdout, NERR_PREFIX); 276 va_start(ap, fmt); 277 vfprintf(stdout, fmt, ap); 278 va_end(ap); 279 fflush(stdout); 280 fflush(stderr); 281 exit(1); 282 } 283 284 /** 285 * perr_exit 286 * 287 * Print and error message and exit the program 288 */ 289 __attribute__((noreturn)) 290 __attribute__((format(printf, 1, 2))) 291 static int perr_exit(const char *fmt, ...) 292 { 293 va_list ap; 294 int eo = errno; 295 296 fprintf(stdout, PERR_PREFIX, eo); 297 va_start(ap, fmt); 298 vfprintf(stdout, fmt, ap); 299 va_end(ap); 300 printf(": %s\n", strerror(eo)); 301 fflush(stdout); 302 fflush(stderr); 303 exit(1); 304 } 305 306 /** 307 * usage - Print a list of the parameters to the program 308 * 309 * Print a list of the parameters and options for the program. 310 * 311 * Return: none 312 */ 313 __attribute__((noreturn)) 314 static void usage(void) 315 { 316 317 printf("\nUsage: %s [OPTIONS] DEVICE\n" 318 " Resize an NTFS volume non-destructively, safely move any data if needed.\n" 319 "\n" 320 " -i, --info Estimate the smallest shrunken size possible\n" 321 " -s, --size SIZE Resize volume to SIZE[k|M|G] bytes\n" 322 "\n" 323 " -n, --no-action Do not write to disk\n" 324 " -b, --bad-sectors Support disks having bad sectors\n" 325 " -f, --force Force to progress\n" 326 " -P, --no-progress-bar Don't show progress bar\n" 327 " -v, --verbose More output\n" 328 " -V, --version Display version information\n" 329 " -h, --help Display this help\n" 330 #ifdef DEBUG 331 " -d, --debug Show debug information\n" 332 #endif 333 "\n" 334 " The options -i and -s are mutually exclusive. If both options are\n" 335 " omitted then the NTFS volume will be enlarged to the DEVICE size.\n" 336 "\n", EXEC_NAME); 337 printf("%s%s", ntfs_bugs, ntfs_home); 338 printf("Ntfsresize FAQ: http://linux-ntfs.sourceforge.net/info/ntfsresize.html\n"); 339 exit(1); 340 } 341 342 /** 343 * proceed_question 344 * 345 * Force the user to confirm an action before performing it. 346 * Copy-paste from e2fsprogs 347 */ 348 static void proceed_question(void) 349 { 350 char buf[256]; 351 const char *short_yes = "yY"; 352 353 fflush(stdout); 354 fflush(stderr); 355 printf("Are you sure you want to proceed (y/[n])? "); 356 buf[0] = 0; 357 fgets(buf, sizeof(buf), stdin); 358 if (!strchr(short_yes, buf[0])) { 359 printf("OK quitting. NO CHANGES have been made to your " 360 "NTFS volume.\n"); 361 exit(1); 362 } 363 } 364 365 /** 366 * version - Print version information about the program 367 * 368 * Print a copyright statement and a brief description of the program. 369 * 370 * Return: none 371 */ 372 static void version(void) 373 { 374 printf("\nResize an NTFS Volume, without data loss.\n\n"); 375 printf("Copyright (c) 2002-2006 Szabolcs Szakacsits\n"); 376 printf("Copyright (c) 2002-2005 Anton Altaparmakov\n"); 377 printf("Copyright (c) 2002-2003 Richard Russon\n"); 378 printf("Copyright (c) 2007 Yura Pakhuchiy\n"); 379 printf("\n%s\n%s%s", ntfs_gpl, ntfs_bugs, ntfs_home); 380 } 381 382 /** 383 * get_new_volume_size 384 * 385 * Convert a user-supplied string into a size. Without any suffix the number 386 * will be assumed to be in bytes. If the number has a suffix of k, M or G it 387 * will be scaled up by 1000, 1000000, or 1000000000. 388 */ 389 static s64 get_new_volume_size(char *s) 390 { 391 s64 size; 392 char *suffix; 393 int prefix_kind = 1000; 394 395 size = strtoll(s, &suffix, 10); 396 if (size <= 0 || errno == ERANGE) 397 err_exit("Illegal new volume size\n"); 398 399 if (!*suffix) 400 return size; 401 402 if (strlen(suffix) == 2 && suffix[1] == 'i') 403 prefix_kind = 1024; 404 else if (strlen(suffix) > 1) 405 usage(); 406 407 /* We follow the SI prefixes: 408 http://physics.nist.gov/cuu/Units/prefixes.html 409 http://physics.nist.gov/cuu/Units/binary.html 410 Disk partitioning tools use prefixes as, 411 k M G 412 fdisk 2.11x- 2^10 2^20 10^3*2^20 413 fdisk 2.11y+ 10^3 10^6 10^9 414 cfdisk 10^3 10^6 10^9 415 sfdisk 2^10 2^20 416 parted 2^10 2^20 (may change) 417 fdisk (DOS) 2^10 2^20 418 */ 419 /* FIXME: check for overflow */ 420 switch (*suffix) { 421 case 'G': 422 size *= prefix_kind; 423 case 'M': 424 size *= prefix_kind; 425 case 'k': 426 size *= prefix_kind; 427 break; 428 default: 429 usage(); 430 } 431 432 return size; 433 } 434 435 /** 436 * parse_options - Read and validate the programs command line 437 * 438 * Read the command line, verify the syntax and parse the options. 439 * This function is very long, but quite simple. 440 * 441 * Return: 1 Success 442 * 0 Error, one or more problems 443 */ 444 static int parse_options(int argc, char **argv) 445 { 446 static const char *sopt = "-bdfhinPs:vV"; 447 static const struct option lopt[] = { 448 { "bad-sectors",no_argument, NULL, 'b' }, 449 #ifdef DEBUG 450 { "debug", no_argument, NULL, 'd' }, 451 #endif 452 { "force", no_argument, NULL, 'f' }, 453 { "help", no_argument, NULL, 'h' }, 454 { "info", no_argument, NULL, 'i' }, 455 { "no-action", no_argument, NULL, 'n' }, 456 { "no-progress-bar", no_argument, NULL, 'P' }, 457 { "size", required_argument, NULL, 's' }, 458 { "verbose", no_argument, NULL, 'v' }, 459 { "version", no_argument, NULL, 'V' }, 460 { NULL, 0, NULL, 0 } 461 }; 462 463 int c; 464 int err = 0; 465 int ver = 0; 466 int help = 0; 467 468 memset(&opt, 0, sizeof(opt)); 469 opt.show_progress = 1; 470 471 while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { 472 switch (c) { 473 case 1: /* A non-option argument */ 474 if (!err && !opt.volume) 475 opt.volume = argv[optind-1]; 476 else 477 err++; 478 break; 479 case 'b': 480 opt.badsectors++; 481 break; 482 case 'd': 483 opt.debug++; 484 break; 485 case 'f': 486 opt.force++; 487 break; 488 case 'h': 489 case '?': 490 help++; 491 break; 492 case 'i': 493 opt.info++; 494 break; 495 case 'n': 496 opt.ro_flag = NTFS_MNT_RDONLY; 497 break; 498 case 'P': 499 opt.show_progress = 0; 500 break; 501 case 's': 502 if (!err && (opt.bytes == 0)) 503 opt.bytes = get_new_volume_size(optarg); 504 else 505 err++; 506 break; 507 case 'v': 508 opt.verbose++; 509 ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE); 510 break; 511 case 'V': 512 ver++; 513 break; 514 default: 515 if (optopt == 's') { 516 printf("Option '%s' requires an argument.\n", argv[optind-1]); 517 } else { 518 printf("Unknown option '%s'.\n", argv[optind-1]); 519 } 520 err++; 521 break; 522 } 523 } 524 525 if (!help && !ver) { 526 if (opt.volume == NULL) { 527 if (argc > 1) 528 printf("You must specify exactly one device.\n"); 529 err++; 530 } 531 if (opt.info) { 532 opt.ro_flag = NTFS_MNT_RDONLY; 533 if (opt.bytes) { 534 printf(NERR_PREFIX "Options --info and --size " 535 "can't be used together.\n"); 536 usage(); 537 } 538 } 539 } 540 541 /* Redirect stderr to stdout, note fflush()es are essential! */ 542 fflush(stdout); 543 fflush(stderr); 544 if (dup2(STDOUT_FILENO, STDERR_FILENO) == -1) 545 perr_exit("Failed to redirect stderr to stdout"); 546 fflush(stdout); 547 fflush(stderr); 548 549 #ifdef DEBUG 550 if (!opt.debug) 551 if (!freopen("/dev/null", "w", stderr)) 552 perr_exit("Failed to redirect stderr to /dev/null"); 553 #endif 554 555 if (ver) 556 version(); 557 if (help || err) 558 usage(); 559 560 return (!err && !help && !ver); 561 } 562 563 static void print_advise(ntfs_volume *vol, s64 supp_lcn) 564 { 565 s64 old_b, new_b, freed_b, old_mb, new_mb, freed_mb; 566 567 old_b = vol->nr_clusters * vol->cluster_size; 568 old_mb = rounded_up_division(old_b, NTFS_MBYTE); 569 570 /* Take the next supported cluster (free or relocatable) 571 plus reserve a cluster for the backup boot sector */ 572 supp_lcn += 2; 573 574 if (supp_lcn > vol->nr_clusters) { 575 err_printf("Very rare fragmentation type detected. " 576 "Sorry, it's not supported yet.\n" 577 "Try to defragment your NTFS, perhaps it helps.\n"); 578 exit(1); 579 } 580 581 new_b = supp_lcn * vol->cluster_size; 582 new_mb = rounded_up_division(new_b, NTFS_MBYTE); 583 freed_b = (vol->nr_clusters - supp_lcn + 1) * vol->cluster_size; 584 freed_mb = freed_b / NTFS_MBYTE; 585 586 /* WARNING: don't modify the text, external tools grep for it */ 587 printf("You might resize at %lld bytes ", (long long)new_b); 588 if ((new_mb * NTFS_MBYTE) < old_b) 589 printf("or %lld MB ", (long long)new_mb); 590 591 printf("(freeing "); 592 if (freed_mb && (old_mb - new_mb)) 593 printf("%lld MB", (long long)(old_mb - new_mb)); 594 else 595 printf("%lld bytes", (long long)freed_b); 596 printf(").\n"); 597 598 printf("Please make a test run using both the -n and -s options " 599 "before real resizing!\n"); 600 } 601 602 static void rl_set(runlist *rl, VCN vcn, LCN lcn, s64 len) 603 { 604 rl->vcn = vcn; 605 rl->lcn = lcn; 606 rl->length = len; 607 } 608 609 static int rl_items(runlist *rl) 610 { 611 int i = 0; 612 613 while (rl[i++].length) 614 ; 615 616 return i; 617 } 618 619 static void dump_run(runlist_element *r) 620 { 621 ntfs_log_verbose(" %8lld %8lld (0x%08llx) %lld\n", (long long)r->vcn, 622 (long long)r->lcn, (long long)r->lcn, 623 (long long)r->length); 624 } 625 626 static void dump_runlist(runlist *rl) 627 { 628 while (rl->length) 629 dump_run(rl++); 630 } 631 632 /** 633 * nr_clusters_to_bitmap_byte_size 634 * 635 * Take the number of clusters in the volume and calculate the size of $Bitmap. 636 * The size must be always a multiple of 8 bytes. 637 */ 638 static s64 nr_clusters_to_bitmap_byte_size(s64 nr_clusters) 639 { 640 s64 bm_bsize; 641 642 bm_bsize = rounded_up_division(nr_clusters, 8); 643 bm_bsize = (bm_bsize + 7) & ~7; 644 645 return bm_bsize; 646 } 647 648 static void collect_resize_constraints(ntfs_resize_t *resize, runlist *rl) 649 { 650 s64 inode, last_lcn; 651 ATTR_FLAGS flags; 652 ATTR_TYPES atype; 653 struct llcn_t *llcn = NULL; 654 int ret, supported = 0; 655 656 last_lcn = rl->lcn + (rl->length - 1); 657 658 inode = resize->ni->mft_no; 659 flags = resize->ctx->attr->flags; 660 atype = resize->ctx->attr->type; 661 662 if ((ret = ntfs_inode_badclus_bad(inode, resize->ctx->attr)) != 0) { 663 if (ret == -1) 664 perr_exit("Bad sector list check failed"); 665 return; 666 } 667 668 if (inode == FILE_Bitmap) { 669 llcn = &resize->last_lcn; 670 if (atype == AT_DATA && NInoAttrList(resize->ni)) 671 err_exit("Highly fragmented $Bitmap isn't supported yet."); 672 673 supported = 1; 674 675 } else if (inode == FILE_MFT) { 676 llcn = &resize->last_mft; 677 /* 678 * First run of $MFT AT_DATA isn't supported yet. 679 */ 680 if (atype != AT_DATA || rl->vcn) 681 supported = 1; 682 683 } else if (NInoAttrList(resize->ni)) { 684 llcn = &resize->last_multi_mft; 685 686 if (inode != FILE_MFTMirr) 687 supported = 1; 688 689 } else if (flags & ATTR_IS_SPARSE) { 690 llcn = &resize->last_sparse; 691 supported = 1; 692 693 } else if (flags & ATTR_IS_COMPRESSED) { 694 llcn = &resize->last_compressed; 695 supported = 1; 696 697 } else if (inode == FILE_MFTMirr) { 698 llcn = &resize->last_mftmir; 699 supported = 1; 700 701 /* Fragmented $MFTMirr DATA attribute isn't supported yet */ 702 if (atype == AT_DATA) 703 if (rl[1].length != 0 || rl->vcn) 704 supported = 0; 705 } else { 706 llcn = &resize->last_lcn; 707 supported = 1; 708 } 709 710 if (llcn->lcn < last_lcn) { 711 llcn->lcn = last_lcn; 712 llcn->inode = inode; 713 } 714 715 if (supported) 716 return; 717 718 if (resize->last_unsupp < last_lcn) 719 resize->last_unsupp = last_lcn; 720 } 721 722 723 static void collect_relocation_info(ntfs_resize_t *resize, runlist *rl) 724 { 725 s64 lcn, lcn_length, start, len, inode; 726 s64 new_vol_size; /* (last LCN on the volume) + 1 */ 727 728 lcn = rl->lcn; 729 lcn_length = rl->length; 730 inode = resize->ni->mft_no; 731 new_vol_size = resize->new_volume_size; 732 733 if (lcn + lcn_length <= new_vol_size) 734 return; 735 736 if (inode == FILE_Bitmap && resize->ctx->attr->type == AT_DATA) 737 return; 738 739 start = lcn; 740 len = lcn_length; 741 742 if (lcn < new_vol_size) { 743 start = new_vol_size; 744 len = lcn_length - (new_vol_size - lcn); 745 746 if (!opt.info && (inode == FILE_MFTMirr)) { 747 err_printf("$MFTMirr can't be split up yet. Please try " 748 "a different size.\n"); 749 print_advise(resize->vol, lcn + lcn_length - 1); 750 exit(1); 751 } 752 } 753 754 resize->relocations += len; 755 756 if (!opt.info || !resize->new_volume_size) 757 return; 758 759 printf("Relocation needed for inode %8lld attr 0x%x LCN 0x%08llx " 760 "length %6lld\n", (long long)inode, 761 (unsigned int)le32_to_cpu(resize->ctx->attr->type), 762 (unsigned long long)start, (long long)len); 763 } 764 765 /** 766 * build_lcn_usage_bitmap 767 * 768 * lcn_bitmap has one bit for each cluster on the disk. Initially, lcn_bitmap 769 * has no bits set. As each attribute record is read the bits in lcn_bitmap are 770 * checked to ensure that no other file already references that cluster. 771 * 772 * This serves as a rudimentary "chkdsk" operation. 773 */ 774 static void build_lcn_usage_bitmap(ntfs_volume *vol, ntfsck_t *fsck) 775 { 776 s64 inode; 777 ATTR_RECORD *a; 778 runlist *rl; 779 int i, j; 780 struct bitmap *lcn_bitmap = &fsck->lcn_bitmap; 781 782 a = fsck->ctx->attr; 783 inode = fsck->ni->mft_no; 784 785 if (!a->non_resident) 786 return; 787 788 if (!(rl = ntfs_mapping_pairs_decompress(vol, a, NULL))) { 789 int err = errno; 790 perr_printf("ntfs_decompress_mapping_pairs"); 791 if (err == EIO) 792 printf("%s", corrupt_volume_msg); 793 exit(1); 794 } 795 796 797 for (i = 0; rl[i].length; i++) { 798 s64 lcn = rl[i].lcn; 799 s64 lcn_length = rl[i].length; 800 801 /* CHECKME: LCN_RL_NOT_MAPPED check isn't needed */ 802 if (lcn == LCN_HOLE || lcn == LCN_RL_NOT_MAPPED) 803 continue; 804 805 /* FIXME: ntfs_mapping_pairs_decompress should return error */ 806 if (lcn < 0 || lcn_length <= 0) 807 err_exit("Corrupt runlist in inode %lld attr %x LCN " 808 "%llx length %llx\n", inode, 809 (unsigned int)le32_to_cpu(a->type), lcn, 810 lcn_length); 811 812 for (j = 0; j < lcn_length; j++) { 813 u64 k = (u64)lcn + j; 814 815 if (k >= (u64)vol->nr_clusters) { 816 long long outsiders = lcn_length - j; 817 818 fsck->outsider += outsiders; 819 820 if (++fsck->show_outsider <= 10 || opt.verbose) 821 printf("Outside of the volume reference" 822 " for inode %lld at %lld:%lld\n", 823 inode, (long long)k, outsiders); 824 825 break; 826 } 827 828 if (ntfs_bit_get_and_set(lcn_bitmap->bm, k, 1)) { 829 if (++fsck->multi_ref <= 10 || opt.verbose) 830 printf("Cluster %lld is referenced " 831 "multiple times!\n", 832 (long long)k); 833 continue; 834 } 835 } 836 fsck->inuse += lcn_length; 837 } 838 free(rl); 839 } 840 841 842 static ntfs_attr_search_ctx *attr_get_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec) 843 { 844 ntfs_attr_search_ctx *ret; 845 846 if ((ret = ntfs_attr_get_search_ctx(ni, mrec)) == NULL) 847 perr_printf("ntfs_attr_get_search_ctx"); 848 849 return ret; 850 } 851 852 /** 853 * walk_attributes 854 * 855 * For a given MFT Record, iterate through all its attributes. Any non-resident 856 * data runs will be marked in lcn_bitmap. 857 */ 858 static int walk_attributes(ntfs_volume *vol, ntfsck_t *fsck) 859 { 860 if (!(fsck->ctx = attr_get_search_ctx(fsck->ni, NULL))) 861 return -1; 862 863 while (!ntfs_attrs_walk(fsck->ctx)) { 864 if (fsck->ctx->attr->type == AT_END) 865 break; 866 build_lcn_usage_bitmap(vol, fsck); 867 } 868 869 ntfs_attr_put_search_ctx(fsck->ctx); 870 return 0; 871 } 872 873 /** 874 * compare_bitmaps 875 * 876 * Compare two bitmaps. In this case, $Bitmap as read from the disk and 877 * lcn_bitmap which we built from the MFT Records. 878 */ 879 static void compare_bitmaps(ntfs_volume *vol, struct bitmap *a) 880 { 881 s64 i, pos, count; 882 int mismatch = 0; 883 int backup_boot = 0; 884 u8 bm[NTFS_BUF_SIZE]; 885 886 printf("Accounting clusters ...\n"); 887 888 pos = 0; 889 while (1) { 890 count = ntfs_attr_pread(vol->lcnbmp_na, pos, NTFS_BUF_SIZE, bm); 891 if (count == -1) 892 perr_exit("Couldn't get $Bitmap $DATA"); 893 894 if (count == 0) { 895 if (a->size > pos) 896 err_exit("$Bitmap size is smaller than expected" 897 " (%lld != %lld)\n", a->size, pos); 898 break; 899 } 900 901 for (i = 0; i < count; i++, pos++) { 902 s64 cl; /* current cluster */ 903 904 if (a->size <= pos) 905 goto done; 906 907 if (a->bm[pos] == bm[i]) 908 continue; 909 910 for (cl = pos * 8; cl < (pos + 1) * 8; cl++) { 911 char bit; 912 913 bit = ntfs_bit_get(a->bm, cl); 914 if (bit == ntfs_bit_get(bm, i * 8 + cl % 8)) 915 continue; 916 917 if (!mismatch && !bit && !backup_boot && 918 cl == vol->nr_clusters / 2) { 919 /* FIXME: call also boot sector check */ 920 backup_boot = 1; 921 printf("Found backup boot sector in " 922 "the middle of the volume.\n"); 923 continue; 924 } 925 926 if (++mismatch > 10 && !opt.verbose) 927 continue; 928 929 printf("Cluster accounting failed at %lld " 930 "(0x%llx): %s cluster in " 931 "$Bitmap\n", (long long)cl, 932 (unsigned long long)cl, 933 bit ? "missing" : "extra"); 934 } 935 } 936 } 937 done: 938 if (mismatch) { 939 printf("Filesystem check failed! Totally %d cluster " 940 "accounting mismatches.\n", mismatch); 941 err_printf("%s", corrupt_volume_msg); 942 exit(1); 943 } 944 } 945 946 /** 947 * progress_init 948 * 949 * Create and scale our progress bar. 950 */ 951 static void progress_init(struct progress_bar *p, u64 start, u64 stop, int flags) 952 { 953 p->start = start; 954 p->stop = stop; 955 p->unit = 100.0 / (stop - start); 956 p->resolution = 100; 957 p->flags = flags; 958 } 959 960 /** 961 * progress_update 962 * 963 * Update the progress bar and tell the user. 964 */ 965 static void progress_update(struct progress_bar *p, u64 current) 966 { 967 float percent; 968 969 if (!(p->flags & NTFS_PROGBAR)) 970 return; 971 if (p->flags & NTFS_PROGBAR_SUPPRESS) 972 return; 973 974 /* WARNING: don't modify the texts, external tools grep for them */ 975 percent = p->unit * current; 976 if (current != p->stop) { 977 if ((current - p->start) % p->resolution) 978 return; 979 printf("%6.2f percent completed\r", percent); 980 } else 981 printf("100.00 percent completed\n"); 982 fflush(stdout); 983 } 984 985 static int inode_close(ntfs_inode *ni) 986 { 987 if (ntfs_inode_close(ni)) { 988 perr_printf("ntfs_inode_close for inode %llu", 989 (unsigned long long)ni->mft_no); 990 return -1; 991 } 992 return 0; 993 } 994 995 /** 996 * walk_inodes 997 * 998 * Read each record in the MFT, skipping the unused ones, and build up a bitmap 999 * from all the non-resident attributes. 1000 */ 1001 static int build_allocation_bitmap(ntfs_volume *vol, ntfsck_t *fsck) 1002 { 1003 s64 nr_mft_records, inode = 0; 1004 ntfs_inode *ni; 1005 struct progress_bar progress; 1006 int pb_flags = 0; /* progress bar flags */ 1007 1008 /* WARNING: don't modify the text, external tools grep for it */ 1009 printf("Checking filesystem consistency ...\n"); 1010 1011 if (fsck->flags & NTFSCK_PROGBAR) 1012 pb_flags |= NTFS_PROGBAR; 1013 1014 nr_mft_records = vol->mft_na->initialized_size >> 1015 vol->mft_record_size_bits; 1016 1017 progress_init(&progress, inode, nr_mft_records - 1, pb_flags); 1018 1019 for (; inode < nr_mft_records; inode++) { 1020 progress_update(&progress, inode); 1021 1022 if ((ni = ntfs_inode_open(vol, (MFT_REF)inode)) == NULL) { 1023 /* FIXME: continue only if it make sense, e.g. 1024 MFT record not in use based on $MFT bitmap */ 1025 if (errno == EIO || errno == ENOENT) 1026 continue; 1027 perr_printf("Reading inode %lld failed", inode); 1028 return -1; 1029 } 1030 1031 if (ni->mrec->base_mft_record) 1032 goto close_inode; 1033 1034 fsck->ni = ni; 1035 if (walk_attributes(vol, fsck) != 0) { 1036 inode_close(ni); 1037 return -1; 1038 } 1039 close_inode: 1040 if (inode_close(ni) != 0) 1041 return -1; 1042 } 1043 return 0; 1044 } 1045 1046 static void build_resize_constraints(ntfs_resize_t *resize) 1047 { 1048 s64 i; 1049 runlist *rl; 1050 1051 if (!resize->ctx->attr->non_resident) 1052 return; 1053 1054 if (!(rl = ntfs_mapping_pairs_decompress(resize->vol, 1055 resize->ctx->attr, NULL))) 1056 perr_exit("ntfs_decompress_mapping_pairs"); 1057 1058 for (i = 0; rl[i].length; i++) { 1059 /* CHECKME: LCN_RL_NOT_MAPPED check isn't needed */ 1060 if (rl[i].lcn == LCN_HOLE || rl[i].lcn == LCN_RL_NOT_MAPPED) 1061 continue; 1062 1063 collect_resize_constraints(resize, rl + i); 1064 if (resize->shrink) 1065 collect_relocation_info(resize, rl + i); 1066 } 1067 free(rl); 1068 } 1069 1070 static void resize_constraints_by_attributes(ntfs_resize_t *resize) 1071 { 1072 if (!(resize->ctx = attr_get_search_ctx(resize->ni, NULL))) 1073 exit(1); 1074 1075 while (!ntfs_attrs_walk(resize->ctx)) { 1076 if (resize->ctx->attr->type == AT_END) 1077 break; 1078 build_resize_constraints(resize); 1079 } 1080 1081 ntfs_attr_put_search_ctx(resize->ctx); 1082 } 1083 1084 static void set_resize_constraints(ntfs_resize_t *resize) 1085 { 1086 s64 nr_mft_records, inode; 1087 ntfs_inode *ni; 1088 1089 printf("Collecting resizing constraints ...\n"); 1090 1091 nr_mft_records = resize->vol->mft_na->initialized_size >> 1092 resize->vol->mft_record_size_bits; 1093 1094 for (inode = 0; inode < nr_mft_records; inode++) { 1095 1096 ni = ntfs_inode_open(resize->vol, (MFT_REF)inode); 1097 if (ni == NULL) { 1098 if (errno == EIO || errno == ENOENT) 1099 continue; 1100 perr_exit("Reading inode %lld failed", inode); 1101 } 1102 1103 if (ni->mrec->base_mft_record) 1104 goto close_inode; 1105 1106 resize->ni = ni; 1107 resize_constraints_by_attributes(resize); 1108 close_inode: 1109 if (inode_close(ni) != 0) 1110 exit(1); 1111 } 1112 } 1113 1114 static void rl_fixup(runlist **rl) 1115 { 1116 runlist *tmp = *rl; 1117 1118 if (tmp->lcn == LCN_RL_NOT_MAPPED) { 1119 s64 unmapped_len = tmp->length; 1120 1121 ntfs_log_verbose("Skip unmapped run at the beginning ...\n"); 1122 1123 if (!tmp->length) 1124 err_exit("Empty unmapped runlist! Please report!\n"); 1125 (*rl)++; 1126 for (tmp = *rl; tmp->length; tmp++) 1127 tmp->vcn -= unmapped_len; 1128 } 1129 1130 for (tmp = *rl; tmp->length; tmp++) { 1131 if (tmp->lcn == LCN_RL_NOT_MAPPED) { 1132 ntfs_log_verbose("Skip unmapped run at the end ...\n"); 1133 1134 if (tmp[1].length) 1135 err_exit("Unmapped runlist in the middle! " 1136 "Please report!\n"); 1137 tmp->lcn = LCN_ENOENT; 1138 tmp->length = 0; 1139 } 1140 } 1141 } 1142 1143 static void replace_attribute_runlist(ntfs_volume *vol, 1144 ntfs_attr_search_ctx *ctx, 1145 runlist *rl) 1146 { 1147 int mp_size, l; 1148 void *mp; 1149 ATTR_RECORD *a = ctx->attr; 1150 1151 rl_fixup(&rl); 1152 1153 if ((mp_size = ntfs_get_size_for_mapping_pairs(vol, rl, 0)) == -1) 1154 perr_exit("ntfs_get_size_for_mapping_pairs"); 1155 1156 if (a->name_length) { 1157 u16 name_offs = le16_to_cpu(a->name_offset); 1158 u16 mp_offs = le16_to_cpu(a->u.nonres.mapping_pairs_offset); 1159 1160 if (name_offs >= mp_offs) 1161 err_exit("Attribute name is after mapping pairs! " 1162 "Please report!\n"); 1163 } 1164 1165 /* CHECKME: don't trust mapping_pairs is always the last item in the 1166 attribute, instead check for the real size/space */ 1167 l = (int)le32_to_cpu(a->length) - le16_to_cpu(a->u.nonres.mapping_pairs_offset); 1168 if (mp_size > l) { 1169 s64 remains_size; 1170 char *next_attr; 1171 1172 ntfs_log_verbose("Enlarging attribute header ...\n"); 1173 1174 mp_size = (mp_size + 7) & ~7; 1175 1176 ntfs_log_verbose("Old mp size : %d\n", l); 1177 ntfs_log_verbose("New mp size : %d\n", mp_size); 1178 ntfs_log_verbose("Bytes in use : %u\n", (unsigned int) 1179 le32_to_cpu(ctx->mrec->bytes_in_use)); 1180 1181 next_attr = (char *)a + le32_to_cpu(a->length); 1182 l = mp_size - l; 1183 1184 ntfs_log_verbose("Bytes in use new : %u\n", l + (unsigned int) 1185 le32_to_cpu(ctx->mrec->bytes_in_use)); 1186 ntfs_log_verbose("Bytes allocated : %u\n", (unsigned int) 1187 le32_to_cpu(ctx->mrec->bytes_allocated)); 1188 1189 remains_size = le32_to_cpu(ctx->mrec->bytes_in_use); 1190 remains_size -= (next_attr - (char *)ctx->mrec); 1191 1192 ntfs_log_verbose("increase : %d\n", l); 1193 ntfs_log_verbose("shift : %lld\n", 1194 (long long)remains_size); 1195 1196 if (le32_to_cpu(ctx->mrec->bytes_in_use) + l > 1197 le32_to_cpu(ctx->mrec->bytes_allocated)) 1198 err_exit("Extended record needed (%u > %u), not yet " 1199 "supported!\nPlease try to free less space.\n", 1200 (unsigned int)le32_to_cpu(ctx->mrec-> 1201 bytes_in_use) + l, 1202 (unsigned int)le32_to_cpu(ctx->mrec-> 1203 bytes_allocated)); 1204 1205 memmove(next_attr + l, next_attr, remains_size); 1206 ctx->mrec->bytes_in_use = cpu_to_le32(l + 1207 le32_to_cpu(ctx->mrec->bytes_in_use)); 1208 a->length = cpu_to_le32(le32_to_cpu(a->length) + l); 1209 } 1210 1211 mp = ntfs_calloc(mp_size); 1212 if (!mp) 1213 perr_exit("ntfsc_calloc couldn't get memory"); 1214 1215 if (ntfs_mapping_pairs_build(vol, mp, mp_size, rl, 0, NULL)) 1216 perr_exit("ntfs_mapping_pairs_build"); 1217 1218 memmove((u8*)a + le16_to_cpu(a->u.nonres.mapping_pairs_offset), mp, mp_size); 1219 1220 free(mp); 1221 } 1222 1223 static void set_bitmap_range(struct bitmap *bm, s64 pos, s64 length, u8 bit) 1224 { 1225 while (length--) 1226 ntfs_bit_set(bm->bm, pos++, bit); 1227 } 1228 1229 static void set_bitmap_clusters(struct bitmap *bm, runlist *rl, u8 bit) 1230 { 1231 for (; rl->length; rl++) 1232 set_bitmap_range(bm, rl->lcn, rl->length, bit); 1233 } 1234 1235 static void release_bitmap_clusters(struct bitmap *bm, runlist *rl) 1236 { 1237 max_free_cluster_range = 0; 1238 set_bitmap_clusters(bm, rl, 0); 1239 } 1240 1241 static void set_max_free_zone(s64 length, s64 end, runlist_element *rle) 1242 { 1243 if (length > rle->length) { 1244 rle->lcn = end - length; 1245 rle->length = length; 1246 } 1247 } 1248 1249 static int find_free_cluster(struct bitmap *bm, 1250 runlist_element *rle, 1251 s64 nr_vol_clusters, 1252 int hint) 1253 { 1254 /* FIXME: get rid of this 'static' variable */ 1255 static s64 pos = 0; 1256 s64 i, items = rle->length; 1257 s64 free_zone = 0; 1258 1259 if (pos >= nr_vol_clusters) 1260 pos = 0; 1261 if (!max_free_cluster_range) 1262 max_free_cluster_range = nr_vol_clusters; 1263 rle->lcn = rle->length = 0; 1264 if (hint) 1265 pos = nr_vol_clusters / 2; 1266 i = pos; 1267 1268 do { 1269 if (!ntfs_bit_get(bm->bm, i)) { 1270 if (++free_zone == items) { 1271 set_max_free_zone(free_zone, i + 1, rle); 1272 break; 1273 } 1274 } else { 1275 set_max_free_zone(free_zone, i, rle); 1276 free_zone = 0; 1277 } 1278 if (++i == nr_vol_clusters) { 1279 set_max_free_zone(free_zone, i, rle); 1280 i = free_zone = 0; 1281 } 1282 if (rle->length == max_free_cluster_range) 1283 break; 1284 } while (i != pos); 1285 1286 if (i) 1287 set_max_free_zone(free_zone, i, rle); 1288 1289 if (!rle->lcn) { 1290 errno = ENOSPC; 1291 return -1; 1292 } 1293 if (rle->length < items && rle->length < max_free_cluster_range) { 1294 max_free_cluster_range = rle->length; 1295 ntfs_log_verbose("Max free range: %7lld \n", 1296 (long long)max_free_cluster_range); 1297 } 1298 pos = rle->lcn + items; 1299 if (pos == nr_vol_clusters) 1300 pos = 0; 1301 1302 set_bitmap_range(bm, rle->lcn, rle->length, 1); 1303 return 0; 1304 } 1305 1306 static runlist *alloc_cluster(struct bitmap *bm, 1307 s64 items, 1308 s64 nr_vol_clusters, 1309 int hint) 1310 { 1311 runlist_element rle; 1312 runlist *rl = NULL; 1313 int rl_size, runs = 0; 1314 s64 vcn = 0; 1315 1316 if (items <= 0) { 1317 errno = EINVAL; 1318 return NULL; 1319 } 1320 1321 while (items > 0) { 1322 1323 if (runs) 1324 hint = 0; 1325 rle.length = items; 1326 if (find_free_cluster(bm, &rle, nr_vol_clusters, hint) == -1) 1327 return NULL; 1328 1329 rl_size = (runs + 2) * sizeof(runlist_element); 1330 if (!(rl = (runlist *)realloc(rl, rl_size))) 1331 return NULL; 1332 1333 rl_set(rl + runs, vcn, rle.lcn, rle.length); 1334 1335 vcn += rle.length; 1336 items -= rle.length; 1337 runs++; 1338 } 1339 1340 rl_set(rl + runs, vcn, -1LL, 0LL); 1341 1342 if (runs > 1) { 1343 ntfs_log_verbose("Multi-run allocation: \n"); 1344 dump_runlist(rl); 1345 } 1346 return rl; 1347 } 1348 1349 static int read_all(struct ntfs_device *dev, void *buf, int count) 1350 { 1351 int i; 1352 1353 while (count > 0) { 1354 1355 i = count; 1356 if (!NDevReadOnly(dev)) 1357 i = dev->d_ops->read(dev, buf, count); 1358 1359 if (i < 0) { 1360 if (errno != EAGAIN && errno != EINTR) 1361 return -1; 1362 } else if (i > 0) { 1363 count -= i; 1364 buf = i + (char *)buf; 1365 } else 1366 err_exit("Unexpected end of file!\n"); 1367 } 1368 return 0; 1369 } 1370 1371 static int write_all(struct ntfs_device *dev, void *buf, int count) 1372 { 1373 int i; 1374 1375 while (count > 0) { 1376 1377 i = count; 1378 if (!NDevReadOnly(dev)) 1379 i = dev->d_ops->write(dev, buf, count); 1380 1381 if (i < 0) { 1382 if (errno != EAGAIN && errno != EINTR) 1383 return -1; 1384 } else { 1385 count -= i; 1386 buf = i + (char *)buf; 1387 } 1388 } 1389 return 0; 1390 } 1391 1392 /** 1393 * write_mft_record 1394 * 1395 * Write an MFT Record back to the disk. If the read-only command line option 1396 * was given, this function will do nothing. 1397 */ 1398 static int write_mft_record(ntfs_volume *v, const MFT_REF mref, MFT_RECORD *buf) 1399 { 1400 if (ntfs_mft_record_write(v, mref, buf)) 1401 perr_exit("ntfs_mft_record_write"); 1402 1403 // if (v->u.dev->d_ops->sync(v->u.dev) == -1) 1404 // perr_exit("Failed to sync device"); 1405 1406 return 0; 1407 } 1408 1409 static void lseek_to_cluster(ntfs_volume *vol, s64 lcn) 1410 { 1411 off_t pos; 1412 pos = (off_t)(lcn * vol->cluster_size); 1413 if (vol->u.dev->d_ops->seek(vol->u.dev, pos, SEEK_SET) == (off_t)-1) 1414 perr_exit("seek failed to position %lld", lcn); 1415 } 1416 1417 static void copy_clusters(ntfs_resize_t *resize, s64 dest, s64 src, s64 len) 1418 { 1419 s64 i; 1420 char buff[NTFS_MAX_CLUSTER_SIZE]; /* overflow checked at mount time */ 1421 ntfs_volume *vol = resize->vol; 1422 1423 for (i = 0; i < len; i++) { 1424 1425 lseek_to_cluster(vol, src + i); 1426 1427 if (read_all(vol->u.dev, buff, vol->cluster_size) == -1) { 1428 perr_printf("Failed to read from the disk"); 1429 if (errno == EIO) 1430 printf("%s", bad_sectors_warning_msg); 1431 exit(1); 1432 } 1433 1434 lseek_to_cluster(vol, dest + i); 1435 1436 if (write_all(vol->u.dev, buff, vol->cluster_size) == -1) { 1437 perr_printf("Failed to write to the disk"); 1438 if (errno == EIO) 1439 printf("%s", bad_sectors_warning_msg); 1440 exit(1); 1441 } 1442 1443 resize->relocations++; 1444 progress_update(&resize->progress, resize->relocations); 1445 } 1446 } 1447 1448 static void relocate_clusters(ntfs_resize_t *r, runlist *dest_rl, s64 src_lcn) 1449 { 1450 /* collect_shrink_constraints() ensured $MFTMir DATA is one run */ 1451 if (r->mref == FILE_MFTMirr && r->ctx->attr->type == AT_DATA) { 1452 if (!r->mftmir_old) { 1453 r->mftmir_rl.lcn = dest_rl->lcn; 1454 r->mftmir_rl.length = dest_rl->length; 1455 r->mftmir_old = src_lcn; 1456 } else 1457 err_exit("Multi-run $MFTMirr. Please report!\n"); 1458 } 1459 1460 for (; dest_rl->length; src_lcn += dest_rl->length, dest_rl++) 1461 copy_clusters(r, dest_rl->lcn, src_lcn, dest_rl->length); 1462 } 1463 1464 static void rl_split_run(runlist **rl, int run, s64 pos) 1465 { 1466 runlist *rl_new, *rle_new, *rle; 1467 int items, new_size, size_head, size_tail; 1468 s64 len_head, len_tail; 1469 1470 items = rl_items(*rl); 1471 new_size = (items + 1) * sizeof(runlist_element); 1472 size_head = run * sizeof(runlist_element); 1473 size_tail = (items - run - 1) * sizeof(runlist_element); 1474 1475 rl_new = ntfs_malloc(new_size); 1476 if (!rl_new) 1477 perr_exit("ntfs_malloc"); 1478 1479 rle_new = rl_new + run; 1480 rle = *rl + run; 1481 1482 memmove(rl_new, *rl, size_head); 1483 memmove(rle_new + 2, rle + 1, size_tail); 1484 1485 len_tail = rle->length - (pos - rle->lcn); 1486 len_head = rle->length - len_tail; 1487 1488 rl_set(rle_new, rle->vcn, rle->lcn, len_head); 1489 rl_set(rle_new + 1, rle->vcn + len_head, rle->lcn + len_head, len_tail); 1490 1491 ntfs_log_verbose("Splitting run at cluster %lld:\n", (long long)pos); 1492 dump_run(rle); dump_run(rle_new); dump_run(rle_new + 1); 1493 1494 free(*rl); 1495 *rl = rl_new; 1496 } 1497 1498 static void rl_insert_at_run(runlist **rl, int run, runlist *ins) 1499 { 1500 int items, ins_items; 1501 int new_size, size_tail; 1502 runlist *rle; 1503 s64 vcn; 1504 1505 items = rl_items(*rl); 1506 ins_items = rl_items(ins) - 1; 1507 new_size = ((items - 1) + ins_items) * sizeof(runlist_element); 1508 size_tail = (items - run - 1) * sizeof(runlist_element); 1509 1510 if (!(*rl = (runlist *)realloc(*rl, new_size))) 1511 perr_exit("realloc"); 1512 1513 rle = *rl + run; 1514 1515 memmove(rle + ins_items, rle + 1, size_tail); 1516 1517 for (vcn = rle->vcn; ins->length; rle++, vcn += ins->length, ins++) { 1518 rl_set(rle, vcn, ins->lcn, ins->length); 1519 // dump_run(rle); 1520 } 1521 1522 return; 1523 1524 /* FIXME: fast path if ins_items = 1 */ 1525 // (*rl + run)->lcn = ins->lcn; 1526 } 1527 1528 static void relocate_run(ntfs_resize_t *resize, runlist **rl, int run) 1529 { 1530 s64 lcn, lcn_length; 1531 s64 new_vol_size; /* (last LCN on the volume) + 1 */ 1532 runlist *relocate_rl; /* relocate runlist to relocate_rl */ 1533 int hint; 1534 1535 lcn = (*rl + run)->lcn; 1536 lcn_length = (*rl + run)->length; 1537 new_vol_size = resize->new_volume_size; 1538 1539 if (lcn + lcn_length <= new_vol_size) 1540 return; 1541 1542 if (lcn < new_vol_size) { 1543 rl_split_run(rl, run, new_vol_size); 1544 return; 1545 } 1546 1547 hint = (resize->mref == FILE_MFTMirr) ? 1 : 0; 1548 if (!(relocate_rl = alloc_cluster(&resize->lcn_bitmap, lcn_length, 1549 new_vol_size, hint))) 1550 perr_exit("Cluster allocation failed for %llu:%lld", 1551 resize->mref, lcn_length); 1552 1553 /* FIXME: check $MFTMirr DATA isn't multi-run (or support it) */ 1554 ntfs_log_verbose("Relocate record %7llu:0x%x:%08lld:0x%08llx:0x%08llx " 1555 "--> 0x%08llx\n", (unsigned long long)resize->mref, 1556 (unsigned int)le32_to_cpu(resize->ctx->attr->type), 1557 (long long)lcn_length, 1558 (unsigned long long)(*rl + run)->vcn, 1559 (unsigned long long)lcn, 1560 (unsigned long long)relocate_rl->lcn); 1561 1562 relocate_clusters(resize, relocate_rl, lcn); 1563 rl_insert_at_run(rl, run, relocate_rl); 1564 1565 /* We don't release old clusters in the bitmap, that area isn't 1566 used by the allocator and will be truncated later on */ 1567 free(relocate_rl); 1568 1569 resize->dirty_inode = DIRTY_ATTRIB; 1570 } 1571 1572 static void relocate_attribute(ntfs_resize_t *resize) 1573 { 1574 ATTR_RECORD *a; 1575 runlist *rl; 1576 int i; 1577 1578 a = resize->ctx->attr; 1579 1580 if (!a->non_resident) 1581 return; 1582 1583 if (!(rl = ntfs_mapping_pairs_decompress(resize->vol, a, NULL))) 1584 perr_exit("ntfs_decompress_mapping_pairs"); 1585 1586 for (i = 0; rl[i].length; i++) { 1587 s64 lcn = rl[i].lcn; 1588 s64 lcn_length = rl[i].length; 1589 1590 if (lcn == LCN_HOLE || lcn == LCN_RL_NOT_MAPPED) 1591 continue; 1592 1593 /* FIXME: ntfs_mapping_pairs_decompress should return error */ 1594 if (lcn < 0 || lcn_length <= 0) 1595 err_exit("Corrupt runlist in MTF %llu attr %x LCN " 1596 "%llx length %llx\n", resize->mref, 1597 (unsigned int)le32_to_cpu(a->type), 1598 lcn, lcn_length); 1599 1600 relocate_run(resize, &rl, i); 1601 } 1602 1603 if (resize->dirty_inode == DIRTY_ATTRIB) { 1604 replace_attribute_runlist(resize->vol, resize->ctx, rl); 1605 resize->dirty_inode = DIRTY_INODE; 1606 } 1607 1608 free(rl); 1609 } 1610 1611 static int is_mftdata(ntfs_resize_t *resize) 1612 { 1613 if (resize->ctx->attr->type != AT_DATA) 1614 return 0; 1615 1616 if (resize->mref == 0) 1617 return 1; 1618 1619 if (MREF_LE(resize->mrec->base_mft_record) == 0 && 1620 MSEQNO_LE(resize->mrec->base_mft_record) != 0) 1621 return 1; 1622 1623 return 0; 1624 } 1625 1626 static int handle_mftdata(ntfs_resize_t *resize, int do_mftdata) 1627 { 1628 ATTR_RECORD *attr = resize->ctx->attr; 1629 VCN highest_vcn, lowest_vcn; 1630 1631 if (do_mftdata) { 1632 1633 if (!is_mftdata(resize)) 1634 return 0; 1635 1636 highest_vcn = sle64_to_cpu(attr->u.nonres.highest_vcn); 1637 lowest_vcn = sle64_to_cpu(attr->u.nonres.lowest_vcn); 1638 1639 if (resize->mft_highest_vcn != highest_vcn) 1640 return 0; 1641 1642 if (lowest_vcn == 0) 1643 resize->mft_highest_vcn = lowest_vcn; 1644 else 1645 resize->mft_highest_vcn = lowest_vcn - 1; 1646 1647 } else if (is_mftdata(resize)) { 1648 1649 highest_vcn = sle64_to_cpu(attr->u.nonres.highest_vcn); 1650 1651 if (resize->mft_highest_vcn < highest_vcn) 1652 resize->mft_highest_vcn = highest_vcn; 1653 1654 return 0; 1655 } 1656 1657 return 1; 1658 } 1659 1660 static void relocate_attributes(ntfs_resize_t *resize, int do_mftdata) 1661 { 1662 int ret; 1663 1664 if (!(resize->ctx = attr_get_search_ctx(NULL, resize->mrec))) 1665 exit(1); 1666 1667 while (!ntfs_attrs_walk(resize->ctx)) { 1668 if (resize->ctx->attr->type == AT_END) 1669 break; 1670 1671 if (handle_mftdata(resize, do_mftdata) == 0) 1672 continue; 1673 1674 ret = ntfs_inode_badclus_bad(resize->mref, resize->ctx->attr); 1675 if (ret == -1) 1676 perr_exit("Bad sector list check failed"); 1677 else if (ret == 1) 1678 continue; 1679 1680 if (resize->mref == FILE_Bitmap && 1681 resize->ctx->attr->type == AT_DATA) 1682 continue; 1683 1684 relocate_attribute(resize); 1685 } 1686 1687 ntfs_attr_put_search_ctx(resize->ctx); 1688 } 1689 1690 static void relocate_inode(ntfs_resize_t *resize, MFT_REF mref, int do_mftdata) 1691 { 1692 if (ntfs_file_record_read(resize->vol, mref, &resize->mrec, NULL)) { 1693 /* FIXME: continue only if it make sense, e.g. 1694 MFT record not in use based on $MFT bitmap */ 1695 if (errno == EIO || errno == ENOENT) 1696 return; 1697 perr_exit("ntfs_file_record_record"); 1698 } 1699 1700 if (!(resize->mrec->flags & MFT_RECORD_IN_USE)) 1701 return; 1702 1703 resize->mref = mref; 1704 resize->dirty_inode = DIRTY_NONE; 1705 1706 relocate_attributes(resize, do_mftdata); 1707 1708 if (resize->dirty_inode == DIRTY_INODE) { 1709 // if (vol->u.dev->d_ops->sync(vol->u.dev) == -1) 1710 // perr_exit("Failed to sync device"); 1711 if (write_mft_record(resize->vol, mref, resize->mrec)) 1712 perr_exit("Couldn't update record %llu", mref); 1713 } 1714 } 1715 1716 static void relocate_inodes(ntfs_resize_t *resize) 1717 { 1718 s64 nr_mft_records; 1719 MFT_REF mref; 1720 VCN highest_vcn; 1721 1722 printf("Relocating needed data ...\n"); 1723 1724 progress_init(&resize->progress, 0, resize->relocations, resize->progress.flags); 1725 resize->relocations = 0; 1726 1727 resize->mrec = ntfs_malloc(resize->vol->mft_record_size); 1728 if (!resize->mrec) 1729 perr_exit("ntfs_malloc failed"); 1730 1731 nr_mft_records = resize->vol->mft_na->initialized_size >> 1732 resize->vol->mft_record_size_bits; 1733 1734 for (mref = 0; mref < (MFT_REF)nr_mft_records; mref++) 1735 relocate_inode(resize, mref, 0); 1736 1737 while (1) { 1738 highest_vcn = resize->mft_highest_vcn; 1739 mref = nr_mft_records; 1740 do { 1741 relocate_inode(resize, --mref, 1); 1742 if (resize->mft_highest_vcn == 0) 1743 goto done; 1744 } while (mref); 1745 1746 if (highest_vcn == resize->mft_highest_vcn) 1747 err_exit("Sanity check failed! Highest_vcn = %lld. " 1748 "Please report!\n", highest_vcn); 1749 } 1750 done: 1751 free(resize->mrec); 1752 } 1753 1754 static void print_hint(ntfs_volume *vol, const char *s, struct llcn_t llcn) 1755 { 1756 s64 runs_b, runs_mb; 1757 1758 if (llcn.lcn == 0) 1759 return; 1760 1761 runs_b = llcn.lcn * vol->cluster_size; 1762 runs_mb = rounded_up_division(runs_b, NTFS_MBYTE); 1763 printf("%-19s: %9lld MB %8lld\n", s, (long long)runs_mb, 1764 (long long)llcn.inode); 1765 } 1766 1767 /** 1768 * advise_on_resize 1769 * 1770 * The metadata file $Bitmap has one bit for each cluster on disk. This has 1771 * already been read into lcn_bitmap. By looking for the last used cluster on 1772 * the disk, we can work out by how much we can shrink the volume. 1773 */ 1774 static void advise_on_resize(ntfs_resize_t *resize) 1775 { 1776 ntfs_volume *vol = resize->vol; 1777 1778 if (opt.verbose) { 1779 printf("Estimating smallest shrunken size supported ...\n"); 1780 printf("File feature Last used at By inode\n"); 1781 print_hint(vol, "$MFT", resize->last_mft); 1782 print_hint(vol, "Multi-Record", resize->last_multi_mft); 1783 print_hint(vol, "$MFTMirr", resize->last_mftmir); 1784 print_hint(vol, "Compressed", resize->last_compressed); 1785 print_hint(vol, "Sparse", resize->last_sparse); 1786 print_hint(vol, "Ordinary", resize->last_lcn); 1787 } 1788 1789 print_advise(vol, resize->last_unsupp); 1790 } 1791 1792 1793 static void rl_expand(runlist **rl, const VCN last_vcn) 1794 { 1795 int len; 1796 runlist *p = *rl; 1797 1798 len = rl_items(p) - 1; 1799 if (len <= 0) 1800 err_exit("rl_expand: bad runlist length: %d\n", len); 1801 1802 if (p[len].vcn > last_vcn) 1803 err_exit("rl_expand: length is already more than requested " 1804 "(%lld > %lld)\n", p[len].vcn, last_vcn); 1805 1806 if (p[len - 1].lcn == LCN_HOLE) { 1807 1808 p[len - 1].length += last_vcn - p[len].vcn; 1809 p[len].vcn = last_vcn; 1810 1811 } else if (p[len - 1].lcn >= 0) { 1812 1813 p = realloc(*rl, (++len + 1) * sizeof(runlist_element)); 1814 if (!p) 1815 perr_exit("rl_expand: realloc"); 1816 1817 p[len - 1].lcn = LCN_HOLE; 1818 p[len - 1].length = last_vcn - p[len - 1].vcn; 1819 rl_set(p + len, last_vcn, LCN_ENOENT, 0LL); 1820 *rl = p; 1821 1822 } else 1823 err_exit("rl_expand: bad LCN: %lld\n", p[len - 1].lcn); 1824 } 1825 1826 static void rl_truncate(runlist **rl, const VCN last_vcn) 1827 { 1828 int len; 1829 VCN vcn; 1830 1831 len = rl_items(*rl) - 1; 1832 if (len <= 0) 1833 err_exit("rl_truncate: bad runlist length: %d\n", len); 1834 1835 vcn = (*rl)[len].vcn; 1836 1837 if (vcn < last_vcn) 1838 rl_expand(rl, last_vcn); 1839 1840 else if (vcn > last_vcn) 1841 if (ntfs_rl_truncate(rl, last_vcn) == -1) 1842 perr_exit("ntfs_rl_truncate"); 1843 } 1844 1845 /** 1846 * bitmap_file_data_fixup 1847 * 1848 * $Bitmap can overlap the end of the volume. Any bits in this region 1849 * must be set. This region also encompasses the backup boot sector. 1850 */ 1851 static void bitmap_file_data_fixup(s64 cluster, struct bitmap *bm) 1852 { 1853 for (; cluster < bm->size << 3; cluster++) 1854 ntfs_bit_set(bm->bm, (u64)cluster, 1); 1855 } 1856 1857 /** 1858 * truncate_badclust_bad_attr 1859 * 1860 * The metadata file $BadClus needs to be shrunk. 1861 * 1862 * FIXME: this function should go away and instead using a generalized 1863 * "truncate_bitmap_data_attr()" 1864 */ 1865 static void truncate_badclust_bad_attr(ntfs_resize_t *resize) 1866 { 1867 ATTR_RECORD *a; 1868 runlist *rl_bad; 1869 s64 nr_clusters = resize->new_volume_size; 1870 ntfs_volume *vol = resize->vol; 1871 1872 a = resize->ctx->attr; 1873 if (!a->non_resident) 1874 /* FIXME: handle resident attribute value */ 1875 err_exit("Resident attribute in $BadClust isn't supported!\n"); 1876 1877 if (!(rl_bad = ntfs_mapping_pairs_decompress(vol, a, NULL))) 1878 perr_exit("ntfs_mapping_pairs_decompress"); 1879 1880 rl_truncate(&rl_bad, nr_clusters); 1881 1882 a->u.nonres.highest_vcn = cpu_to_sle64(nr_clusters - 1LL); 1883 a->u.nonres.allocated_size = cpu_to_sle64(nr_clusters * vol->cluster_size); 1884 a->u.nonres.data_size = cpu_to_sle64(nr_clusters * vol->cluster_size); 1885 1886 replace_attribute_runlist(vol, resize->ctx, rl_bad); 1887 1888 free(rl_bad); 1889 } 1890 1891 /** 1892 * realloc_bitmap_data_attr 1893 * 1894 * Reallocate the metadata file $Bitmap. It must be large enough for one bit 1895 * per cluster of the shrunken volume. Also it must be a of 8 bytes in size. 1896 */ 1897 static void realloc_bitmap_data_attr(ntfs_resize_t *resize, 1898 runlist **rl, 1899 s64 nr_bm_clusters) 1900 { 1901 s64 i; 1902 ntfs_volume *vol = resize->vol; 1903 ATTR_RECORD *a = resize->ctx->attr; 1904 s64 new_size = resize->new_volume_size; 1905 struct bitmap *bm = &resize->lcn_bitmap; 1906 1907 if (!(*rl = ntfs_mapping_pairs_decompress(vol, a, NULL))) 1908 perr_exit("ntfs_mapping_pairs_decompress"); 1909 1910 release_bitmap_clusters(bm, *rl); 1911 free(*rl); 1912 1913 for (i = vol->nr_clusters; i < new_size; i++) 1914 ntfs_bit_set(bm->bm, i, 0); 1915 1916 if (!(*rl = alloc_cluster(bm, nr_bm_clusters, new_size, 0))) 1917 perr_exit("Couldn't allocate $Bitmap clusters"); 1918 } 1919 1920 static void realloc_lcn_bitmap(ntfs_resize_t *resize, s64 bm_bsize) 1921 { 1922 u8 *tmp; 1923 1924 if (!(tmp = realloc(resize->lcn_bitmap.bm, bm_bsize))) 1925 perr_exit("realloc"); 1926 1927 resize->lcn_bitmap.bm = tmp; 1928 resize->lcn_bitmap.size = bm_bsize; 1929 bitmap_file_data_fixup(resize->new_volume_size, &resize->lcn_bitmap); 1930 } 1931 1932 /** 1933 * truncate_bitmap_data_attr 1934 */ 1935 static void truncate_bitmap_data_attr(ntfs_resize_t *resize) 1936 { 1937 ATTR_RECORD *a; 1938 runlist *rl; 1939 s64 bm_bsize, size; 1940 s64 nr_bm_clusters; 1941 ntfs_volume *vol = resize->vol; 1942 1943 a = resize->ctx->attr; 1944 if (!a->non_resident) 1945 /* FIXME: handle resident attribute value */ 1946 err_exit("Resident attribute in $Bitmap isn't supported!\n"); 1947 1948 bm_bsize = nr_clusters_to_bitmap_byte_size(resize->new_volume_size); 1949 nr_bm_clusters = rounded_up_division(bm_bsize, vol->cluster_size); 1950 1951 if (resize->shrink) { 1952 realloc_bitmap_data_attr(resize, &rl, nr_bm_clusters); 1953 realloc_lcn_bitmap(resize, bm_bsize); 1954 } else { 1955 realloc_lcn_bitmap(resize, bm_bsize); 1956 realloc_bitmap_data_attr(resize, &rl, nr_bm_clusters); 1957 } 1958 1959 a->u.nonres.highest_vcn = cpu_to_sle64(nr_bm_clusters - 1LL); 1960 a->u.nonres.allocated_size = cpu_to_sle64(nr_bm_clusters * vol->cluster_size); 1961 a->u.nonres.data_size = cpu_to_sle64(bm_bsize); 1962 a->u.nonres.initialized_size = cpu_to_sle64(bm_bsize); 1963 1964 replace_attribute_runlist(vol, resize->ctx, rl); 1965 1966 /* 1967 * FIXME: update allocated/data sizes and timestamps in $FILE_NAME 1968 * attribute too, for now chkdsk will do this for us. 1969 */ 1970 1971 size = ntfs_rl_pwrite(vol, rl, 0, bm_bsize, resize->lcn_bitmap.bm); 1972 if (bm_bsize != size) { 1973 if (size == -1) 1974 perr_exit("Couldn't write $Bitmap"); 1975 err_exit("Couldn't write full $Bitmap file (%lld from %lld)\n", 1976 (long long)size, (long long)bm_bsize); 1977 } 1978 1979 free(rl); 1980 } 1981 1982 /** 1983 * lookup_data_attr 1984 * 1985 * Find the $DATA attribute (with or without a name) for the given MFT reference 1986 * (inode number). 1987 */ 1988 static void lookup_data_attr(ntfs_volume *vol, 1989 MFT_REF mref, 1990 const char *aname, 1991 ntfs_attr_search_ctx **ctx) 1992 { 1993 ntfs_inode *ni; 1994 ntfschar *ustr; 1995 int len = 0; 1996 1997 if (!(ni = ntfs_inode_open(vol, mref))) 1998 perr_exit("ntfs_open_inode"); 1999 2000 if (!(*ctx = attr_get_search_ctx(ni, NULL))) 2001 exit(1); 2002 2003 if ((ustr = ntfs_str2ucs(aname, &len)) == NULL) { 2004 perr_printf("Couldn't convert '%s' to Unicode", aname); 2005 exit(1); 2006 } 2007 2008 if (ntfs_attr_lookup(AT_DATA, ustr, len, 0, 0, NULL, 0, *ctx)) 2009 perr_exit("ntfs_lookup_attr"); 2010 2011 ntfs_ucsfree(ustr); 2012 } 2013 2014 static int check_bad_sectors(ntfs_volume *vol) 2015 { 2016 ntfs_attr_search_ctx *ctx; 2017 ntfs_inode *base_ni; 2018 runlist *rl; 2019 s64 i, badclusters = 0; 2020 2021 ntfs_log_verbose("Checking for bad sectors ...\n"); 2022 2023 lookup_data_attr(vol, FILE_BadClus, "$Bad", &ctx); 2024 2025 base_ni = ctx->base_ntfs_ino; 2026 if (!base_ni) 2027 base_ni = ctx->ntfs_ino; 2028 2029 if (NInoAttrList(base_ni)) { 2030 err_printf("Hopelessly many bad sectors has been detected!\n"); 2031 printf("%s", many_bad_sectors_msg); 2032 exit(1); 2033 } 2034 2035 if (!ctx->attr->non_resident) 2036 err_exit("Resident attribute in $BadClust! Please report to " 2037 "%s\n", NTFS_DEV_LIST); 2038 /* 2039 * FIXME: The below would be partial for non-base records in the 2040 * not yet supported multi-record case. Alternatively use audited 2041 * ntfs_attr_truncate after an umount & mount. 2042 */ 2043 if (!(rl = ntfs_mapping_pairs_decompress(vol, ctx->attr, NULL))) 2044 perr_exit("Decompressing $BadClust:$Bad mapping pairs failed"); 2045 2046 for (i = 0; rl[i].length; i++) { 2047 /* CHECKME: LCN_RL_NOT_MAPPED check isn't needed */ 2048 if (rl[i].lcn == LCN_HOLE || rl[i].lcn == LCN_RL_NOT_MAPPED) 2049 continue; 2050 2051 badclusters += rl[i].length; 2052 ntfs_log_verbose("Bad cluster: %#8llx - %#llx (%lld)\n", 2053 rl[i].lcn, rl[i].lcn + rl[i].length - 1, 2054 rl[i].length); 2055 } 2056 2057 if (badclusters) { 2058 printf("%sThis software has detected that the disk has at least" 2059 " %lld bad sector%s.\n", 2060 !opt.badsectors ? NERR_PREFIX : "WARNING: ", 2061 badclusters, badclusters - 1 ? "s" : ""); 2062 if (!opt.badsectors) { 2063 printf("%s", bad_sectors_warning_msg); 2064 exit(1); 2065 } else 2066 printf("WARNING: Bad sectors can cause reliability " 2067 "problems and massive data loss!!!\n"); 2068 } 2069 2070 free(rl); 2071 ntfs_attr_put_search_ctx(ctx); 2072 2073 return badclusters; 2074 } 2075 2076 /** 2077 * truncate_badclust_file 2078 * 2079 * Shrink the $BadClus file to match the new volume size. 2080 */ 2081 static void truncate_badclust_file(ntfs_resize_t *resize) 2082 { 2083 printf("Updating $BadClust file ...\n"); 2084 2085 lookup_data_attr(resize->vol, FILE_BadClus, "$Bad", &resize->ctx); 2086 /* FIXME: sanity_check_attr(ctx->attr); */ 2087 truncate_badclust_bad_attr(resize); 2088 2089 if (write_mft_record(resize->vol, resize->ctx->ntfs_ino->mft_no, 2090 resize->ctx->mrec)) 2091 perr_exit("Couldn't update $BadClust"); 2092 2093 ntfs_attr_put_search_ctx(resize->ctx); 2094 } 2095 2096 /** 2097 * truncate_bitmap_file 2098 * 2099 * Shrink the $Bitmap file to match the new volume size. 2100 */ 2101 static void truncate_bitmap_file(ntfs_resize_t *resize) 2102 { 2103 printf("Updating $Bitmap file ...\n"); 2104 2105 lookup_data_attr(resize->vol, FILE_Bitmap, NULL, &resize->ctx); 2106 truncate_bitmap_data_attr(resize); 2107 2108 if (write_mft_record(resize->vol, resize->ctx->ntfs_ino->mft_no, 2109 resize->ctx->mrec)) 2110 perr_exit("Couldn't update $Bitmap"); 2111 2112 ntfs_attr_put_search_ctx(resize->ctx); 2113 } 2114 2115 /** 2116 * setup_lcn_bitmap 2117 * 2118 * Allocate a block of memory with one bit for each cluster of the disk. 2119 * All the bits are set to 0, except those representing the region beyond the 2120 * end of the disk. 2121 */ 2122 static int setup_lcn_bitmap(struct bitmap *bm, s64 nr_clusters) 2123 { 2124 /* Determine lcn bitmap byte size and allocate it. */ 2125 bm->size = rounded_up_division(nr_clusters, 8); 2126 2127 bm->bm = ntfs_calloc(bm->size); 2128 if (!bm->bm) 2129 return -1; 2130 2131 bitmap_file_data_fixup(nr_clusters, bm); 2132 return 0; 2133 } 2134 2135 /** 2136 * update_bootsector 2137 * 2138 * FIXME: should be done using ntfs_* functions 2139 */ 2140 static void update_bootsector(ntfs_resize_t *r) 2141 { 2142 NTFS_BOOT_SECTOR bs; 2143 s64 bs_size = sizeof(NTFS_BOOT_SECTOR); 2144 ntfs_volume *vol = r->vol; 2145 2146 printf("Updating Boot record ...\n"); 2147 2148 if (vol->u.dev->d_ops->seek(vol->u.dev, 0, SEEK_SET) == (off_t)-1) 2149 perr_exit("lseek"); 2150 2151 if (vol->u.dev->d_ops->read(vol->u.dev, &bs, bs_size) == -1) 2152 perr_exit("read() error"); 2153 2154 bs.number_of_sectors = cpu_to_sle64(r->new_volume_size * 2155 bs.bpb.sectors_per_cluster); 2156 2157 if (r->mftmir_old) { 2158 r->progress.flags |= NTFS_PROGBAR_SUPPRESS; 2159 copy_clusters(r, r->mftmir_rl.lcn, r->mftmir_old, 2160 r->mftmir_rl.length); 2161 bs.mftmirr_lcn = cpu_to_sle64(r->mftmir_rl.lcn); 2162 r->progress.flags &= ~NTFS_PROGBAR_SUPPRESS; 2163 } 2164 2165 if (vol->u.dev->d_ops->seek(vol->u.dev, 0, SEEK_SET) == (off_t)-1) 2166 perr_exit("lseek"); 2167 2168 if (!opt.ro_flag) 2169 if (vol->u.dev->d_ops->write(vol->u.dev, &bs, bs_size) == -1) 2170 perr_exit("write() error"); 2171 } 2172 2173 /** 2174 * vol_size 2175 */ 2176 static s64 vol_size(ntfs_volume *v, s64 nr_clusters) 2177 { 2178 /* add one sector_size for the backup boot sector */ 2179 return nr_clusters * v->cluster_size + v->sector_size; 2180 } 2181 2182 /** 2183 * print_vol_size 2184 * 2185 * Print the volume size in bytes and decimal megabytes. 2186 */ 2187 static void print_vol_size(const char *str, s64 bytes) 2188 { 2189 printf("%s: %lld bytes (%lld MB)\n", str, (long long)bytes, 2190 (long long)rounded_up_division(bytes, NTFS_MBYTE)); 2191 } 2192 2193 /** 2194 * print_disk_usage 2195 * 2196 * Display the amount of disk space in use. 2197 */ 2198 static void print_disk_usage(ntfs_volume *vol, s64 nr_used_clusters) 2199 { 2200 s64 total, used; 2201 2202 total = vol->nr_clusters * vol->cluster_size; 2203 used = nr_used_clusters * vol->cluster_size; 2204 2205 /* WARNING: don't modify the text, external tools grep for it */ 2206 printf("Space in use : %lld MB (%.1f%%)\n", 2207 (long long)rounded_up_division(used, NTFS_MBYTE), 2208 100.0 * ((float)used / total)); 2209 } 2210 2211 static void print_num_of_relocations(ntfs_resize_t *resize) 2212 { 2213 s64 relocations = resize->relocations * resize->vol->cluster_size; 2214 2215 printf("Needed relocations : %lld (%lld MB)\n", 2216 (long long)resize->relocations, (long long) 2217 rounded_up_division(relocations, NTFS_MBYTE)); 2218 } 2219 2220 /** 2221 * mount_volume 2222 * 2223 * First perform some checks to determine if the volume is already mounted, or 2224 * is dirty (Windows wasn't shutdown properly). If everything is OK, then mount 2225 * the volume (load the metadata into memory). 2226 */ 2227 static ntfs_volume *mount_volume(void) 2228 { 2229 unsigned long mntflag; 2230 ntfs_volume *vol = NULL; 2231 2232 if (ntfs_check_if_mounted(opt.volume, &mntflag)) { 2233 perr_printf("Failed to check '%s' mount state", opt.volume); 2234 printf("Probably /etc/mtab is missing. It's too risky to " 2235 "continue. You might try\nan another Linux distro.\n"); 2236 exit(1); 2237 } 2238 if (mntflag & NTFS_MF_MOUNTED) { 2239 if (!(mntflag & NTFS_MF_READONLY)) 2240 err_exit("Device '%s' is mounted read-write. " 2241 "You must 'umount' it first.\n", opt.volume); 2242 if (!opt.ro_flag) 2243 err_exit("Device '%s' is mounted. " 2244 "You must 'umount' it first.\n", opt.volume); 2245 } 2246 /* 2247 * Pass NTFS_MNT_FORENSIC so that the mount process does not modify the 2248 * volume at all. We will do the logfile emptying and dirty setting 2249 * later if needed. 2250 */ 2251 if (!(vol = ntfs_mount(opt.volume, opt.ro_flag | NTFS_MNT_FORENSIC))) { 2252 int err = errno; 2253 2254 perr_printf("Opening '%s' as NTFS failed", opt.volume); 2255 if (err == EINVAL) 2256 printf(invalid_ntfs_msg, opt.volume); 2257 else if (err == EIO) 2258 printf("%s", corrupt_volume_msg); 2259 else if (err == EPERM) 2260 printf("%s", hibernated_volume_msg); 2261 else if (err == EOPNOTSUPP) 2262 printf("%s", unclean_journal_msg); 2263 else if (err == EBUSY) 2264 printf("%s", opened_volume_msg); 2265 exit(1); 2266 } 2267 2268 if (NVolWasDirty(vol)) 2269 if (opt.force-- <= 0) 2270 err_exit("Volume is scheduled for check.\nRun chkdsk /f" 2271 " and please try again, or see option -f.\n"); 2272 2273 if (NTFS_MAX_CLUSTER_SIZE < vol->cluster_size) 2274 err_exit("Cluster size %u is too large!\n", 2275 (unsigned int)vol->cluster_size); 2276 2277 printf("Device name : %s\n", opt.volume); 2278 printf("NTFS volume version: %d.%d\n", vol->major_ver, vol->minor_ver); 2279 if (ntfs_version_is_supported(vol)) 2280 perr_exit("Unknown NTFS version"); 2281 2282 printf("Cluster size : %u bytes\n", 2283 (unsigned int)vol->cluster_size); 2284 print_vol_size("Current volume size", vol_size(vol, vol->nr_clusters)); 2285 2286 return vol; 2287 } 2288 2289 /** 2290 * prepare_volume_fixup 2291 * 2292 * Set the volume's dirty flag and wipe the filesystem journal. When Windows 2293 * boots it will automatically run chkdsk to check for any problems. If the 2294 * read-only command line option was given, this function will do nothing. 2295 */ 2296 static void prepare_volume_fixup(ntfs_volume *vol) 2297 { 2298 printf("Schedule chkdsk for NTFS consistency check at Windows boot " 2299 "time ...\n"); 2300 vol->flags |= VOLUME_IS_DIRTY; 2301 if (ntfs_volume_write_flags(vol, vol->flags)) 2302 perr_exit("Failed to set the volume dirty"); 2303 NVolSetWasDirty(vol); 2304 if (vol->u.dev->d_ops->sync(vol->u.dev) == -1) 2305 perr_exit("Failed to sync device"); 2306 printf("Resetting $LogFile ... (this might take a while)\n"); 2307 if (ntfs_logfile_reset(vol)) 2308 perr_exit("Failed to reset $LogFile"); 2309 if (vol->u.dev->d_ops->sync(vol->u.dev) == -1) 2310 perr_exit("Failed to sync device"); 2311 } 2312 2313 static void set_disk_usage_constraint(ntfs_resize_t *resize) 2314 { 2315 /* last lcn for a filled up volume (no empty space) */ 2316 s64 last = resize->inuse - 1; 2317 2318 if (resize->last_unsupp < last) 2319 resize->last_unsupp = last; 2320 } 2321 2322 static void check_resize_constraints(ntfs_resize_t *resize) 2323 { 2324 s64 new_size = resize->new_volume_size; 2325 2326 /* FIXME: resize.shrink true also if only -i is used */ 2327 if (!resize->shrink) 2328 return; 2329 2330 if (resize->inuse == resize->vol->nr_clusters) 2331 err_exit("Volume is full. To shrink it, " 2332 "delete unused files.\n"); 2333 2334 if (opt.info) 2335 return; 2336 2337 /* FIXME: reserve some extra space so Windows can boot ... */ 2338 if (new_size < resize->inuse) 2339 err_exit("New size can't be less than the space already" 2340 " occupied by data.\nYou either need to delete unused" 2341 " files or see the -i option.\n"); 2342 2343 if (new_size <= resize->last_unsupp) 2344 err_exit("The fragmentation type, you have, isn't " 2345 "supported yet. Rerun ntfsresize\nwith " 2346 "the -i option to estimate the smallest " 2347 "shrunken volume size supported.\n"); 2348 2349 print_num_of_relocations(resize); 2350 } 2351 2352 static void check_cluster_allocation(ntfs_volume *vol, ntfsck_t *fsck) 2353 { 2354 memset(fsck, 0, sizeof(ntfsck_t)); 2355 2356 if (opt.show_progress) 2357 fsck->flags |= NTFSCK_PROGBAR; 2358 2359 if (setup_lcn_bitmap(&fsck->lcn_bitmap, vol->nr_clusters) != 0) 2360 perr_exit("Failed to setup allocation bitmap"); 2361 if (build_allocation_bitmap(vol, fsck) != 0) 2362 exit(1); 2363 if (fsck->outsider || fsck->multi_ref) { 2364 err_printf("Filesystem check failed!\n"); 2365 if (fsck->outsider) 2366 err_printf("%d clusters are referenced outside " 2367 "of the volume.\n", fsck->outsider); 2368 if (fsck->multi_ref) 2369 err_printf("%d clusters are referenced multiply" 2370 " times.\n", fsck->multi_ref); 2371 printf("%s", corrupt_volume_msg); 2372 exit(1); 2373 } 2374 2375 compare_bitmaps(vol, &fsck->lcn_bitmap); 2376 } 2377 2378 int main(int argc, char **argv) 2379 { 2380 ntfsck_t fsck; 2381 ntfs_resize_t resize; 2382 s64 new_size = 0; /* in clusters; 0 = --info w/o --size */ 2383 s64 device_size; /* in bytes */ 2384 ntfs_volume *vol; 2385 2386 ntfs_log_set_handler(ntfs_log_handler_outerr); 2387 2388 printf("%s v%s (libntfs %s)\n", EXEC_NAME, VERSION, 2389 ntfs_libntfs_version()); 2390 2391 if (!parse_options(argc, argv)) 2392 return 1; 2393 2394 utils_set_locale(); 2395 2396 if (!(vol = mount_volume())) 2397 err_exit("Couldn't open volume '%s'!\n", opt.volume); 2398 2399 device_size = ntfs_device_size_get(vol->u.dev, vol->sector_size); 2400 device_size *= vol->sector_size; 2401 if (device_size <= 0) 2402 err_exit("Couldn't get device size (%lld)!\n", device_size); 2403 2404 print_vol_size("Current device size", device_size); 2405 2406 if (device_size < vol->nr_clusters * vol->cluster_size) 2407 err_exit("Current NTFS volume size is bigger than the device " 2408 "size!\nCorrupt partition table or incorrect device " 2409 "partitioning?\n"); 2410 2411 if (!opt.bytes && !opt.info) 2412 opt.bytes = device_size; 2413 2414 /* Take the integer part: don't make the volume bigger than requested */ 2415 new_size = opt.bytes / vol->cluster_size; 2416 2417 /* Backup boot sector at the end of device isn't counted in NTFS 2418 volume size thus we have to reserve space for it. */ 2419 if (new_size) 2420 --new_size; 2421 2422 if (!opt.info) { 2423 print_vol_size("New volume size ", vol_size(vol, new_size)); 2424 if (device_size < opt.bytes) 2425 err_exit("New size can't be bigger than the device size" 2426 ".\nIf you want to enlarge NTFS then first " 2427 "enlarge the device size by e.g. fdisk.\n"); 2428 } 2429 2430 if (!opt.info && (new_size == vol->nr_clusters || 2431 (opt.bytes == device_size && 2432 new_size == vol->nr_clusters - 1))) { 2433 printf("Nothing to do: NTFS volume size is already OK.\n"); 2434 exit(0); 2435 } 2436 2437 memset(&resize, 0, sizeof(resize)); 2438 resize.vol = vol; 2439 resize.new_volume_size = new_size; 2440 /* This is also true if --info was used w/o --size (new_size = 0) */ 2441 if (new_size < vol->nr_clusters) 2442 resize.shrink = 1; 2443 if (opt.show_progress) 2444 resize.progress.flags |= NTFS_PROGBAR; 2445 /* 2446 * Checking and __reporting__ of bad sectors must be done before cluster 2447 * allocation check because chkdsk doesn't fix $Bitmap's w/ bad sectors 2448 * thus users would (were) quite confused why chkdsk doesn't work. 2449 */ 2450 resize.badclusters = check_bad_sectors(vol); 2451 2452 check_cluster_allocation(vol, &fsck); 2453 2454 print_disk_usage(vol, fsck.inuse); 2455 2456 resize.inuse = fsck.inuse; 2457 resize.lcn_bitmap = fsck.lcn_bitmap; 2458 2459 set_resize_constraints(&resize); 2460 set_disk_usage_constraint(&resize); 2461 check_resize_constraints(&resize); 2462 2463 if (opt.info) { 2464 advise_on_resize(&resize); 2465 exit(0); 2466 } 2467 2468 if (opt.force-- <= 0 && !opt.ro_flag) { 2469 printf("%s", resize_warning_msg); 2470 proceed_question(); 2471 } 2472 2473 /* FIXME: performance - relocate logfile here if it's needed */ 2474 prepare_volume_fixup(vol); 2475 2476 if (resize.relocations) 2477 relocate_inodes(&resize); 2478 2479 truncate_badclust_file(&resize); 2480 truncate_bitmap_file(&resize); 2481 update_bootsector(&resize); 2482 2483 /* We don't create backup boot sector because we don't know where the 2484 partition will be split. The scheduled chkdsk will fix it */ 2485 2486 if (opt.ro_flag) { 2487 printf("The read-only test run ended successfully.\n"); 2488 exit(0); 2489 } 2490 2491 /* WARNING: don't modify the texts, external tools grep for them */ 2492 printf("Syncing device ...\n"); 2493 if (vol->u.dev->d_ops->sync(vol->u.dev) == -1) 2494 perr_exit("fsync"); 2495 2496 printf("Successfully resized NTFS on device '%s'.\n", vol->u.dev->d_name); 2497 if (resize.shrink) 2498 printf("%s", resize_important_msg); 2499 2500 return 0; 2501 }