diff --git a/ChangeLog b/ChangeLog index 0bdd47a4..e9ef1810 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,11 @@ xx/xx/xxxx - 1.12.0-WIP ntfs_inode_open. Update ntfsmount to use them. (Yura) - index.c::ntfs_index_lookup: fix bug when index context didn't point on index root in which entry located. (Yura) + - ntfsresize: relocate_attributes(): don't stop processing of MFT + record attributes at AT_DATA of $BadClus and $Bitmap. In practice, + there aren't non-resident attributes after them so this bug, + introduced in 1.11.0, shouldn't have ever caused data loss. (Szaka) + - ntfsresize: support relocation of $MFT with $ATTRIBUTE_LIST. (Szaka) 20/07/2005 - 1.11.1 - Fix several ntfsmount bugs. diff --git a/TODO.ntfsprogs b/TODO.ntfsprogs index 72798b1a..a5557154 100644 --- a/TODO.ntfsprogs +++ b/TODO.ntfsprogs @@ -73,7 +73,6 @@ Thanks, ************** High priority - - support $MFT with $ATTRIBUTE_LIST - support splitting up $MFT runs - move ntfs consistency check to libntfs (for ntfsck, ntfsclone, etc) - use different exit codes (e.g. corrupt volume detected, unsupported case, diff --git a/ntfsprogs/ntfsresize.8.in b/ntfsprogs/ntfsresize.8.in index 96b518a6..cd191efd 100644 --- a/ntfsprogs/ntfsresize.8.in +++ b/ntfsprogs/ntfsresize.8.in @@ -1,7 +1,7 @@ .\" -*- nroff -*- .\" Copyright 2002-2005 by Szabolcs Szakacsits All Rights Reserved. .\" -.TH NTFSRESIZE 8 "Jun 2005" "ntfsprogs version @VERSION@" +.TH NTFSRESIZE 8 "Jul 2005" "ntfsprogs version @VERSION@" .SH NAME ntfsresize \- resize an NTFS filesystem without data loss .SH SYNOPSIS @@ -159,7 +159,7 @@ Continue with the real resizing only if the test run passed. Support disks having physical errors, bad sectors. Make a backup by .BR ntfsclone (8) using option --rescue, then run from the command line 'chkdsk /f /r -volume:' on Windows prior using this option with ntfsresize. +volume:' on Windows prior using this option. If the guarantee is still valid for the disk then replace it. It's defected. .TP @@ -181,8 +181,8 @@ don't find your answer then send your question, comment or bug report to but the mailing list is moderated and it can take a short time to approve your post. .PP -There are some very rarely met limitations at present: filesystems having -unknown bad sectors, highly fragmented Master File Table (MFT), relocation +There are a few very rarely met restrictions at present: filesystems having +unknown bad sectors, relocation of the first MFT extent and resizing in the middle of some metadata in some cases aren't supported yet. These cases are detected and resizing is refused, restricted to a safe size or the closest safe @@ -192,7 +192,7 @@ size is displayed. schedules an NTFS consistency check and after the first boot into Windows you must see .B chkdsk -running on a blue background. This is intentional. +running on a blue background. This is intentional and no need to worry about it. Windows may force a quick reboot after the consistency check. Moreover after repartitioning your disk and depending on the hardware configuration, the Windows message @@ -222,7 +222,8 @@ at the University of Granada for their continuous and highly valuable help, furthermore to Erik Meade, Martin Fick, Sandro Hawke, Dave Croal, Lorrin Nelson, Geert Hendrickx, Robert Bjorkman and Richard Burdick for beta testing the relocation support, to Florian Eyben, Fritz Oppliger, -Richard Ebling, Sid-Ahmed Touati, Jan Kiszka for the valued +Richard Ebling, Sid-Ahmed Touati, Jan Kiszka, Benjamin Redelings, Christopher +Haney, Ryan Durk for the valued contributions and to Theodore Ts'o whose .BR resize2fs (8) man page originally formed the basis of this page. diff --git a/ntfsprogs/ntfsresize.c b/ntfsprogs/ntfsresize.c index dd4ecb74..4f614d31 100644 --- a/ntfsprogs/ntfsresize.c +++ b/ntfsprogs/ntfsresize.c @@ -155,6 +155,7 @@ typedef struct { int dirty_inode; /* some inode data got relocated */ int shrink; /* shrink = 1, enlarge = 0 */ s64 badclusters; /* num of physically dead clusters */ + VCN mft_highest_vcn; /* used for relocating the $MFT */ struct progress_bar progress; struct bitmap lcn_bitmap; /* Temporary statistics until all case is supported */ @@ -689,12 +690,10 @@ static void collect_resize_constraints(ntfs_resize_t *resize, runlist *rl) } else if (inode == FILE_MFT) { llcn = &resize->last_mft; - /* - * First run of $MFT AT_DATA and $MFT with AT_ATTRIBUTE_LIST - * isn't supported yet. + * First run of $MFT AT_DATA isn't supported yet. */ - if ((atype != AT_DATA || rl->vcn) && !NInoAttrList(resize->ni)) + if (atype != AT_DATA || rl->vcn) supported = 1; } else if (NInoAttrList(resize->ni)) { @@ -1625,7 +1624,56 @@ static void relocate_attribute(ntfs_resize_t *resize) free(rl); } -static void relocate_attributes(ntfs_resize_t *resize) +static int is_mftdata(ntfs_resize_t *resize) +{ + if (resize->ctx->attr->type != AT_DATA) + return 0; + + if (resize->mref == 0) + return 1; + + if ( MREF(resize->mrec->base_mft_record) == 0 && + MSEQNO(resize->mrec->base_mft_record) != 0) + return 1; + + return 0; +} + +static int handle_mftdata(ntfs_resize_t *resize, int do_mftdata) +{ + ATTR_RECORD *attr = resize->ctx->attr; + VCN highest_vcn, lowest_vcn; + + if (do_mftdata) { + + if (!is_mftdata(resize)) + return 0; + + highest_vcn = sle64_to_cpu(attr->highest_vcn); + lowest_vcn = sle64_to_cpu(attr->lowest_vcn); + + if (resize->mft_highest_vcn != highest_vcn) + return 0; + + if (lowest_vcn == 0) + resize->mft_highest_vcn = lowest_vcn; + else + resize->mft_highest_vcn = lowest_vcn - 1; + + } else if (is_mftdata(resize)) { + + highest_vcn = sle64_to_cpu(attr->highest_vcn); + + if (resize->mft_highest_vcn < highest_vcn) + resize->mft_highest_vcn = highest_vcn; + + return 0; + } + + return 1; +} + +static void relocate_attributes(ntfs_resize_t *resize, int do_mftdata) { int ret; @@ -1636,6 +1684,9 @@ static void relocate_attributes(ntfs_resize_t *resize) if (resize->ctx->attr->type == AT_END) break; + if (handle_mftdata(resize, do_mftdata) == 0) + continue; + ret = has_bad_sectors(resize, 0); if (ret == -1) exit(1); @@ -1652,7 +1703,7 @@ static void relocate_attributes(ntfs_resize_t *resize) ntfs_attr_put_search_ctx(resize->ctx); } -static void relocate_inode(ntfs_resize_t *resize, MFT_REF mref) +static void relocate_inode(ntfs_resize_t *resize, MFT_REF mref, int do_mftdata) { if (ntfs_file_record_read(resize->vol, mref, &resize->mrec, NULL)) { /* FIXME: continue only if it make sense, e.g. @@ -1668,7 +1719,7 @@ static void relocate_inode(ntfs_resize_t *resize, MFT_REF mref) resize->mref = mref; resize->dirty_inode = DIRTY_NONE; - relocate_attributes(resize); + relocate_attributes(resize, do_mftdata); if (resize->dirty_inode == DIRTY_INODE) { // if (vol->dev->d_ops->sync(vol->dev) == -1) @@ -1682,6 +1733,7 @@ static void relocate_inodes(ntfs_resize_t *resize) { s64 nr_mft_records; MFT_REF mref; + VCN highest_vcn; printf("Relocating needed data ...\n"); @@ -1695,11 +1747,23 @@ static void relocate_inodes(ntfs_resize_t *resize) nr_mft_records = resize->vol->mft_na->initialized_size >> resize->vol->mft_record_size_bits; - for (mref = 1; mref < (MFT_REF)nr_mft_records; mref++) - relocate_inode(resize, mref); + for (mref = 0; mref < (MFT_REF)nr_mft_records; mref++) + relocate_inode(resize, mref, 0); - relocate_inode(resize, 0); + while(1) { + highest_vcn = resize->mft_highest_vcn; + mref = nr_mft_records; + do { + relocate_inode(resize, --mref, 1); + if (resize->mft_highest_vcn == 0) + goto done; + } while (mref); + if (highest_vcn == resize->mft_highest_vcn) + err_exit("Sanity check failed! Highest_vcn = %lld. " + "Please report!", highest_vcn); + } +done: if (resize->mrec) free(resize->mrec); }