2 * ntfsresize - Part of the Linux-NTFS project.
4 * Copyright (c) 2002-2003 Szabolcs Szakacsits
5 * Copyright (c) 2002-2003 Anton Altaparmakov
6 * Copyright (c) 2002-2003 Richard Russon
8 * This utility will resize an NTFS volume.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program (in the main directory of the Linux-NTFS
22 * distribution in the file COPYING); if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
50 static const char *EXEC_NAME = "ntfsresize";
52 static const char *resize_warning_msg =
53 "WARNING: Every sanity check passed and only the DANGEROUS operations left.\n"
54 "Please make sure all your important data had been backed up in case of an\n"
55 "unexpected failure!\n";
57 static const char *resize_important_msg =
58 "You can go on to shrink the device e.g. with 'fdisk'.\n"
59 "IMPORTANT: When recreating the partition, make sure you\n"
60 " 1) create it with the same starting disk cylinder\n"
61 " 2) create it with the same partition type (usually 7, HPFS/NTFS)\n"
62 " 3) do not make it smaller than the new NTFS filesystem size\n"
63 " 4) set the bootable flag for the partition if it existed before\n"
64 "Otherwise you may lose your data or can't boot your computer from the disk!\n";
66 static const char *fragmented_volume_msg =
67 "The volume end is fragmented, this case is not yet supported. Defragment it\n"
68 "(Windows 2000, XP and .NET have built in defragmentation tool) and try again.\n";
93 struct __ntfs_resize_t {
95 ntfs_inode *ni; /* inode being processed */
96 ntfs_attr_search_ctx *ctx; /* inode attribute being processed */
97 u64 relocations; /* num of clusters to relocate */
98 u64 inuse; /* num of clusters in use */
99 int multi_ref; /* num of clusters ref'd many times */
102 typedef struct __ntfs_resize_t ntfs_resize_t;
104 ntfs_volume *vol = NULL;
105 struct bitmap lcn_bitmap;
107 #define NTFS_MBYTE (1000 * 1000)
109 #define ERR_PREFIX "ERROR"
110 #define PERR_PREFIX ERR_PREFIX "(%d): "
111 #define NERR_PREFIX ERR_PREFIX ": "
113 #define rounded_up_division(a, b) (((a) + (b - 1)) / (b))
115 GEN_PRINTF (Eprintf, stderr, NULL, FALSE)
116 GEN_PRINTF (Vprintf, stdout, &opt.verbose, TRUE)
117 GEN_PRINTF (Qprintf, stdout, &opt.quiet, FALSE)
122 * Print an error message.
124 void perr_printf(const char *fmt, ...)
129 fprintf(stdout, PERR_PREFIX, eo);
131 vfprintf(stdout, fmt, ap);
133 printf(": %s\n", strerror(eo));
141 * Print and error message and exit the program.
143 int err_exit(const char *fmt, ...)
147 fprintf(stdout, NERR_PREFIX);
149 vfprintf(stdout, fmt, ap);
159 * Print and error message and exit the program
161 int perr_exit(const char *fmt, ...)
166 fprintf(stdout, PERR_PREFIX, eo);
168 vfprintf(stdout, fmt, ap);
170 printf(": %s\n", strerror(eo));
177 * usage - Print a list of the parameters to the program
179 * Print a list of the parameters and options for the program.
186 printf ("\nUsage: %s [options] device\n"
187 " Resize an NTFS volume non-destructively.\n"
189 " -i --info Calculate the smallest shrunken size supported\n"
190 " -s num --size num Resize volume to num[k|M|G] bytes\n"
192 " -n --no-action Do not write to disk\n"
193 " -f --force Force to progress (DANGEROUS)\n"
194 /* " -q --quiet Less output\n"*/
195 /* " -v --verbose More output\n"*/
196 " -V --version Display version information\n"
197 " -h --help Display this help\n"
199 " -d --debug Show debug information\n"
202 " The options -i and -s are mutually exclusive. If both options are\n"
203 " omitted then the NTFS volume will be enlarged to the device size.\n"
205 printf ("%s%s\n", ntfs_bugs, ntfs_home);
212 * Force the user to confirm an action before performing it.
213 * Copy-paste from e2fsprogs
215 void proceed_question(void)
218 const char *short_yes = "yY";
222 printf("Are you sure you want to proceed (y/[n])? ");
224 fgets(buf, sizeof(buf), stdin);
225 if (strchr(short_yes, buf[0]) == 0) {
226 printf("OK quitting. NO CHANGES have been made to your "
233 * version - Print version information about the program
235 * Print a copyright statement and a brief description of the program.
241 printf ("\nResize an NTFS Volume, without data loss.\n\n");
242 printf ("Copyright (c)\n");
243 printf (" 2002-2003 Szabolcs Szakacsits\n");
244 printf (" 2002-2003 Anton Altaparmakov\n");
245 printf (" 2002-2003 Richard Russon\n");
246 printf ("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
250 * get_new_volume_size
252 * Convert a user-supplied string into a size. Without any suffix the number
253 * will be assumed to be in bytes. If the number has a suffix of k, M or G it
254 * will be scaled up by 1000, 1000000, or 1000000000.
256 s64 get_new_volume_size(char *s)
260 int prefix_kind = 1000;
262 size = strtoll(s, &suffix, 10);
263 if (size <= 0 || errno == ERANGE)
264 err_exit("Illegal new volume size\n");
269 if (strlen(suffix) == 2 && suffix[1] == 'i')
271 else if (strlen(suffix) > 1)
274 /* We follow the SI prefixes:
275 http://physics.nist.gov/cuu/Units/prefixes.html
276 http://physics.nist.gov/cuu/Units/binary.html
277 Disk partitioning tools use prefixes as,
279 old fdisk 2^10 2^20 10^3*2^20
280 recent fdisk 10^3 10^6 10^9
281 cfdisk 10^3 10^6 10^9
283 parted 2^10 2^20 (may change)
284 fdisk (DOS) 2^10 2^20
286 /* FIXME: check for overflow */
303 * parse_options - Read and validate the programs command line
305 * Read the command line, verify the syntax and parse the options.
306 * This function is very long, but quite simple.
309 * 0 Error, one or more problems
311 int parse_options(int argc, char **argv)
313 static const char *sopt = "-dfhins:vV";
314 static const struct option lopt[] = {
316 { "debug", no_argument, NULL, 'd' },
318 { "force", no_argument, NULL, 'f' },
319 { "help", no_argument, NULL, 'h' },
320 { "info", no_argument, NULL, 'i' },
321 { "no-action", no_argument, NULL, 'n' },
322 /* { "quiet", no_argument, NULL, 'q' },*/
323 { "size", required_argument, NULL, 's' },
324 /* { "verbose", no_argument, NULL, 'v' },*/
325 { "version", no_argument, NULL, 'V' },
334 memset(&opt, 0, sizeof(opt));
336 while ((c = getopt_long (argc, argv, sopt, lopt, NULL)) != -1) {
338 case 1: /* A non-option argument */
339 if (!err && !opt.volume)
340 opt.volume = argv[optind-1];
358 opt.ro_flag = MS_RDONLY;
364 if (!err && (opt.bytes == 0))
365 opt.bytes = get_new_volume_size(optarg);
377 Eprintf ("Option '%s' requires an argument.\n", argv[optind-1]);
379 Eprintf ("Unknown option '%s'.\n", argv[optind-1]);
389 if (opt.volume == NULL) {
391 Eprintf ("You must specify exactly one device.\n");
396 if (opt.quiet && opt.verbose) {
397 Eprintf ("You may not use --quiet and --verbose at the same time.\n");
403 opt.ro_flag = MS_RDONLY;
405 Eprintf (NERR_PREFIX "Options --info and --size"
406 " can't be used together.\n");
416 if (!(stderr = fopen("/dev/null", "rw")))
417 perr_exit("Couldn't open /dev/null");
425 return (!err && !help && !ver);
429 * runlist_extent_number
431 * Count the runs in a runlist.
433 int runlist_extent_number(runlist *rl)
437 for (i = 0; rl[i].length; i++)
444 * nr_clusters_to_bitmap_byte_size
446 * Take the number of clusters in the volume and calculate the size of $Bitmap.
447 * The size will always be a multiple of 8 bytes.
449 s64 nr_clusters_to_bitmap_byte_size(s64 nr_clusters)
453 bm_bsize = rounded_up_division(nr_clusters, 8);
455 bm_bsize = (bm_bsize + 7) & ~7;
456 Dprintf("Bitmap byte size : %lld (%lld clusters)\n",
457 bm_bsize, rounded_up_division(bm_bsize, vol->cluster_size));
463 * build_lcn_usage_bitmap
465 * lcn_bitmap has one bit for each cluster on the disk. Initially, lcn_bitmap
466 * has no bits set. As each attribute record is read the bits in lcn_bitmap are
467 * checked to ensure that no other file already references that cluster.
469 * This serves as a rudimentary "chkdsk" operation.
471 void build_lcn_usage_bitmap(ntfs_resize_t *resize)
473 s64 new_volume_size, inode;
478 a = resize->ctx->attr;
479 new_volume_size = resize->new_volume_size;
480 inode = resize->ni->mft_no;
482 if (!a->non_resident)
485 if (!(rl = ntfs_mapping_pairs_decompress(vol, a, NULL)))
486 perr_exit("ntfs_decompress_mapping_pairs");
488 //runs = runlist_extent_number(rl);
490 for (i = 0; rl[i].length; i++) {
492 s64 lcn_length = rl[i].length;
494 if (lcn == LCN_HOLE || lcn == LCN_RL_NOT_MAPPED)
497 /* FIXME: ntfs_mapping_pairs_decompress should return error */
498 if (lcn < 0 || lcn_length <= 0)
499 err_exit("Corrupt runlist in inode %lld attr %x LCN "
500 "%llx length %llx\n", inode,
501 le32_to_cpu (a->type), lcn, lcn_length);
503 for (j = 0; j < lcn_length; j++) {
504 u64 k = (u64)lcn + j;
505 if (ntfs_bit_get_and_set(lcn_bitmap.bm, k, 1)) {
507 if (++resize->multi_ref > 10)
510 printf("Cluster %Lu (0x%Lx) referenced "
511 "multiply times!\n", k, k);
515 resize->inuse += lcn_length;
520 if (lcn + (lcn_length - 1) > new_volume_size) {
523 s64 len = lcn_length;
525 if (start <= new_volume_size) {
526 start = new_volume_size + 1;
527 len = lcn_length - (start - lcn);
530 resize->relocations += len;
539 * For a given MFT Record, iterate through all its attributes. Any non-resident
540 * data runs will be marked in lcn_bitmap.
542 void walk_attributes(ntfs_resize_t *resize)
544 ntfs_attr_search_ctx *ctx;
546 if (!(ctx = ntfs_attr_get_search_ctx(resize->ni, NULL)))
547 perr_exit("ntfs_get_attr_search_ctx");
549 while (!ntfs_attrs_walk(ctx)) {
550 if (ctx->attr->type == AT_END)
553 build_lcn_usage_bitmap(resize);
556 ntfs_attr_put_search_ctx(ctx);
562 * Compare two bitmaps. In this case, $Bitmap as read from the disk and
563 * lcn_bitmap which we built from the MFT Records.
565 void compare_bitmaps(struct bitmap *a)
569 u8 bm[NTFS_BUF_SIZE];
571 printf("Accounting clusters ...\n");
575 count = ntfs_attr_pread(vol->lcnbmp_na, pos, NTFS_BUF_SIZE, bm);
577 perr_exit("Couldn't get $Bitmap $DATA");
581 err_exit("$Bitmap file size doesn't match "
582 "calculated size ((%Ld != %Ld)\n",
587 for (i = 0; i < count; i++, pos++) {
588 u64 cl; /* current cluster */
590 if (a->bm[pos] == bm[i])
593 for (cl = pos * 8; cl < (pos + 1) * 8; cl++) {
596 bit = ntfs_bit_get(a->bm, cl);
597 if (bit == ntfs_bit_get(bm, i * 8 + cl % 8))
603 printf("Cluster accounting failed at %Lu "
604 "(0x%Lx): %s cluster in $Bitmap\n",
605 cl, cl, bit ? "missing" : "extra");
611 printf("Totally %d cluster accounting mismatches.\n",
613 err_exit("Filesystem check failed! Windows wasn't shutdown "
614 "properly or inconsistent\nfilesystem. Please run "
615 "chkdsk on Windows.\n");
622 * Create and scale our progress bar.
624 void progress_init(struct progress_bar *p, u64 start, u64 stop, int res)
628 p->unit = 100.0 / (stop - start);
635 * Update the progress bar and tell the user.
637 void progress_update(struct progress_bar *p, u64 current)
639 float percent = p->unit * current;
641 if (current != p->stop) {
642 if ((current - p->start) % p->resolution)
644 printf("%6.2f percent completed\r", percent);
646 printf("100.00 percent completed\n");
653 * Read each record in the MFT, skipping the unused ones, and build up a bitmap
654 * from all the non-resident attributes.
656 void walk_inodes(ntfs_resize_t *resize)
661 struct progress_bar progress;
663 printf("Checking filesystem consistency ...\n");
665 last_mft_rec = vol->nr_mft_records - 1;
666 progress_init(&progress, inode, last_mft_rec, 100);
668 for (; inode <= last_mft_rec; inode++) {
669 progress_update(&progress, inode);
671 if ((ni = ntfs_inode_open(vol, (MFT_REF)inode)) == NULL) {
672 /* FIXME: continue only if it make sense, e.g.
673 MFT record not in use based on $MFT bitmap */
674 if (errno == EIO || errno == ENOENT)
676 perr_exit("Reading inode %lld failed", inode);
679 if (!(ni->mrec->flags & MFT_RECORD_IN_USE))
682 if ((ni->mrec->base_mft_record) != 0)
686 walk_attributes(resize);
688 if (ntfs_inode_close(ni))
689 perr_exit("ntfs_inode_close for inode %Ld", inode);
696 * The metadata file $Bitmap has one bit for each cluster on disk. This has
697 * already been read into lcn_bitmap. By looking for the last used cluster on
698 * the disk, we can work out by how much we can shrink the volume.
700 void advise_on_resize()
702 s64 i, old_b, new_b, g_b, old_mb, new_mb, g_mb;
705 printf("Calculating smallest shrunken size supported ...\n");
707 for (i = vol->nr_clusters - 1; i > 0 && (i % 8); i--)
708 if (ntfs_bit_get(lcn_bitmap.bm, i))
709 goto found_used_cluster;
712 if (ntfs_bit_get(lcn_bitmap.bm, i))
713 goto found_used_cluster;
715 goto found_used_cluster;
717 for (i -= 8; i >= 0; i -= 8)
718 if (lcn_bitmap.bm[i / 8])
721 for (i += 7; i > 0; i--)
722 if (ntfs_bit_get(lcn_bitmap.bm, i))
726 i += 2; /* first free + we reserve one for the backup boot sector */
727 fragmanted_end = (i >= vol->nr_clusters) ? 1 : 0;
729 if (fragmanted_end || !opt.info) {
730 printf(fragmented_volume_msg);
736 old_b = vol->nr_clusters * vol->cluster_size;
737 old_mb = rounded_up_division(old_b, NTFS_MBYTE);
738 new_b = i * vol->cluster_size;
739 new_mb = rounded_up_division(new_b, NTFS_MBYTE);
740 g_b = (vol->nr_clusters - i) * vol->cluster_size;
741 g_mb = g_b / NTFS_MBYTE;
743 printf("You could resize at %lld bytes ", new_b);
745 if ((new_mb * NTFS_MBYTE) < old_b)
746 printf("or %lld MB ", new_mb);
750 if (g_mb && (old_mb - new_mb))
751 printf("%lld MB", old_mb - new_mb);
753 printf("%lld bytes", g_b);
759 * look_for_bad_sector
761 * Read through the metadata file $BadClus looking for bad sectors on the disk.
763 void look_for_bad_sector(ATTR_RECORD *a)
768 rl = ntfs_mapping_pairs_decompress(vol, a, NULL);
770 perr_exit("ntfs_mapping_pairs_decompress");
772 for (i = 0; rl[i].length; i++)
773 if (rl[i].lcn != LCN_HOLE)
774 err_exit("Device has bad sectors, not supported\n");
782 * Helper to set up a runlist object
784 void rl_set(runlist *rl, VCN vcn, LCN lcn, s64 len)
792 * bitmap_file_data_fixup
794 * $Bitmap can overlap the end of the volume. Any bits in this region
795 * must be set. This region also encompasses the backup boot sector.
797 void bitmap_file_data_fixup(s64 cluster, struct bitmap *bm)
799 for (; cluster < bm->size << 3; cluster++)
800 ntfs_bit_set(bm->bm, (u64)cluster, 1);
804 * truncate_badclust_bad_attr
806 * The metadata file $BadClus needs to be shrunk.
808 * FIXME: this function should go away and instead using a generalized
809 * "truncate_bitmap_data_attr()"
811 void truncate_badclust_bad_attr(ATTR_RECORD *a, s64 nr_clusters)
817 if (!a->non_resident)
818 /* FIXME: handle resident attribute value */
819 perr_exit("Resident attribute in $BadClust not supported!");
821 if (!(rl_bad = (runlist *)malloc(2 * sizeof(runlist))))
822 perr_exit("Couldn't get memory");
824 rl_set(rl_bad, 0LL, (LCN)LCN_HOLE, nr_clusters);
825 rl_set(rl_bad + 1, nr_clusters, -1LL, 0LL);
827 if ((mp_size = ntfs_get_size_for_mapping_pairs(vol, rl_bad)) == -1)
828 perr_exit("ntfs_get_size_for_mapping_pairs");
830 if (mp_size > le32_to_cpu (a->length) -
831 le16_to_cpu (a->mapping_pairs_offset))
832 err_exit("Enlarging attribute header isn't supported yet.\n");
834 if (!(mp = (char *)calloc(1, mp_size)))
835 perr_exit("Couldn't get memory");
837 if (ntfs_mapping_pairs_build(vol, mp, mp_size, rl_bad))
838 perr_exit("ntfs_mapping_pairs_build");
840 memcpy((char *)a + le16_to_cpu (a->mapping_pairs_offset), mp, mp_size);
841 a->highest_vcn = cpu_to_le64(nr_clusters - 1LL);
842 a->allocated_size = cpu_to_le64(nr_clusters * vol->cluster_size);
843 a->data_size = cpu_to_le64(nr_clusters * vol->cluster_size);
850 * shrink_bitmap_data_attr
852 * Shrink the metadata file $Bitmap. It must be large enough for one bit per
853 * cluster of the shrunken volume. Also it must be a of 8 bytes in size.
855 void shrink_bitmap_data_attr(runlist **rlist, s64 nr_bm_clusters, s64 new_size)
857 runlist *rl = *rlist;
860 int trunc_at = -1; /* FIXME: -1 means unset */
862 /* Unallocate truncated clusters in $Bitmap */
863 for (i = 0; rl[i].length; i++) {
864 if (rl[i].vcn + rl[i].length <= nr_bm_clusters)
868 if (rl[i].lcn == LCN_HOLE || rl[i].lcn == LCN_RL_NOT_MAPPED)
870 for (j = 0; j < rl[i].length; j++) {
871 if (rl[i].vcn + j < nr_bm_clusters)
874 k = (u64)rl[i].lcn + j;
876 ntfs_bit_set(lcn_bitmap.bm, k, 0);
877 Dprintf("Unallocate cluster: "
878 "%llu (%llx)\n", k, k);
883 if (trunc_at != -1) {
884 /* NOTE: 'i' always > 0 */
885 i = nr_bm_clusters - rl[trunc_at].vcn;
886 rl[trunc_at].length = i;
887 rl_set(rl + trunc_at + 1, nr_bm_clusters, -1LL, 0LL);
889 Dprintf("Runlist truncated at index %d, "
890 "new cluster length %d\n", trunc_at, i);
895 * enlarge_bitmap_data_attr
897 * Enlarge the metadata file $Bitmap. It must be large enough for one bit per
898 * cluster of the shrunken volume. Also it must be a of 8 bytes in size.
900 void enlarge_bitmap_data_attr(runlist **rlist, s64 nr_bm_clusters, s64 new_size)
902 runlist *rl = *rlist;
903 s64 i, j, free_zone = 0;
905 for (i = 0; rl[i].length; i++)
906 for (j = 0; j < rl[i].length; j++)
907 ntfs_bit_set(lcn_bitmap.bm, rl[i].lcn + j, 0);
910 if (!(rl = *rlist = (runlist *)malloc(2 * sizeof(runlist))))
911 perr_exit("Couldn't get memory");
913 for (i = vol->nr_clusters; i < new_size; i++)
914 ntfs_bit_set(lcn_bitmap.bm, i, 0);
916 for (i = 0; i < new_size; i++) {
917 if (!ntfs_bit_get(lcn_bitmap.bm, i)) {
918 if (++free_zone == nr_bm_clusters)
924 if (free_zone != nr_bm_clusters)
925 err_exit("Couldn't allocate $Bitmap clusters.\n");
927 for (; free_zone; free_zone--, i--)
928 ntfs_bit_set(lcn_bitmap.bm, i, 1);
930 rl_set(rl, 0LL, i + 1, nr_bm_clusters);
931 rl_set(rl + 1, nr_bm_clusters, -1LL, 0LL);
935 * truncate_bitmap_data_attr
937 void truncate_bitmap_data_attr(ATTR_RECORD *a, s64 nr_clusters)
946 if (!a->non_resident)
947 /* FIXME: handle resident attribute value */
948 perr_exit("Resident data attribute in $Bitmap not supported!");
950 bm_bsize = nr_clusters_to_bitmap_byte_size(nr_clusters);
951 nr_bm_clusters = rounded_up_division(bm_bsize, vol->cluster_size);
953 if (!(tmp = (u8 *)realloc(lcn_bitmap.bm, bm_bsize)))
954 perr_exit("realloc");
956 lcn_bitmap.size = bm_bsize;
957 bitmap_file_data_fixup(nr_clusters, &lcn_bitmap);
959 if (!(rl = ntfs_mapping_pairs_decompress(vol, a, NULL)))
960 perr_exit("ntfs_mapping_pairs_decompress");
962 if (nr_clusters < vol->nr_clusters)
963 shrink_bitmap_data_attr(&rl, nr_bm_clusters, nr_clusters);
965 enlarge_bitmap_data_attr(&rl, nr_bm_clusters, nr_clusters);
967 if ((mp_size = ntfs_get_size_for_mapping_pairs(vol, rl)) == -1)
968 perr_exit("ntfs_get_size_for_mapping_pairs");
970 if (mp_size > le32_to_cpu (a->length) -
971 le16_to_cpu (a->mapping_pairs_offset))
972 err_exit("Enlarging attribute header isn't supported yet.\n");
974 if (!(mp = (char *)calloc(1, mp_size)))
975 perr_exit("Couldn't get memory");
977 if (ntfs_mapping_pairs_build(vol, mp, mp_size, rl))
978 perr_exit("ntfs_mapping_pairs_build");
980 memcpy((char *)a + le16_to_cpu (a->mapping_pairs_offset), mp, mp_size);
981 a->highest_vcn = cpu_to_le64(nr_bm_clusters - 1LL);
982 a->allocated_size = cpu_to_le64(nr_bm_clusters * vol->cluster_size);
983 a->data_size = cpu_to_le64(bm_bsize);
984 a->initialized_size = cpu_to_le64(bm_bsize);
987 * FIXME: update allocated/data sizes and timestamps in $FILE_NAME
988 * attribute too, for now chkdsk will do this for us.
991 size = ntfs_rl_pwrite(vol, rl, 0, bm_bsize, lcn_bitmap.bm);
992 if (bm_bsize != size) {
994 perr_exit("Couldn't write $Bitmap");
995 printf("Couldn't write full $Bitmap file "
996 "(%lld from %lld)\n", size, bm_bsize);
1007 * Find the $DATA attribute (with or without a name) for the given MFT reference
1010 void lookup_data_attr(MFT_REF mref, char *aname, ntfs_attr_search_ctx **ctx)
1013 uchar_t *ustr = NULL;
1016 if (!(ni = ntfs_inode_open(vol, mref)))
1017 perr_exit("ntfs_open_inode");
1019 if (NInoAttrList(ni))
1020 perr_exit("Attribute list attribute not yet supported");
1022 if (!(*ctx = ntfs_attr_get_search_ctx(ni, NULL)))
1023 perr_exit("ntfs_get_attr_search_ctx");
1025 if (aname && ((len = ntfs_mbstoucs(aname, &ustr, 0)) == -1))
1026 perr_exit("Unable to convert string to Unicode");
1028 if (!ustr || !len) {
1033 if (ntfs_attr_lookup(AT_DATA, ustr, len, 0, 0, NULL, 0, *ctx))
1034 perr_exit("ntfs_lookup_attr");
1036 if (ustr != AT_UNNAMED)
1043 * Write an MFT Record back to the disk. If the read-only command line option
1044 * was given, this function will do nothing.
1046 int write_mft_record(ntfs_attr_search_ctx *ctx)
1048 if (ntfs_mft_record_write(vol, ctx->ntfs_ino->mft_no, ctx->mrec))
1049 perr_exit("ntfs_mft_record_write");
1051 if (vol->dev->d_ops->sync(vol->dev) == -1)
1052 perr_exit("Failed to sync device");
1058 * truncate_badclust_file
1060 * Shrink the $BadClus file to match the new volume size.
1062 void truncate_badclust_file(s64 nr_clusters)
1064 ntfs_attr_search_ctx *ctx = NULL;
1066 printf("Updating $BadClust file ...\n");
1068 lookup_data_attr((MFT_REF)FILE_BadClus, "$Bad", &ctx);
1069 look_for_bad_sector(ctx->attr);
1070 /* FIXME: sanity_check_attr(ctx->attr); */
1071 truncate_badclust_bad_attr(ctx->attr, nr_clusters);
1073 if (write_mft_record(ctx))
1074 perr_exit("Couldn't update $BadClust");
1076 ntfs_attr_put_search_ctx(ctx);
1080 * truncate_bitmap_file
1082 * Shrink the $Bitmap file to match the new volume size.
1084 void truncate_bitmap_file(s64 nr_clusters)
1086 ntfs_attr_search_ctx *ctx = NULL;
1088 printf("Updating $Bitmap file ...\n");
1090 lookup_data_attr((MFT_REF)FILE_Bitmap, NULL, &ctx);
1091 /* FIXME: sanity_check_attr(ctx->attr); */
1092 truncate_bitmap_data_attr(ctx->attr, nr_clusters);
1094 if (write_mft_record(ctx))
1095 perr_exit("Couldn't update $Bitmap");
1097 ntfs_attr_put_search_ctx(ctx);
1103 * Allocate a block of memory with one bit for each cluster of the disk.
1104 * All the bits are set to 0, except those representing the region beyond the
1107 void setup_lcn_bitmap()
1109 /* Determine lcn bitmap byte size and allocate it. */
1110 lcn_bitmap.size = nr_clusters_to_bitmap_byte_size(vol->nr_clusters);
1112 if (!(lcn_bitmap.bm = (unsigned char *)calloc(1, lcn_bitmap.size)))
1113 perr_exit("Failed to allocate internal buffer");
1115 bitmap_file_data_fixup(vol->nr_clusters, &lcn_bitmap);
1121 * FIXME: should be done using ntfs_* functions
1123 void update_bootsector(s64 nr_clusters)
1125 NTFS_BOOT_SECTOR bs;
1127 printf("Updating Boot record ...\n");
1129 if (vol->dev->d_ops->seek(vol->dev, 0, SEEK_SET) == (off_t)-1)
1132 if (vol->dev->d_ops->read(vol->dev, &bs,
1133 sizeof(NTFS_BOOT_SECTOR)) == -1)
1134 perr_exit("read() error");
1136 bs.number_of_sectors = nr_clusters * bs.bpb.sectors_per_cluster;
1137 bs.number_of_sectors = cpu_to_le64(bs.number_of_sectors);
1139 if (vol->dev->d_ops->seek(vol->dev, 0, SEEK_SET) == (off_t)-1)
1143 if (vol->dev->d_ops->write(vol->dev, &bs,
1144 sizeof(NTFS_BOOT_SECTOR)) == -1)
1145 perr_exit("write() error");
1151 s64 volume_size(ntfs_volume *vol, s64 nr_clusters)
1153 return nr_clusters * vol->cluster_size;
1159 * Print the volume size in bytes and decimal megabytes.
1161 void print_volume_size(char *str, s64 bytes)
1163 printf("%s: %lld bytes (%lld MB)\n",
1164 str, bytes, rounded_up_division(bytes, NTFS_MBYTE));
1170 * Display the amount of disk space in use.
1172 void print_disk_usage(ntfs_resize_t *resize)
1174 s64 total, used, free, relocations;
1176 total = vol->nr_clusters * vol->cluster_size;
1177 used = resize->inuse * vol->cluster_size;
1178 free = total - used;
1179 relocations = resize->relocations * vol->cluster_size;
1181 printf("Space in use : %lld MB (%.1f%%) ",
1182 rounded_up_division(used, NTFS_MBYTE),
1183 100.0 * ((float)used / total));
1191 * First perform some checks to determine if the volume is already mounted, or
1192 * is dirty (Windows wasn't shutdown properly). If everything is OK, then mount
1193 * the volume (load the metadata into memory).
1197 unsigned long mntflag;
1199 if (ntfs_check_if_mounted(opt.volume, &mntflag))
1200 perr_exit("Failed to check '%s' mount state", opt.volume);
1202 if (mntflag & NTFS_MF_MOUNTED) {
1203 if (!(mntflag & NTFS_MF_READONLY))
1204 err_exit("Device %s is mounted read-write. "
1205 "You must 'umount' it first.\n", opt.volume);
1207 err_exit("Device %s is mounted. "
1208 "You must 'umount' it first.\n", opt.volume);
1211 if (!(vol = ntfs_mount(opt.volume, opt.ro_flag))) {
1215 perr_printf("ntfs_mount failed");
1216 if (err == EINVAL) {
1217 printf("Apparently device '%s' doesn't have a "
1218 "valid NTFS. Maybe you selected\nthe whole "
1219 "disk instead of a partition (e.g. /dev/hda, "
1220 "not /dev/hda1)?\n", opt.volume);
1225 if (vol->flags & VOLUME_IS_DIRTY)
1226 if (opt.force-- <= 0)
1227 err_exit("Volume is dirty. Run chkdsk and "
1228 "please try again (or see -f option).\n");
1230 printf("NTFS volume version: %d.%d\n", vol->major_ver, vol->minor_ver);
1231 if (ntfs_version_is_supported(vol))
1232 perr_exit("Unknown NTFS version");
1234 printf("Cluster size : %u bytes\n", vol->cluster_size);
1235 print_volume_size("Current volume size",
1236 volume_size(vol, vol->nr_clusters));
1240 * prepare_volume_fixup
1242 * Set the volume's dirty flag and wipe the filesystem journal. When Windows
1243 * boots it will automatically run chkdsk to check for any problems. If the
1244 * read-only command line option was given, this function will do nothing.
1246 void prepare_volume_fixup()
1250 flags = vol->flags | VOLUME_IS_DIRTY;
1251 if (vol->major_ver >= 2)
1252 flags |= VOLUME_MOUNTED_ON_NT4;
1254 printf("Schedule chkdsk for NTFS consistency check at Windows "
1257 if (ntfs_volume_set_flags(vol, flags))
1258 perr_exit("Failed to set $Volume dirty");
1260 if (vol->dev->d_ops->sync(vol->dev) == -1)
1261 perr_exit("Failed to sync device");
1263 printf("Resetting $LogFile ... (this might take a while)\n");
1265 if (ntfs_logfile_reset(vol))
1266 perr_exit("Failed to reset $LogFile");
1268 if (vol->dev->d_ops->sync(vol->dev) == -1)
1269 perr_exit("Failed to sync device");
1277 int main(int argc, char **argv)
1279 ntfs_resize_t resize;
1280 s64 new_size = 0; /* in clusters */
1281 s64 device_size; /* in bytes */
1284 printf("%s v%s\n", EXEC_NAME, VERSION);
1286 if (!parse_options (argc, argv))
1293 device_size = ntfs_device_size_get(vol->dev, vol->sector_size);
1294 device_size *= vol->sector_size;
1295 if (device_size <= 0)
1296 err_exit("Couldn't get device size (%Ld)!\n", device_size);
1298 print_volume_size("Current device size", device_size);
1300 if (device_size < vol->nr_clusters * vol->cluster_size)
1301 err_exit("Current NTFS volume size is bigger than the device "
1302 "size (%Ld)!\nCorrupt partition table or incorrect "
1303 "device partitioning?\n", device_size);
1306 if (device_size < opt.bytes)
1307 err_exit("New size can't be bigger than the "
1308 "device size (%Ld bytes).\n", device_size);
1310 opt.bytes = device_size;
1313 * Take the integer part: we don't want to make the volume bigger
1314 * than requested. Later on we will also decrease this value to save
1315 * room for the backup boot sector.
1317 new_size = opt.bytes / vol->cluster_size;
1320 print_volume_size("New volume size ",
1321 volume_size(vol, new_size));
1323 /* Backup boot sector at the end of device isn't counted in NTFS
1324 volume size thus we have to reserve space for. We don't trust
1325 the user does this for us: better to be on the safe side ;) */
1329 if (!opt.info && (new_size == vol->nr_clusters ||
1330 (opt.bytes == device_size &&
1331 new_size == vol->nr_clusters - 1))) {
1332 printf("Nothing to do: NTFS volume size is already OK.\n");
1338 memset(&resize, 0, sizeof(resize));
1339 resize.new_volume_size = new_size;
1341 walk_inodes(&resize);
1342 if (resize.multi_ref) {
1343 printf("Totally %d clusters referenced multiply times.\n",
1345 err_exit("Filesystem check failed! Windows wasn't shutdown "
1346 "properly or inconsistent\nfilesystem. Please run "
1347 "chkdsk on Windows.\n");
1349 compare_bitmaps(&lcn_bitmap);
1351 print_disk_usage(&resize);
1358 for (i = new_size; i < vol->nr_clusters; i++)
1359 if (ntfs_bit_get(lcn_bitmap.bm, (u64)i)) {
1360 /* FIXME: relocate cluster */
1365 if (opt.force-- <= 0 && !opt.ro_flag) {
1366 printf(resize_warning_msg);
1370 prepare_volume_fixup();
1372 truncate_badclust_file(new_size);
1373 truncate_bitmap_file(new_size);
1374 update_bootsector(new_size);
1376 /* We don't create backup boot sector because we don't know where the
1377 partition will be split. The scheduled chkdsk will fix it anyway */
1380 printf("The read-only test run ended successfully.\n");
1384 printf("Syncing device ...\n");
1385 if (vol->dev->d_ops->sync(vol->dev) == -1)
1388 printf("Successfully resized NTFS on device '%s'.\n", vol->dev->d_name);
1389 if (new_size < vol->nr_clusters)
1390 printf(resize_important_msg);