📄 inode.c
字号:
* is still mapped. Teach this nesting to the lock validator by creating * a separate class for nested inode's mrec_lock's: */static struct lock_class_key extent_inode_mrec_lock_key;inline ntfs_inode *ntfs_new_extent_inode(struct super_block *sb, unsigned long mft_no){ ntfs_inode *ni = ntfs_alloc_extent_inode(); ntfs_debug("Entering."); if (likely(ni != NULL)) { __ntfs_init_inode(sb, ni); lockdep_set_class(&ni->mrec_lock, &extent_inode_mrec_lock_key); ni->mft_no = mft_no; ni->type = AT_UNUSED; ni->name = NULL; ni->name_len = 0; } return ni;}/** * ntfs_is_extended_system_file - check if a file is in the $Extend directory * @ctx: initialized attribute search context * * Search all file name attributes in the inode described by the attribute * search context @ctx and check if any of the names are in the $Extend system * directory. * * Return values: * 1: file is in $Extend directory * 0: file is not in $Extend directory * -errno: failed to determine if the file is in the $Extend directory */static int ntfs_is_extended_system_file(ntfs_attr_search_ctx *ctx){ int nr_links, err; /* Restart search. */ ntfs_attr_reinit_search_ctx(ctx); /* Get number of hard links. */ nr_links = le16_to_cpu(ctx->mrec->link_count); /* Loop through all hard links. */ while (!(err = ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, 0, 0, NULL, 0, ctx))) { FILE_NAME_ATTR *file_name_attr; ATTR_RECORD *attr = ctx->attr; u8 *p, *p2; nr_links--; /* * Maximum sanity checking as we are called on an inode that * we suspect might be corrupt. */ p = (u8*)attr + le32_to_cpu(attr->length); if (p < (u8*)ctx->mrec || (u8*)p > (u8*)ctx->mrec + le32_to_cpu(ctx->mrec->bytes_in_use)) {err_corrupt_attr: ntfs_error(ctx->ntfs_ino->vol->sb, "Corrupt file name " "attribute. You should run chkdsk."); return -EIO; } if (attr->non_resident) { ntfs_error(ctx->ntfs_ino->vol->sb, "Non-resident file " "name. You should run chkdsk."); return -EIO; } if (attr->flags) { ntfs_error(ctx->ntfs_ino->vol->sb, "File name with " "invalid flags. You should run " "chkdsk."); return -EIO; } if (!(attr->data.resident.flags & RESIDENT_ATTR_IS_INDEXED)) { ntfs_error(ctx->ntfs_ino->vol->sb, "Unindexed file " "name. You should run chkdsk."); return -EIO; } file_name_attr = (FILE_NAME_ATTR*)((u8*)attr + le16_to_cpu(attr->data.resident.value_offset)); p2 = (u8*)attr + le32_to_cpu(attr->data.resident.value_length); if (p2 < (u8*)attr || p2 > p) goto err_corrupt_attr; /* This attribute is ok, but is it in the $Extend directory? */ if (MREF_LE(file_name_attr->parent_directory) == FILE_Extend) return 1; /* YES, it's an extended system file. */ } if (unlikely(err != -ENOENT)) return err; if (unlikely(nr_links)) { ntfs_error(ctx->ntfs_ino->vol->sb, "Inode hard link count " "doesn't match number of name attributes. You " "should run chkdsk."); return -EIO; } return 0; /* NO, it is not an extended system file. */}/** * ntfs_read_locked_inode - read an inode from its device * @vi: inode to read * * ntfs_read_locked_inode() is called from ntfs_iget() to read the inode * described by @vi into memory from the device. * * The only fields in @vi that we need to/can look at when the function is * called are i_sb, pointing to the mounted device's super block, and i_ino, * the number of the inode to load. * * ntfs_read_locked_inode() maps, pins and locks the mft record number i_ino * for reading and sets up the necessary @vi fields 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 * i_flags is set to 0 and we have no business touching it. Only an ioctl() * is allowed to write to them. We should of course be honouring them but * we need to do that using the IS_* macros defined in include/linux/fs.h. * In any case ntfs_read_locked_inode() has nothing to do with i_flags. * * 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_inode(struct inode *vi){ ntfs_volume *vol = NTFS_SB(vi->i_sb); ntfs_inode *ni; struct inode *bvi; MFT_RECORD *m; ATTR_RECORD *a; STANDARD_INFORMATION *si; ntfs_attr_search_ctx *ctx; int err = 0; ntfs_debug("Entering for i_ino 0x%lx.", vi->i_ino); /* Setup the generic vfs inode parts now. */ /* * This is for checking whether an inode has changed w.r.t. a file so * that the file can be updated if necessary (compare with f_version). */ vi->i_version = 1; vi->i_uid = vol->uid; vi->i_gid = vol->gid; vi->i_mode = 0; /* * Initialize the ntfs specific part of @vi special casing * FILE_MFT which we need to do at mount time. */ if (vi->i_ino != FILE_MFT) ntfs_init_big_inode(vi); ni = NTFS_I(vi); m = map_mft_record(ni); if (IS_ERR(m)) { err = PTR_ERR(m); goto err_out; } ctx = ntfs_attr_get_search_ctx(ni, m); if (!ctx) { err = -ENOMEM; goto unm_err_out; } if (!(m->flags & MFT_RECORD_IN_USE)) { ntfs_error(vi->i_sb, "Inode is not in use!"); goto unm_err_out; } if (m->base_mft_record) { ntfs_error(vi->i_sb, "Inode is an extent inode!"); goto unm_err_out; } /* Transfer information from mft record into vfs and ntfs inodes. */ vi->i_generation = ni->seq_no = le16_to_cpu(m->sequence_number); /* * FIXME: Keep in mind that link_count is two for files which have both * a long file name and a short file name as separate entries, so if * we are hiding short file names this will be too high. Either we need * to account for the short file names by subtracting them or we need * to make sure we delete files even though i_nlink is not zero which * might be tricky due to vfs interactions. Need to think about this * some more when implementing the unlink command. */ vi->i_nlink = le16_to_cpu(m->link_count); /* * FIXME: Reparse points can have the directory bit set even though * they would be S_IFLNK. Need to deal with this further below when we * implement reparse points / symbolic links but it will do for now. * Also if not a directory, it could be something else, rather than * a regular file. But again, will do for now. */ /* 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; if (m->flags & MFT_RECORD_IS_DIRECTORY) { vi->i_mode |= S_IFDIR; /* * Apply the directory permissions mask set in the mount * options. */ vi->i_mode &= ~vol->dmask; /* Things break without this kludge! */ if (vi->i_nlink > 1) vi->i_nlink = 1; } else { vi->i_mode |= S_IFREG; /* Apply the file permissions mask set in the mount options. */ vi->i_mode &= ~vol->fmask; } /* * Find the standard information attribute in the mft record. At this * stage we haven't setup the attribute list stuff yet, so this could * in fact fail if the standard information is in an extent record, but * I don't think this actually ever happens. */ err = ntfs_attr_lookup(AT_STANDARD_INFORMATION, NULL, 0, 0, 0, NULL, 0, ctx); if (unlikely(err)) { if (err == -ENOENT) { /* * TODO: We should be performing a hot fix here (if the * recover mount option is set) by creating a new * attribute. */ ntfs_error(vi->i_sb, "$STANDARD_INFORMATION attribute " "is missing."); } goto unm_err_out; } a = ctx->attr; /* Get the standard information attribute value. */ si = (STANDARD_INFORMATION*)((u8*)a + le16_to_cpu(a->data.resident.value_offset)); /* Transfer information from the standard information into vi. */ /* * Note: The i_?times do not quite map perfectly onto the NTFS times, * but they are close enough, and in the end it doesn't really matter * that much... */ /* * mtime is the last change of the data within the file. Not changed * when only metadata is changed, e.g. a rename doesn't affect mtime. */ vi->i_mtime = ntfs2utc(si->last_data_change_time); /* * ctime is the last change of the metadata of the file. This obviously * always changes, when mtime is changed. ctime can be changed on its * own, mtime is then not changed, e.g. when a file is renamed. */ vi->i_ctime = ntfs2utc(si->last_mft_change_time); /* * Last access to the data within the file. Not changed during a rename * for example but changed whenever the file is written to. */ vi->i_atime = ntfs2utc(si->last_access_time); /* Find the attribute list attribute if present. */ ntfs_attr_reinit_search_ctx(ctx); err = ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0, 0, 0, NULL, 0, ctx); if (err) { if (unlikely(err != -ENOENT)) { ntfs_error(vi->i_sb, "Failed to lookup attribute list " "attribute."); goto unm_err_out; } } else /* if (!err) */ { if (vi->i_ino == FILE_MFT) goto skip_attr_list_load; ntfs_debug("Attribute list found in inode 0x%lx.", vi->i_ino); NInoSetAttrList(ni); a = ctx->attr; if (a->flags & ATTR_COMPRESSION_MASK) { ntfs_error(vi->i_sb, "Attribute list attribute is " "compressed."); goto unm_err_out; } if (a->flags & ATTR_IS_ENCRYPTED || a->flags & ATTR_IS_SPARSE) { if (a->non_resident) { ntfs_error(vi->i_sb, "Non-resident attribute " "list attribute is encrypted/" "sparse."); goto unm_err_out; } ntfs_warning(vi->i_sb, "Resident attribute list " "attribute in inode 0x%lx is marked " "encrypted/sparse which is not true. " "However, Windows allows this and " "chkdsk does not detect or correct it " "so we will just ignore the invalid " "flags and pretend they are not set.", vi->i_ino); } /* Now allocate memory for the attribute list. */ 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 " "buffer for attribute list."); err = -ENOMEM; goto unm_err_out; } if (a->non_resident) { NInoSetAttrListNonResident(ni); if (a->data.non_resident.lowest_vcn) { ntfs_error(vi->i_sb, "Attribute list has non " "zero lowest_vcn."); goto unm_err_out; } /* * Setup the runlist. No need for locking as we have * exclusive access to the inode at this time. */ ni->attr_list_rl.rl = ntfs_mapping_pairs_decompress(vol, a, NULL); if (IS_ERR(ni->attr_list_rl.rl)) { err = PTR_ERR(ni->attr_list_rl.rl); ni->attr_list_rl.rl = NULL; ntfs_error(vi->i_sb, "Mapping pairs " "decompression failed."); goto unm_err_out; } /* 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(a->data.non_resident. initialized_size)))) { ntfs_error(vi->i_sb, "Failed to load " "attribute list attribute."); goto unm_err_out; } } 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*)a + le16_to_cpu( a->data.resident.value_offset), le32_to_cpu( a->data.resident.value_length)); } }skip_attr_list_load: /* * If an attribute list is present we now have the attribute list value * in ntfs_ino->attr_list and it is ntfs_ino->attr_list_size bytes. */ if (S_ISDIR(vi->i_mode)) { loff_t bvi_size; ntfs_inode *bni; INDEX_ROOT *ir; u8 *ir_end, *index_end; /* It is a directory, find index root attribute. */ ntfs_attr_reinit_search_ctx(ctx); err = ntfs_attr_lookup(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL, 0, ctx); if (unlikely(err)) { if (err == -ENOENT) { // FIXME: File is corrupt! Hot-fix with empty // index root attribute if recovery option is // set. 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 index root just means that the newly * created files in that directory should be created compressed/ * encrypted. However index root cannot be both compressed and * encrypted. */ if (a->flags & ATTR_COMPRESSION_MASK) NInoSetCompressed(ni); 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); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -