inode.c
来自「一个类似windows」· C语言 代码 · 共 2,026 行 · 第 1/5 页
C
2,026 行
if (!lookup_attr(AT_INDEX_ALLOCATION, I30, 4, CASE_SENSITIVE,
0, NULL, 0, ctx)) {
ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
"is not present but $INDEX_ROOT "
"indicated it is.");
goto unm_err_out;
}
if (!ctx->attr->non_resident) {
ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
"is resident.");
goto unm_err_out;
}
if (ctx->attr->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) {
ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
"is sparse.");
goto unm_err_out;
}
if (ctx->attr->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) {
ntfs_error(vi->i_sb, "First extent of "
"$INDEX_ALLOCATION attribute has non "
"zero lowest_vcn. Inode is corrupt. "
"You should run chkdsk.");
goto unm_err_out;
}
vi->i_size = sle64_to_cpu(
ctx->attr->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);
/*
* We are done with the mft record, so we release it. Otherwise
* we would deadlock in ntfs_attr_iget().
*/
put_attr_search_ctx(ctx);
unmap_mft_record(ni);
m = NULL;
ctx = NULL;
/* Get the index bitmap attribute inode. */
bvi = ntfs_attr_iget(vi, AT_BITMAP, I30, 4);
if (unlikely(IS_ERR(bvi))) {
ntfs_error(vi->i_sb, "Failed to get bitmap attribute.");
err = PTR_ERR(bvi);
goto unm_err_out;
}
ni->itype.index.bmp_ino = bvi;
bni = NTFS_I(bvi);
if (NInoCompressed(bni) || NInoEncrypted(bni) ||
NInoSparse(bni)) {
ntfs_error(vi->i_sb, "$BITMAP attribute is compressed "
"and/or encrypted and/or sparse.");
goto unm_err_out;
}
/* Consistency check bitmap size vs. index allocation size. */
if ((bvi->i_size << 3) < (vi->i_size >>
ni->itype.index.block_size_bits)) {
ntfs_error(vi->i_sb, "Index bitmap too small (0x%Lx) "
"for index allocation (0x%Lx).",
bvi->i_size << 3, vi->i_size);
goto unm_err_out;
}
skip_large_dir_stuff:
/* Everyone gets read and scan permissions. */
vi->i_mode |= S_IRUGO | S_IXUGO;
/* If not read-only, set write permissions. */
if (!IS_RDONLY(vi))
vi->i_mode |= S_IWUGO;
/*
* Apply the directory permissions mask set in the mount
* options.
*/
vi->i_mode &= ~vol->dmask;
/* Setup the operations for this inode. */
vi->i_op = &ntfs_dir_inode_ops;
vi->i_fop = &ntfs_dir_ops;
vi->i_mapping->a_ops = &ntfs_aops;
} else {
/* It is a file. */
reinit_attr_search_ctx(ctx);
/* Setup the data attribute, even if not present. */
ni->type = AT_DATA;
ni->name = NULL;
ni->name_len = 0;
/* Find first extent of the unnamed data attribute. */
if (!lookup_attr(AT_DATA, NULL, 0, 0, 0, NULL, 0, ctx)) {
vi->i_size = ni->initialized_size =
ni->allocated_size = 0LL;
/*
* FILE_Secure does not have an unnamed $DATA
* attribute, so we special case it here.
*/
if (vi->i_ino == FILE_Secure)
goto no_data_attr_special_case;
/*
* Most if not all the system files in the $Extend
* system directory do not have unnamed data
* attributes so we need to check if the parent
* directory of the file is FILE_Extend and if it is
* ignore this error. To do this we need to get the
* name of this inode from the mft record as the name
* contains the back reference to the parent directory.
*/
if (ntfs_is_extended_system_file(ctx) > 0)
goto no_data_attr_special_case;
// FIXME: File is corrupt! Hot-fix with empty data
// attribute if recovery option is set.
ntfs_error(vi->i_sb, "$DATA attribute is "
"missing.");
goto unm_err_out;
}
/* Setup the state. */
if (ctx->attr->non_resident) {
NInoSetNonResident(ni);
if (ctx->attr->flags & ATTR_COMPRESSION_MASK) {
NInoSetCompressed(ni);
if (vol->cluster_size > 4096) {
ntfs_error(vi->i_sb, "Found "
"compressed data but "
"compression is disabled due "
"to cluster size (%i) > 4kiB.",
vol->cluster_size);
goto unm_err_out;
}
if ((ctx->attr->flags & ATTR_COMPRESSION_MASK)
!= ATTR_IS_COMPRESSED) {
ntfs_error(vi->i_sb, "Found "
"unknown compression method or "
"corrupt file.");
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) {
ntfs_error(vi->i_sb, "Found "
"nonstandard compression unit "
"(%u instead of 4). Cannot "
"handle this. This might "
"indicate corruption so you "
"should run chkdsk.",
ctx->attr->data.non_resident.
compression_unit);
err = -EOPNOTSUPP;
goto unm_err_out;
}
ni->itype.compressed.block_size = 1U << (
ctx->attr->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) {
ntfs_error(vi->i_sb, "Found encrypted "
"and compressed data.");
goto unm_err_out;
}
NInoSetEncrypted(ni);
}
if (ctx->attr->flags & ATTR_IS_SPARSE)
NInoSetSparse(ni);
if (ctx->attr->data.non_resident.lowest_vcn) {
ntfs_error(vi->i_sb, "First extent of $DATA "
"attribute has non zero "
"lowest_vcn. Inode is corrupt. "
"You should run chkdsk.");
goto unm_err_out;
}
/* Setup all the sizes. */
vi->i_size = sle64_to_cpu(
ctx->attr->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);
if (NInoCompressed(ni)) {
ni->itype.compressed.size = sle64_to_cpu(
ctx->attr->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);
}
no_data_attr_special_case:
/* We are done with the mft record, so we release it. */
put_attr_search_ctx(ctx);
unmap_mft_record(ni);
m = NULL;
ctx = NULL;
/* Everyone gets all permissions. */
vi->i_mode |= S_IRWXUGO;
/* If read-only, noone gets write permissions. */
if (IS_RDONLY(vi))
vi->i_mode &= ~S_IWUGO;
/* Apply the file permissions mask set in the mount options. */
vi->i_mode &= ~vol->fmask;
/* Setup the operations for this inode. */
vi->i_op = &ntfs_file_inode_ops;
vi->i_fop = &ntfs_file_ops;
vi->i_mapping->a_ops = &ntfs_aops;
}
/*
* The number of 512-byte blocks used on disk (for stat). This is in so
* far inaccurate as it doesn't account for any named streams or other
* special non-resident attributes, but that is how Windows works, too,
* so we are at least consistent with Windows, if not entirely
* consistent with the Linux Way. Doing it the Linux Way would cause a
* significant slowdown as it would involve iterating over all
* attributes in the mft record and adding the allocated/compressed
* sizes of all non-resident attributes present to give us the Linux
* correct size that should go into i_blocks (after division by 512).
*/
if (!NInoCompressed(ni))
vi->i_blocks = ni->allocated_size >> 9;
else
vi->i_blocks = ni->itype.compressed.size >> 9;
ntfs_debug("Done.");
return 0;
unm_err_out:
if (!err)
err = -EIO;
if (ctx)
put_attr_search_ctx(ctx);
if (m)
unmap_mft_record(ni);
err_out:
ntfs_error(vi->i_sb, "Failed with error code %i. Marking inode 0x%lx "
"as bad.", -err, vi->i_ino);
make_bad_inode(vi);
return err;
}
/**
* ntfs_read_locked_attr_inode - read an attribute inode from its base inode
* @base_vi: base inode
* @vi: attribute inode to read
*
* ntfs_read_locked_attr_inode() is called from the ntfs_attr_iget() to read
* the attribute inode described by @vi into memory from the base mft record
* described by @base_ni.
*
* ntfs_read_locked_attr_inode() maps, pins and locks the base inode for
* reading and looks up the attribute described by @vi before setting up the
* necessary fields in @vi as well as initializing the ntfs inode.
*
* 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
*/
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_search_context *ctx;
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_blksize = base_vi->i_blksize;
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;
ni->seq_no = base_ni->seq_no;
/* 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 = get_attr_search_ctx(base_ni, m);
if (!ctx) {
err = -ENOMEM;
goto unm_err_out;
}
/* Find the attribute. */
if (!lookup_attr(ni->type, ni->name, ni->name_len, IGNORE_CASE, 0,
NULL, 0, ctx))
goto unm_err_out;
if (!ctx->attr->non_resident) {
if (NInoMstProtected(ni) || ctx->attr->flags) {
ntfs_error(vi->i_sb, "Found mst protected attribute "
"or attribute with non-zero flags but "
"the attribute is resident (mft_no "
"0x%lx, type 0x%x, name_len %i). "
"Please report you saw this message "
"to linux-ntfs-dev@lists.sf.net",
vi->i_ino, ni->type, ni->name_len);
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);
} else {
NInoSetNonResident(ni);
if (ctx->attr->flags & ATTR_COMPRESSION_MASK) {
if (NInoMstProtected(ni)) {
ntfs_error(vi->i_sb, "Found mst protected "
"attribute but the attribute "
"is compressed (mft_no 0x%lx, "
"type 0x%x, name_len %i). "
"Please report you saw this "
"message to linux-ntfs-dev@"
"lists.sf.net", vi->i_ino,
ni->type, ni->name_len);
goto unm_err_out;
}
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 "
"(mft_no 0x%lx, type 0x%x, "
"name_len %i). Please report "
"you saw this message to "
"linux-ntfs-dev@lists.sf.net",
vi->i_ino, ni->type,
ni->name_len);
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 ((ctx->attr->flags & ATTR_COMPRESSION_MASK)
!= ATTR_IS_COMPRESSED) {
ntfs_error(vi->i_sb, "Found unknown "
"compression method or "
"corrupt file.");
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) {
ntfs_error(vi->i_sb, "Found "
"nonstandard compression unit "
"(%u instead of 4). Cannot "
"handle this. This might "
"indicate corruption so you "
"should run chkdsk.",
ctx->attr->data.non_resident.
compression_unit);
err = -EOPNOTSUPP;
goto unm_err_out;
}
ni->itype.compressed.block_size = 1U << (
ctx->attr->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) {
ntfs_error(vi->i_sb, "Found encrypted "
"and compressed data.");
goto unm_err_out;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?