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 {
84*34e3220eSKonstantin Komarov ni_lock_dir(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
184f73f9397SKonstantin Komarov if (unlikely(ntfs3_forced_shutdown(dir->i_sb)))
185f73f9397SKonstantin Komarov return -EIO;
186f73f9397SKonstantin 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
205f73f9397SKonstantin Komarov if (unlikely(ntfs3_forced_shutdown(dir->i_sb)))
206f73f9397SKonstantin Komarov return -EIO;
207f73f9397SKonstantin 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
236f73f9397SKonstantin Komarov if (unlikely(ntfs3_forced_shutdown(dir->i_sb)))
237f73f9397SKonstantin Komarov return -EIO;
238f73f9397SKonstantin 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
276f73f9397SKonstantin Komarov if (unlikely(ntfs3_forced_shutdown(sb)))
277f73f9397SKonstantin Komarov return -EIO;
278f73f9397SKonstantin 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 */
504c556e72cSDiogo Jahchan Koike uni = kmem_cache_alloc(names_cachep, GFP_NOWAIT);
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:
526c556e72cSDiogo Jahchan Koike kmem_cache_free(names_cachep, 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