提交 5ae9fcf8 编写于 作者: A Anton Altaparmakov

NTFS: - Set the ntfs_inode->allocated_size to the real allocated size in the

        mft record for resident attributes (fs/ntfs/inode.c).
      - Small readability cleanup to use "a" instead of "ctx->attr"
        everywhere (fs/ntfs/inode.c).
Signed-off-by: NAnton Altaparmakov <aia21@cantab.net>
上级 37e4c13b
...@@ -76,6 +76,10 @@ ToDo/Notes: ...@@ -76,6 +76,10 @@ ToDo/Notes:
warning in the do_div() call on sparc32. Thanks to Meelis Roos for warning in the do_div() call on sparc32. Thanks to Meelis Roos for
the report and analysis of the warning. the report and analysis of the warning.
- Fix a nasty runlist merge bug when merging two holes. - Fix a nasty runlist merge bug when merging two holes.
- Set the ntfs_inode->allocated_size to the real allocated size in the
mft record for resident attributes (fs/ntfs/inode.c).
- Small readability cleanup to use "a" instead of "ctx->attr"
everywhere (fs/ntfs/inode.c).
2.1.22 - Many bug and race fixes and error handling improvements. 2.1.22 - Many bug and race fixes and error handling improvements.
......
...@@ -525,6 +525,7 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -525,6 +525,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
ntfs_volume *vol = NTFS_SB(vi->i_sb); ntfs_volume *vol = NTFS_SB(vi->i_sb);
ntfs_inode *ni; ntfs_inode *ni;
MFT_RECORD *m; MFT_RECORD *m;
ATTR_RECORD *a;
STANDARD_INFORMATION *si; STANDARD_INFORMATION *si;
ntfs_attr_search_ctx *ctx; ntfs_attr_search_ctx *ctx;
int err = 0; int err = 0;
...@@ -633,9 +634,10 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -633,9 +634,10 @@ static int ntfs_read_locked_inode(struct inode *vi)
} }
goto unm_err_out; goto unm_err_out;
} }
a = ctx->attr;
/* Get the standard information attribute value. */ /* Get the standard information attribute value. */
si = (STANDARD_INFORMATION*)((char*)ctx->attr + si = (STANDARD_INFORMATION*)((u8*)a +
le16_to_cpu(ctx->attr->data.resident.value_offset)); le16_to_cpu(a->data.resident.value_offset));
/* Transfer information from the standard information into vi. */ /* Transfer information from the standard information into vi. */
/* /*
...@@ -674,15 +676,16 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -674,15 +676,16 @@ static int ntfs_read_locked_inode(struct inode *vi)
goto skip_attr_list_load; goto skip_attr_list_load;
ntfs_debug("Attribute list found in inode 0x%lx.", vi->i_ino); ntfs_debug("Attribute list found in inode 0x%lx.", vi->i_ino);
NInoSetAttrList(ni); NInoSetAttrList(ni);
if (ctx->attr->flags & ATTR_IS_ENCRYPTED || a = ctx->attr;
ctx->attr->flags & ATTR_COMPRESSION_MASK || if (a->flags & ATTR_IS_ENCRYPTED ||
ctx->attr->flags & ATTR_IS_SPARSE) { a->flags & ATTR_COMPRESSION_MASK ||
a->flags & ATTR_IS_SPARSE) {
ntfs_error(vi->i_sb, "Attribute list attribute is " ntfs_error(vi->i_sb, "Attribute list attribute is "
"compressed/encrypted/sparse."); "compressed/encrypted/sparse.");
goto unm_err_out; goto unm_err_out;
} }
/* Now allocate memory for the attribute list. */ /* Now allocate memory for the attribute list. */
ni->attr_list_size = (u32)ntfs_attr_size(ctx->attr); ni->attr_list_size = (u32)ntfs_attr_size(a);
ni->attr_list = ntfs_malloc_nofs(ni->attr_list_size); ni->attr_list = ntfs_malloc_nofs(ni->attr_list_size);
if (!ni->attr_list) { if (!ni->attr_list) {
ntfs_error(vi->i_sb, "Not enough memory to allocate " ntfs_error(vi->i_sb, "Not enough memory to allocate "
...@@ -690,9 +693,9 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -690,9 +693,9 @@ static int ntfs_read_locked_inode(struct inode *vi)
err = -ENOMEM; err = -ENOMEM;
goto unm_err_out; goto unm_err_out;
} }
if (ctx->attr->non_resident) { if (a->non_resident) {
NInoSetAttrListNonResident(ni); NInoSetAttrListNonResident(ni);
if (ctx->attr->data.non_resident.lowest_vcn) { if (a->data.non_resident.lowest_vcn) {
ntfs_error(vi->i_sb, "Attribute list has non " ntfs_error(vi->i_sb, "Attribute list has non "
"zero lowest_vcn."); "zero lowest_vcn.");
goto unm_err_out; goto unm_err_out;
...@@ -702,7 +705,7 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -702,7 +705,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
* exclusive access to the inode at this time. * exclusive access to the inode at this time.
*/ */
ni->attr_list_rl.rl = ntfs_mapping_pairs_decompress(vol, ni->attr_list_rl.rl = ntfs_mapping_pairs_decompress(vol,
ctx->attr, NULL); a, NULL);
if (IS_ERR(ni->attr_list_rl.rl)) { if (IS_ERR(ni->attr_list_rl.rl)) {
err = PTR_ERR(ni->attr_list_rl.rl); err = PTR_ERR(ni->attr_list_rl.rl);
ni->attr_list_rl.rl = NULL; ni->attr_list_rl.rl = NULL;
...@@ -713,27 +716,26 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -713,27 +716,26 @@ static int ntfs_read_locked_inode(struct inode *vi)
/* Now load the attribute list. */ /* Now load the attribute list. */
if ((err = load_attribute_list(vol, &ni->attr_list_rl, if ((err = load_attribute_list(vol, &ni->attr_list_rl,
ni->attr_list, ni->attr_list_size, ni->attr_list, ni->attr_list_size,
sle64_to_cpu(ctx->attr->data. sle64_to_cpu(a->data.non_resident.
non_resident.initialized_size)))) { initialized_size)))) {
ntfs_error(vi->i_sb, "Failed to load " ntfs_error(vi->i_sb, "Failed to load "
"attribute list attribute."); "attribute list attribute.");
goto unm_err_out; goto unm_err_out;
} }
} else /* if (!ctx.attr->non_resident) */ { } else /* if (!a->non_resident) */ {
if ((u8*)ctx->attr + le16_to_cpu( if ((u8*)a + le16_to_cpu(a->data.resident.value_offset)
ctx->attr->data.resident.value_offset) + + le32_to_cpu(
le32_to_cpu( a->data.resident.value_length) >
ctx->attr->data.resident.value_length) >
(u8*)ctx->mrec + vol->mft_record_size) { (u8*)ctx->mrec + vol->mft_record_size) {
ntfs_error(vi->i_sb, "Corrupt attribute list " ntfs_error(vi->i_sb, "Corrupt attribute list "
"in inode."); "in inode.");
goto unm_err_out; goto unm_err_out;
} }
/* Now copy the attribute list. */ /* Now copy the attribute list. */
memcpy(ni->attr_list, (u8*)ctx->attr + le16_to_cpu( memcpy(ni->attr_list, (u8*)a + le16_to_cpu(
ctx->attr->data.resident.value_offset), a->data.resident.value_offset),
le32_to_cpu( le32_to_cpu(
ctx->attr->data.resident.value_length)); a->data.resident.value_length));
} }
} }
skip_attr_list_load: skip_attr_list_load:
...@@ -746,7 +748,7 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -746,7 +748,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
struct inode *bvi; struct inode *bvi;
ntfs_inode *bni; ntfs_inode *bni;
INDEX_ROOT *ir; INDEX_ROOT *ir;
char *ir_end, *index_end; u8 *ir_end, *index_end;
/* It is a directory, find index root attribute. */ /* It is a directory, find index root attribute. */
ntfs_attr_reinit_search_ctx(ctx); ntfs_attr_reinit_search_ctx(ctx);
...@@ -762,17 +764,16 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -762,17 +764,16 @@ static int ntfs_read_locked_inode(struct inode *vi)
} }
goto unm_err_out; goto unm_err_out;
} }
a = ctx->attr;
/* Set up the state. */ /* Set up the state. */
if (unlikely(ctx->attr->non_resident)) { if (unlikely(a->non_resident)) {
ntfs_error(vol->sb, "$INDEX_ROOT attribute is not " ntfs_error(vol->sb, "$INDEX_ROOT attribute is not "
"resident."); "resident.");
goto unm_err_out; goto unm_err_out;
} }
/* Ensure the attribute name is placed before the value. */ /* Ensure the attribute name is placed before the value. */
if (unlikely(ctx->attr->name_length && if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >=
(le16_to_cpu(ctx->attr->name_offset) >= le16_to_cpu(a->data.resident.value_offset)))) {
le16_to_cpu(ctx->attr->data.resident.
value_offset)))) {
ntfs_error(vol->sb, "$INDEX_ROOT attribute name is " ntfs_error(vol->sb, "$INDEX_ROOT attribute name is "
"placed after the attribute value."); "placed after the attribute value.");
goto unm_err_out; goto unm_err_out;
...@@ -783,28 +784,27 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -783,28 +784,27 @@ static int ntfs_read_locked_inode(struct inode *vi)
* encrypted. However index root cannot be both compressed and * encrypted. However index root cannot be both compressed and
* encrypted. * encrypted.
*/ */
if (ctx->attr->flags & ATTR_COMPRESSION_MASK) if (a->flags & ATTR_COMPRESSION_MASK)
NInoSetCompressed(ni); NInoSetCompressed(ni);
if (ctx->attr->flags & ATTR_IS_ENCRYPTED) { if (a->flags & ATTR_IS_ENCRYPTED) {
if (ctx->attr->flags & ATTR_COMPRESSION_MASK) { if (a->flags & ATTR_COMPRESSION_MASK) {
ntfs_error(vi->i_sb, "Found encrypted and " ntfs_error(vi->i_sb, "Found encrypted and "
"compressed attribute."); "compressed attribute.");
goto unm_err_out; goto unm_err_out;
} }
NInoSetEncrypted(ni); NInoSetEncrypted(ni);
} }
if (ctx->attr->flags & ATTR_IS_SPARSE) if (a->flags & ATTR_IS_SPARSE)
NInoSetSparse(ni); NInoSetSparse(ni);
ir = (INDEX_ROOT*)((char*)ctx->attr + le16_to_cpu( ir = (INDEX_ROOT*)((u8*)a +
ctx->attr->data.resident.value_offset)); le16_to_cpu(a->data.resident.value_offset));
ir_end = (char*)ir + le32_to_cpu( ir_end = (u8*)ir + le32_to_cpu(a->data.resident.value_length);
ctx->attr->data.resident.value_length); if (ir_end > (u8*)ctx->mrec + vol->mft_record_size) {
if (ir_end > (char*)ctx->mrec + vol->mft_record_size) {
ntfs_error(vi->i_sb, "$INDEX_ROOT attribute is " ntfs_error(vi->i_sb, "$INDEX_ROOT attribute is "
"corrupt."); "corrupt.");
goto unm_err_out; goto unm_err_out;
} }
index_end = (char*)&ir->index + index_end = (u8*)&ir->index +
le32_to_cpu(ir->index.index_length); le32_to_cpu(ir->index.index_length);
if (index_end > ir_end) { if (index_end > ir_end) {
ntfs_error(vi->i_sb, "Directory index is corrupt."); ntfs_error(vi->i_sb, "Directory index is corrupt.");
...@@ -891,7 +891,8 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -891,7 +891,8 @@ static int ntfs_read_locked_inode(struct inode *vi)
"attribute."); "attribute.");
goto unm_err_out; goto unm_err_out;
} }
if (!ctx->attr->non_resident) { a = ctx->attr;
if (!a->non_resident) {
ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute " ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
"is resident."); "is resident.");
goto unm_err_out; goto unm_err_out;
...@@ -900,42 +901,40 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -900,42 +901,40 @@ static int ntfs_read_locked_inode(struct inode *vi)
* Ensure the attribute name is placed before the mapping pairs * Ensure the attribute name is placed before the mapping pairs
* array. * array.
*/ */
if (unlikely(ctx->attr->name_length && if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >=
(le16_to_cpu(ctx->attr->name_offset) >= le16_to_cpu(
le16_to_cpu(ctx->attr->data.non_resident. a->data.non_resident.mapping_pairs_offset)))) {
mapping_pairs_offset)))) {
ntfs_error(vol->sb, "$INDEX_ALLOCATION attribute name " ntfs_error(vol->sb, "$INDEX_ALLOCATION attribute name "
"is placed after the mapping pairs " "is placed after the mapping pairs "
"array."); "array.");
goto unm_err_out; goto unm_err_out;
} }
if (ctx->attr->flags & ATTR_IS_ENCRYPTED) { if (a->flags & ATTR_IS_ENCRYPTED) {
ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute " ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
"is encrypted."); "is encrypted.");
goto unm_err_out; goto unm_err_out;
} }
if (ctx->attr->flags & ATTR_IS_SPARSE) { if (a->flags & ATTR_IS_SPARSE) {
ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute " ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
"is sparse."); "is sparse.");
goto unm_err_out; goto unm_err_out;
} }
if (ctx->attr->flags & ATTR_COMPRESSION_MASK) { if (a->flags & ATTR_COMPRESSION_MASK) {
ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute " ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
"is compressed."); "is compressed.");
goto unm_err_out; goto unm_err_out;
} }
if (ctx->attr->data.non_resident.lowest_vcn) { if (a->data.non_resident.lowest_vcn) {
ntfs_error(vi->i_sb, "First extent of " ntfs_error(vi->i_sb, "First extent of "
"$INDEX_ALLOCATION attribute has non " "$INDEX_ALLOCATION attribute has non "
"zero lowest_vcn."); "zero lowest_vcn.");
goto unm_err_out; goto unm_err_out;
} }
vi->i_size = sle64_to_cpu( vi->i_size = sle64_to_cpu(a->data.non_resident.data_size);
ctx->attr->data.non_resident.data_size);
ni->initialized_size = sle64_to_cpu( ni->initialized_size = sle64_to_cpu(
ctx->attr->data.non_resident.initialized_size); a->data.non_resident.initialized_size);
ni->allocated_size = sle64_to_cpu( ni->allocated_size = sle64_to_cpu(
ctx->attr->data.non_resident.allocated_size); a->data.non_resident.allocated_size);
/* /*
* We are done with the mft record, so we release it. Otherwise * We are done with the mft record, so we release it. Otherwise
* we would deadlock in ntfs_attr_iget(). * we would deadlock in ntfs_attr_iget().
...@@ -1013,10 +1012,11 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -1013,10 +1012,11 @@ static int ntfs_read_locked_inode(struct inode *vi)
ntfs_error(vi->i_sb, "$DATA attribute is missing."); ntfs_error(vi->i_sb, "$DATA attribute is missing.");
goto unm_err_out; goto unm_err_out;
} }
a = ctx->attr;
/* Setup the state. */ /* Setup the state. */
if (ctx->attr->non_resident) { if (a->non_resident) {
NInoSetNonResident(ni); NInoSetNonResident(ni);
if (ctx->attr->flags & ATTR_COMPRESSION_MASK) { if (a->flags & ATTR_COMPRESSION_MASK) {
NInoSetCompressed(ni); NInoSetCompressed(ni);
if (vol->cluster_size > 4096) { if (vol->cluster_size > 4096) {
ntfs_error(vi->i_sb, "Found " ntfs_error(vi->i_sb, "Found "
...@@ -1026,7 +1026,7 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -1026,7 +1026,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
vol->cluster_size); vol->cluster_size);
goto unm_err_out; goto unm_err_out;
} }
if ((ctx->attr->flags & ATTR_COMPRESSION_MASK) if ((a->flags & ATTR_COMPRESSION_MASK)
!= ATTR_IS_COMPRESSED) { != ATTR_IS_COMPRESSED) {
ntfs_error(vi->i_sb, "Found " ntfs_error(vi->i_sb, "Found "
"unknown compression method or " "unknown compression method or "
...@@ -1034,37 +1034,37 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -1034,37 +1034,37 @@ static int ntfs_read_locked_inode(struct inode *vi)
goto unm_err_out; goto unm_err_out;
} }
ni->itype.compressed.block_clusters = 1U << ni->itype.compressed.block_clusters = 1U <<
ctx->attr->data.non_resident. a->data.non_resident.
compression_unit; compression_unit;
if (ctx->attr->data.non_resident. if (a->data.non_resident.compression_unit !=
compression_unit != 4) { 4) {
ntfs_error(vi->i_sb, "Found " ntfs_error(vi->i_sb, "Found "
"nonstandard compression unit " "nonstandard compression unit "
"(%u instead of 4). Cannot " "(%u instead of 4). Cannot "
"handle this.", "handle this.",
ctx->attr->data.non_resident. a->data.non_resident.
compression_unit); compression_unit);
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto unm_err_out; goto unm_err_out;
} }
ni->itype.compressed.block_size = 1U << ( ni->itype.compressed.block_size = 1U << (
ctx->attr->data.non_resident. a->data.non_resident.
compression_unit + compression_unit +
vol->cluster_size_bits); vol->cluster_size_bits);
ni->itype.compressed.block_size_bits = ffs( ni->itype.compressed.block_size_bits = ffs(
ni->itype.compressed.block_size) - 1; ni->itype.compressed.block_size) - 1;
} }
if (ctx->attr->flags & ATTR_IS_ENCRYPTED) { if (a->flags & ATTR_IS_ENCRYPTED) {
if (ctx->attr->flags & ATTR_COMPRESSION_MASK) { if (a->flags & ATTR_COMPRESSION_MASK) {
ntfs_error(vi->i_sb, "Found encrypted " ntfs_error(vi->i_sb, "Found encrypted "
"and compressed data."); "and compressed data.");
goto unm_err_out; goto unm_err_out;
} }
NInoSetEncrypted(ni); NInoSetEncrypted(ni);
} }
if (ctx->attr->flags & ATTR_IS_SPARSE) if (a->flags & ATTR_IS_SPARSE)
NInoSetSparse(ni); NInoSetSparse(ni);
if (ctx->attr->data.non_resident.lowest_vcn) { if (a->data.non_resident.lowest_vcn) {
ntfs_error(vi->i_sb, "First extent of $DATA " ntfs_error(vi->i_sb, "First extent of $DATA "
"attribute has non zero " "attribute has non zero "
"lowest_vcn."); "lowest_vcn.");
...@@ -1072,28 +1072,28 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -1072,28 +1072,28 @@ static int ntfs_read_locked_inode(struct inode *vi)
} }
/* Setup all the sizes. */ /* Setup all the sizes. */
vi->i_size = sle64_to_cpu( vi->i_size = sle64_to_cpu(
ctx->attr->data.non_resident.data_size); a->data.non_resident.data_size);
ni->initialized_size = sle64_to_cpu( ni->initialized_size = sle64_to_cpu(
ctx->attr->data.non_resident. a->data.non_resident.initialized_size);
initialized_size);
ni->allocated_size = sle64_to_cpu( ni->allocated_size = sle64_to_cpu(
ctx->attr->data.non_resident. a->data.non_resident.allocated_size);
allocated_size); if (NInoCompressed(ni))
if (NInoCompressed(ni)) {
ni->itype.compressed.size = sle64_to_cpu( ni->itype.compressed.size = sle64_to_cpu(
ctx->attr->data.non_resident. a->data.non_resident.
compressed_size); compressed_size);
}
} else { /* Resident attribute. */ } else { /* Resident attribute. */
/* /* Setup all the sizes. */
* Make all sizes equal for simplicity in read code vi->i_size = ni->initialized_size = le32_to_cpu(
* paths. FIXME: Need to keep this in mind when a->data.resident.value_length);
* converting to non-resident attribute in write code ni->allocated_size = le32_to_cpu(a->length) -
* path. (Probably only affects truncate().) le16_to_cpu(
*/ a->data.resident.value_offset);
vi->i_size = ni->initialized_size = ni->allocated_size = if (vi->i_size > ni->allocated_size) {
le32_to_cpu( ntfs_error(vi->i_sb, "Resident data attribute "
ctx->attr->data.resident.value_length); "is corrupt (size exceeds "
"allocation).");
goto unm_err_out;
}
} }
no_data_attr_special_case: no_data_attr_special_case:
/* We are done with the mft record, so we release it. */ /* We are done with the mft record, so we release it. */
...@@ -1169,6 +1169,7 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) ...@@ -1169,6 +1169,7 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
ntfs_volume *vol = NTFS_SB(vi->i_sb); ntfs_volume *vol = NTFS_SB(vi->i_sb);
ntfs_inode *ni, *base_ni; ntfs_inode *ni, *base_ni;
MFT_RECORD *m; MFT_RECORD *m;
ATTR_RECORD *a;
ntfs_attr_search_ctx *ctx; ntfs_attr_search_ctx *ctx;
int err = 0; int err = 0;
...@@ -1203,24 +1204,21 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) ...@@ -1203,24 +1204,21 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
err = -ENOMEM; err = -ENOMEM;
goto unm_err_out; goto unm_err_out;
} }
/* Find the attribute. */ /* Find the attribute. */
err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len,
CASE_SENSITIVE, 0, NULL, 0, ctx); CASE_SENSITIVE, 0, NULL, 0, ctx);
if (unlikely(err)) if (unlikely(err))
goto unm_err_out; goto unm_err_out;
a = ctx->attr;
if (!ctx->attr->non_resident) { if (!a->non_resident) {
/* Ensure the attribute name is placed before the value. */ /* Ensure the attribute name is placed before the value. */
if (unlikely(ctx->attr->name_length && if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >=
(le16_to_cpu(ctx->attr->name_offset) >= le16_to_cpu(a->data.resident.value_offset)))) {
le16_to_cpu(ctx->attr->data.resident.
value_offset)))) {
ntfs_error(vol->sb, "Attribute name is placed after " ntfs_error(vol->sb, "Attribute name is placed after "
"the attribute value."); "the attribute value.");
goto unm_err_out; goto unm_err_out;
} }
if (NInoMstProtected(ni) || ctx->attr->flags) { if (NInoMstProtected(ni) || a->flags) {
ntfs_error(vi->i_sb, "Found mst protected attribute " ntfs_error(vi->i_sb, "Found mst protected attribute "
"or attribute with non-zero flags but " "or attribute with non-zero flags but "
"the attribute is resident. Please " "the attribute is resident. Please "
...@@ -1228,27 +1226,30 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) ...@@ -1228,27 +1226,30 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
"linux-ntfs-dev@lists.sourceforge.net"); "linux-ntfs-dev@lists.sourceforge.net");
goto unm_err_out; goto unm_err_out;
} }
/* /* Resident attribute. Setup all the sizes. */
* Resident attribute. Make all sizes equal for simplicity in vi->i_size = ni->initialized_size = le32_to_cpu(
* read code paths. a->data.resident.value_length);
*/ ni->allocated_size = le32_to_cpu(a->length) -
vi->i_size = ni->initialized_size = ni->allocated_size = le16_to_cpu(a->data.resident.value_offset);
le32_to_cpu(ctx->attr->data.resident.value_length); if (vi->i_size > ni->allocated_size) {
ntfs_error(vi->i_sb, "Resident data attribute is "
"corrupt (size exceeds allocation).");
goto unm_err_out;
}
} else { } else {
NInoSetNonResident(ni); NInoSetNonResident(ni);
/* /*
* Ensure the attribute name is placed before the mapping pairs * Ensure the attribute name is placed before the mapping pairs
* array. * array.
*/ */
if (unlikely(ctx->attr->name_length && if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >=
(le16_to_cpu(ctx->attr->name_offset) >= le16_to_cpu(
le16_to_cpu(ctx->attr->data.non_resident. a->data.non_resident.mapping_pairs_offset)))) {
mapping_pairs_offset)))) {
ntfs_error(vol->sb, "Attribute name is placed after " ntfs_error(vol->sb, "Attribute name is placed after "
"the mapping pairs array."); "the mapping pairs array.");
goto unm_err_out; goto unm_err_out;
} }
if (ctx->attr->flags & ATTR_COMPRESSION_MASK) { if (a->flags & ATTR_COMPRESSION_MASK) {
if (NInoMstProtected(ni)) { if (NInoMstProtected(ni)) {
ntfs_error(vi->i_sb, "Found mst protected " ntfs_error(vi->i_sb, "Found mst protected "
"attribute but the attribute " "attribute but the attribute "
...@@ -1277,36 +1278,33 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) ...@@ -1277,36 +1278,33 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
vol->cluster_size); vol->cluster_size);
goto unm_err_out; goto unm_err_out;
} }
if ((ctx->attr->flags & ATTR_COMPRESSION_MASK) if ((a->flags & ATTR_COMPRESSION_MASK) !=
!= ATTR_IS_COMPRESSED) { ATTR_IS_COMPRESSED) {
ntfs_error(vi->i_sb, "Found unknown " ntfs_error(vi->i_sb, "Found unknown "
"compression method."); "compression method.");
goto unm_err_out; goto unm_err_out;
} }
ni->itype.compressed.block_clusters = 1U << ni->itype.compressed.block_clusters = 1U <<
ctx->attr->data.non_resident. a->data.non_resident.compression_unit;
compression_unit; if (a->data.non_resident.compression_unit != 4) {
if (ctx->attr->data.non_resident.compression_unit !=
4) {
ntfs_error(vi->i_sb, "Found nonstandard " ntfs_error(vi->i_sb, "Found nonstandard "
"compression unit (%u instead " "compression unit (%u instead "
"of 4). Cannot handle this.", "of 4). Cannot handle this.",
ctx->attr->data.non_resident. a->data.non_resident.
compression_unit); compression_unit);
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto unm_err_out; goto unm_err_out;
} }
ni->itype.compressed.block_size = 1U << ( ni->itype.compressed.block_size = 1U << (
ctx->attr->data.non_resident. a->data.non_resident.compression_unit +
compression_unit +
vol->cluster_size_bits); vol->cluster_size_bits);
ni->itype.compressed.block_size_bits = ffs( ni->itype.compressed.block_size_bits = ffs(
ni->itype.compressed.block_size) - 1; ni->itype.compressed.block_size) - 1;
} }
if (ctx->attr->flags & ATTR_IS_ENCRYPTED) { if (a->flags & ATTR_IS_ENCRYPTED) {
if (ctx->attr->flags & ATTR_COMPRESSION_MASK) { if (a->flags & ATTR_COMPRESSION_MASK) {
ntfs_error(vi->i_sb, "Found encrypted " ntfs_error(vi->i_sb, "Found encrypted and "
"and compressed data."); "compressed data.");
goto unm_err_out; goto unm_err_out;
} }
if (NInoMstProtected(ni)) { if (NInoMstProtected(ni)) {
...@@ -1320,7 +1318,7 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) ...@@ -1320,7 +1318,7 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
} }
NInoSetEncrypted(ni); NInoSetEncrypted(ni);
} }
if (ctx->attr->flags & ATTR_IS_SPARSE) { if (a->flags & ATTR_IS_SPARSE) {
if (NInoMstProtected(ni)) { if (NInoMstProtected(ni)) {
ntfs_error(vi->i_sb, "Found mst protected " ntfs_error(vi->i_sb, "Found mst protected "
"attribute but the attribute " "attribute but the attribute "
...@@ -1332,23 +1330,20 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) ...@@ -1332,23 +1330,20 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
} }
NInoSetSparse(ni); NInoSetSparse(ni);
} }
if (ctx->attr->data.non_resident.lowest_vcn) { if (a->data.non_resident.lowest_vcn) {
ntfs_error(vi->i_sb, "First extent of attribute has " ntfs_error(vi->i_sb, "First extent of attribute has "
"non-zero lowest_vcn."); "non-zero lowest_vcn.");
goto unm_err_out; goto unm_err_out;
} }
/* Setup all the sizes. */ /* Setup all the sizes. */
vi->i_size = sle64_to_cpu( vi->i_size = sle64_to_cpu(a->data.non_resident.data_size);
ctx->attr->data.non_resident.data_size);
ni->initialized_size = sle64_to_cpu( ni->initialized_size = sle64_to_cpu(
ctx->attr->data.non_resident.initialized_size); a->data.non_resident.initialized_size);
ni->allocated_size = sle64_to_cpu( ni->allocated_size = sle64_to_cpu(
ctx->attr->data.non_resident.allocated_size); a->data.non_resident.allocated_size);
if (NInoCompressed(ni)) { if (NInoCompressed(ni))
ni->itype.compressed.size = sle64_to_cpu( ni->itype.compressed.size = sle64_to_cpu(
ctx->attr->data.non_resident. a->data.non_resident.compressed_size);
compressed_size);
}
} }
/* Setup the operations for this attribute inode. */ /* Setup the operations for this attribute inode. */
...@@ -1437,6 +1432,7 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi) ...@@ -1437,6 +1432,7 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi)
ntfs_inode *ni, *base_ni, *bni; ntfs_inode *ni, *base_ni, *bni;
struct inode *bvi; struct inode *bvi;
MFT_RECORD *m; MFT_RECORD *m;
ATTR_RECORD *a;
ntfs_attr_search_ctx *ctx; ntfs_attr_search_ctx *ctx;
INDEX_ROOT *ir; INDEX_ROOT *ir;
u8 *ir_end, *index_end; u8 *ir_end, *index_end;
...@@ -1478,30 +1474,28 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi) ...@@ -1478,30 +1474,28 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi)
"missing."); "missing.");
goto unm_err_out; goto unm_err_out;
} }
a = ctx->attr;
/* Set up the state. */ /* Set up the state. */
if (unlikely(ctx->attr->non_resident)) { if (unlikely(a->non_resident)) {
ntfs_error(vol->sb, "$INDEX_ROOT attribute is not resident."); ntfs_error(vol->sb, "$INDEX_ROOT attribute is not resident.");
goto unm_err_out; goto unm_err_out;
} }
/* Ensure the attribute name is placed before the value. */ /* Ensure the attribute name is placed before the value. */
if (unlikely(ctx->attr->name_length && if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >=
(le16_to_cpu(ctx->attr->name_offset) >= le16_to_cpu(a->data.resident.value_offset)))) {
le16_to_cpu(ctx->attr->data.resident.
value_offset)))) {
ntfs_error(vol->sb, "$INDEX_ROOT attribute name is placed " ntfs_error(vol->sb, "$INDEX_ROOT attribute name is placed "
"after the attribute value."); "after the attribute value.");
goto unm_err_out; goto unm_err_out;
} }
/* Compressed/encrypted/sparse index root is not allowed. */ /* Compressed/encrypted/sparse index root is not allowed. */
if (ctx->attr->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_ENCRYPTED | if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_ENCRYPTED |
ATTR_IS_SPARSE)) { ATTR_IS_SPARSE)) {
ntfs_error(vi->i_sb, "Found compressed/encrypted/sparse index " ntfs_error(vi->i_sb, "Found compressed/encrypted/sparse index "
"root attribute."); "root attribute.");
goto unm_err_out; goto unm_err_out;
} }
ir = (INDEX_ROOT*)((u8*)ctx->attr + ir = (INDEX_ROOT*)((u8*)a + le16_to_cpu(a->data.resident.value_offset));
le16_to_cpu(ctx->attr->data.resident.value_offset)); ir_end = (u8*)ir + le32_to_cpu(a->data.resident.value_length);
ir_end = (u8*)ir + le32_to_cpu(ctx->attr->data.resident.value_length);
if (ir_end > (u8*)ctx->mrec + vol->mft_record_size) { if (ir_end > (u8*)ctx->mrec + vol->mft_record_size) {
ntfs_error(vi->i_sb, "$INDEX_ROOT attribute is corrupt."); ntfs_error(vi->i_sb, "$INDEX_ROOT attribute is corrupt.");
goto unm_err_out; goto unm_err_out;
...@@ -1574,7 +1568,7 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi) ...@@ -1574,7 +1568,7 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi)
"$INDEX_ALLOCATION attribute."); "$INDEX_ALLOCATION attribute.");
goto unm_err_out; goto unm_err_out;
} }
if (!ctx->attr->non_resident) { if (!a->non_resident) {
ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is " ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is "
"resident."); "resident.");
goto unm_err_out; goto unm_err_out;
...@@ -1582,37 +1576,36 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi) ...@@ -1582,37 +1576,36 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi)
/* /*
* Ensure the attribute name is placed before the mapping pairs array. * Ensure the attribute name is placed before the mapping pairs array.
*/ */
if (unlikely(ctx->attr->name_length && (le16_to_cpu( if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >=
ctx->attr->name_offset) >= le16_to_cpu( le16_to_cpu(
ctx->attr->data.non_resident.mapping_pairs_offset)))) { a->data.non_resident.mapping_pairs_offset)))) {
ntfs_error(vol->sb, "$INDEX_ALLOCATION attribute name is " ntfs_error(vol->sb, "$INDEX_ALLOCATION attribute name is "
"placed after the mapping pairs array."); "placed after the mapping pairs array.");
goto unm_err_out; goto unm_err_out;
} }
if (ctx->attr->flags & ATTR_IS_ENCRYPTED) { if (a->flags & ATTR_IS_ENCRYPTED) {
ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is " ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is "
"encrypted."); "encrypted.");
goto unm_err_out; goto unm_err_out;
} }
if (ctx->attr->flags & ATTR_IS_SPARSE) { if (a->flags & ATTR_IS_SPARSE) {
ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is sparse."); ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is sparse.");
goto unm_err_out; goto unm_err_out;
} }
if (ctx->attr->flags & ATTR_COMPRESSION_MASK) { if (a->flags & ATTR_COMPRESSION_MASK) {
ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is " ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is "
"compressed."); "compressed.");
goto unm_err_out; goto unm_err_out;
} }
if (ctx->attr->data.non_resident.lowest_vcn) { if (a->data.non_resident.lowest_vcn) {
ntfs_error(vi->i_sb, "First extent of $INDEX_ALLOCATION " ntfs_error(vi->i_sb, "First extent of $INDEX_ALLOCATION "
"attribute has non zero lowest_vcn."); "attribute has non zero lowest_vcn.");
goto unm_err_out; goto unm_err_out;
} }
vi->i_size = sle64_to_cpu(ctx->attr->data.non_resident.data_size); vi->i_size = sle64_to_cpu(a->data.non_resident.data_size);
ni->initialized_size = sle64_to_cpu( ni->initialized_size = sle64_to_cpu(
ctx->attr->data.non_resident.initialized_size); a->data.non_resident.initialized_size);
ni->allocated_size = sle64_to_cpu( ni->allocated_size = sle64_to_cpu(a->data.non_resident.allocated_size);
ctx->attr->data.non_resident.allocated_size);
/* /*
* We are done with the mft record, so we release it. Otherwise * We are done with the mft record, so we release it. Otherwise
* we would deadlock in ntfs_attr_iget(). * we would deadlock in ntfs_attr_iget().
...@@ -1716,7 +1709,7 @@ int ntfs_read_inode_mount(struct inode *vi) ...@@ -1716,7 +1709,7 @@ int ntfs_read_inode_mount(struct inode *vi)
struct buffer_head *bh; struct buffer_head *bh;
ntfs_inode *ni; ntfs_inode *ni;
MFT_RECORD *m = NULL; MFT_RECORD *m = NULL;
ATTR_RECORD *attr; ATTR_RECORD *a;
ntfs_attr_search_ctx *ctx; ntfs_attr_search_ctx *ctx;
unsigned int i, nr_blocks; unsigned int i, nr_blocks;
int err; int err;
...@@ -1813,9 +1806,10 @@ int ntfs_read_inode_mount(struct inode *vi) ...@@ -1813,9 +1806,10 @@ int ntfs_read_inode_mount(struct inode *vi)
ntfs_debug("Attribute list attribute found in $MFT."); ntfs_debug("Attribute list attribute found in $MFT.");
NInoSetAttrList(ni); NInoSetAttrList(ni);
if (ctx->attr->flags & ATTR_IS_ENCRYPTED || a = ctx->attr;
ctx->attr->flags & ATTR_COMPRESSION_MASK || if (a->flags & ATTR_IS_ENCRYPTED ||
ctx->attr->flags & ATTR_IS_SPARSE) { a->flags & ATTR_COMPRESSION_MASK ||
a->flags & ATTR_IS_SPARSE) {
ntfs_error(sb, "Attribute list attribute is " ntfs_error(sb, "Attribute list attribute is "
"compressed/encrypted/sparse. Not " "compressed/encrypted/sparse. Not "
"allowed. $MFT is corrupt. You should " "allowed. $MFT is corrupt. You should "
...@@ -1823,16 +1817,16 @@ int ntfs_read_inode_mount(struct inode *vi) ...@@ -1823,16 +1817,16 @@ int ntfs_read_inode_mount(struct inode *vi)
goto put_err_out; goto put_err_out;
} }
/* Now allocate memory for the attribute list. */ /* Now allocate memory for the attribute list. */
ni->attr_list_size = (u32)ntfs_attr_size(ctx->attr); ni->attr_list_size = (u32)ntfs_attr_size(a);
ni->attr_list = ntfs_malloc_nofs(ni->attr_list_size); ni->attr_list = ntfs_malloc_nofs(ni->attr_list_size);
if (!ni->attr_list) { if (!ni->attr_list) {
ntfs_error(sb, "Not enough memory to allocate buffer " ntfs_error(sb, "Not enough memory to allocate buffer "
"for attribute list."); "for attribute list.");
goto put_err_out; goto put_err_out;
} }
if (ctx->attr->non_resident) { if (a->non_resident) {
NInoSetAttrListNonResident(ni); NInoSetAttrListNonResident(ni);
if (ctx->attr->data.non_resident.lowest_vcn) { if (a->data.non_resident.lowest_vcn) {
ntfs_error(sb, "Attribute list has non zero " ntfs_error(sb, "Attribute list has non zero "
"lowest_vcn. $MFT is corrupt. " "lowest_vcn. $MFT is corrupt. "
"You should run chkdsk."); "You should run chkdsk.");
...@@ -1840,7 +1834,7 @@ int ntfs_read_inode_mount(struct inode *vi) ...@@ -1840,7 +1834,7 @@ int ntfs_read_inode_mount(struct inode *vi)
} }
/* Setup the runlist. */ /* Setup the runlist. */
ni->attr_list_rl.rl = ntfs_mapping_pairs_decompress(vol, ni->attr_list_rl.rl = ntfs_mapping_pairs_decompress(vol,
ctx->attr, NULL); a, NULL);
if (IS_ERR(ni->attr_list_rl.rl)) { if (IS_ERR(ni->attr_list_rl.rl)) {
err = PTR_ERR(ni->attr_list_rl.rl); err = PTR_ERR(ni->attr_list_rl.rl);
ni->attr_list_rl.rl = NULL; ni->attr_list_rl.rl = NULL;
...@@ -1852,7 +1846,7 @@ int ntfs_read_inode_mount(struct inode *vi) ...@@ -1852,7 +1846,7 @@ int ntfs_read_inode_mount(struct inode *vi)
/* Now load the attribute list. */ /* Now load the attribute list. */
if ((err = load_attribute_list(vol, &ni->attr_list_rl, if ((err = load_attribute_list(vol, &ni->attr_list_rl,
ni->attr_list, ni->attr_list_size, ni->attr_list, ni->attr_list_size,
sle64_to_cpu(ctx->attr->data. sle64_to_cpu(a->data.
non_resident.initialized_size)))) { non_resident.initialized_size)))) {
ntfs_error(sb, "Failed to load attribute list " ntfs_error(sb, "Failed to load attribute list "
"attribute with error code %i.", "attribute with error code %i.",
...@@ -1860,20 +1854,20 @@ int ntfs_read_inode_mount(struct inode *vi) ...@@ -1860,20 +1854,20 @@ int ntfs_read_inode_mount(struct inode *vi)
goto put_err_out; goto put_err_out;
} }
} else /* if (!ctx.attr->non_resident) */ { } else /* if (!ctx.attr->non_resident) */ {
if ((u8*)ctx->attr + le16_to_cpu( if ((u8*)a + le16_to_cpu(
ctx->attr->data.resident.value_offset) + a->data.resident.value_offset) +
le32_to_cpu( le32_to_cpu(
ctx->attr->data.resident.value_length) > a->data.resident.value_length) >
(u8*)ctx->mrec + vol->mft_record_size) { (u8*)ctx->mrec + vol->mft_record_size) {
ntfs_error(sb, "Corrupt attribute list " ntfs_error(sb, "Corrupt attribute list "
"attribute."); "attribute.");
goto put_err_out; goto put_err_out;
} }
/* Now copy the attribute list. */ /* Now copy the attribute list. */
memcpy(ni->attr_list, (u8*)ctx->attr + le16_to_cpu( memcpy(ni->attr_list, (u8*)a + le16_to_cpu(
ctx->attr->data.resident.value_offset), a->data.resident.value_offset),
le32_to_cpu( le32_to_cpu(
ctx->attr->data.resident.value_length)); a->data.resident.value_length));
} }
/* The attribute list is now setup in memory. */ /* The attribute list is now setup in memory. */
/* /*
...@@ -1939,25 +1933,25 @@ int ntfs_read_inode_mount(struct inode *vi) ...@@ -1939,25 +1933,25 @@ int ntfs_read_inode_mount(struct inode *vi)
ntfs_attr_reinit_search_ctx(ctx); ntfs_attr_reinit_search_ctx(ctx);
/* Now load all attribute extents. */ /* Now load all attribute extents. */
attr = NULL; a = NULL;
next_vcn = last_vcn = highest_vcn = 0; next_vcn = last_vcn = highest_vcn = 0;
while (!(err = ntfs_attr_lookup(AT_DATA, NULL, 0, 0, next_vcn, NULL, 0, while (!(err = ntfs_attr_lookup(AT_DATA, NULL, 0, 0, next_vcn, NULL, 0,
ctx))) { ctx))) {
runlist_element *nrl; runlist_element *nrl;
/* Cache the current attribute. */ /* Cache the current attribute. */
attr = ctx->attr; a = ctx->attr;
/* $MFT must be non-resident. */ /* $MFT must be non-resident. */
if (!attr->non_resident) { if (!a->non_resident) {
ntfs_error(sb, "$MFT must be non-resident but a " ntfs_error(sb, "$MFT must be non-resident but a "
"resident extent was found. $MFT is " "resident extent was found. $MFT is "
"corrupt. Run chkdsk."); "corrupt. Run chkdsk.");
goto put_err_out; goto put_err_out;
} }
/* $MFT must be uncompressed and unencrypted. */ /* $MFT must be uncompressed and unencrypted. */
if (attr->flags & ATTR_COMPRESSION_MASK || if (a->flags & ATTR_COMPRESSION_MASK ||
attr->flags & ATTR_IS_ENCRYPTED || a->flags & ATTR_IS_ENCRYPTED ||
attr->flags & ATTR_IS_SPARSE) { a->flags & ATTR_IS_SPARSE) {
ntfs_error(sb, "$MFT must be uncompressed, " ntfs_error(sb, "$MFT must be uncompressed, "
"non-sparse, and unencrypted but a " "non-sparse, and unencrypted but a "
"compressed/sparse/encrypted extent " "compressed/sparse/encrypted extent "
...@@ -1971,7 +1965,7 @@ int ntfs_read_inode_mount(struct inode *vi) ...@@ -1971,7 +1965,7 @@ int ntfs_read_inode_mount(struct inode *vi)
* as we have exclusive access to the inode at this time and we * as we have exclusive access to the inode at this time and we
* are a mount in progress task, too. * are a mount in progress task, too.
*/ */
nrl = ntfs_mapping_pairs_decompress(vol, attr, ni->runlist.rl); nrl = ntfs_mapping_pairs_decompress(vol, a, ni->runlist.rl);
if (IS_ERR(nrl)) { if (IS_ERR(nrl)) {
ntfs_error(sb, "ntfs_mapping_pairs_decompress() " ntfs_error(sb, "ntfs_mapping_pairs_decompress() "
"failed with error code %ld. $MFT is " "failed with error code %ld. $MFT is "
...@@ -1982,7 +1976,7 @@ int ntfs_read_inode_mount(struct inode *vi) ...@@ -1982,7 +1976,7 @@ int ntfs_read_inode_mount(struct inode *vi)
/* Are we in the first extent? */ /* Are we in the first extent? */
if (!next_vcn) { if (!next_vcn) {
if (attr->data.non_resident.lowest_vcn) { if (a->data.non_resident.lowest_vcn) {
ntfs_error(sb, "First extent of $DATA " ntfs_error(sb, "First extent of $DATA "
"attribute has non zero " "attribute has non zero "
"lowest_vcn. $MFT is corrupt. " "lowest_vcn. $MFT is corrupt. "
...@@ -1991,15 +1985,15 @@ int ntfs_read_inode_mount(struct inode *vi) ...@@ -1991,15 +1985,15 @@ int ntfs_read_inode_mount(struct inode *vi)
} }
/* Get the last vcn in the $DATA attribute. */ /* Get the last vcn in the $DATA attribute. */
last_vcn = sle64_to_cpu( last_vcn = sle64_to_cpu(
attr->data.non_resident.allocated_size) a->data.non_resident.allocated_size)
>> vol->cluster_size_bits; >> vol->cluster_size_bits;
/* Fill in the inode size. */ /* Fill in the inode size. */
vi->i_size = sle64_to_cpu( vi->i_size = sle64_to_cpu(
attr->data.non_resident.data_size); a->data.non_resident.data_size);
ni->initialized_size = sle64_to_cpu(attr->data. ni->initialized_size = sle64_to_cpu(
non_resident.initialized_size); a->data.non_resident.initialized_size);
ni->allocated_size = sle64_to_cpu( ni->allocated_size = sle64_to_cpu(
attr->data.non_resident.allocated_size); a->data.non_resident.allocated_size);
/* /*
* Verify the number of mft records does not exceed * Verify the number of mft records does not exceed
* 2^32 - 1. * 2^32 - 1.
...@@ -2056,7 +2050,7 @@ int ntfs_read_inode_mount(struct inode *vi) ...@@ -2056,7 +2050,7 @@ int ntfs_read_inode_mount(struct inode *vi)
} }
/* Get the lowest vcn for the next extent. */ /* Get the lowest vcn for the next extent. */
highest_vcn = sle64_to_cpu(attr->data.non_resident.highest_vcn); highest_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn);
next_vcn = highest_vcn + 1; next_vcn = highest_vcn + 1;
/* Only one extent or error, which we catch below. */ /* Only one extent or error, which we catch below. */
...@@ -2065,7 +2059,7 @@ int ntfs_read_inode_mount(struct inode *vi) ...@@ -2065,7 +2059,7 @@ int ntfs_read_inode_mount(struct inode *vi)
/* Avoid endless loops due to corruption. */ /* Avoid endless loops due to corruption. */
if (next_vcn < sle64_to_cpu( if (next_vcn < sle64_to_cpu(
attr->data.non_resident.lowest_vcn)) { a->data.non_resident.lowest_vcn)) {
ntfs_error(sb, "$MFT has corrupt attribute list " ntfs_error(sb, "$MFT has corrupt attribute list "
"attribute. Run chkdsk."); "attribute. Run chkdsk.");
goto put_err_out; goto put_err_out;
...@@ -2076,7 +2070,7 @@ int ntfs_read_inode_mount(struct inode *vi) ...@@ -2076,7 +2070,7 @@ int ntfs_read_inode_mount(struct inode *vi)
"$MFT is corrupt. Run chkdsk."); "$MFT is corrupt. Run chkdsk.");
goto put_err_out; goto put_err_out;
} }
if (!attr) { if (!a) {
ntfs_error(sb, "$MFT/$DATA attribute not found. $MFT is " ntfs_error(sb, "$MFT/$DATA attribute not found. $MFT is "
"corrupt. Run chkdsk."); "corrupt. Run chkdsk.");
goto put_err_out; goto put_err_out;
...@@ -2318,6 +2312,7 @@ int ntfs_truncate(struct inode *vi) ...@@ -2318,6 +2312,7 @@ int ntfs_truncate(struct inode *vi)
ntfs_volume *vol = ni->vol; ntfs_volume *vol = ni->vol;
ntfs_attr_search_ctx *ctx; ntfs_attr_search_ctx *ctx;
MFT_RECORD *m; MFT_RECORD *m;
ATTR_RECORD *a;
const char *te = " Leaving file length out of sync with i_size."; const char *te = " Leaving file length out of sync with i_size.";
int err; int err;
...@@ -2354,14 +2349,15 @@ int ntfs_truncate(struct inode *vi) ...@@ -2354,14 +2349,15 @@ int ntfs_truncate(struct inode *vi)
vi->i_ino, err); vi->i_ino, err);
goto err_out; goto err_out;
} }
a = ctx->attr;
/* If the size has not changed there is nothing to do. */ /* If the size has not changed there is nothing to do. */
if (ntfs_attr_size(ctx->attr) == i_size_read(vi)) if (ntfs_attr_size(a) == i_size_read(vi))
goto done; goto done;
// TODO: Implement the truncate... // TODO: Implement the truncate...
ntfs_error(vi->i_sb, "Inode size has changed but this is not " ntfs_error(vi->i_sb, "Inode size has changed but this is not "
"implemented yet. Resetting inode size to old value. " "implemented yet. Resetting inode size to old value. "
" This is most likely a bug in the ntfs driver!"); " This is most likely a bug in the ntfs driver!");
i_size_write(vi, ntfs_attr_size(ctx->attr)); i_size_write(vi, ntfs_attr_size(a));
done: done:
ntfs_attr_put_search_ctx(ctx); ntfs_attr_put_search_ctx(ctx);
unmap_mft_record(ni); unmap_mft_record(ni);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册