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