Support relocation of $MFT with $ATTRIBUTE_LIST

edge.strict_endians
szaka 2005-07-24 22:34:36 +00:00
parent 6377902ed4
commit 34c676fad3
4 changed files with 86 additions and 17 deletions

View File

@ -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.

View File

@ -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,

View File

@ -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.

View File

@ -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);
}