summaryrefslogtreecommitdiff
path: root/fs/ntfs3/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ntfs3/inode.c')
-rw-r--r--fs/ntfs3/inode.c134
1 files changed, 75 insertions, 59 deletions
diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c
index 309d9b46b5d5..6c560245eef4 100644
--- a/fs/ntfs3/inode.c
+++ b/fs/ntfs3/inode.c
@@ -100,6 +100,12 @@ static struct inode *ntfs_read_mft(struct inode *inode,
/* Record should contain $I30 root. */
is_dir = rec->flags & RECORD_FLAG_DIR;
+ /* MFT_REC_MFT is not a dir */
+ if (is_dir && ino == MFT_REC_MFT) {
+ err = -EINVAL;
+ goto out;
+ }
+
inode->i_generation = le16_to_cpu(rec->seq);
/* Enumerate all struct Attributes MFT. */
@@ -131,7 +137,13 @@ next_attr:
rsize = attr->non_res ? 0 : le32_to_cpu(attr->res.data_size);
asize = le32_to_cpu(attr->size);
- if (le16_to_cpu(attr->name_off) + attr->name_len > asize)
+ /*
+ * Really this check was done in 'ni_enum_attr_ex' -> ... 'mi_enum_attr'.
+ * There not critical to check this case again
+ */
+ if (attr->name_len &&
+ sizeof(short) * attr->name_len + le16_to_cpu(attr->name_off) >
+ asize)
goto out;
if (attr->non_res) {
@@ -250,8 +262,8 @@ next_attr:
if (!attr->nres.alloc_size)
goto next_attr;
- run = ino == MFT_REC_BITMAP ? &sbi->used.bitmap.run
- : &ni->file.run;
+ run = ino == MFT_REC_BITMAP ? &sbi->used.bitmap.run :
+ &ni->file.run;
break;
case ATTR_ROOT:
@@ -259,7 +271,6 @@ next_attr:
goto out;
root = Add2Ptr(attr, roff);
- is_root = true;
if (attr->name_len != ARRAY_SIZE(I30_NAME) ||
memcmp(attr_name(attr), I30_NAME, sizeof(I30_NAME)))
@@ -272,15 +283,16 @@ next_attr:
if (!is_dir)
goto next_attr;
+ is_root = true;
ni->ni_flags |= NI_FLAG_DIR;
err = indx_init(&ni->dir, sbi, attr, INDEX_MUTEX_I30);
if (err)
goto out;
- mode = sb->s_root
- ? (S_IFDIR | (0777 & sbi->options->fs_dmask_inv))
- : (S_IFDIR | 0777);
+ mode = sb->s_root ?
+ (S_IFDIR | (0777 & sbi->options->fs_dmask_inv)) :
+ (S_IFDIR | 0777);
goto next_attr;
case ATTR_ALLOC:
@@ -437,8 +449,8 @@ end_enum:
ni->std_fa &= ~FILE_ATTRIBUTE_DIRECTORY;
inode->i_op = &ntfs_file_inode_operations;
inode->i_fop = &ntfs_file_operations;
- inode->i_mapping->a_ops =
- is_compressed(ni) ? &ntfs_aops_cmpr : &ntfs_aops;
+ inode->i_mapping->a_ops = is_compressed(ni) ? &ntfs_aops_cmpr :
+ &ntfs_aops;
if (ino != MFT_REC_MFT)
init_rwsem(&ni->file.run_lock);
} else if (S_ISCHR(mode) || S_ISBLK(mode) || S_ISFIFO(mode) ||
@@ -636,6 +648,7 @@ static noinline int ntfs_get_block_vbo(struct inode *inode, u64 vbo,
bh->b_size = block_size;
off = vbo & (PAGE_SIZE - 1);
set_bh_page(bh, page, off);
+
err = bh_read(bh, 0);
if (err < 0)
goto out;
@@ -773,8 +786,8 @@ static ssize_t ntfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
}
ret = blockdev_direct_IO(iocb, inode, iter,
- wr ? ntfs_get_block_direct_IO_W
- : ntfs_get_block_direct_IO_R);
+ wr ? ntfs_get_block_direct_IO_W :
+ ntfs_get_block_direct_IO_R);
if (ret > 0)
end = vbo + ret;
@@ -833,7 +846,7 @@ out:
}
static int ntfs_resident_writepage(struct folio *folio,
- struct writeback_control *wbc, void *data)
+ struct writeback_control *wbc, void *data)
{
struct address_space *mapping = data;
struct ntfs_inode *ni = ntfs_i(mapping->host);
@@ -874,8 +887,8 @@ int ntfs_write_begin(struct file *file, struct address_space *mapping,
*pagep = NULL;
if (is_resident(ni)) {
- struct page *page = grab_cache_page_write_begin(
- mapping, pos >> PAGE_SHIFT);
+ struct page *page =
+ grab_cache_page_write_begin(mapping, pos >> PAGE_SHIFT);
if (!page) {
err = -ENOMEM;
@@ -907,9 +920,8 @@ out:
/*
* ntfs_write_end - Address_space_operations::write_end.
*/
-int ntfs_write_end(struct file *file, struct address_space *mapping,
- loff_t pos, u32 len, u32 copied, struct page *page,
- void *fsdata)
+int ntfs_write_end(struct file *file, struct address_space *mapping, loff_t pos,
+ u32 len, u32 copied, struct page *page, void *fsdata)
{
struct inode *inode = mapping->host;
struct ntfs_inode *ni = ntfs_i(inode);
@@ -1307,8 +1319,7 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap,
inode_init_owner(idmap, inode, dir, mode);
mode = inode->i_mode;
- inode->i_atime = inode->i_mtime = inode->i_ctime = ni->i_crtime =
- current_time(inode);
+ ni->i_crtime = current_time(inode);
rec = ni->mi.mrec;
rec->hard_links = cpu_to_le16(1);
@@ -1349,10 +1360,9 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap,
attr->res.data_size = cpu_to_le32(dsize);
std5->cr_time = std5->m_time = std5->c_time = std5->a_time =
- kernel2nt(&inode->i_atime);
+ kernel2nt(&ni->i_crtime);
- ni->std_fa = fa;
- std5->fa = fa;
+ std5->fa = ni->std_fa = fa;
attr = Add2Ptr(attr, asize);
@@ -1551,11 +1561,15 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap,
}
asize = SIZEOF_NONRESIDENT + ALIGN(err, 8);
+ /* Write non resident data. */
+ err = ntfs_sb_write_run(sbi, &ni->file.run, 0, rp,
+ nsize, 0);
+ if (err)
+ goto out5;
} else {
attr->res.data_off = SIZEOF_RESIDENT_LE;
attr->res.data_size = cpu_to_le32(nsize);
memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), rp, nsize);
- nsize = 0;
}
/* Size of symlink equals the length of input string. */
inode->i_size = size;
@@ -1576,19 +1590,8 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap,
rec->used = cpu_to_le32(PtrOffset(rec, attr) + 8);
rec->next_attr_id = cpu_to_le16(aid);
- /* Step 2: Add new name in index. */
- err = indx_insert_entry(&dir_ni->dir, dir_ni, new_de, sbi, fnd, 0);
- if (err)
- goto out6;
-
- /* Unlock parent directory before ntfs_init_acl. */
- if (!fnd)
- ni_unlock(dir_ni);
-
inode->i_generation = le16_to_cpu(rec->seq);
- dir->i_mtime = dir->i_ctime = inode->i_atime;
-
if (S_ISDIR(mode)) {
inode->i_op = &ntfs_dir_inode_operations;
inode->i_fop = &ntfs_dir_operations;
@@ -1601,8 +1604,8 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap,
} else if (S_ISREG(mode)) {
inode->i_op = &ntfs_file_inode_operations;
inode->i_fop = &ntfs_file_operations;
- inode->i_mapping->a_ops =
- is_compressed(ni) ? &ntfs_aops_cmpr : &ntfs_aops;
+ inode->i_mapping->a_ops = is_compressed(ni) ? &ntfs_aops_cmpr :
+ &ntfs_aops;
init_rwsem(&ni->file.run_lock);
} else {
inode->i_op = &ntfs_special_inode_operations;
@@ -1613,41 +1616,58 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap,
if (!S_ISLNK(mode) && (sb->s_flags & SB_POSIXACL)) {
err = ntfs_init_acl(idmap, inode, dir);
if (err)
- goto out7;
+ goto out5;
} else
#endif
{
inode->i_flags |= S_NOSEC;
}
- /* Write non resident data. */
- if (nsize) {
- err = ntfs_sb_write_run(sbi, &ni->file.run, 0, rp, nsize, 0);
- if (err)
- goto out7;
+ /*
+ * ntfs_init_acl and ntfs_save_wsl_perm update extended attribute.
+ * The packed size of extended attribute is stored in direntry too.
+ * 'fname' here points to inside new_de.
+ */
+ ntfs_save_wsl_perm(inode, &fname->dup.ea_size);
+
+ /*
+ * update ea_size in file_name attribute too.
+ * Use ni_find_attr cause layout of MFT record may be changed
+ * in ntfs_init_acl and ntfs_save_wsl_perm.
+ */
+ attr = ni_find_attr(ni, NULL, NULL, ATTR_NAME, NULL, 0, NULL, NULL);
+ if (attr) {
+ struct ATTR_FILE_NAME *fn;
+
+ fn = resident_data_ex(attr, SIZEOF_ATTRIBUTE_FILENAME);
+ if (fn)
+ fn->dup.ea_size = fname->dup.ea_size;
}
+ /* We do not need to update parent directory later */
+ ni->ni_flags &= ~NI_FLAG_UPDATE_PARENT;
+
+ /* Step 2: Add new name in index. */
+ err = indx_insert_entry(&dir_ni->dir, dir_ni, new_de, sbi, fnd, 0);
+ if (err)
+ goto out6;
+
/*
* Call 'd_instantiate' after inode->i_op is set
* but before finish_open.
*/
d_instantiate(dentry, inode);
- ntfs_save_wsl_perm(inode);
+ /* Set original time. inode times (i_ctime) may be changed in ntfs_init_acl. */
+ inode->i_atime = inode->i_mtime = inode->i_ctime = dir->i_mtime =
+ dir->i_ctime = ni->i_crtime;
+
mark_inode_dirty(dir);
mark_inode_dirty(inode);
/* Normal exit. */
goto out2;
-out7:
-
- /* Undo 'indx_insert_entry'. */
- if (!fnd)
- ni_lock_dir(dir_ni);
- indx_delete_entry(&dir_ni->dir, dir_ni, new_de + 1,
- le16_to_cpu(new_de->key_size), sbi);
- /* ni_unlock(dir_ni); will be called later. */
out6:
if (rp_inserted)
ntfs_remove_reparse(sbi, IO_REPARSE_TAG_SYMLINK, &new_de->ref);
@@ -1669,11 +1689,11 @@ out2:
kfree(rp);
out1:
- if (err) {
- if (!fnd)
- ni_unlock(dir_ni);
+ if (!fnd)
+ ni_unlock(dir_ni);
+
+ if (err)
return ERR_PTR(err);
- }
unlock_new_inode(inode);
@@ -1770,9 +1790,6 @@ void ntfs_evict_inode(struct inode *inode)
{
truncate_inode_pages_final(&inode->i_data);
- if (inode->i_nlink)
- _ni_write_inode(inode, inode_needs_sync(inode));
-
invalidate_inode_buffers(inode);
clear_inode(inode);
@@ -2057,7 +2074,6 @@ const struct inode_operations ntfs_link_inode_operations = {
.get_link = ntfs_get_link,
.setattr = ntfs3_setattr,
.listxattr = ntfs_listxattr,
- .permission = ntfs_permission,
};
const struct address_space_operations ntfs_aops = {