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