xref: /openbmc/linux/fs/ntfs3/namei.c (revision f73f9397)
14342306fSKonstantin Komarov // SPDX-License-Identifier: GPL-2.0
24342306fSKonstantin Komarov /*
34342306fSKonstantin Komarov  *
44342306fSKonstantin Komarov  * Copyright (C) 2019-2021 Paragon Software GmbH, All rights reserved.
54342306fSKonstantin Komarov  *
64342306fSKonstantin Komarov  */
74342306fSKonstantin Komarov 
84342306fSKonstantin Komarov #include <linux/fs.h>
94342306fSKonstantin Komarov #include <linux/nls.h>
10a3a956c7SKonstantin Komarov #include <linux/ctype.h>
112b108260SKonstantin Komarov #include <linux/posix_acl.h>
124342306fSKonstantin Komarov 
134342306fSKonstantin Komarov #include "debug.h"
144342306fSKonstantin Komarov #include "ntfs.h"
154342306fSKonstantin Komarov #include "ntfs_fs.h"
164342306fSKonstantin Komarov 
174342306fSKonstantin Komarov /*
18e8b8e97fSKari Argillander  * fill_name_de - Format NTFS_DE in @buf.
194342306fSKonstantin Komarov  */
fill_name_de(struct ntfs_sb_info * sbi,void * buf,const struct qstr * name,const struct cpu_str * uni)204342306fSKonstantin Komarov int fill_name_de(struct ntfs_sb_info *sbi, void *buf, const struct qstr *name,
214342306fSKonstantin Komarov 		 const struct cpu_str *uni)
224342306fSKonstantin Komarov {
234342306fSKonstantin Komarov 	int err;
244342306fSKonstantin Komarov 	struct NTFS_DE *e = buf;
254342306fSKonstantin Komarov 	u16 data_size;
264342306fSKonstantin Komarov 	struct ATTR_FILE_NAME *fname = (struct ATTR_FILE_NAME *)(e + 1);
274342306fSKonstantin Komarov 
284342306fSKonstantin Komarov #ifndef CONFIG_NTFS3_64BIT_CLUSTER
294342306fSKonstantin Komarov 	e->ref.high = fname->home.high = 0;
304342306fSKonstantin Komarov #endif
314342306fSKonstantin Komarov 	if (uni) {
324342306fSKonstantin Komarov #ifdef __BIG_ENDIAN
334342306fSKonstantin Komarov 		int ulen = uni->len;
344342306fSKonstantin Komarov 		__le16 *uname = fname->name;
354342306fSKonstantin Komarov 		const u16 *name_cpu = uni->name;
364342306fSKonstantin Komarov 
374342306fSKonstantin Komarov 		while (ulen--)
384342306fSKonstantin Komarov 			*uname++ = cpu_to_le16(*name_cpu++);
394342306fSKonstantin Komarov #else
404342306fSKonstantin Komarov 		memcpy(fname->name, uni->name, uni->len * sizeof(u16));
414342306fSKonstantin Komarov #endif
424342306fSKonstantin Komarov 		fname->name_len = uni->len;
434342306fSKonstantin Komarov 
444342306fSKonstantin Komarov 	} else {
45e8b8e97fSKari Argillander 		/* Convert input string to unicode. */
464342306fSKonstantin Komarov 		err = ntfs_nls_to_utf16(sbi, name->name, name->len,
474342306fSKonstantin Komarov 					(struct cpu_str *)&fname->name_len,
484342306fSKonstantin Komarov 					NTFS_NAME_LEN, UTF16_LITTLE_ENDIAN);
494342306fSKonstantin Komarov 		if (err < 0)
504342306fSKonstantin Komarov 			return err;
514342306fSKonstantin Komarov 	}
524342306fSKonstantin Komarov 
534342306fSKonstantin Komarov 	fname->type = FILE_NAME_POSIX;
544342306fSKonstantin Komarov 	data_size = fname_full_size(fname);
554342306fSKonstantin Komarov 
56fa3cacf5SKari Argillander 	e->size = cpu_to_le16(ALIGN(data_size, 8) + sizeof(struct NTFS_DE));
574342306fSKonstantin Komarov 	e->key_size = cpu_to_le16(data_size);
584342306fSKonstantin Komarov 	e->flags = 0;
594342306fSKonstantin Komarov 	e->res = 0;
604342306fSKonstantin Komarov 
614342306fSKonstantin Komarov 	return 0;
624342306fSKonstantin Komarov }
634342306fSKonstantin Komarov 
644342306fSKonstantin Komarov /*
65e8b8e97fSKari Argillander  * ntfs_lookup - inode_operations::lookup
664342306fSKonstantin Komarov  */
ntfs_lookup(struct inode * dir,struct dentry * dentry,u32 flags)674342306fSKonstantin Komarov static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *dentry,
684342306fSKonstantin Komarov 				  u32 flags)
694342306fSKonstantin Komarov {
704342306fSKonstantin Komarov 	struct ntfs_inode *ni = ntfs_i(dir);
714342306fSKonstantin Komarov 	struct cpu_str *uni = __getname();
724342306fSKonstantin Komarov 	struct inode *inode;
734342306fSKonstantin Komarov 	int err;
744342306fSKonstantin Komarov 
754342306fSKonstantin Komarov 	if (!uni)
764342306fSKonstantin Komarov 		inode = ERR_PTR(-ENOMEM);
774342306fSKonstantin Komarov 	else {
784342306fSKonstantin Komarov 		err = ntfs_nls_to_utf16(ni->mi.sbi, dentry->d_name.name,
794342306fSKonstantin Komarov 					dentry->d_name.len, uni, NTFS_NAME_LEN,
804342306fSKonstantin Komarov 					UTF16_HOST_ENDIAN);
814342306fSKonstantin Komarov 		if (err < 0)
824342306fSKonstantin Komarov 			inode = ERR_PTR(err);
834342306fSKonstantin Komarov 		else {
844342306fSKonstantin Komarov 			ni_lock(ni);
854342306fSKonstantin Komarov 			inode = dir_search_u(dir, uni, NULL);
864342306fSKonstantin Komarov 			ni_unlock(ni);
874342306fSKonstantin Komarov 		}
884342306fSKonstantin Komarov 		__putname(uni);
894342306fSKonstantin Komarov 	}
904342306fSKonstantin Komarov 
91254e69f2SZhangPeng 	/*
92254e69f2SZhangPeng 	 * Check for a null pointer
93254e69f2SZhangPeng 	 * If the MFT record of ntfs inode is not a base record, inode->i_op can be NULL.
94254e69f2SZhangPeng 	 * This causes null pointer dereference in d_splice_alias().
95254e69f2SZhangPeng 	 */
966827d50bSKonstantin Komarov 	if (!IS_ERR_OR_NULL(inode) && !inode->i_op) {
97254e69f2SZhangPeng 		iput(inode);
98254e69f2SZhangPeng 		inode = ERR_PTR(-EINVAL);
99254e69f2SZhangPeng 	}
100254e69f2SZhangPeng 
1014342306fSKonstantin Komarov 	return d_splice_alias(inode, dentry);
1024342306fSKonstantin Komarov }
1034342306fSKonstantin Komarov 
1044342306fSKonstantin Komarov /*
105e8b8e97fSKari Argillander  * ntfs_create - inode_operations::create
1064342306fSKonstantin Komarov  */
ntfs_create(struct mnt_idmap * idmap,struct inode * dir,struct dentry * dentry,umode_t mode,bool excl)1076c960e68SChristian Brauner static int ntfs_create(struct mnt_idmap *idmap, struct inode *dir,
1084342306fSKonstantin Komarov 		       struct dentry *dentry, umode_t mode, bool excl)
1094342306fSKonstantin Komarov {
1104342306fSKonstantin Komarov 	struct inode *inode;
1114342306fSKonstantin Komarov 
112f0377761SKonstantin Komarov 	inode = ntfs_create_inode(idmap, dir, dentry, NULL, S_IFREG | mode, 0,
113f0377761SKonstantin Komarov 				  NULL, 0, NULL);
1144342306fSKonstantin Komarov 
1154342306fSKonstantin Komarov 	return IS_ERR(inode) ? PTR_ERR(inode) : 0;
1164342306fSKonstantin Komarov }
1174342306fSKonstantin Komarov 
1184342306fSKonstantin Komarov /*
1194342306fSKonstantin Komarov  * ntfs_mknod
1204342306fSKonstantin Komarov  *
1214342306fSKonstantin Komarov  * inode_operations::mknod
1224342306fSKonstantin Komarov  */
ntfs_mknod(struct mnt_idmap * idmap,struct inode * dir,struct dentry * dentry,umode_t mode,dev_t rdev)1235ebb29beSChristian Brauner static int ntfs_mknod(struct mnt_idmap *idmap, struct inode *dir,
1244342306fSKonstantin Komarov 		      struct dentry *dentry, umode_t mode, dev_t rdev)
1254342306fSKonstantin Komarov {
1264342306fSKonstantin Komarov 	struct inode *inode;
1274342306fSKonstantin Komarov 
128f0377761SKonstantin Komarov 	inode = ntfs_create_inode(idmap, dir, dentry, NULL, mode, rdev, NULL, 0,
129f0377761SKonstantin Komarov 				  NULL);
1304342306fSKonstantin Komarov 
1314342306fSKonstantin Komarov 	return IS_ERR(inode) ? PTR_ERR(inode) : 0;
1324342306fSKonstantin Komarov }
1334342306fSKonstantin Komarov 
1344342306fSKonstantin Komarov /*
135e8b8e97fSKari Argillander  * ntfs_link - inode_operations::link
1364342306fSKonstantin Komarov  */
ntfs_link(struct dentry * ode,struct inode * dir,struct dentry * de)1374342306fSKonstantin Komarov static int ntfs_link(struct dentry *ode, struct inode *dir, struct dentry *de)
1384342306fSKonstantin Komarov {
1394342306fSKonstantin Komarov 	int err;
1404342306fSKonstantin Komarov 	struct inode *inode = d_inode(ode);
1414342306fSKonstantin Komarov 	struct ntfs_inode *ni = ntfs_i(inode);
1424342306fSKonstantin Komarov 
1434342306fSKonstantin Komarov 	if (S_ISDIR(inode->i_mode))
1444342306fSKonstantin Komarov 		return -EPERM;
1454342306fSKonstantin Komarov 
1464342306fSKonstantin Komarov 	if (inode->i_nlink >= NTFS_LINK_MAX)
1474342306fSKonstantin Komarov 		return -EMLINK;
1484342306fSKonstantin Komarov 
1494342306fSKonstantin Komarov 	ni_lock_dir(ntfs_i(dir));
1504342306fSKonstantin Komarov 	if (inode != dir)
1514342306fSKonstantin Komarov 		ni_lock(ni);
1524342306fSKonstantin Komarov 
1534342306fSKonstantin Komarov 	inc_nlink(inode);
1544342306fSKonstantin Komarov 	ihold(inode);
1554342306fSKonstantin Komarov 
1564342306fSKonstantin Komarov 	err = ntfs_link_inode(inode, de);
15778ab59feSKonstantin Komarov 
1584342306fSKonstantin Komarov 	if (!err) {
159f684073cSKonstantin Komarov 		dir->i_mtime = inode_set_ctime_to_ts(
160f684073cSKonstantin Komarov 			inode, inode_set_ctime_current(dir));
1614342306fSKonstantin Komarov 		mark_inode_dirty(inode);
1624342306fSKonstantin Komarov 		mark_inode_dirty(dir);
1634342306fSKonstantin Komarov 		d_instantiate(de, inode);
1644342306fSKonstantin Komarov 	} else {
1654342306fSKonstantin Komarov 		drop_nlink(inode);
1664342306fSKonstantin Komarov 		iput(inode);
1674342306fSKonstantin Komarov 	}
1684342306fSKonstantin Komarov 
1694342306fSKonstantin Komarov 	if (inode != dir)
1704342306fSKonstantin Komarov 		ni_unlock(ni);
1714342306fSKonstantin Komarov 	ni_unlock(ntfs_i(dir));
1724342306fSKonstantin Komarov 
1734342306fSKonstantin Komarov 	return err;
1744342306fSKonstantin Komarov }
1754342306fSKonstantin Komarov 
1764342306fSKonstantin Komarov /*
177e8b8e97fSKari Argillander  * ntfs_unlink - inode_operations::unlink
1784342306fSKonstantin Komarov  */
ntfs_unlink(struct inode * dir,struct dentry * dentry)1794342306fSKonstantin Komarov static int ntfs_unlink(struct inode *dir, struct dentry *dentry)
1804342306fSKonstantin Komarov {
1814342306fSKonstantin Komarov 	struct ntfs_inode *ni = ntfs_i(dir);
1824342306fSKonstantin Komarov 	int err;
1834342306fSKonstantin Komarov 
184*f73f9397SKonstantin Komarov 	if (unlikely(ntfs3_forced_shutdown(dir->i_sb)))
185*f73f9397SKonstantin Komarov 		return -EIO;
186*f73f9397SKonstantin Komarov 
1874342306fSKonstantin Komarov 	ni_lock_dir(ni);
1884342306fSKonstantin Komarov 
1894342306fSKonstantin Komarov 	err = ntfs_unlink_inode(dir, dentry);
1904342306fSKonstantin Komarov 
1914342306fSKonstantin Komarov 	ni_unlock(ni);
1924342306fSKonstantin Komarov 
1934342306fSKonstantin Komarov 	return err;
1944342306fSKonstantin Komarov }
1954342306fSKonstantin Komarov 
1964342306fSKonstantin Komarov /*
197e8b8e97fSKari Argillander  * ntfs_symlink - inode_operations::symlink
1984342306fSKonstantin Komarov  */
ntfs_symlink(struct mnt_idmap * idmap,struct inode * dir,struct dentry * dentry,const char * symname)1997a77db95SChristian Brauner static int ntfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
2004342306fSKonstantin Komarov 			struct dentry *dentry, const char *symname)
2014342306fSKonstantin Komarov {
2024342306fSKonstantin Komarov 	u32 size = strlen(symname);
2034342306fSKonstantin Komarov 	struct inode *inode;
2044342306fSKonstantin Komarov 
205*f73f9397SKonstantin Komarov 	if (unlikely(ntfs3_forced_shutdown(dir->i_sb)))
206*f73f9397SKonstantin Komarov 		return -EIO;
207*f73f9397SKonstantin Komarov 
208f0377761SKonstantin Komarov 	inode = ntfs_create_inode(idmap, dir, dentry, NULL, S_IFLNK | 0777, 0,
209f0377761SKonstantin Komarov 				  symname, size, NULL);
2104342306fSKonstantin Komarov 
2114342306fSKonstantin Komarov 	return IS_ERR(inode) ? PTR_ERR(inode) : 0;
2124342306fSKonstantin Komarov }
2134342306fSKonstantin Komarov 
2144342306fSKonstantin Komarov /*
215e8b8e97fSKari Argillander  * ntfs_mkdir- inode_operations::mkdir
2164342306fSKonstantin Komarov  */
ntfs_mkdir(struct mnt_idmap * idmap,struct inode * dir,struct dentry * dentry,umode_t mode)217c54bd91eSChristian Brauner static int ntfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
2184342306fSKonstantin Komarov 		      struct dentry *dentry, umode_t mode)
2194342306fSKonstantin Komarov {
2204342306fSKonstantin Komarov 	struct inode *inode;
2214342306fSKonstantin Komarov 
222f0377761SKonstantin Komarov 	inode = ntfs_create_inode(idmap, dir, dentry, NULL, S_IFDIR | mode, 0,
223f0377761SKonstantin Komarov 				  NULL, 0, NULL);
2244342306fSKonstantin Komarov 
2254342306fSKonstantin Komarov 	return IS_ERR(inode) ? PTR_ERR(inode) : 0;
2264342306fSKonstantin Komarov }
2274342306fSKonstantin Komarov 
2284342306fSKonstantin Komarov /*
2296700eabbSKonstantin Komarov  * ntfs_rmdir - inode_operations::rmdir
2304342306fSKonstantin Komarov  */
ntfs_rmdir(struct inode * dir,struct dentry * dentry)2314342306fSKonstantin Komarov static int ntfs_rmdir(struct inode *dir, struct dentry *dentry)
2324342306fSKonstantin Komarov {
2334342306fSKonstantin Komarov 	struct ntfs_inode *ni = ntfs_i(dir);
2344342306fSKonstantin Komarov 	int err;
2354342306fSKonstantin Komarov 
236*f73f9397SKonstantin Komarov 	if (unlikely(ntfs3_forced_shutdown(dir->i_sb)))
237*f73f9397SKonstantin Komarov 		return -EIO;
238*f73f9397SKonstantin Komarov 
2394342306fSKonstantin Komarov 	ni_lock_dir(ni);
2404342306fSKonstantin Komarov 
2414342306fSKonstantin Komarov 	err = ntfs_unlink_inode(dir, dentry);
2424342306fSKonstantin Komarov 
2434342306fSKonstantin Komarov 	ni_unlock(ni);
2444342306fSKonstantin Komarov 
2454342306fSKonstantin Komarov 	return err;
2464342306fSKonstantin Komarov }
2474342306fSKonstantin Komarov 
2484342306fSKonstantin Komarov /*
249e8b8e97fSKari Argillander  * ntfs_rename - inode_operations::rename
2504342306fSKonstantin Komarov  */
ntfs_rename(struct mnt_idmap * idmap,struct inode * dir,struct dentry * dentry,struct inode * new_dir,struct dentry * new_dentry,u32 flags)251e18275aeSChristian Brauner static int ntfs_rename(struct mnt_idmap *idmap, struct inode *dir,
25278ab59feSKonstantin Komarov 		       struct dentry *dentry, struct inode *new_dir,
2534342306fSKonstantin Komarov 		       struct dentry *new_dentry, u32 flags)
2544342306fSKonstantin Komarov {
2554342306fSKonstantin Komarov 	int err;
25678ab59feSKonstantin Komarov 	struct super_block *sb = dir->i_sb;
2574342306fSKonstantin Komarov 	struct ntfs_sb_info *sbi = sb->s_fs_info;
25878ab59feSKonstantin Komarov 	struct ntfs_inode *dir_ni = ntfs_i(dir);
2594342306fSKonstantin Komarov 	struct ntfs_inode *new_dir_ni = ntfs_i(new_dir);
26078ab59feSKonstantin Komarov 	struct inode *inode = d_inode(dentry);
26178ab59feSKonstantin Komarov 	struct ntfs_inode *ni = ntfs_i(inode);
26278ab59feSKonstantin Komarov 	struct inode *new_inode = d_inode(new_dentry);
26378ab59feSKonstantin Komarov 	struct NTFS_DE *de, *new_de;
26478ab59feSKonstantin Komarov 	bool is_same, is_bad;
26578ab59feSKonstantin Komarov 	/*
26678ab59feSKonstantin Komarov 	 * de		- memory of PATH_MAX bytes:
26778ab59feSKonstantin Komarov 	 * [0-1024)	- original name (dentry->d_name)
26878ab59feSKonstantin Komarov 	 * [1024-2048)	- paired to original name, usually DOS variant of dentry->d_name
26978ab59feSKonstantin Komarov 	 * [2048-3072)	- new name (new_dentry->d_name)
27078ab59feSKonstantin Komarov 	 */
2714342306fSKonstantin Komarov 	static_assert(SIZEOF_ATTRIBUTE_FILENAME_MAX + SIZEOF_RESIDENT < 1024);
2724342306fSKonstantin Komarov 	static_assert(SIZEOF_ATTRIBUTE_FILENAME_MAX + sizeof(struct NTFS_DE) <
2734342306fSKonstantin Komarov 		      1024);
2744342306fSKonstantin Komarov 	static_assert(PATH_MAX >= 4 * 1024);
2754342306fSKonstantin Komarov 
276*f73f9397SKonstantin Komarov 	if (unlikely(ntfs3_forced_shutdown(sb)))
277*f73f9397SKonstantin Komarov 		return -EIO;
278*f73f9397SKonstantin Komarov 
2794342306fSKonstantin Komarov 	if (flags & ~RENAME_NOREPLACE)
2804342306fSKonstantin Komarov 		return -EINVAL;
2814342306fSKonstantin Komarov 
28278ab59feSKonstantin Komarov 	is_same = dentry->d_name.len == new_dentry->d_name.len &&
28378ab59feSKonstantin Komarov 		  !memcmp(dentry->d_name.name, new_dentry->d_name.name,
28478ab59feSKonstantin Komarov 			  dentry->d_name.len);
2854342306fSKonstantin Komarov 
28678ab59feSKonstantin Komarov 	if (is_same && dir == new_dir) {
287e8b8e97fSKari Argillander 		/* Nothing to do. */
28878ab59feSKonstantin Komarov 		return 0;
2894342306fSKonstantin Komarov 	}
2904342306fSKonstantin Komarov 
29178ab59feSKonstantin Komarov 	if (ntfs_is_meta_file(sbi, inode->i_ino)) {
29278ab59feSKonstantin Komarov 		/* Should we print an error? */
29378ab59feSKonstantin Komarov 		return -EINVAL;
2944342306fSKonstantin Komarov 	}
2954342306fSKonstantin Komarov 
2964342306fSKonstantin Komarov 	if (new_inode) {
297e8b8e97fSKari Argillander 		/* Target name exists. Unlink it. */
2984342306fSKonstantin Komarov 		dget(new_dentry);
2994342306fSKonstantin Komarov 		ni_lock_dir(new_dir_ni);
3004342306fSKonstantin Komarov 		err = ntfs_unlink_inode(new_dir, new_dentry);
3014342306fSKonstantin Komarov 		ni_unlock(new_dir_ni);
3024342306fSKonstantin Komarov 		dput(new_dentry);
3034342306fSKonstantin Komarov 		if (err)
30478ab59feSKonstantin Komarov 			return err;
3054342306fSKonstantin Komarov 	}
3064342306fSKonstantin Komarov 
307e8b8e97fSKari Argillander 	/* Allocate PATH_MAX bytes. */
30878ab59feSKonstantin Komarov 	de = __getname();
30978ab59feSKonstantin Komarov 	if (!de)
31078ab59feSKonstantin Komarov 		return -ENOMEM;
31178ab59feSKonstantin Komarov 
31278ab59feSKonstantin Komarov 	/* Translate dentry->d_name into unicode form. */
31378ab59feSKonstantin Komarov 	err = fill_name_de(sbi, de, &dentry->d_name, NULL);
31478ab59feSKonstantin Komarov 	if (err < 0)
31578ab59feSKonstantin Komarov 		goto out;
31678ab59feSKonstantin Komarov 
31778ab59feSKonstantin Komarov 	if (is_same) {
31878ab59feSKonstantin Komarov 		/* Reuse 'de'. */
31978ab59feSKonstantin Komarov 		new_de = de;
32078ab59feSKonstantin Komarov 	} else {
32178ab59feSKonstantin Komarov 		/* Translate new_dentry->d_name into unicode form. */
32278ab59feSKonstantin Komarov 		new_de = Add2Ptr(de, 2048);
32378ab59feSKonstantin Komarov 		err = fill_name_de(sbi, new_de, &new_dentry->d_name, NULL);
32478ab59feSKonstantin Komarov 		if (err < 0)
3254342306fSKonstantin Komarov 			goto out;
3264342306fSKonstantin Komarov 	}
3274342306fSKonstantin Komarov 
32878ab59feSKonstantin Komarov 	ni_lock_dir(dir_ni);
32978ab59feSKonstantin Komarov 	ni_lock(ni);
3300ad9dfcbSKonstantin Komarov 	if (dir_ni != new_dir_ni)
3310ad9dfcbSKonstantin Komarov 		ni_lock_dir2(new_dir_ni);
3324342306fSKonstantin Komarov 
33378ab59feSKonstantin Komarov 	is_bad = false;
33478ab59feSKonstantin Komarov 	err = ni_rename(dir_ni, new_dir_ni, ni, de, new_de, &is_bad);
33578ab59feSKonstantin Komarov 	if (is_bad) {
33678ab59feSKonstantin Komarov 		/* Restore after failed rename failed too. */
337c12df45eSKonstantin Komarov 		_ntfs_bad_inode(inode);
33878ab59feSKonstantin Komarov 	} else if (!err) {
339487e34fcSJeff Layton 		simple_rename_timestamp(dir, dentry, new_dir, new_dentry);
34078ab59feSKonstantin Komarov 		mark_inode_dirty(inode);
34178ab59feSKonstantin Komarov 		mark_inode_dirty(dir);
342487e34fcSJeff Layton 		if (dir != new_dir)
3434342306fSKonstantin Komarov 			mark_inode_dirty(new_dir);
3444342306fSKonstantin Komarov 
34578ab59feSKonstantin Komarov 		if (IS_DIRSYNC(dir))
34678ab59feSKonstantin Komarov 			ntfs_sync_inode(dir);
34778ab59feSKonstantin Komarov 
34878ab59feSKonstantin Komarov 		if (IS_DIRSYNC(new_dir))
34978ab59feSKonstantin Komarov 			ntfs_sync_inode(inode);
3504342306fSKonstantin Komarov 	}
3514342306fSKonstantin Komarov 
3520ad9dfcbSKonstantin Komarov 	if (dir_ni != new_dir_ni)
3530ad9dfcbSKonstantin Komarov 		ni_unlock(new_dir_ni);
35478ab59feSKonstantin Komarov 	ni_unlock(ni);
35578ab59feSKonstantin Komarov 	ni_unlock(dir_ni);
3564342306fSKonstantin Komarov out:
35778ab59feSKonstantin Komarov 	__putname(de);
3584342306fSKonstantin Komarov 	return err;
3594342306fSKonstantin Komarov }
3604342306fSKonstantin Komarov 
3612b108260SKonstantin Komarov /*
3622b108260SKonstantin Komarov  * ntfs_atomic_open
3632b108260SKonstantin Komarov  *
3642b108260SKonstantin Komarov  * inode_operations::atomic_open
3652b108260SKonstantin Komarov  */
ntfs_atomic_open(struct inode * dir,struct dentry * dentry,struct file * file,u32 flags,umode_t mode)3662b108260SKonstantin Komarov static int ntfs_atomic_open(struct inode *dir, struct dentry *dentry,
3672b108260SKonstantin Komarov 			    struct file *file, u32 flags, umode_t mode)
3682b108260SKonstantin Komarov {
3692b108260SKonstantin Komarov 	int err;
3702b108260SKonstantin Komarov 	struct inode *inode;
3712b108260SKonstantin Komarov 	struct ntfs_fnd *fnd = NULL;
3722b108260SKonstantin Komarov 	struct ntfs_inode *ni = ntfs_i(dir);
3732b108260SKonstantin Komarov 	struct dentry *d = NULL;
3742b108260SKonstantin Komarov 	struct cpu_str *uni = __getname();
3752b108260SKonstantin Komarov 	bool locked = false;
3762b108260SKonstantin Komarov 
3772b108260SKonstantin Komarov 	if (!uni)
3782b108260SKonstantin Komarov 		return -ENOMEM;
3792b108260SKonstantin Komarov 
3802b108260SKonstantin Komarov 	err = ntfs_nls_to_utf16(ni->mi.sbi, dentry->d_name.name,
3812b108260SKonstantin Komarov 				dentry->d_name.len, uni, NTFS_NAME_LEN,
3822b108260SKonstantin Komarov 				UTF16_HOST_ENDIAN);
3832b108260SKonstantin Komarov 	if (err < 0)
3842b108260SKonstantin Komarov 		goto out;
3852b108260SKonstantin Komarov 
3862b108260SKonstantin Komarov #ifdef CONFIG_NTFS3_FS_POSIX_ACL
3872b108260SKonstantin Komarov 	if (IS_POSIXACL(dir)) {
3882b108260SKonstantin Komarov 		/*
3892b108260SKonstantin Komarov 		 * Load in cache current acl to avoid ni_lock(dir):
3902b108260SKonstantin Komarov 		 * ntfs_create_inode -> ntfs_init_acl -> posix_acl_create ->
3912b108260SKonstantin Komarov 		 * ntfs_get_acl -> ntfs_get_acl_ex -> ni_lock
3922b108260SKonstantin Komarov 		 */
3936022ec6eSLinus Torvalds 		struct posix_acl *p = get_inode_acl(dir, ACL_TYPE_DEFAULT);
3942b108260SKonstantin Komarov 
3952b108260SKonstantin Komarov 		if (IS_ERR(p)) {
3962b108260SKonstantin Komarov 			err = PTR_ERR(p);
3972b108260SKonstantin Komarov 			goto out;
3982b108260SKonstantin Komarov 		}
3992b108260SKonstantin Komarov 		posix_acl_release(p);
4002b108260SKonstantin Komarov 	}
4012b108260SKonstantin Komarov #endif
4022b108260SKonstantin Komarov 
4032b108260SKonstantin Komarov 	if (d_in_lookup(dentry)) {
4042b108260SKonstantin Komarov 		ni_lock_dir(ni);
4052b108260SKonstantin Komarov 		locked = true;
4062b108260SKonstantin Komarov 		fnd = fnd_get();
4072b108260SKonstantin Komarov 		if (!fnd) {
4082b108260SKonstantin Komarov 			err = -ENOMEM;
4092b108260SKonstantin Komarov 			goto out1;
4102b108260SKonstantin Komarov 		}
4112b108260SKonstantin Komarov 
4122b108260SKonstantin Komarov 		d = d_splice_alias(dir_search_u(dir, uni, fnd), dentry);
4132b108260SKonstantin Komarov 		if (IS_ERR(d)) {
4142b108260SKonstantin Komarov 			err = PTR_ERR(d);
4152b108260SKonstantin Komarov 			d = NULL;
4162b108260SKonstantin Komarov 			goto out2;
4172b108260SKonstantin Komarov 		}
4182b108260SKonstantin Komarov 
4192b108260SKonstantin Komarov 		if (d)
4202b108260SKonstantin Komarov 			dentry = d;
4212b108260SKonstantin Komarov 	}
4222b108260SKonstantin Komarov 
4232b108260SKonstantin Komarov 	if (!(flags & O_CREAT) || d_really_is_positive(dentry)) {
4242b108260SKonstantin Komarov 		err = finish_no_open(file, d);
4252b108260SKonstantin Komarov 		goto out2;
4262b108260SKonstantin Komarov 	}
4272b108260SKonstantin Komarov 
4282b108260SKonstantin Komarov 	file->f_mode |= FMODE_CREATED;
4292b108260SKonstantin Komarov 
4302b108260SKonstantin Komarov 	/*
4312b108260SKonstantin Komarov 	 * fnd contains tree's path to insert to.
4322b108260SKonstantin Komarov 	 * If fnd is not NULL then dir is locked.
4332b108260SKonstantin Komarov 	 */
434d6cd7cecSKonstantin Komarov 	inode = ntfs_create_inode(mnt_idmap(file->f_path.mnt), dir, dentry, uni,
435d6cd7cecSKonstantin Komarov 				  mode, 0, NULL, 0, fnd);
43696de65a9SKonstantin Komarov 	err = IS_ERR(inode) ? PTR_ERR(inode) :
43796de65a9SKonstantin Komarov 			      finish_open(file, dentry, ntfs_file_open);
4382b108260SKonstantin Komarov 	dput(d);
4392b108260SKonstantin Komarov 
4402b108260SKonstantin Komarov out2:
4412b108260SKonstantin Komarov 	fnd_put(fnd);
4422b108260SKonstantin Komarov out1:
4432b108260SKonstantin Komarov 	if (locked)
4442b108260SKonstantin Komarov 		ni_unlock(ni);
4452b108260SKonstantin Komarov out:
4462b108260SKonstantin Komarov 	__putname(uni);
4472b108260SKonstantin Komarov 	return err;
4482b108260SKonstantin Komarov }
4492b108260SKonstantin Komarov 
ntfs3_get_parent(struct dentry * child)4504342306fSKonstantin Komarov struct dentry *ntfs3_get_parent(struct dentry *child)
4514342306fSKonstantin Komarov {
4524342306fSKonstantin Komarov 	struct inode *inode = d_inode(child);
4534342306fSKonstantin Komarov 	struct ntfs_inode *ni = ntfs_i(inode);
4544342306fSKonstantin Komarov 
4554342306fSKonstantin Komarov 	struct ATTR_LIST_ENTRY *le = NULL;
4564342306fSKonstantin Komarov 	struct ATTRIB *attr = NULL;
4574342306fSKonstantin Komarov 	struct ATTR_FILE_NAME *fname;
4584342306fSKonstantin Komarov 
4594342306fSKonstantin Komarov 	while ((attr = ni_find_attr(ni, attr, &le, ATTR_NAME, NULL, 0, NULL,
4604342306fSKonstantin Komarov 				    NULL))) {
4614342306fSKonstantin Komarov 		fname = resident_data_ex(attr, SIZEOF_ATTRIBUTE_FILENAME);
4624342306fSKonstantin Komarov 		if (!fname)
4634342306fSKonstantin Komarov 			continue;
4644342306fSKonstantin Komarov 
4654342306fSKonstantin Komarov 		return d_obtain_alias(
4664342306fSKonstantin Komarov 			ntfs_iget5(inode->i_sb, &fname->home, NULL));
4674342306fSKonstantin Komarov 	}
4684342306fSKonstantin Komarov 
4694342306fSKonstantin Komarov 	return ERR_PTR(-ENOENT);
4704342306fSKonstantin Komarov }
4714342306fSKonstantin Komarov 
472a3a956c7SKonstantin Komarov /*
473a3a956c7SKonstantin Komarov  * dentry_operations::d_hash
474a3a956c7SKonstantin Komarov  */
ntfs_d_hash(const struct dentry * dentry,struct qstr * name)475a3a956c7SKonstantin Komarov static int ntfs_d_hash(const struct dentry *dentry, struct qstr *name)
476a3a956c7SKonstantin Komarov {
477a3a956c7SKonstantin Komarov 	struct ntfs_sb_info *sbi;
478a3a956c7SKonstantin Komarov 	const char *n = name->name;
479a3a956c7SKonstantin Komarov 	unsigned int len = name->len;
480a3a956c7SKonstantin Komarov 	unsigned long hash;
481a3a956c7SKonstantin Komarov 	struct cpu_str *uni;
482a3a956c7SKonstantin Komarov 	unsigned int c;
483a3a956c7SKonstantin Komarov 	int err;
484a3a956c7SKonstantin Komarov 
485a3a956c7SKonstantin Komarov 	/* First try fast implementation. */
486a3a956c7SKonstantin Komarov 	hash = init_name_hash(dentry);
487a3a956c7SKonstantin Komarov 
488a3a956c7SKonstantin Komarov 	for (;;) {
489a3a956c7SKonstantin Komarov 		if (!len--) {
490a3a956c7SKonstantin Komarov 			name->hash = end_name_hash(hash);
491a3a956c7SKonstantin Komarov 			return 0;
492a3a956c7SKonstantin Komarov 		}
493a3a956c7SKonstantin Komarov 
494a3a956c7SKonstantin Komarov 		c = *n++;
495a3a956c7SKonstantin Komarov 		if (c >= 0x80)
496a3a956c7SKonstantin Komarov 			break;
497a3a956c7SKonstantin Komarov 
498a3a956c7SKonstantin Komarov 		hash = partial_name_hash(toupper(c), hash);
499a3a956c7SKonstantin Komarov 	}
500a3a956c7SKonstantin Komarov 
501a3a956c7SKonstantin Komarov 	/*
502a3a956c7SKonstantin Komarov 	 * Try slow way with current upcase table
503a3a956c7SKonstantin Komarov 	 */
504a3a956c7SKonstantin Komarov 	uni = __getname();
505a3a956c7SKonstantin Komarov 	if (!uni)
506a3a956c7SKonstantin Komarov 		return -ENOMEM;
507a3a956c7SKonstantin Komarov 
508a3a956c7SKonstantin Komarov 	sbi = dentry->d_sb->s_fs_info;
509a3a956c7SKonstantin Komarov 
510a3a956c7SKonstantin Komarov 	err = ntfs_nls_to_utf16(sbi, name->name, name->len, uni, NTFS_NAME_LEN,
511a3a956c7SKonstantin Komarov 				UTF16_HOST_ENDIAN);
512a3a956c7SKonstantin Komarov 	if (err < 0)
513a3a956c7SKonstantin Komarov 		goto out;
514a3a956c7SKonstantin Komarov 
515a3a956c7SKonstantin Komarov 	if (!err) {
516a3a956c7SKonstantin Komarov 		err = -EINVAL;
517a3a956c7SKonstantin Komarov 		goto out;
518a3a956c7SKonstantin Komarov 	}
519a3a956c7SKonstantin Komarov 
520a3a956c7SKonstantin Komarov 	hash = ntfs_names_hash(uni->name, uni->len, sbi->upcase,
521a3a956c7SKonstantin Komarov 			       init_name_hash(dentry));
522a3a956c7SKonstantin Komarov 	name->hash = end_name_hash(hash);
523a3a956c7SKonstantin Komarov 	err = 0;
524a3a956c7SKonstantin Komarov 
525a3a956c7SKonstantin Komarov out:
526a3a956c7SKonstantin Komarov 	__putname(uni);
527a3a956c7SKonstantin Komarov 	return err;
528a3a956c7SKonstantin Komarov }
529a3a956c7SKonstantin Komarov 
530a3a956c7SKonstantin Komarov /*
531a3a956c7SKonstantin Komarov  * dentry_operations::d_compare
532a3a956c7SKonstantin Komarov  */
ntfs_d_compare(const struct dentry * dentry,unsigned int len1,const char * str,const struct qstr * name)533a3a956c7SKonstantin Komarov static int ntfs_d_compare(const struct dentry *dentry, unsigned int len1,
534a3a956c7SKonstantin Komarov 			  const char *str, const struct qstr *name)
535a3a956c7SKonstantin Komarov {
536a3a956c7SKonstantin Komarov 	struct ntfs_sb_info *sbi;
537a3a956c7SKonstantin Komarov 	int ret;
538a3a956c7SKonstantin Komarov 	const char *n1 = str;
539a3a956c7SKonstantin Komarov 	const char *n2 = name->name;
540a3a956c7SKonstantin Komarov 	unsigned int len2 = name->len;
541a3a956c7SKonstantin Komarov 	unsigned int lm = min(len1, len2);
542a3a956c7SKonstantin Komarov 	unsigned char c1, c2;
5439144b438SKonstantin Komarov 	struct cpu_str *uni1;
5449144b438SKonstantin Komarov 	struct le_str *uni2;
545a3a956c7SKonstantin Komarov 
546a3a956c7SKonstantin Komarov 	/* First try fast implementation. */
547a3a956c7SKonstantin Komarov 	for (;;) {
5480d6d7c61SNathan Chancellor 		if (!lm--)
54975b5e472SNathan Chancellor 			return len1 != len2;
550a3a956c7SKonstantin Komarov 
551a3a956c7SKonstantin Komarov 		if ((c1 = *n1++) == (c2 = *n2++))
552a3a956c7SKonstantin Komarov 			continue;
553a3a956c7SKonstantin Komarov 
554a3a956c7SKonstantin Komarov 		if (c1 >= 0x80 || c2 >= 0x80)
555a3a956c7SKonstantin Komarov 			break;
556a3a956c7SKonstantin Komarov 
5570d6d7c61SNathan Chancellor 		if (toupper(c1) != toupper(c2))
5580d6d7c61SNathan Chancellor 			return 1;
559a3a956c7SKonstantin Komarov 	}
560a3a956c7SKonstantin Komarov 
561a3a956c7SKonstantin Komarov 	/*
562a3a956c7SKonstantin Komarov 	 * Try slow way with current upcase table
563a3a956c7SKonstantin Komarov 	 */
564a3a956c7SKonstantin Komarov 	sbi = dentry->d_sb->s_fs_info;
565a3a956c7SKonstantin Komarov 	uni1 = __getname();
566a3a956c7SKonstantin Komarov 	if (!uni1)
567a3a956c7SKonstantin Komarov 		return -ENOMEM;
568a3a956c7SKonstantin Komarov 
569a3a956c7SKonstantin Komarov 	ret = ntfs_nls_to_utf16(sbi, str, len1, uni1, NTFS_NAME_LEN,
570a3a956c7SKonstantin Komarov 				UTF16_HOST_ENDIAN);
571a3a956c7SKonstantin Komarov 	if (ret < 0)
572a3a956c7SKonstantin Komarov 		goto out;
573a3a956c7SKonstantin Komarov 
574a3a956c7SKonstantin Komarov 	if (!ret) {
575a3a956c7SKonstantin Komarov 		ret = -EINVAL;
576a3a956c7SKonstantin Komarov 		goto out;
577a3a956c7SKonstantin Komarov 	}
578a3a956c7SKonstantin Komarov 
579a3a956c7SKonstantin Komarov 	uni2 = Add2Ptr(uni1, 2048);
580a3a956c7SKonstantin Komarov 
5819144b438SKonstantin Komarov 	ret = ntfs_nls_to_utf16(sbi, name->name, name->len,
5829144b438SKonstantin Komarov 				(struct cpu_str *)uni2, NTFS_NAME_LEN,
5839144b438SKonstantin Komarov 				UTF16_LITTLE_ENDIAN);
584a3a956c7SKonstantin Komarov 	if (ret < 0)
585a3a956c7SKonstantin Komarov 		goto out;
586a3a956c7SKonstantin Komarov 
587a3a956c7SKonstantin Komarov 	if (!ret) {
588a3a956c7SKonstantin Komarov 		ret = -EINVAL;
589a3a956c7SKonstantin Komarov 		goto out;
590a3a956c7SKonstantin Komarov 	}
591a3a956c7SKonstantin Komarov 
5929144b438SKonstantin Komarov 	ret = !ntfs_cmp_names_cpu(uni1, uni2, sbi->upcase, false) ? 0 : 1;
593a3a956c7SKonstantin Komarov 
594a3a956c7SKonstantin Komarov out:
595a3a956c7SKonstantin Komarov 	__putname(uni1);
596a3a956c7SKonstantin Komarov 	return ret;
597a3a956c7SKonstantin Komarov }
598a3a956c7SKonstantin Komarov 
5994342306fSKonstantin Komarov // clang-format off
6004342306fSKonstantin Komarov const struct inode_operations ntfs_dir_inode_operations = {
6014342306fSKonstantin Komarov 	.lookup		= ntfs_lookup,
6024342306fSKonstantin Komarov 	.create		= ntfs_create,
6034342306fSKonstantin Komarov 	.link		= ntfs_link,
6044342306fSKonstantin Komarov 	.unlink		= ntfs_unlink,
6054342306fSKonstantin Komarov 	.symlink	= ntfs_symlink,
6064342306fSKonstantin Komarov 	.mkdir		= ntfs_mkdir,
6074342306fSKonstantin Komarov 	.rmdir		= ntfs_rmdir,
6084342306fSKonstantin Komarov 	.mknod		= ntfs_mknod,
6094342306fSKonstantin Komarov 	.rename		= ntfs_rename,
61075c5e0c9SKonstantin Komarov 	.get_acl	= ntfs_get_acl,
6114342306fSKonstantin Komarov 	.set_acl	= ntfs_set_acl,
6124342306fSKonstantin Komarov 	.setattr	= ntfs3_setattr,
6134342306fSKonstantin Komarov 	.getattr	= ntfs_getattr,
6144342306fSKonstantin Komarov 	.listxattr	= ntfs_listxattr,
6152b108260SKonstantin Komarov 	.atomic_open	= ntfs_atomic_open,
6164342306fSKonstantin Komarov 	.fiemap		= ntfs_fiemap,
6174342306fSKonstantin Komarov };
6184342306fSKonstantin Komarov 
6194342306fSKonstantin Komarov const struct inode_operations ntfs_special_inode_operations = {
6204342306fSKonstantin Komarov 	.setattr	= ntfs3_setattr,
6214342306fSKonstantin Komarov 	.getattr	= ntfs_getattr,
6224342306fSKonstantin Komarov 	.listxattr	= ntfs_listxattr,
62375c5e0c9SKonstantin Komarov 	.get_acl	= ntfs_get_acl,
6244342306fSKonstantin Komarov 	.set_acl	= ntfs_set_acl,
6254342306fSKonstantin Komarov };
626a3a956c7SKonstantin Komarov 
627a3a956c7SKonstantin Komarov const struct dentry_operations ntfs_dentry_ops = {
628a3a956c7SKonstantin Komarov 	.d_hash		= ntfs_d_hash,
629a3a956c7SKonstantin Komarov 	.d_compare	= ntfs_d_compare,
630a3a956c7SKonstantin Komarov };
631a3a956c7SKonstantin Komarov 
6324342306fSKonstantin Komarov // clang-format on
633