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: Anton Altaparmakov <aia21@cantab.net>
This commit is contained in:
parent
37e4c13b98
commit
5ae9fcf8f3
|
@ -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.
|
||||||
|
|
||||||
|
|
344
fs/ntfs/inode.c
344
fs/ntfs/inode.c
|
@ -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)
|
||||||
}
|
}
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
* 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)
|
||||||
/* 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 @@ skip_attr_list_load:
|
||||||
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 @@ skip_attr_list_load:
|
||||||
}
|
}
|
||||||
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 @@ skip_attr_list_load:
|
||||||
* 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 @@ skip_attr_list_load:
|
||||||
"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 @@ skip_attr_list_load:
|
||||||
* 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 @@ skip_large_dir_stuff:
|
||||||
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 @@ skip_large_dir_stuff:
|
||||||
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 @@ skip_large_dir_stuff:
|
||||||
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 @@ skip_large_dir_stuff:
|
||||||
}
|
}
|
||||||
/* 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)
|
||||||
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)
|
||||||
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)
|
||||||
"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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
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)
|
||||||
}
|
}
|
||||||
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)
|
||||||
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)
|
||||||
"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)
|
||||||
"$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)
|
||||||
/*
|
/*
|
||||||
* 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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
/* 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)
|
||||||
/* 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)
|
||||||
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)
|
||||||
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)
|
||||||
* 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)
|
||||||
|
|
||||||
/* 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)
|
||||||
}
|
}
|
||||||
/* 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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)
|
||||||
|
|
||||||
/* 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)
|
||||||
"$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)
|
||||||
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)
|
||||||
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);
|
||||||
|
|
Loading…
Reference in New Issue