diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index 53bb6c1404f2330869c8f6f348fadcfe465e5a92..ad2c4e88f053ed15b51acabb91a4f33b1b601782 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog @@ -76,6 +76,10 @@ ToDo/Notes: warning in the do_div() call on sparc32. Thanks to Meelis Roos for the report and analysis of the warning. - 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. diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 372c7fcdc068aafbac8434106810507169d38231..cfca17384115b92e254c530e0526e1f4cb15e0aa 100644 --- a/fs/ntfs/inode.c +++ b/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_inode *ni; MFT_RECORD *m; + ATTR_RECORD *a; STANDARD_INFORMATION *si; ntfs_attr_search_ctx *ctx; int err = 0; @@ -633,9 +634,10 @@ static int ntfs_read_locked_inode(struct inode *vi) } goto unm_err_out; } + a = ctx->attr; /* Get the standard information attribute value. */ - si = (STANDARD_INFORMATION*)((char*)ctx->attr + - le16_to_cpu(ctx->attr->data.resident.value_offset)); + si = (STANDARD_INFORMATION*)((u8*)a + + le16_to_cpu(a->data.resident.value_offset)); /* 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; ntfs_debug("Attribute list found in inode 0x%lx.", vi->i_ino); NInoSetAttrList(ni); - if (ctx->attr->flags & ATTR_IS_ENCRYPTED || - ctx->attr->flags & ATTR_COMPRESSION_MASK || - ctx->attr->flags & ATTR_IS_SPARSE) { + a = ctx->attr; + if (a->flags & ATTR_IS_ENCRYPTED || + a->flags & ATTR_COMPRESSION_MASK || + a->flags & ATTR_IS_SPARSE) { ntfs_error(vi->i_sb, "Attribute list attribute is " "compressed/encrypted/sparse."); goto unm_err_out; } /* 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); if (!ni->attr_list) { 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; goto unm_err_out; } - if (ctx->attr->non_resident) { + if (a->non_resident) { 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 " "zero lowest_vcn."); 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. */ ni->attr_list_rl.rl = ntfs_mapping_pairs_decompress(vol, - ctx->attr, NULL); + a, NULL); if (IS_ERR(ni->attr_list_rl.rl)) { err = PTR_ERR(ni->attr_list_rl.rl); ni->attr_list_rl.rl = NULL; @@ -713,27 +716,26 @@ static int ntfs_read_locked_inode(struct inode *vi) /* Now load the attribute list. */ if ((err = load_attribute_list(vol, &ni->attr_list_rl, ni->attr_list, ni->attr_list_size, - sle64_to_cpu(ctx->attr->data. - non_resident.initialized_size)))) { + sle64_to_cpu(a->data.non_resident. + initialized_size)))) { ntfs_error(vi->i_sb, "Failed to load " "attribute list attribute."); goto unm_err_out; } - } else /* if (!ctx.attr->non_resident) */ { - if ((u8*)ctx->attr + le16_to_cpu( - ctx->attr->data.resident.value_offset) + - le32_to_cpu( - ctx->attr->data.resident.value_length) > + } else /* if (!a->non_resident) */ { + if ((u8*)a + le16_to_cpu(a->data.resident.value_offset) + + le32_to_cpu( + a->data.resident.value_length) > (u8*)ctx->mrec + vol->mft_record_size) { ntfs_error(vi->i_sb, "Corrupt attribute list " "in inode."); goto unm_err_out; } /* Now copy the attribute list. */ - memcpy(ni->attr_list, (u8*)ctx->attr + le16_to_cpu( - ctx->attr->data.resident.value_offset), + memcpy(ni->attr_list, (u8*)a + le16_to_cpu( + a->data.resident.value_offset), le32_to_cpu( - ctx->attr->data.resident.value_length)); + a->data.resident.value_length)); } } skip_attr_list_load: @@ -746,7 +748,7 @@ static int ntfs_read_locked_inode(struct inode *vi) struct inode *bvi; ntfs_inode *bni; INDEX_ROOT *ir; - char *ir_end, *index_end; + u8 *ir_end, *index_end; /* It is a directory, find index root attribute. */ ntfs_attr_reinit_search_ctx(ctx); @@ -762,17 +764,16 @@ static int ntfs_read_locked_inode(struct inode *vi) } goto unm_err_out; } + a = ctx->attr; /* 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."); goto unm_err_out; } /* Ensure the attribute name is placed before the value. */ - if (unlikely(ctx->attr->name_length && - (le16_to_cpu(ctx->attr->name_offset) >= - le16_to_cpu(ctx->attr->data.resident. - value_offset)))) { + if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >= + le16_to_cpu(a->data.resident.value_offset)))) { ntfs_error(vol->sb, "$INDEX_ROOT attribute name is " "placed after the attribute value."); goto unm_err_out; @@ -783,28 +784,27 @@ static int ntfs_read_locked_inode(struct inode *vi) * encrypted. However index root cannot be both compressed and * encrypted. */ - if (ctx->attr->flags & ATTR_COMPRESSION_MASK) + if (a->flags & ATTR_COMPRESSION_MASK) NInoSetCompressed(ni); - if (ctx->attr->flags & ATTR_IS_ENCRYPTED) { - if (ctx->attr->flags & ATTR_COMPRESSION_MASK) { + if (a->flags & ATTR_IS_ENCRYPTED) { + if (a->flags & ATTR_COMPRESSION_MASK) { ntfs_error(vi->i_sb, "Found encrypted and " "compressed attribute."); goto unm_err_out; } NInoSetEncrypted(ni); } - if (ctx->attr->flags & ATTR_IS_SPARSE) + if (a->flags & ATTR_IS_SPARSE) NInoSetSparse(ni); - ir = (INDEX_ROOT*)((char*)ctx->attr + le16_to_cpu( - ctx->attr->data.resident.value_offset)); - ir_end = (char*)ir + le32_to_cpu( - ctx->attr->data.resident.value_length); - if (ir_end > (char*)ctx->mrec + vol->mft_record_size) { + ir = (INDEX_ROOT*)((u8*)a + + le16_to_cpu(a->data.resident.value_offset)); + ir_end = (u8*)ir + le32_to_cpu(a->data.resident.value_length); + if (ir_end > (u8*)ctx->mrec + vol->mft_record_size) { ntfs_error(vi->i_sb, "$INDEX_ROOT attribute is " "corrupt."); goto unm_err_out; } - index_end = (char*)&ir->index + + index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length); if (index_end > ir_end) { ntfs_error(vi->i_sb, "Directory index is corrupt."); @@ -891,7 +891,8 @@ static int ntfs_read_locked_inode(struct inode *vi) "attribute."); goto unm_err_out; } - if (!ctx->attr->non_resident) { + a = ctx->attr; + if (!a->non_resident) { ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute " "is resident."); goto unm_err_out; @@ -900,42 +901,40 @@ static int ntfs_read_locked_inode(struct inode *vi) * Ensure the attribute name is placed before the mapping pairs * array. */ - if (unlikely(ctx->attr->name_length && - (le16_to_cpu(ctx->attr->name_offset) >= - le16_to_cpu(ctx->attr->data.non_resident. - mapping_pairs_offset)))) { + if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >= + le16_to_cpu( + a->data.non_resident.mapping_pairs_offset)))) { ntfs_error(vol->sb, "$INDEX_ALLOCATION attribute name " "is placed after the mapping pairs " "array."); 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 encrypted."); 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."); 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 compressed."); 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 attribute has non " "zero lowest_vcn."); 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( - ctx->attr->data.non_resident.initialized_size); + a->data.non_resident.initialized_size); 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 would deadlock in ntfs_attr_iget(). @@ -1013,10 +1012,11 @@ static int ntfs_read_locked_inode(struct inode *vi) ntfs_error(vi->i_sb, "$DATA attribute is missing."); goto unm_err_out; } + a = ctx->attr; /* Setup the state. */ - if (ctx->attr->non_resident) { + if (a->non_resident) { NInoSetNonResident(ni); - if (ctx->attr->flags & ATTR_COMPRESSION_MASK) { + if (a->flags & ATTR_COMPRESSION_MASK) { NInoSetCompressed(ni); if (vol->cluster_size > 4096) { ntfs_error(vi->i_sb, "Found " @@ -1026,7 +1026,7 @@ static int ntfs_read_locked_inode(struct inode *vi) vol->cluster_size); goto unm_err_out; } - if ((ctx->attr->flags & ATTR_COMPRESSION_MASK) + if ((a->flags & ATTR_COMPRESSION_MASK) != ATTR_IS_COMPRESSED) { ntfs_error(vi->i_sb, "Found " "unknown compression method or " @@ -1034,37 +1034,37 @@ static int ntfs_read_locked_inode(struct inode *vi) goto unm_err_out; } ni->itype.compressed.block_clusters = 1U << - ctx->attr->data.non_resident. + a->data.non_resident. compression_unit; - if (ctx->attr->data.non_resident. - compression_unit != 4) { + if (a->data.non_resident.compression_unit != + 4) { ntfs_error(vi->i_sb, "Found " "nonstandard compression unit " "(%u instead of 4). Cannot " "handle this.", - ctx->attr->data.non_resident. + a->data.non_resident. compression_unit); err = -EOPNOTSUPP; goto unm_err_out; } ni->itype.compressed.block_size = 1U << ( - ctx->attr->data.non_resident. + a->data.non_resident. compression_unit + vol->cluster_size_bits); ni->itype.compressed.block_size_bits = ffs( ni->itype.compressed.block_size) - 1; } - if (ctx->attr->flags & ATTR_IS_ENCRYPTED) { - if (ctx->attr->flags & ATTR_COMPRESSION_MASK) { + if (a->flags & ATTR_IS_ENCRYPTED) { + if (a->flags & ATTR_COMPRESSION_MASK) { ntfs_error(vi->i_sb, "Found encrypted " "and compressed data."); goto unm_err_out; } NInoSetEncrypted(ni); } - if (ctx->attr->flags & ATTR_IS_SPARSE) + if (a->flags & ATTR_IS_SPARSE) 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 " "attribute has non zero " "lowest_vcn."); @@ -1072,28 +1072,28 @@ static int ntfs_read_locked_inode(struct inode *vi) } /* Setup all the sizes. */ 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( - ctx->attr->data.non_resident. - initialized_size); + a->data.non_resident.initialized_size); ni->allocated_size = sle64_to_cpu( - ctx->attr->data.non_resident. - allocated_size); - if (NInoCompressed(ni)) { + a->data.non_resident.allocated_size); + if (NInoCompressed(ni)) ni->itype.compressed.size = sle64_to_cpu( - ctx->attr->data.non_resident. + a->data.non_resident. compressed_size); - } } else { /* Resident attribute. */ - /* - * Make all sizes equal for simplicity in read code - * paths. FIXME: Need to keep this in mind when - * converting to non-resident attribute in write code - * path. (Probably only affects truncate().) - */ - vi->i_size = ni->initialized_size = ni->allocated_size = - le32_to_cpu( - ctx->attr->data.resident.value_length); + /* Setup all the sizes. */ + vi->i_size = ni->initialized_size = le32_to_cpu( + a->data.resident.value_length); + ni->allocated_size = le32_to_cpu(a->length) - + le16_to_cpu( + a->data.resident.value_offset); + if (vi->i_size > ni->allocated_size) { + ntfs_error(vi->i_sb, "Resident data attribute " + "is corrupt (size exceeds " + "allocation)."); + goto unm_err_out; + } } no_data_attr_special_case: /* 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_inode *ni, *base_ni; MFT_RECORD *m; + ATTR_RECORD *a; ntfs_attr_search_ctx *ctx; int err = 0; @@ -1203,24 +1204,21 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) err = -ENOMEM; goto unm_err_out; } - /* Find the attribute. */ err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, CASE_SENSITIVE, 0, NULL, 0, ctx); if (unlikely(err)) goto unm_err_out; - - if (!ctx->attr->non_resident) { + a = ctx->attr; + if (!a->non_resident) { /* Ensure the attribute name is placed before the value. */ - if (unlikely(ctx->attr->name_length && - (le16_to_cpu(ctx->attr->name_offset) >= - le16_to_cpu(ctx->attr->data.resident. - value_offset)))) { + if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >= + le16_to_cpu(a->data.resident.value_offset)))) { ntfs_error(vol->sb, "Attribute name is placed after " "the attribute value."); goto unm_err_out; } - if (NInoMstProtected(ni) || ctx->attr->flags) { + if (NInoMstProtected(ni) || a->flags) { ntfs_error(vi->i_sb, "Found mst protected attribute " "or attribute with non-zero flags but " "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"); goto unm_err_out; } - /* - * Resident attribute. Make all sizes equal for simplicity in - * read code paths. - */ - vi->i_size = ni->initialized_size = ni->allocated_size = - le32_to_cpu(ctx->attr->data.resident.value_length); + /* Resident attribute. Setup all the sizes. */ + vi->i_size = ni->initialized_size = le32_to_cpu( + a->data.resident.value_length); + ni->allocated_size = le32_to_cpu(a->length) - + le16_to_cpu(a->data.resident.value_offset); + 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 { NInoSetNonResident(ni); /* * Ensure the attribute name is placed before the mapping pairs * array. */ - if (unlikely(ctx->attr->name_length && - (le16_to_cpu(ctx->attr->name_offset) >= - le16_to_cpu(ctx->attr->data.non_resident. - mapping_pairs_offset)))) { + if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >= + le16_to_cpu( + a->data.non_resident.mapping_pairs_offset)))) { ntfs_error(vol->sb, "Attribute name is placed after " "the mapping pairs array."); goto unm_err_out; } - if (ctx->attr->flags & ATTR_COMPRESSION_MASK) { + if (a->flags & ATTR_COMPRESSION_MASK) { if (NInoMstProtected(ni)) { ntfs_error(vi->i_sb, "Found mst protected " "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); goto unm_err_out; } - if ((ctx->attr->flags & ATTR_COMPRESSION_MASK) - != ATTR_IS_COMPRESSED) { + if ((a->flags & ATTR_COMPRESSION_MASK) != + ATTR_IS_COMPRESSED) { ntfs_error(vi->i_sb, "Found unknown " "compression method."); goto unm_err_out; } ni->itype.compressed.block_clusters = 1U << - ctx->attr->data.non_resident. - compression_unit; - if (ctx->attr->data.non_resident.compression_unit != - 4) { + a->data.non_resident.compression_unit; + if (a->data.non_resident.compression_unit != 4) { ntfs_error(vi->i_sb, "Found nonstandard " "compression unit (%u instead " "of 4). Cannot handle this.", - ctx->attr->data.non_resident. + a->data.non_resident. compression_unit); err = -EOPNOTSUPP; goto unm_err_out; } ni->itype.compressed.block_size = 1U << ( - ctx->attr->data.non_resident. - compression_unit + + a->data.non_resident.compression_unit + vol->cluster_size_bits); 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 (ctx->attr->flags & ATTR_COMPRESSION_MASK) { - ntfs_error(vi->i_sb, "Found encrypted " - "and compressed data."); + if (a->flags & ATTR_IS_ENCRYPTED) { + if (a->flags & ATTR_COMPRESSION_MASK) { + ntfs_error(vi->i_sb, "Found encrypted and " + "compressed data."); goto unm_err_out; } if (NInoMstProtected(ni)) { @@ -1320,7 +1318,7 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) } NInoSetEncrypted(ni); } - if (ctx->attr->flags & ATTR_IS_SPARSE) { + if (a->flags & ATTR_IS_SPARSE) { if (NInoMstProtected(ni)) { ntfs_error(vi->i_sb, "Found mst protected " "attribute but the attribute " @@ -1332,23 +1330,20 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) } 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 " "non-zero lowest_vcn."); goto unm_err_out; } /* Setup all the sizes. */ - 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( - ctx->attr->data.non_resident.initialized_size); + a->data.non_resident.initialized_size); ni->allocated_size = sle64_to_cpu( - ctx->attr->data.non_resident.allocated_size); - if (NInoCompressed(ni)) { + a->data.non_resident.allocated_size); + if (NInoCompressed(ni)) ni->itype.compressed.size = sle64_to_cpu( - ctx->attr->data.non_resident. - compressed_size); - } + a->data.non_resident.compressed_size); } /* 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; struct inode *bvi; MFT_RECORD *m; + ATTR_RECORD *a; ntfs_attr_search_ctx *ctx; INDEX_ROOT *ir; u8 *ir_end, *index_end; @@ -1478,30 +1474,28 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi) "missing."); goto unm_err_out; } + a = ctx->attr; /* 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."); goto unm_err_out; } /* Ensure the attribute name is placed before the value. */ - if (unlikely(ctx->attr->name_length && - (le16_to_cpu(ctx->attr->name_offset) >= - le16_to_cpu(ctx->attr->data.resident. - value_offset)))) { + if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >= + le16_to_cpu(a->data.resident.value_offset)))) { ntfs_error(vol->sb, "$INDEX_ROOT attribute name is placed " "after the attribute value."); goto unm_err_out; } /* 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)) { ntfs_error(vi->i_sb, "Found compressed/encrypted/sparse index " "root attribute."); goto unm_err_out; } - ir = (INDEX_ROOT*)((u8*)ctx->attr + - le16_to_cpu(ctx->attr->data.resident.value_offset)); - ir_end = (u8*)ir + le32_to_cpu(ctx->attr->data.resident.value_length); + ir = (INDEX_ROOT*)((u8*)a + le16_to_cpu(a->data.resident.value_offset)); + ir_end = (u8*)ir + le32_to_cpu(a->data.resident.value_length); if (ir_end > (u8*)ctx->mrec + vol->mft_record_size) { ntfs_error(vi->i_sb, "$INDEX_ROOT attribute is corrupt."); 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."); goto unm_err_out; } - if (!ctx->attr->non_resident) { + if (!a->non_resident) { ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is " "resident."); 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. */ - if (unlikely(ctx->attr->name_length && (le16_to_cpu( - ctx->attr->name_offset) >= le16_to_cpu( - ctx->attr->data.non_resident.mapping_pairs_offset)))) { + if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >= + le16_to_cpu( + a->data.non_resident.mapping_pairs_offset)))) { ntfs_error(vol->sb, "$INDEX_ALLOCATION attribute name is " "placed after the mapping pairs array."); 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 " "encrypted."); 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."); 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 " "compressed."); 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 " "attribute has non zero lowest_vcn."); 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( - ctx->attr->data.non_resident.initialized_size); - ni->allocated_size = sle64_to_cpu( - ctx->attr->data.non_resident.allocated_size); + a->data.non_resident.initialized_size); + ni->allocated_size = sle64_to_cpu(a->data.non_resident.allocated_size); /* * We are done with the mft record, so we release it. Otherwise * we would deadlock in ntfs_attr_iget(). @@ -1716,7 +1709,7 @@ int ntfs_read_inode_mount(struct inode *vi) struct buffer_head *bh; ntfs_inode *ni; MFT_RECORD *m = NULL; - ATTR_RECORD *attr; + ATTR_RECORD *a; ntfs_attr_search_ctx *ctx; unsigned int i, nr_blocks; int err; @@ -1813,9 +1806,10 @@ int ntfs_read_inode_mount(struct inode *vi) ntfs_debug("Attribute list attribute found in $MFT."); NInoSetAttrList(ni); - if (ctx->attr->flags & ATTR_IS_ENCRYPTED || - ctx->attr->flags & ATTR_COMPRESSION_MASK || - ctx->attr->flags & ATTR_IS_SPARSE) { + a = ctx->attr; + if (a->flags & ATTR_IS_ENCRYPTED || + a->flags & ATTR_COMPRESSION_MASK || + a->flags & ATTR_IS_SPARSE) { ntfs_error(sb, "Attribute list attribute is " "compressed/encrypted/sparse. Not " "allowed. $MFT is corrupt. You should " @@ -1823,16 +1817,16 @@ int ntfs_read_inode_mount(struct inode *vi) goto put_err_out; } /* 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); if (!ni->attr_list) { ntfs_error(sb, "Not enough memory to allocate buffer " "for attribute list."); goto put_err_out; } - if (ctx->attr->non_resident) { + if (a->non_resident) { 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 " "lowest_vcn. $MFT is corrupt. " "You should run chkdsk."); @@ -1840,7 +1834,7 @@ int ntfs_read_inode_mount(struct inode *vi) } /* Setup the runlist. */ ni->attr_list_rl.rl = ntfs_mapping_pairs_decompress(vol, - ctx->attr, NULL); + a, NULL); if (IS_ERR(ni->attr_list_rl.rl)) { err = PTR_ERR(ni->attr_list_rl.rl); ni->attr_list_rl.rl = NULL; @@ -1852,7 +1846,7 @@ int ntfs_read_inode_mount(struct inode *vi) /* Now load the attribute list. */ if ((err = load_attribute_list(vol, &ni->attr_list_rl, ni->attr_list, ni->attr_list_size, - sle64_to_cpu(ctx->attr->data. + sle64_to_cpu(a->data. non_resident.initialized_size)))) { ntfs_error(sb, "Failed to load attribute list " "attribute with error code %i.", @@ -1860,20 +1854,20 @@ int ntfs_read_inode_mount(struct inode *vi) goto put_err_out; } } else /* if (!ctx.attr->non_resident) */ { - if ((u8*)ctx->attr + le16_to_cpu( - ctx->attr->data.resident.value_offset) + + if ((u8*)a + le16_to_cpu( + a->data.resident.value_offset) + le32_to_cpu( - ctx->attr->data.resident.value_length) > + a->data.resident.value_length) > (u8*)ctx->mrec + vol->mft_record_size) { ntfs_error(sb, "Corrupt attribute list " "attribute."); goto put_err_out; } /* Now copy the attribute list. */ - memcpy(ni->attr_list, (u8*)ctx->attr + le16_to_cpu( - ctx->attr->data.resident.value_offset), + memcpy(ni->attr_list, (u8*)a + le16_to_cpu( + a->data.resident.value_offset), le32_to_cpu( - ctx->attr->data.resident.value_length)); + a->data.resident.value_length)); } /* 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); /* Now load all attribute extents. */ - attr = NULL; + a = NULL; next_vcn = last_vcn = highest_vcn = 0; while (!(err = ntfs_attr_lookup(AT_DATA, NULL, 0, 0, next_vcn, NULL, 0, ctx))) { runlist_element *nrl; /* Cache the current attribute. */ - attr = ctx->attr; + a = ctx->attr; /* $MFT must be non-resident. */ - if (!attr->non_resident) { + if (!a->non_resident) { ntfs_error(sb, "$MFT must be non-resident but a " "resident extent was found. $MFT is " "corrupt. Run chkdsk."); goto put_err_out; } /* $MFT must be uncompressed and unencrypted. */ - if (attr->flags & ATTR_COMPRESSION_MASK || - attr->flags & ATTR_IS_ENCRYPTED || - attr->flags & ATTR_IS_SPARSE) { + if (a->flags & ATTR_COMPRESSION_MASK || + a->flags & ATTR_IS_ENCRYPTED || + a->flags & ATTR_IS_SPARSE) { ntfs_error(sb, "$MFT must be uncompressed, " "non-sparse, and unencrypted but a " "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 * 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)) { ntfs_error(sb, "ntfs_mapping_pairs_decompress() " "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? */ if (!next_vcn) { - if (attr->data.non_resident.lowest_vcn) { + if (a->data.non_resident.lowest_vcn) { ntfs_error(sb, "First extent of $DATA " "attribute has non zero " "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. */ last_vcn = sle64_to_cpu( - attr->data.non_resident.allocated_size) + a->data.non_resident.allocated_size) >> vol->cluster_size_bits; /* Fill in the inode size. */ vi->i_size = sle64_to_cpu( - attr->data.non_resident.data_size); - ni->initialized_size = sle64_to_cpu(attr->data. - non_resident.initialized_size); + a->data.non_resident.data_size); + ni->initialized_size = sle64_to_cpu( + a->data.non_resident.initialized_size); 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 * 2^32 - 1. @@ -2056,7 +2050,7 @@ int ntfs_read_inode_mount(struct inode *vi) } /* 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; /* 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. */ 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 " "attribute. Run chkdsk."); goto put_err_out; @@ -2076,7 +2070,7 @@ int ntfs_read_inode_mount(struct inode *vi) "$MFT is corrupt. Run chkdsk."); goto put_err_out; } - if (!attr) { + if (!a) { ntfs_error(sb, "$MFT/$DATA attribute not found. $MFT is " "corrupt. Run chkdsk."); goto put_err_out; @@ -2318,6 +2312,7 @@ int ntfs_truncate(struct inode *vi) ntfs_volume *vol = ni->vol; ntfs_attr_search_ctx *ctx; MFT_RECORD *m; + ATTR_RECORD *a; const char *te = " Leaving file length out of sync with i_size."; int err; @@ -2354,14 +2349,15 @@ int ntfs_truncate(struct inode *vi) vi->i_ino, err); goto err_out; } + a = ctx->attr; /* 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; // TODO: Implement the truncate... ntfs_error(vi->i_sb, "Inode size has changed but this is not " "implemented yet. Resetting inode size to old value. " " 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: ntfs_attr_put_search_ctx(ctx); unmap_mft_record(ni);