diff options
Diffstat (limited to 'fs/ntfs3/namei.c')
-rw-r--r-- | fs/ntfs3/namei.c | 236 |
1 files changed, 63 insertions, 173 deletions
diff --git a/fs/ntfs3/namei.c b/fs/ntfs3/namei.c index f79a399bd015..e58415d07132 100644 --- a/fs/ntfs3/namei.c +++ b/fs/ntfs3/namei.c @@ -152,12 +152,14 @@ static int ntfs_link(struct dentry *ode, struct inode *dir, struct dentry *de) if (inode != dir) ni_lock(ni); - dir->i_ctime = dir->i_mtime = inode->i_ctime = current_time(inode); inc_nlink(inode); ihold(inode); err = ntfs_link_inode(inode, de); + if (!err) { + dir->i_ctime = dir->i_mtime = inode->i_ctime = + current_time(dir); mark_inode_dirty(inode); mark_inode_dirty(dir); d_instantiate(de, inode); @@ -249,25 +251,26 @@ static int ntfs_rmdir(struct inode *dir, struct dentry *dentry) /* * ntfs_rename - inode_operations::rename */ -static int ntfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir, - struct dentry *old_dentry, struct inode *new_dir, +static int ntfs_rename(struct user_namespace *mnt_userns, struct inode *dir, + struct dentry *dentry, struct inode *new_dir, struct dentry *new_dentry, u32 flags) { int err; - struct super_block *sb = old_dir->i_sb; + struct super_block *sb = dir->i_sb; struct ntfs_sb_info *sbi = sb->s_fs_info; - struct ntfs_inode *old_dir_ni = ntfs_i(old_dir); + struct ntfs_inode *dir_ni = ntfs_i(dir); struct ntfs_inode *new_dir_ni = ntfs_i(new_dir); - struct ntfs_inode *old_ni; - struct ATTR_FILE_NAME *old_name, *new_name, *fname; - u8 name_type; - bool is_same; - struct inode *old_inode, *new_inode; - struct NTFS_DE *old_de, *new_de; - struct ATTRIB *attr; - struct ATTR_LIST_ENTRY *le; - u16 new_de_key_size; - + struct inode *inode = d_inode(dentry); + struct ntfs_inode *ni = ntfs_i(inode); + struct inode *new_inode = d_inode(new_dentry); + struct NTFS_DE *de, *new_de; + bool is_same, is_bad; + /* + * de - memory of PATH_MAX bytes: + * [0-1024) - original name (dentry->d_name) + * [1024-2048) - paired to original name, usually DOS variant of dentry->d_name + * [2048-3072) - new name (new_dentry->d_name) + */ static_assert(SIZEOF_ATTRIBUTE_FILENAME_MAX + SIZEOF_RESIDENT < 1024); static_assert(SIZEOF_ATTRIBUTE_FILENAME_MAX + sizeof(struct NTFS_DE) < 1024); @@ -276,24 +279,18 @@ static int ntfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir, if (flags & ~RENAME_NOREPLACE) return -EINVAL; - old_inode = d_inode(old_dentry); - new_inode = d_inode(new_dentry); - - old_ni = ntfs_i(old_inode); + is_same = dentry->d_name.len == new_dentry->d_name.len && + !memcmp(dentry->d_name.name, new_dentry->d_name.name, + dentry->d_name.len); - is_same = old_dentry->d_name.len == new_dentry->d_name.len && - !memcmp(old_dentry->d_name.name, new_dentry->d_name.name, - old_dentry->d_name.len); - - if (is_same && old_dir == new_dir) { + if (is_same && dir == new_dir) { /* Nothing to do. */ - err = 0; - goto out; + return 0; } - if (ntfs_is_meta_file(sbi, old_inode->i_ino)) { - err = -EINVAL; - goto out; + if (ntfs_is_meta_file(sbi, inode->i_ino)) { + /* Should we print an error? */ + return -EINVAL; } if (new_inode) { @@ -304,168 +301,61 @@ static int ntfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir, ni_unlock(new_dir_ni); dput(new_dentry); if (err) - goto out; + return err; } /* Allocate PATH_MAX bytes. */ - old_de = __getname(); - if (!old_de) { - err = -ENOMEM; - goto out; - } + de = __getname(); + if (!de) + return -ENOMEM; - err = fill_name_de(sbi, old_de, &old_dentry->d_name, NULL); + /* Translate dentry->d_name into unicode form. */ + err = fill_name_de(sbi, de, &dentry->d_name, NULL); if (err < 0) - goto out1; - - old_name = (struct ATTR_FILE_NAME *)(old_de + 1); + goto out; if (is_same) { - new_de = old_de; + /* Reuse 'de'. */ + new_de = de; } else { - new_de = Add2Ptr(old_de, 1024); + /* Translate new_dentry->d_name into unicode form. */ + new_de = Add2Ptr(de, 2048); err = fill_name_de(sbi, new_de, &new_dentry->d_name, NULL); if (err < 0) - goto out1; - } - - ni_lock_dir(old_dir_ni); - ni_lock(old_ni); - - mi_get_ref(&old_dir_ni->mi, &old_name->home); - - /* Get pointer to file_name in MFT. */ - fname = ni_fname_name(old_ni, (struct cpu_str *)&old_name->name_len, - &old_name->home, &le); - if (!fname) { - err = -EINVAL; - goto out2; + goto out; } - /* Copy fname info from record into new fname. */ - new_name = (struct ATTR_FILE_NAME *)(new_de + 1); - memcpy(&new_name->dup, &fname->dup, sizeof(fname->dup)); - - name_type = paired_name(fname->type); - - /* Remove first name from directory. */ - err = indx_delete_entry(&old_dir_ni->dir, old_dir_ni, old_de + 1, - le16_to_cpu(old_de->key_size), sbi); - if (err) - goto out3; - - /* Remove first name from MFT. */ - err = ni_remove_attr_le(old_ni, attr_from_name(fname), le); - if (err) - goto out4; - - le16_add_cpu(&old_ni->mi.mrec->hard_links, -1); - old_ni->mi.dirty = true; - - if (name_type != FILE_NAME_POSIX) { - /* Get paired name. */ - fname = ni_fname_type(old_ni, name_type, &le); - if (fname) { - /* Remove second name from directory. */ - err = indx_delete_entry(&old_dir_ni->dir, old_dir_ni, - fname, fname_full_size(fname), - sbi); - if (err) - goto out5; - - /* Remove second name from MFT. */ - err = ni_remove_attr_le(old_ni, attr_from_name(fname), - le); - if (err) - goto out6; - - le16_add_cpu(&old_ni->mi.mrec->hard_links, -1); - old_ni->mi.dirty = true; + ni_lock_dir(dir_ni); + ni_lock(ni); + + is_bad = false; + err = ni_rename(dir_ni, new_dir_ni, ni, de, new_de, &is_bad); + if (is_bad) { + /* Restore after failed rename failed too. */ + make_bad_inode(inode); + ntfs_inode_err(inode, "failed to undo rename"); + ntfs_set_state(sbi, NTFS_DIRTY_ERROR); + } else if (!err) { + inode->i_ctime = dir->i_ctime = dir->i_mtime = + current_time(dir); + mark_inode_dirty(inode); + mark_inode_dirty(dir); + if (dir != new_dir) { + new_dir->i_mtime = new_dir->i_ctime = dir->i_ctime; + mark_inode_dirty(new_dir); } - } - - /* Add new name. */ - mi_get_ref(&old_ni->mi, &new_de->ref); - mi_get_ref(&ntfs_i(new_dir)->mi, &new_name->home); - - new_de_key_size = le16_to_cpu(new_de->key_size); - - /* Insert new name in MFT. */ - err = ni_insert_resident(old_ni, new_de_key_size, ATTR_NAME, NULL, 0, - &attr, NULL); - if (err) - goto out7; - - attr->res.flags = RESIDENT_FLAG_INDEXED; - - memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), new_name, new_de_key_size); - - le16_add_cpu(&old_ni->mi.mrec->hard_links, 1); - old_ni->mi.dirty = true; - - /* Insert new name in directory. */ - err = indx_insert_entry(&new_dir_ni->dir, new_dir_ni, new_de, sbi, - NULL); - if (err) - goto out8; - if (IS_DIRSYNC(new_dir)) - err = ntfs_sync_inode(old_inode); - else - mark_inode_dirty(old_inode); + if (IS_DIRSYNC(dir)) + ntfs_sync_inode(dir); - old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir); - if (IS_DIRSYNC(old_dir)) - (void)ntfs_sync_inode(old_dir); - else - mark_inode_dirty(old_dir); - - if (old_dir != new_dir) { - new_dir->i_mtime = new_dir->i_ctime = old_dir->i_ctime; - mark_inode_dirty(new_dir); - } - - if (old_inode) { - old_inode->i_ctime = old_dir->i_ctime; - mark_inode_dirty(old_inode); + if (IS_DIRSYNC(new_dir)) + ntfs_sync_inode(inode); } - err = 0; - /* Normal way* */ - goto out2; - -out8: - /* undo - * ni_insert_resident(old_ni, new_de_key_size, ATTR_NAME, NULL, 0, - * &attr, NULL); - */ - mi_remove_attr(&old_ni->mi, attr); -out7: - /* undo - * ni_remove_attr_le(old_ni, attr_from_name(fname), le); - */ -out6: - /* undo - * indx_delete_entry(&old_dir_ni->dir, old_dir_ni, - * fname, fname_full_size(fname), - * sbi); - */ -out5: - /* undo - * ni_remove_attr_le(old_ni, attr_from_name(fname), le); - */ -out4: - /* undo: - * indx_delete_entry(&old_dir_ni->dir, old_dir_ni, old_de + 1, - * old_de->key_size, NULL); - */ -out3: -out2: - ni_unlock(old_ni); - ni_unlock(old_dir_ni); -out1: - __putname(old_de); + ni_unlock(ni); + ni_unlock(dir_ni); out: + __putname(de); return err; } |