Re: [PATCH v27 04/10] fs/ntfs3: Add file operations and implementation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Le 29/07/2021 à 15:49, Konstantin Komarov a écrit :
This adds file operations and implementation

Signed-off-by: Konstantin Komarov <almaz.alexandrovich@xxxxxxxxxxxxxxxxxxxx>
---
  fs/ntfs3/dir.c     |  594 +++++++++
  fs/ntfs3/file.c    | 1130 ++++++++++++++++
  fs/ntfs3/frecord.c | 3071 ++++++++++++++++++++++++++++++++++++++++++++
  fs/ntfs3/namei.c   |  578 +++++++++
  fs/ntfs3/record.c  |  609 +++++++++
  fs/ntfs3/run.c     | 1111 ++++++++++++++++
  6 files changed, 7093 insertions(+)
  create mode 100644 fs/ntfs3/dir.c
  create mode 100644 fs/ntfs3/file.c
  create mode 100644 fs/ntfs3/frecord.c
  create mode 100644 fs/ntfs3/namei.c
  create mode 100644 fs/ntfs3/record.c
  create mode 100644 fs/ntfs3/run.c


[...]

diff --git a/fs/ntfs3/namei.c b/fs/ntfs3/namei.c
new file mode 100644
index 000000000..f5db12cd3
--- /dev/null
+++ b/fs/ntfs3/namei.c

[...]

+/*
+ * 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,
+		       struct dentry *new_dentry, u32 flags)
+{
+	int err;
+	struct super_block *sb = old_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 *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;
+
+	static_assert(SIZEOF_ATTRIBUTE_FILENAME_MAX + SIZEOF_RESIDENT < 1024);
+	static_assert(SIZEOF_ATTRIBUTE_FILENAME_MAX + sizeof(struct NTFS_DE) <
+		      1024);
+	static_assert(PATH_MAX >= 4 * 1024);
+
+	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 = 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) {
+		/* Nothing to do */
+		err = 0;
+		goto out;
+	}
+
+	if (ntfs_is_meta_file(sbi, old_inode->i_ino)) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	if (new_inode) {
+		/*target name exists. unlink it*/
+		dget(new_dentry);
+		ni_lock_dir(new_dir_ni);
+		err = ntfs_unlink_inode(new_dir, new_dentry);
+		ni_unlock(new_dir_ni);
+		dput(new_dentry);
+		if (err)
+			goto out;
+	}
+
+	/* allocate PATH_MAX bytes */
+	old_de = __getname();
+	if (!old_de) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	err = fill_name_de(sbi, old_de, &old_dentry->d_name, NULL);
+	if (err < 0)
+		goto out1;
+
+	old_name = (struct ATTR_FILE_NAME *)(old_de + 1);
+
+	if (is_same) {
+		new_de = old_de;
+	} else {
+		new_de = Add2Ptr(old_de, 1024);
+		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;
+	}
+
+	/* 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;
+		}
+	}
+
+	/* 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);

This value returned by 'ntfs_sync_inode()' is silenced below.
Maybe the same should be done here?
Anyway, this 'err' is never used and is forced to 0 below

+	else
+		mark_inode_dirty(old_inode);
+
+	old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir);
+	if (IS_DIRSYNC(old_dir))
+		(void)ntfs_sync_inode(old_dir);

here

+	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);
+	}
+
+	err = 0;

and here.

+	/* 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);
+out:
+	return err;
+}

[...]



[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux