📄 inode.c
字号:
/* Set inode type to zero but preserve permissions. */ vi->i_mode = base_vi->i_mode & ~S_IFMT; m = map_mft_record(base_ni); if (IS_ERR(m)) { err = PTR_ERR(m); goto err_out; } ctx = ntfs_attr_get_search_ctx(base_ni, m); if (!ctx) { 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; a = ctx->attr; if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_SPARSE)) { if (a->flags & ATTR_COMPRESSION_MASK) { NInoSetCompressed(ni); if ((ni->type != AT_DATA) || (ni->type == AT_DATA && ni->name_len)) { ntfs_error(vi->i_sb, "Found compressed " "non-data or named data " "attribute. Please report " "you saw this message to " "linux-ntfs-dev@lists." "sourceforge.net"); goto unm_err_out; } if (vol->cluster_size > 4096) { ntfs_error(vi->i_sb, "Found compressed " "attribute but compression is " "disabled due to cluster size " "(%i) > 4kiB.", vol->cluster_size); goto unm_err_out; } if ((a->flags & ATTR_COMPRESSION_MASK) != ATTR_IS_COMPRESSED) { ntfs_error(vi->i_sb, "Found unknown " "compression method."); goto unm_err_out; } } /* * The compressed/sparse flag set in an index root just means * to compress all files. */ if (NInoMstProtected(ni) && ni->type != AT_INDEX_ROOT) { ntfs_error(vi->i_sb, "Found mst protected attribute " "but the attribute is %s. Please " "report you saw this message to " "linux-ntfs-dev@lists.sourceforge.net", NInoCompressed(ni) ? "compressed" : "sparse"); goto unm_err_out; } if (a->flags & ATTR_IS_SPARSE) NInoSetSparse(ni); } if (a->flags & ATTR_IS_ENCRYPTED) { if (NInoCompressed(ni)) { ntfs_error(vi->i_sb, "Found encrypted and compressed " "data."); goto unm_err_out; } /* * The encryption flag set in an index root just means to * encrypt all files. */ if (NInoMstProtected(ni) && ni->type != AT_INDEX_ROOT) { ntfs_error(vi->i_sb, "Found mst protected attribute " "but the attribute is encrypted. " "Please report you saw this message " "to linux-ntfs-dev@lists.sourceforge." "net"); goto unm_err_out; } if (ni->type != AT_DATA) { ntfs_error(vi->i_sb, "Found encrypted non-data " "attribute."); goto unm_err_out; } NInoSetEncrypted(ni); } if (!a->non_resident) { /* Ensure the attribute name is placed before the value. */ 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)) { ntfs_error(vi->i_sb, "Found mst protected attribute " "but the attribute is resident. " "Please report you saw this message to " "linux-ntfs-dev@lists.sourceforge.net"); goto unm_err_out; } 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 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(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 (NInoCompressed(ni) || NInoSparse(ni)) { if (NInoCompressed(ni) && a->data.non_resident. compression_unit != 4) { ntfs_error(vi->i_sb, "Found non-standard " "compression unit (%u instead " "of 4). Cannot handle this.", a->data.non_resident. compression_unit); err = -EOPNOTSUPP; goto unm_err_out; } if (a->data.non_resident.compression_unit) { ni->itype.compressed.block_size = 1U << (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_clusters = 1U << a->data.non_resident. compression_unit; } else { ni->itype.compressed.block_size = 0; ni->itype.compressed.block_size_bits = 0; ni->itype.compressed.block_clusters = 0; } ni->itype.compressed.size = sle64_to_cpu( a->data.non_resident.compressed_size); } 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; } vi->i_size = sle64_to_cpu(a->data.non_resident.data_size); ni->initialized_size = sle64_to_cpu( a->data.non_resident.initialized_size); ni->allocated_size = sle64_to_cpu( a->data.non_resident.allocated_size); } /* Setup the operations for this attribute inode. */ vi->i_op = NULL; vi->i_fop = NULL; if (NInoMstProtected(ni)) vi->i_mapping->a_ops = &ntfs_mst_aops; else vi->i_mapping->a_ops = &ntfs_aops; if ((NInoCompressed(ni) || NInoSparse(ni)) && ni->type != AT_INDEX_ROOT) vi->i_blocks = ni->itype.compressed.size >> 9; else vi->i_blocks = ni->allocated_size >> 9; /* * Make sure the base inode does not go away and attach it to the * attribute inode. */ igrab(base_vi); ni->ext.base_ntfs_ino = base_ni; ni->nr_extents = -1; ntfs_attr_put_search_ctx(ctx); unmap_mft_record(base_ni); ntfs_debug("Done."); return 0;unm_err_out: if (!err) err = -EIO; if (ctx) ntfs_attr_put_search_ctx(ctx); unmap_mft_record(base_ni);err_out: ntfs_error(vol->sb, "Failed with error code %i while reading attribute " "inode (mft_no 0x%lx, type 0x%x, name_len %i). " "Marking corrupt inode and base inode 0x%lx as bad. " "Run chkdsk.", err, vi->i_ino, ni->type, ni->name_len, base_vi->i_ino); make_bad_inode(vi); if (err != -ENOMEM) NVolSetErrors(vol); return err;}/** * ntfs_read_locked_index_inode - read an index inode from its base inode * @base_vi: base inode * @vi: index inode to read * * ntfs_read_locked_index_inode() is called from ntfs_index_iget() to read the * index inode described by @vi into memory from the base mft record described * by @base_ni. * * ntfs_read_locked_index_inode() maps, pins and locks the base inode for * reading and looks up the attributes relating to the index described by @vi * before setting up the necessary fields in @vi as well as initializing the * ntfs inode. * * Note, index inodes are essentially attribute inodes (NInoAttr() is true) * with the attribute type set to AT_INDEX_ALLOCATION. Apart from that, they * are setup like directory inodes since directories are a special case of * indices ao they need to be treated in much the same way. Most importantly, * for small indices the index allocation attribute might not actually exist. * However, the index root attribute always exists but this does not need to * have an inode associated with it and this is why we define a new inode type * index. Also, like for directories, we need to have an attribute inode for * the bitmap attribute corresponding to the index allocation attribute and we * can store this in the appropriate field of the inode, just like we do for * normal directory inodes. * * Q: What locks are held when the function is called? * A: i_state has I_LOCK set, hence the inode is locked, also * i_count is set to 1, so it is not going to go away * * Return 0 on success and -errno on error. In the error case, the inode will * have had make_bad_inode() executed on it. */static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi){ loff_t bvi_size; ntfs_volume *vol = NTFS_SB(vi->i_sb); 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; int err = 0; ntfs_debug("Entering for i_ino 0x%lx.", vi->i_ino); ntfs_init_big_inode(vi); ni = NTFS_I(vi); base_ni = NTFS_I(base_vi); /* Just mirror the values from the base inode. */ vi->i_version = base_vi->i_version; vi->i_uid = base_vi->i_uid; vi->i_gid = base_vi->i_gid; vi->i_nlink = base_vi->i_nlink; vi->i_mtime = base_vi->i_mtime; vi->i_ctime = base_vi->i_ctime; vi->i_atime = base_vi->i_atime; vi->i_generation = ni->seq_no = base_ni->seq_no; /* Set inode type to zero but preserve permissions. */ vi->i_mode = base_vi->i_mode & ~S_IFMT; /* Map the mft record for the base inode. */ m = map_mft_record(base_ni); if (IS_ERR(m)) { err = PTR_ERR(m); goto err_out; } ctx = ntfs_attr_get_search_ctx(base_ni, m); if (!ctx) { err = -ENOMEM; goto unm_err_out; } /* Find the index root attribute. */ err = ntfs_attr_lookup(AT_INDEX_ROOT, ni->name, ni->name_len, CASE_SENSITIVE, 0, NULL, 0, ctx); if (unlikely(err)) { if (err == -ENOENT) ntfs_error(vi->i_sb, "$INDEX_ROOT attribute is " "missing."); goto unm_err_out; } a = ctx->attr; /* Set up the state. */ 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(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, except for * directories of course but those are not dealt with here. */ 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*)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 = (u8*)&ir->index + le32_to_cpu(ir->index.index_length); if (index_end > ir_end) { ntfs_error(vi->i_sb, "Index is corrupt."); goto unm_err_out; } if (ir->type) { ntfs_error(vi->i_sb, "Index type is not 0 (type is 0x%x).", le32_to_cpu(ir->type)); goto unm_err_out; } ni->itype.index.collation_rule = ir->collation_rule; ntfs_debug("Index collation rule is 0x%x.", le32_to_cpu(ir->collation_rule)); ni->itype.index.block_size = le32_to_cpu(ir->index_block_size); if (ni->itype.index.block_size & (ni->itype.index.block_size - 1)) { ntfs_error(vi->i_sb, "Index block size (%u) is not a power of " "two.", ni->itype.index.block_size); goto unm_err_out; } if (ni->itype.index.block_size > PAGE_CACHE_SIZE) { ntfs_error(vi->i_sb, "Index block size (%u) > PAGE_CACHE_SIZE " "(%ld) is not supported. Sorry.", ni->itype.index.block_size, PAGE_CACHE_SIZE); err = -EOPNOTSUPP; goto unm_err_out; } if (ni->itype.index.block_size < NTFS_BLOCK_SIZE) { ntfs_error(vi->i_sb, "Index block size (%u) < NTFS_BLOCK_SIZE " "(%i) is not supported. Sorry.", ni->itype.index.block_size, NTFS_BLOCK_SIZE); err = -EOPNOTSUPP; goto unm_err_out; } ni->itype.index.block_size_bits = ffs(ni->itype.index.block_size) - 1; /* Determine the size of a vcn in the index. */ if (vol->cluster_size <= ni->itype.index.block_size) { ni->itype.index.vcn_size = vol->cluster_size; ni->itype.index.vcn_size_bits = vol->cluster_size_bits; } else { ni->itype.index.vcn_size = vol->sector_size; ni->itype.index.vcn_size_bits = vol->sector_size_bits; } /* Check for presence of index allocation attribute. */ if (!(ir->index.flags & LARGE_INDEX)) { /* No index allocation. */ vi->i_size = ni->initialized_size = ni->allocated_size = 0; /* We are done with the mft record, so we release it. */ ntfs_attr_put_search_ctx(ctx); unmap_mft_record(base_ni); m = NULL; ctx = NULL; goto skip_large_index_stuff; } /* LARGE_INDEX: Index allocation present. Setup state. */ NInoSetIndexAllocPresent(ni); /* Find index allocation attribute. */ ntfs_attr_reinit_search_ctx(ctx); err = ntfs_attr_lookup(AT_INDEX_ALLOCATION, ni->name, ni->name_len, CASE_SENSITIVE, 0, NULL, 0, ctx); if (unlikely(err)) { if (err == -ENOENT) ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is " "not present but $INDEX_ROOT " "indicated it is."); else ntfs_error(vi->i_sb, "Failed to lookup " "$INDEX_ALLOCATION attribute."); goto unm_err_out; } a = ctx->attr; if (!a->non_resident) { ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is " "resident."); goto unm_err_out; } /* * Ensure the attribute name is placed before the mapping pairs array. */ 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 (a->flags & ATTR_IS_ENCRYPTED) { ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is " "encrypted."); goto unm_err_out; } if (a->flags & ATTR_IS_SPARSE) { ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is sparse."); goto unm_err_out; } if (a->flags & ATTR_COMPRESSION_MASK) { ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is "
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -