1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * linux/fs/affs/namei.c
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * (c) 1996 Hans-Joachim Widmaier - Rewritten
61da177e4SLinus Torvalds *
71da177e4SLinus Torvalds * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem.
81da177e4SLinus Torvalds *
91da177e4SLinus Torvalds * (C) 1991 Linus Torvalds - minix filesystem
101da177e4SLinus Torvalds */
111da177e4SLinus Torvalds
121da177e4SLinus Torvalds #include "affs.h"
13ed4433d7SFabian Frederick #include <linux/exportfs.h>
141da177e4SLinus Torvalds
151da177e4SLinus Torvalds typedef int (*toupper_t)(int);
161da177e4SLinus Torvalds
171da177e4SLinus Torvalds /* Simple toupper() for DOS\1 */
181da177e4SLinus Torvalds
191da177e4SLinus Torvalds static int
affs_toupper(int ch)201da177e4SLinus Torvalds affs_toupper(int ch)
211da177e4SLinus Torvalds {
221da177e4SLinus Torvalds return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch;
231da177e4SLinus Torvalds }
241da177e4SLinus Torvalds
251da177e4SLinus Torvalds /* International toupper() for DOS\3 ("international") */
261da177e4SLinus Torvalds
271da177e4SLinus Torvalds static int
affs_intl_toupper(int ch)281da177e4SLinus Torvalds affs_intl_toupper(int ch)
291da177e4SLinus Torvalds {
301da177e4SLinus Torvalds return (ch >= 'a' && ch <= 'z') || (ch >= 0xE0
311da177e4SLinus Torvalds && ch <= 0xFE && ch != 0xF7) ?
321da177e4SLinus Torvalds ch - ('a' - 'A') : ch;
331da177e4SLinus Torvalds }
341da177e4SLinus Torvalds
351da177e4SLinus Torvalds static inline toupper_t
affs_get_toupper(struct super_block * sb)361da177e4SLinus Torvalds affs_get_toupper(struct super_block *sb)
371da177e4SLinus Torvalds {
3879bda4d5SFabian Frederick return affs_test_opt(AFFS_SB(sb)->s_flags, SF_INTL) ?
39a0016ff2SFabian Frederick affs_intl_toupper : affs_toupper;
401da177e4SLinus Torvalds }
411da177e4SLinus Torvalds
421da177e4SLinus Torvalds /*
431da177e4SLinus Torvalds * Note: the dentry argument is the parent dentry.
441da177e4SLinus Torvalds */
451da177e4SLinus Torvalds static inline int
__affs_hash_dentry(const struct dentry * dentry,struct qstr * qstr,toupper_t fn,bool notruncate)46*4d4f1468SAndy Shevchenko __affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr, toupper_t fn, bool notruncate)
471da177e4SLinus Torvalds {
481da177e4SLinus Torvalds const u8 *name = qstr->name;
491da177e4SLinus Torvalds unsigned long hash;
50eeb36f8eSFabian Frederick int retval;
51eeb36f8eSFabian Frederick u32 len;
521da177e4SLinus Torvalds
53eeb36f8eSFabian Frederick retval = affs_check_name(qstr->name, qstr->len, notruncate);
54eeb36f8eSFabian Frederick if (retval)
55eeb36f8eSFabian Frederick return retval;
561da177e4SLinus Torvalds
578387ff25SLinus Torvalds hash = init_name_hash(dentry);
58f157853eSFabian Frederick len = min(qstr->len, AFFSNAMEMAX);
59eeb36f8eSFabian Frederick for (; len > 0; name++, len--)
60*4d4f1468SAndy Shevchenko hash = partial_name_hash(fn(*name), hash);
611da177e4SLinus Torvalds qstr->hash = end_name_hash(hash);
621da177e4SLinus Torvalds
631da177e4SLinus Torvalds return 0;
641da177e4SLinus Torvalds }
651da177e4SLinus Torvalds
661da177e4SLinus Torvalds static int
affs_hash_dentry(const struct dentry * dentry,struct qstr * qstr)67da53be12SLinus Torvalds affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
681da177e4SLinus Torvalds {
698387ff25SLinus Torvalds return __affs_hash_dentry(dentry, qstr, affs_toupper,
708ca57722SFabian Frederick affs_nofilenametruncate(dentry));
718ca57722SFabian Frederick
721da177e4SLinus Torvalds }
738ca57722SFabian Frederick
741da177e4SLinus Torvalds static int
affs_intl_hash_dentry(const struct dentry * dentry,struct qstr * qstr)75da53be12SLinus Torvalds affs_intl_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
761da177e4SLinus Torvalds {
778387ff25SLinus Torvalds return __affs_hash_dentry(dentry, qstr, affs_intl_toupper,
788ca57722SFabian Frederick affs_nofilenametruncate(dentry));
798ca57722SFabian Frederick
801da177e4SLinus Torvalds }
811da177e4SLinus Torvalds
__affs_compare_dentry(unsigned int len,const char * str,const struct qstr * name,toupper_t fn,bool notruncate)82621e155aSNick Piggin static inline int __affs_compare_dentry(unsigned int len,
83*4d4f1468SAndy Shevchenko const char *str, const struct qstr *name, toupper_t fn,
848ca57722SFabian Frederick bool notruncate)
851da177e4SLinus Torvalds {
86621e155aSNick Piggin const u8 *aname = str;
87621e155aSNick Piggin const u8 *bname = name->name;
881da177e4SLinus Torvalds
89621e155aSNick Piggin /*
90621e155aSNick Piggin * 'str' is the name of an already existing dentry, so the name
91621e155aSNick Piggin * must be valid. 'name' must be validated first.
921da177e4SLinus Torvalds */
931da177e4SLinus Torvalds
948ca57722SFabian Frederick if (affs_check_name(name->name, name->len, notruncate))
951da177e4SLinus Torvalds return 1;
961da177e4SLinus Torvalds
97621e155aSNick Piggin /*
98621e155aSNick Piggin * If the names are longer than the allowed 30 chars,
991da177e4SLinus Torvalds * the excess is ignored, so their length may differ.
1001da177e4SLinus Torvalds */
101f157853eSFabian Frederick if (len >= AFFSNAMEMAX) {
102f157853eSFabian Frederick if (name->len < AFFSNAMEMAX)
1031da177e4SLinus Torvalds return 1;
104f157853eSFabian Frederick len = AFFSNAMEMAX;
105621e155aSNick Piggin } else if (len != name->len)
1061da177e4SLinus Torvalds return 1;
1071da177e4SLinus Torvalds
1081da177e4SLinus Torvalds for (; len > 0; len--)
109*4d4f1468SAndy Shevchenko if (fn(*aname++) != fn(*bname++))
1101da177e4SLinus Torvalds return 1;
1111da177e4SLinus Torvalds
1121da177e4SLinus Torvalds return 0;
1131da177e4SLinus Torvalds }
1141da177e4SLinus Torvalds
1151da177e4SLinus Torvalds static int
affs_compare_dentry(const struct dentry * dentry,unsigned int len,const char * str,const struct qstr * name)1166fa67e70SAl Viro affs_compare_dentry(const struct dentry *dentry,
117621e155aSNick Piggin unsigned int len, const char *str, const struct qstr *name)
1181da177e4SLinus Torvalds {
1198ca57722SFabian Frederick
1208ca57722SFabian Frederick return __affs_compare_dentry(len, str, name, affs_toupper,
121e0b3f595SAl Viro affs_nofilenametruncate(dentry));
1221da177e4SLinus Torvalds }
1238ca57722SFabian Frederick
1241da177e4SLinus Torvalds static int
affs_intl_compare_dentry(const struct dentry * dentry,unsigned int len,const char * str,const struct qstr * name)1256fa67e70SAl Viro affs_intl_compare_dentry(const struct dentry *dentry,
126621e155aSNick Piggin unsigned int len, const char *str, const struct qstr *name)
1271da177e4SLinus Torvalds {
1288ca57722SFabian Frederick return __affs_compare_dentry(len, str, name, affs_intl_toupper,
129e0b3f595SAl Viro affs_nofilenametruncate(dentry));
1308ca57722SFabian Frederick
1311da177e4SLinus Torvalds }
1321da177e4SLinus Torvalds
1331da177e4SLinus Torvalds /*
1341da177e4SLinus Torvalds * NOTE! unlike strncmp, affs_match returns 1 for success, 0 for failure.
1351da177e4SLinus Torvalds */
1361da177e4SLinus Torvalds
1371da177e4SLinus Torvalds static inline int
affs_match(struct dentry * dentry,const u8 * name2,toupper_t fn)138*4d4f1468SAndy Shevchenko affs_match(struct dentry *dentry, const u8 *name2, toupper_t fn)
1391da177e4SLinus Torvalds {
1401da177e4SLinus Torvalds const u8 *name = dentry->d_name.name;
1411da177e4SLinus Torvalds int len = dentry->d_name.len;
1421da177e4SLinus Torvalds
143f157853eSFabian Frederick if (len >= AFFSNAMEMAX) {
144f157853eSFabian Frederick if (*name2 < AFFSNAMEMAX)
1451da177e4SLinus Torvalds return 0;
146f157853eSFabian Frederick len = AFFSNAMEMAX;
1471da177e4SLinus Torvalds } else if (len != *name2)
1481da177e4SLinus Torvalds return 0;
1491da177e4SLinus Torvalds
1501da177e4SLinus Torvalds for (name2++; len > 0; len--)
151*4d4f1468SAndy Shevchenko if (fn(*name++) != fn(*name2++))
1521da177e4SLinus Torvalds return 0;
1531da177e4SLinus Torvalds return 1;
1541da177e4SLinus Torvalds }
1551da177e4SLinus Torvalds
1561da177e4SLinus Torvalds int
affs_hash_name(struct super_block * sb,const u8 * name,unsigned int len)1571da177e4SLinus Torvalds affs_hash_name(struct super_block *sb, const u8 *name, unsigned int len)
1581da177e4SLinus Torvalds {
159*4d4f1468SAndy Shevchenko toupper_t fn = affs_get_toupper(sb);
160eeb36f8eSFabian Frederick u32 hash;
1611da177e4SLinus Torvalds
162f157853eSFabian Frederick hash = len = min(len, AFFSNAMEMAX);
1631da177e4SLinus Torvalds for (; len > 0; len--)
164*4d4f1468SAndy Shevchenko hash = (hash * 13 + fn(*name++)) & 0x7ff;
1651da177e4SLinus Torvalds
1661da177e4SLinus Torvalds return hash % AFFS_SB(sb)->s_hashsize;
1671da177e4SLinus Torvalds }
1681da177e4SLinus Torvalds
1691da177e4SLinus Torvalds static struct buffer_head *
affs_find_entry(struct inode * dir,struct dentry * dentry)1701da177e4SLinus Torvalds affs_find_entry(struct inode *dir, struct dentry *dentry)
1711da177e4SLinus Torvalds {
1721da177e4SLinus Torvalds struct super_block *sb = dir->i_sb;
1731da177e4SLinus Torvalds struct buffer_head *bh;
174*4d4f1468SAndy Shevchenko toupper_t fn = affs_get_toupper(sb);
1751da177e4SLinus Torvalds u32 key;
1761da177e4SLinus Torvalds
177a455589fSAl Viro pr_debug("%s(\"%pd\")\n", __func__, dentry);
1781da177e4SLinus Torvalds
1791da177e4SLinus Torvalds bh = affs_bread(sb, dir->i_ino);
1801da177e4SLinus Torvalds if (!bh)
1811da177e4SLinus Torvalds return ERR_PTR(-EIO);
1821da177e4SLinus Torvalds
1831da177e4SLinus Torvalds key = be32_to_cpu(AFFS_HEAD(bh)->table[affs_hash_name(sb, dentry->d_name.name, dentry->d_name.len)]);
1841da177e4SLinus Torvalds
1851da177e4SLinus Torvalds for (;;) {
1861da177e4SLinus Torvalds affs_brelse(bh);
1871da177e4SLinus Torvalds if (key == 0)
1881da177e4SLinus Torvalds return NULL;
1891da177e4SLinus Torvalds bh = affs_bread(sb, key);
1901da177e4SLinus Torvalds if (!bh)
1911da177e4SLinus Torvalds return ERR_PTR(-EIO);
192*4d4f1468SAndy Shevchenko if (affs_match(dentry, AFFS_TAIL(sb, bh)->name, fn))
1931da177e4SLinus Torvalds return bh;
1941da177e4SLinus Torvalds key = be32_to_cpu(AFFS_TAIL(sb, bh)->hash_chain);
1951da177e4SLinus Torvalds }
1961da177e4SLinus Torvalds }
1971da177e4SLinus Torvalds
1981da177e4SLinus Torvalds struct dentry *
affs_lookup(struct inode * dir,struct dentry * dentry,unsigned int flags)19900cd8dd3SAl Viro affs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
2001da177e4SLinus Torvalds {
2011da177e4SLinus Torvalds struct super_block *sb = dir->i_sb;
2021da177e4SLinus Torvalds struct buffer_head *bh;
2031da177e4SLinus Torvalds struct inode *inode = NULL;
20487fbd639SAl Viro struct dentry *res;
2051da177e4SLinus Torvalds
206a455589fSAl Viro pr_debug("%s(\"%pd\")\n", __func__, dentry);
2071da177e4SLinus Torvalds
2081da177e4SLinus Torvalds affs_lock_dir(dir);
2091da177e4SLinus Torvalds bh = affs_find_entry(dir, dentry);
21030da870cSAl Viro if (IS_ERR(bh)) {
2111da177e4SLinus Torvalds affs_unlock_dir(dir);
212e231c2eeSDavid Howells return ERR_CAST(bh);
21330da870cSAl Viro }
2141da177e4SLinus Torvalds if (bh) {
2151da177e4SLinus Torvalds u32 ino = bh->b_blocknr;
2161da177e4SLinus Torvalds
2171da177e4SLinus Torvalds /* store the real header ino in d_fsdata for faster lookups */
2181da177e4SLinus Torvalds dentry->d_fsdata = (void *)(long)ino;
2191da177e4SLinus Torvalds switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
2201da177e4SLinus Torvalds //link to dirs disabled
2211da177e4SLinus Torvalds //case ST_LINKDIR:
2221da177e4SLinus Torvalds case ST_LINKFILE:
2231da177e4SLinus Torvalds ino = be32_to_cpu(AFFS_TAIL(sb, bh)->original);
2241da177e4SLinus Torvalds }
2251da177e4SLinus Torvalds affs_brelse(bh);
226210f8559SDavid Howells inode = affs_iget(sb, ino);
2271da177e4SLinus Torvalds }
22887fbd639SAl Viro res = d_splice_alias(inode, dentry);
22987fbd639SAl Viro if (!IS_ERR_OR_NULL(res))
23087fbd639SAl Viro res->d_fsdata = dentry->d_fsdata;
23130da870cSAl Viro affs_unlock_dir(dir);
23287fbd639SAl Viro return res;
2331da177e4SLinus Torvalds }
2341da177e4SLinus Torvalds
2351da177e4SLinus Torvalds int
affs_unlink(struct inode * dir,struct dentry * dentry)2361da177e4SLinus Torvalds affs_unlink(struct inode *dir, struct dentry *dentry)
2371da177e4SLinus Torvalds {
23808fe100dSGeert Uytterhoeven pr_debug("%s(dir=%lu, %lu \"%pd\")\n", __func__, dir->i_ino,
2392b0143b5SDavid Howells d_inode(dentry)->i_ino, dentry);
2401da177e4SLinus Torvalds
2411da177e4SLinus Torvalds return affs_remove_header(dentry);
2421da177e4SLinus Torvalds }
2431da177e4SLinus Torvalds
2441da177e4SLinus Torvalds int
affs_create(struct mnt_idmap * idmap,struct inode * dir,struct dentry * dentry,umode_t mode,bool excl)2456c960e68SChristian Brauner affs_create(struct mnt_idmap *idmap, struct inode *dir,
246549c7297SChristian Brauner struct dentry *dentry, umode_t mode, bool excl)
2471da177e4SLinus Torvalds {
2481da177e4SLinus Torvalds struct super_block *sb = dir->i_sb;
2491da177e4SLinus Torvalds struct inode *inode;
2501da177e4SLinus Torvalds int error;
2511da177e4SLinus Torvalds
252a455589fSAl Viro pr_debug("%s(%lu,\"%pd\",0%ho)\n",
253a455589fSAl Viro __func__, dir->i_ino, dentry, mode);
2541da177e4SLinus Torvalds
2551da177e4SLinus Torvalds inode = affs_new_inode(dir);
2561da177e4SLinus Torvalds if (!inode)
2571da177e4SLinus Torvalds return -ENOSPC;
2581da177e4SLinus Torvalds
2591da177e4SLinus Torvalds inode->i_mode = mode;
260c1618208SFabian Frederick affs_mode_to_prot(inode);
2611da177e4SLinus Torvalds mark_inode_dirty(inode);
2621da177e4SLinus Torvalds
2631da177e4SLinus Torvalds inode->i_op = &affs_file_inode_operations;
2641da177e4SLinus Torvalds inode->i_fop = &affs_file_operations;
26579bda4d5SFabian Frederick inode->i_mapping->a_ops = affs_test_opt(AFFS_SB(sb)->s_flags, SF_OFS) ?
266a0016ff2SFabian Frederick &affs_aops_ofs : &affs_aops;
2671da177e4SLinus Torvalds error = affs_add_entry(dir, inode, dentry, ST_FILE);
2681da177e4SLinus Torvalds if (error) {
2696d6b77f1SMiklos Szeredi clear_nlink(inode);
2701da177e4SLinus Torvalds iput(inode);
2711da177e4SLinus Torvalds return error;
2721da177e4SLinus Torvalds }
2731da177e4SLinus Torvalds return 0;
2741da177e4SLinus Torvalds }
2751da177e4SLinus Torvalds
2761da177e4SLinus Torvalds int
affs_mkdir(struct mnt_idmap * idmap,struct inode * dir,struct dentry * dentry,umode_t mode)277c54bd91eSChristian Brauner affs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
278549c7297SChristian Brauner struct dentry *dentry, umode_t mode)
2791da177e4SLinus Torvalds {
2801da177e4SLinus Torvalds struct inode *inode;
2811da177e4SLinus Torvalds int error;
2821da177e4SLinus Torvalds
283a455589fSAl Viro pr_debug("%s(%lu,\"%pd\",0%ho)\n",
284a455589fSAl Viro __func__, dir->i_ino, dentry, mode);
2851da177e4SLinus Torvalds
2861da177e4SLinus Torvalds inode = affs_new_inode(dir);
2871da177e4SLinus Torvalds if (!inode)
2881da177e4SLinus Torvalds return -ENOSPC;
2891da177e4SLinus Torvalds
2901da177e4SLinus Torvalds inode->i_mode = S_IFDIR | mode;
291c1618208SFabian Frederick affs_mode_to_prot(inode);
2921da177e4SLinus Torvalds
2931da177e4SLinus Torvalds inode->i_op = &affs_dir_inode_operations;
2941da177e4SLinus Torvalds inode->i_fop = &affs_dir_operations;
2951da177e4SLinus Torvalds
2961da177e4SLinus Torvalds error = affs_add_entry(dir, inode, dentry, ST_USERDIR);
2971da177e4SLinus Torvalds if (error) {
2986d6b77f1SMiklos Szeredi clear_nlink(inode);
2991da177e4SLinus Torvalds mark_inode_dirty(inode);
3001da177e4SLinus Torvalds iput(inode);
3011da177e4SLinus Torvalds return error;
3021da177e4SLinus Torvalds }
3031da177e4SLinus Torvalds return 0;
3041da177e4SLinus Torvalds }
3051da177e4SLinus Torvalds
3061da177e4SLinus Torvalds int
affs_rmdir(struct inode * dir,struct dentry * dentry)3071da177e4SLinus Torvalds affs_rmdir(struct inode *dir, struct dentry *dentry)
3081da177e4SLinus Torvalds {
30908fe100dSGeert Uytterhoeven pr_debug("%s(dir=%lu, %lu \"%pd\")\n", __func__, dir->i_ino,
3102b0143b5SDavid Howells d_inode(dentry)->i_ino, dentry);
3111da177e4SLinus Torvalds
3121da177e4SLinus Torvalds return affs_remove_header(dentry);
3131da177e4SLinus Torvalds }
3141da177e4SLinus Torvalds
3151da177e4SLinus Torvalds int
affs_symlink(struct mnt_idmap * idmap,struct inode * dir,struct dentry * dentry,const char * symname)3167a77db95SChristian Brauner affs_symlink(struct mnt_idmap *idmap, struct inode *dir,
317549c7297SChristian Brauner struct dentry *dentry, const char *symname)
3181da177e4SLinus Torvalds {
3191da177e4SLinus Torvalds struct super_block *sb = dir->i_sb;
3201da177e4SLinus Torvalds struct buffer_head *bh;
3211da177e4SLinus Torvalds struct inode *inode;
3221da177e4SLinus Torvalds char *p;
3231da177e4SLinus Torvalds int i, maxlen, error;
3241da177e4SLinus Torvalds char c, lc;
3251da177e4SLinus Torvalds
326a455589fSAl Viro pr_debug("%s(%lu,\"%pd\" -> \"%s\")\n",
327a455589fSAl Viro __func__, dir->i_ino, dentry, symname);
3281da177e4SLinus Torvalds
3291da177e4SLinus Torvalds maxlen = AFFS_SB(sb)->s_hashsize * sizeof(u32) - 1;
3301da177e4SLinus Torvalds inode = affs_new_inode(dir);
3311da177e4SLinus Torvalds if (!inode)
3321da177e4SLinus Torvalds return -ENOSPC;
3331da177e4SLinus Torvalds
3341da177e4SLinus Torvalds inode->i_op = &affs_symlink_inode_operations;
33521fc61c7SAl Viro inode_nohighmem(inode);
3361da177e4SLinus Torvalds inode->i_data.a_ops = &affs_symlink_aops;
3371da177e4SLinus Torvalds inode->i_mode = S_IFLNK | 0777;
338c1618208SFabian Frederick affs_mode_to_prot(inode);
3391da177e4SLinus Torvalds
3401da177e4SLinus Torvalds error = -EIO;
3411da177e4SLinus Torvalds bh = affs_bread(sb, inode->i_ino);
3421da177e4SLinus Torvalds if (!bh)
3431da177e4SLinus Torvalds goto err;
3441da177e4SLinus Torvalds i = 0;
3451da177e4SLinus Torvalds p = (char *)AFFS_HEAD(bh)->table;
3461da177e4SLinus Torvalds lc = '/';
3471da177e4SLinus Torvalds if (*symname == '/') {
34829333920SAl Viro struct affs_sb_info *sbi = AFFS_SB(sb);
3491da177e4SLinus Torvalds while (*symname == '/')
3501da177e4SLinus Torvalds symname++;
35129333920SAl Viro spin_lock(&sbi->symlink_lock);
35229333920SAl Viro while (sbi->s_volume[i]) /* Cannot overflow */
35329333920SAl Viro *p++ = sbi->s_volume[i++];
35429333920SAl Viro spin_unlock(&sbi->symlink_lock);
3551da177e4SLinus Torvalds }
3561da177e4SLinus Torvalds while (i < maxlen && (c = *symname++)) {
3571da177e4SLinus Torvalds if (c == '.' && lc == '/' && *symname == '.' && symname[1] == '/') {
3581da177e4SLinus Torvalds *p++ = '/';
3591da177e4SLinus Torvalds i++;
3601da177e4SLinus Torvalds symname += 2;
3611da177e4SLinus Torvalds lc = '/';
3621da177e4SLinus Torvalds } else if (c == '.' && lc == '/' && *symname == '/') {
3631da177e4SLinus Torvalds symname++;
3641da177e4SLinus Torvalds lc = '/';
3651da177e4SLinus Torvalds } else {
3661da177e4SLinus Torvalds *p++ = c;
3671da177e4SLinus Torvalds lc = c;
3681da177e4SLinus Torvalds i++;
3691da177e4SLinus Torvalds }
3701da177e4SLinus Torvalds if (lc == '/')
3711da177e4SLinus Torvalds while (*symname == '/')
3721da177e4SLinus Torvalds symname++;
3731da177e4SLinus Torvalds }
3741da177e4SLinus Torvalds *p = 0;
375f1bf9072SFabian Frederick inode->i_size = i + 1;
3761da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode);
3771da177e4SLinus Torvalds affs_brelse(bh);
3781da177e4SLinus Torvalds mark_inode_dirty(inode);
3791da177e4SLinus Torvalds
3801da177e4SLinus Torvalds error = affs_add_entry(dir, inode, dentry, ST_SOFTLINK);
3811da177e4SLinus Torvalds if (error)
3821da177e4SLinus Torvalds goto err;
3831da177e4SLinus Torvalds
3841da177e4SLinus Torvalds return 0;
3851da177e4SLinus Torvalds
3861da177e4SLinus Torvalds err:
3876d6b77f1SMiklos Szeredi clear_nlink(inode);
3881da177e4SLinus Torvalds mark_inode_dirty(inode);
3891da177e4SLinus Torvalds iput(inode);
3901da177e4SLinus Torvalds return error;
3911da177e4SLinus Torvalds }
3921da177e4SLinus Torvalds
3931da177e4SLinus Torvalds int
affs_link(struct dentry * old_dentry,struct inode * dir,struct dentry * dentry)3941da177e4SLinus Torvalds affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
3951da177e4SLinus Torvalds {
3962b0143b5SDavid Howells struct inode *inode = d_inode(old_dentry);
3971da177e4SLinus Torvalds
39808fe100dSGeert Uytterhoeven pr_debug("%s(%lu, %lu, \"%pd\")\n", __func__, inode->i_ino, dir->i_ino,
399a455589fSAl Viro dentry);
4001da177e4SLinus Torvalds
4011da177e4SLinus Torvalds return affs_add_entry(dir, inode, dentry, ST_LINKFILE);
4021da177e4SLinus Torvalds }
4031da177e4SLinus Torvalds
404c6184028SFabian Frederick static int
affs_rename(struct inode * old_dir,struct dentry * old_dentry,struct inode * new_dir,struct dentry * new_dentry)4051da177e4SLinus Torvalds affs_rename(struct inode *old_dir, struct dentry *old_dentry,
406c6184028SFabian Frederick struct inode *new_dir, struct dentry *new_dentry)
4071da177e4SLinus Torvalds {
4081da177e4SLinus Torvalds struct super_block *sb = old_dir->i_sb;
4091da177e4SLinus Torvalds struct buffer_head *bh = NULL;
4101da177e4SLinus Torvalds int retval;
4111da177e4SLinus Torvalds
4128ca57722SFabian Frederick retval = affs_check_name(new_dentry->d_name.name,
4138ca57722SFabian Frederick new_dentry->d_name.len,
4148ca57722SFabian Frederick affs_nofilenametruncate(old_dentry));
4158ca57722SFabian Frederick
4161da177e4SLinus Torvalds if (retval)
4171da177e4SLinus Torvalds return retval;
4181da177e4SLinus Torvalds
4191da177e4SLinus Torvalds /* Unlink destination if it already exists */
4202b0143b5SDavid Howells if (d_really_is_positive(new_dentry)) {
4211da177e4SLinus Torvalds retval = affs_remove_header(new_dentry);
4221da177e4SLinus Torvalds if (retval)
4231da177e4SLinus Torvalds return retval;
4241da177e4SLinus Torvalds }
4251da177e4SLinus Torvalds
4262b0143b5SDavid Howells bh = affs_bread(sb, d_inode(old_dentry)->i_ino);
4271da177e4SLinus Torvalds if (!bh)
4283ac81413SFlorin Malita return -EIO;
4291da177e4SLinus Torvalds
4301da177e4SLinus Torvalds /* Remove header from its parent directory. */
4311da177e4SLinus Torvalds affs_lock_dir(old_dir);
4321da177e4SLinus Torvalds retval = affs_remove_hash(old_dir, bh);
4331da177e4SLinus Torvalds affs_unlock_dir(old_dir);
4341da177e4SLinus Torvalds if (retval)
4351da177e4SLinus Torvalds goto done;
4361da177e4SLinus Torvalds
4371da177e4SLinus Torvalds /* And insert it into the new directory with the new name. */
4381da177e4SLinus Torvalds affs_copy_name(AFFS_TAIL(sb, bh)->name, new_dentry);
4391da177e4SLinus Torvalds affs_fix_checksum(sb, bh);
4401da177e4SLinus Torvalds affs_lock_dir(new_dir);
4411da177e4SLinus Torvalds retval = affs_insert_hash(new_dir, bh);
4421da177e4SLinus Torvalds affs_unlock_dir(new_dir);
4431da177e4SLinus Torvalds /* TODO: move it back to old_dir, if error? */
4441da177e4SLinus Torvalds
4451da177e4SLinus Torvalds done:
4461da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, retval ? old_dir : new_dir);
4471da177e4SLinus Torvalds affs_brelse(bh);
4481da177e4SLinus Torvalds return retval;
4491da177e4SLinus Torvalds }
450ed4433d7SFabian Frederick
4516b465766SFabian Frederick static int
affs_xrename(struct inode * old_dir,struct dentry * old_dentry,struct inode * new_dir,struct dentry * new_dentry)4526b465766SFabian Frederick affs_xrename(struct inode *old_dir, struct dentry *old_dentry,
4536b465766SFabian Frederick struct inode *new_dir, struct dentry *new_dentry)
4546b465766SFabian Frederick {
4556b465766SFabian Frederick
4566b465766SFabian Frederick struct super_block *sb = old_dir->i_sb;
4576b465766SFabian Frederick struct buffer_head *bh_old = NULL;
4586b465766SFabian Frederick struct buffer_head *bh_new = NULL;
4596b465766SFabian Frederick int retval;
4606b465766SFabian Frederick
4616b465766SFabian Frederick bh_old = affs_bread(sb, d_inode(old_dentry)->i_ino);
4626b465766SFabian Frederick if (!bh_old)
4636b465766SFabian Frederick return -EIO;
4646b465766SFabian Frederick
4656b465766SFabian Frederick bh_new = affs_bread(sb, d_inode(new_dentry)->i_ino);
46670779b89SPan Bian if (!bh_new) {
46770779b89SPan Bian affs_brelse(bh_old);
4686b465766SFabian Frederick return -EIO;
46970779b89SPan Bian }
4706b465766SFabian Frederick
4716b465766SFabian Frederick /* Remove old header from its parent directory. */
4726b465766SFabian Frederick affs_lock_dir(old_dir);
4736b465766SFabian Frederick retval = affs_remove_hash(old_dir, bh_old);
4746b465766SFabian Frederick affs_unlock_dir(old_dir);
4756b465766SFabian Frederick if (retval)
4766b465766SFabian Frederick goto done;
4776b465766SFabian Frederick
4786b465766SFabian Frederick /* Remove new header from its parent directory. */
4796b465766SFabian Frederick affs_lock_dir(new_dir);
4806b465766SFabian Frederick retval = affs_remove_hash(new_dir, bh_new);
4816b465766SFabian Frederick affs_unlock_dir(new_dir);
4826b465766SFabian Frederick if (retval)
4836b465766SFabian Frederick goto done;
4846b465766SFabian Frederick
4856b465766SFabian Frederick /* Insert old into the new directory with the new name. */
4866b465766SFabian Frederick affs_copy_name(AFFS_TAIL(sb, bh_old)->name, new_dentry);
4876b465766SFabian Frederick affs_fix_checksum(sb, bh_old);
4886b465766SFabian Frederick affs_lock_dir(new_dir);
4896b465766SFabian Frederick retval = affs_insert_hash(new_dir, bh_old);
4906b465766SFabian Frederick affs_unlock_dir(new_dir);
4916b465766SFabian Frederick
4926b465766SFabian Frederick /* Insert new into the old directory with the old name. */
4936b465766SFabian Frederick affs_copy_name(AFFS_TAIL(sb, bh_new)->name, old_dentry);
4946b465766SFabian Frederick affs_fix_checksum(sb, bh_new);
4956b465766SFabian Frederick affs_lock_dir(old_dir);
4966b465766SFabian Frederick retval = affs_insert_hash(old_dir, bh_new);
4976b465766SFabian Frederick affs_unlock_dir(old_dir);
4986b465766SFabian Frederick done:
4996b465766SFabian Frederick mark_buffer_dirty_inode(bh_old, new_dir);
5006b465766SFabian Frederick mark_buffer_dirty_inode(bh_new, old_dir);
5016b465766SFabian Frederick affs_brelse(bh_old);
5026b465766SFabian Frederick affs_brelse(bh_new);
5036b465766SFabian Frederick return retval;
5046b465766SFabian Frederick }
5056b465766SFabian Frederick
affs_rename2(struct mnt_idmap * idmap,struct inode * old_dir,struct dentry * old_dentry,struct inode * new_dir,struct dentry * new_dentry,unsigned int flags)506e18275aeSChristian Brauner int affs_rename2(struct mnt_idmap *idmap, struct inode *old_dir,
507549c7297SChristian Brauner struct dentry *old_dentry, struct inode *new_dir,
508549c7297SChristian Brauner struct dentry *new_dentry, unsigned int flags)
509c6184028SFabian Frederick {
510c6184028SFabian Frederick
5116b465766SFabian Frederick if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
512c6184028SFabian Frederick return -EINVAL;
513c6184028SFabian Frederick
514c6184028SFabian Frederick pr_debug("%s(old=%lu,\"%pd\" to new=%lu,\"%pd\")\n", __func__,
515c6184028SFabian Frederick old_dir->i_ino, old_dentry, new_dir->i_ino, new_dentry);
516c6184028SFabian Frederick
5176b465766SFabian Frederick if (flags & RENAME_EXCHANGE)
5186b465766SFabian Frederick return affs_xrename(old_dir, old_dentry, new_dir, new_dentry);
5196b465766SFabian Frederick
520c6184028SFabian Frederick return affs_rename(old_dir, old_dentry, new_dir, new_dentry);
521c6184028SFabian Frederick }
522c6184028SFabian Frederick
affs_get_parent(struct dentry * child)523b3b42c0dSFabian Frederick static struct dentry *affs_get_parent(struct dentry *child)
524b3b42c0dSFabian Frederick {
525b3b42c0dSFabian Frederick struct inode *parent;
526b3b42c0dSFabian Frederick struct buffer_head *bh;
527b3b42c0dSFabian Frederick
528b3b42c0dSFabian Frederick bh = affs_bread(child->d_sb, d_inode(child)->i_ino);
529b3b42c0dSFabian Frederick if (!bh)
530b3b42c0dSFabian Frederick return ERR_PTR(-EIO);
531b3b42c0dSFabian Frederick
532b3b42c0dSFabian Frederick parent = affs_iget(child->d_sb,
533b3b42c0dSFabian Frederick be32_to_cpu(AFFS_TAIL(child->d_sb, bh)->parent));
534b3b42c0dSFabian Frederick brelse(bh);
535b3b42c0dSFabian Frederick if (IS_ERR(parent))
536b3b42c0dSFabian Frederick return ERR_CAST(parent);
537b3b42c0dSFabian Frederick
538b3b42c0dSFabian Frederick return d_obtain_alias(parent);
539b3b42c0dSFabian Frederick }
540b3b42c0dSFabian Frederick
affs_nfs_get_inode(struct super_block * sb,u64 ino,u32 generation)541ed4433d7SFabian Frederick static struct inode *affs_nfs_get_inode(struct super_block *sb, u64 ino,
542ed4433d7SFabian Frederick u32 generation)
543ed4433d7SFabian Frederick {
544ed4433d7SFabian Frederick struct inode *inode;
545ed4433d7SFabian Frederick
546ed4433d7SFabian Frederick if (!affs_validblock(sb, ino))
547ed4433d7SFabian Frederick return ERR_PTR(-ESTALE);
548ed4433d7SFabian Frederick
549ed4433d7SFabian Frederick inode = affs_iget(sb, ino);
550ed4433d7SFabian Frederick if (IS_ERR(inode))
551ed4433d7SFabian Frederick return ERR_CAST(inode);
552ed4433d7SFabian Frederick
553ed4433d7SFabian Frederick return inode;
554ed4433d7SFabian Frederick }
555ed4433d7SFabian Frederick
affs_fh_to_dentry(struct super_block * sb,struct fid * fid,int fh_len,int fh_type)556ed4433d7SFabian Frederick static struct dentry *affs_fh_to_dentry(struct super_block *sb, struct fid *fid,
557ed4433d7SFabian Frederick int fh_len, int fh_type)
558ed4433d7SFabian Frederick {
559ed4433d7SFabian Frederick return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
560ed4433d7SFabian Frederick affs_nfs_get_inode);
561ed4433d7SFabian Frederick }
562ed4433d7SFabian Frederick
affs_fh_to_parent(struct super_block * sb,struct fid * fid,int fh_len,int fh_type)563ed4433d7SFabian Frederick static struct dentry *affs_fh_to_parent(struct super_block *sb, struct fid *fid,
564ed4433d7SFabian Frederick int fh_len, int fh_type)
565ed4433d7SFabian Frederick {
566ed4433d7SFabian Frederick return generic_fh_to_parent(sb, fid, fh_len, fh_type,
567ed4433d7SFabian Frederick affs_nfs_get_inode);
568ed4433d7SFabian Frederick }
569ed4433d7SFabian Frederick
570ed4433d7SFabian Frederick const struct export_operations affs_export_ops = {
571ed4433d7SFabian Frederick .fh_to_dentry = affs_fh_to_dentry,
572ed4433d7SFabian Frederick .fh_to_parent = affs_fh_to_parent,
573b3b42c0dSFabian Frederick .get_parent = affs_get_parent,
574ed4433d7SFabian Frederick };
575f567accbSFabian Frederick
576f567accbSFabian Frederick const struct dentry_operations affs_dentry_operations = {
577f567accbSFabian Frederick .d_hash = affs_hash_dentry,
578f567accbSFabian Frederick .d_compare = affs_compare_dentry,
579f567accbSFabian Frederick };
580f567accbSFabian Frederick
581f567accbSFabian Frederick const struct dentry_operations affs_intl_dentry_operations = {
582f567accbSFabian Frederick .d_hash = affs_intl_hash_dentry,
583f567accbSFabian Frederick .d_compare = affs_intl_compare_dentry,
584f567accbSFabian Frederick };
585