162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/affs/namei.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * (c) 1996 Hans-Joachim Widmaier - Rewritten 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * (C) 1991 Linus Torvalds - minix filesystem 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "affs.h" 1362306a36Sopenharmony_ci#include <linux/exportfs.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_citypedef int (*toupper_t)(int); 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* Simple toupper() for DOS\1 */ 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic int 2062306a36Sopenharmony_ciaffs_toupper(int ch) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch; 2362306a36Sopenharmony_ci} 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* International toupper() for DOS\3 ("international") */ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic int 2862306a36Sopenharmony_ciaffs_intl_toupper(int ch) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci return (ch >= 'a' && ch <= 'z') || (ch >= 0xE0 3162306a36Sopenharmony_ci && ch <= 0xFE && ch != 0xF7) ? 3262306a36Sopenharmony_ci ch - ('a' - 'A') : ch; 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic inline toupper_t 3662306a36Sopenharmony_ciaffs_get_toupper(struct super_block *sb) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci return affs_test_opt(AFFS_SB(sb)->s_flags, SF_INTL) ? 3962306a36Sopenharmony_ci affs_intl_toupper : affs_toupper; 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* 4362306a36Sopenharmony_ci * Note: the dentry argument is the parent dentry. 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_cistatic inline int 4662306a36Sopenharmony_ci__affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr, toupper_t fn, bool notruncate) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci const u8 *name = qstr->name; 4962306a36Sopenharmony_ci unsigned long hash; 5062306a36Sopenharmony_ci int retval; 5162306a36Sopenharmony_ci u32 len; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci retval = affs_check_name(qstr->name, qstr->len, notruncate); 5462306a36Sopenharmony_ci if (retval) 5562306a36Sopenharmony_ci return retval; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci hash = init_name_hash(dentry); 5862306a36Sopenharmony_ci len = min(qstr->len, AFFSNAMEMAX); 5962306a36Sopenharmony_ci for (; len > 0; name++, len--) 6062306a36Sopenharmony_ci hash = partial_name_hash(fn(*name), hash); 6162306a36Sopenharmony_ci qstr->hash = end_name_hash(hash); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci return 0; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic int 6762306a36Sopenharmony_ciaffs_hash_dentry(const struct dentry *dentry, struct qstr *qstr) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci return __affs_hash_dentry(dentry, qstr, affs_toupper, 7062306a36Sopenharmony_ci affs_nofilenametruncate(dentry)); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic int 7562306a36Sopenharmony_ciaffs_intl_hash_dentry(const struct dentry *dentry, struct qstr *qstr) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci return __affs_hash_dentry(dentry, qstr, affs_intl_toupper, 7862306a36Sopenharmony_ci affs_nofilenametruncate(dentry)); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic inline int __affs_compare_dentry(unsigned int len, 8362306a36Sopenharmony_ci const char *str, const struct qstr *name, toupper_t fn, 8462306a36Sopenharmony_ci bool notruncate) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci const u8 *aname = str; 8762306a36Sopenharmony_ci const u8 *bname = name->name; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci /* 9062306a36Sopenharmony_ci * 'str' is the name of an already existing dentry, so the name 9162306a36Sopenharmony_ci * must be valid. 'name' must be validated first. 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci if (affs_check_name(name->name, name->len, notruncate)) 9562306a36Sopenharmony_ci return 1; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci /* 9862306a36Sopenharmony_ci * If the names are longer than the allowed 30 chars, 9962306a36Sopenharmony_ci * the excess is ignored, so their length may differ. 10062306a36Sopenharmony_ci */ 10162306a36Sopenharmony_ci if (len >= AFFSNAMEMAX) { 10262306a36Sopenharmony_ci if (name->len < AFFSNAMEMAX) 10362306a36Sopenharmony_ci return 1; 10462306a36Sopenharmony_ci len = AFFSNAMEMAX; 10562306a36Sopenharmony_ci } else if (len != name->len) 10662306a36Sopenharmony_ci return 1; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci for (; len > 0; len--) 10962306a36Sopenharmony_ci if (fn(*aname++) != fn(*bname++)) 11062306a36Sopenharmony_ci return 1; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci return 0; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic int 11662306a36Sopenharmony_ciaffs_compare_dentry(const struct dentry *dentry, 11762306a36Sopenharmony_ci unsigned int len, const char *str, const struct qstr *name) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci return __affs_compare_dentry(len, str, name, affs_toupper, 12162306a36Sopenharmony_ci affs_nofilenametruncate(dentry)); 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic int 12562306a36Sopenharmony_ciaffs_intl_compare_dentry(const struct dentry *dentry, 12662306a36Sopenharmony_ci unsigned int len, const char *str, const struct qstr *name) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci return __affs_compare_dentry(len, str, name, affs_intl_toupper, 12962306a36Sopenharmony_ci affs_nofilenametruncate(dentry)); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/* 13462306a36Sopenharmony_ci * NOTE! unlike strncmp, affs_match returns 1 for success, 0 for failure. 13562306a36Sopenharmony_ci */ 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic inline int 13862306a36Sopenharmony_ciaffs_match(struct dentry *dentry, const u8 *name2, toupper_t fn) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci const u8 *name = dentry->d_name.name; 14162306a36Sopenharmony_ci int len = dentry->d_name.len; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (len >= AFFSNAMEMAX) { 14462306a36Sopenharmony_ci if (*name2 < AFFSNAMEMAX) 14562306a36Sopenharmony_ci return 0; 14662306a36Sopenharmony_ci len = AFFSNAMEMAX; 14762306a36Sopenharmony_ci } else if (len != *name2) 14862306a36Sopenharmony_ci return 0; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci for (name2++; len > 0; len--) 15162306a36Sopenharmony_ci if (fn(*name++) != fn(*name2++)) 15262306a36Sopenharmony_ci return 0; 15362306a36Sopenharmony_ci return 1; 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ciint 15762306a36Sopenharmony_ciaffs_hash_name(struct super_block *sb, const u8 *name, unsigned int len) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci toupper_t fn = affs_get_toupper(sb); 16062306a36Sopenharmony_ci u32 hash; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci hash = len = min(len, AFFSNAMEMAX); 16362306a36Sopenharmony_ci for (; len > 0; len--) 16462306a36Sopenharmony_ci hash = (hash * 13 + fn(*name++)) & 0x7ff; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci return hash % AFFS_SB(sb)->s_hashsize; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic struct buffer_head * 17062306a36Sopenharmony_ciaffs_find_entry(struct inode *dir, struct dentry *dentry) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci struct super_block *sb = dir->i_sb; 17362306a36Sopenharmony_ci struct buffer_head *bh; 17462306a36Sopenharmony_ci toupper_t fn = affs_get_toupper(sb); 17562306a36Sopenharmony_ci u32 key; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci pr_debug("%s(\"%pd\")\n", __func__, dentry); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci bh = affs_bread(sb, dir->i_ino); 18062306a36Sopenharmony_ci if (!bh) 18162306a36Sopenharmony_ci return ERR_PTR(-EIO); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci key = be32_to_cpu(AFFS_HEAD(bh)->table[affs_hash_name(sb, dentry->d_name.name, dentry->d_name.len)]); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci for (;;) { 18662306a36Sopenharmony_ci affs_brelse(bh); 18762306a36Sopenharmony_ci if (key == 0) 18862306a36Sopenharmony_ci return NULL; 18962306a36Sopenharmony_ci bh = affs_bread(sb, key); 19062306a36Sopenharmony_ci if (!bh) 19162306a36Sopenharmony_ci return ERR_PTR(-EIO); 19262306a36Sopenharmony_ci if (affs_match(dentry, AFFS_TAIL(sb, bh)->name, fn)) 19362306a36Sopenharmony_ci return bh; 19462306a36Sopenharmony_ci key = be32_to_cpu(AFFS_TAIL(sb, bh)->hash_chain); 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistruct dentry * 19962306a36Sopenharmony_ciaffs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci struct super_block *sb = dir->i_sb; 20262306a36Sopenharmony_ci struct buffer_head *bh; 20362306a36Sopenharmony_ci struct inode *inode = NULL; 20462306a36Sopenharmony_ci struct dentry *res; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci pr_debug("%s(\"%pd\")\n", __func__, dentry); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci affs_lock_dir(dir); 20962306a36Sopenharmony_ci bh = affs_find_entry(dir, dentry); 21062306a36Sopenharmony_ci if (IS_ERR(bh)) { 21162306a36Sopenharmony_ci affs_unlock_dir(dir); 21262306a36Sopenharmony_ci return ERR_CAST(bh); 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci if (bh) { 21562306a36Sopenharmony_ci u32 ino = bh->b_blocknr; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci /* store the real header ino in d_fsdata for faster lookups */ 21862306a36Sopenharmony_ci dentry->d_fsdata = (void *)(long)ino; 21962306a36Sopenharmony_ci switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) { 22062306a36Sopenharmony_ci //link to dirs disabled 22162306a36Sopenharmony_ci //case ST_LINKDIR: 22262306a36Sopenharmony_ci case ST_LINKFILE: 22362306a36Sopenharmony_ci ino = be32_to_cpu(AFFS_TAIL(sb, bh)->original); 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci affs_brelse(bh); 22662306a36Sopenharmony_ci inode = affs_iget(sb, ino); 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci res = d_splice_alias(inode, dentry); 22962306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(res)) 23062306a36Sopenharmony_ci res->d_fsdata = dentry->d_fsdata; 23162306a36Sopenharmony_ci affs_unlock_dir(dir); 23262306a36Sopenharmony_ci return res; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ciint 23662306a36Sopenharmony_ciaffs_unlink(struct inode *dir, struct dentry *dentry) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci pr_debug("%s(dir=%lu, %lu \"%pd\")\n", __func__, dir->i_ino, 23962306a36Sopenharmony_ci d_inode(dentry)->i_ino, dentry); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci return affs_remove_header(dentry); 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ciint 24562306a36Sopenharmony_ciaffs_create(struct mnt_idmap *idmap, struct inode *dir, 24662306a36Sopenharmony_ci struct dentry *dentry, umode_t mode, bool excl) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci struct super_block *sb = dir->i_sb; 24962306a36Sopenharmony_ci struct inode *inode; 25062306a36Sopenharmony_ci int error; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci pr_debug("%s(%lu,\"%pd\",0%ho)\n", 25362306a36Sopenharmony_ci __func__, dir->i_ino, dentry, mode); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci inode = affs_new_inode(dir); 25662306a36Sopenharmony_ci if (!inode) 25762306a36Sopenharmony_ci return -ENOSPC; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci inode->i_mode = mode; 26062306a36Sopenharmony_ci affs_mode_to_prot(inode); 26162306a36Sopenharmony_ci mark_inode_dirty(inode); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci inode->i_op = &affs_file_inode_operations; 26462306a36Sopenharmony_ci inode->i_fop = &affs_file_operations; 26562306a36Sopenharmony_ci inode->i_mapping->a_ops = affs_test_opt(AFFS_SB(sb)->s_flags, SF_OFS) ? 26662306a36Sopenharmony_ci &affs_aops_ofs : &affs_aops; 26762306a36Sopenharmony_ci error = affs_add_entry(dir, inode, dentry, ST_FILE); 26862306a36Sopenharmony_ci if (error) { 26962306a36Sopenharmony_ci clear_nlink(inode); 27062306a36Sopenharmony_ci iput(inode); 27162306a36Sopenharmony_ci return error; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci return 0; 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ciint 27762306a36Sopenharmony_ciaffs_mkdir(struct mnt_idmap *idmap, struct inode *dir, 27862306a36Sopenharmony_ci struct dentry *dentry, umode_t mode) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci struct inode *inode; 28162306a36Sopenharmony_ci int error; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci pr_debug("%s(%lu,\"%pd\",0%ho)\n", 28462306a36Sopenharmony_ci __func__, dir->i_ino, dentry, mode); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci inode = affs_new_inode(dir); 28762306a36Sopenharmony_ci if (!inode) 28862306a36Sopenharmony_ci return -ENOSPC; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci inode->i_mode = S_IFDIR | mode; 29162306a36Sopenharmony_ci affs_mode_to_prot(inode); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci inode->i_op = &affs_dir_inode_operations; 29462306a36Sopenharmony_ci inode->i_fop = &affs_dir_operations; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci error = affs_add_entry(dir, inode, dentry, ST_USERDIR); 29762306a36Sopenharmony_ci if (error) { 29862306a36Sopenharmony_ci clear_nlink(inode); 29962306a36Sopenharmony_ci mark_inode_dirty(inode); 30062306a36Sopenharmony_ci iput(inode); 30162306a36Sopenharmony_ci return error; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci return 0; 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ciint 30762306a36Sopenharmony_ciaffs_rmdir(struct inode *dir, struct dentry *dentry) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci pr_debug("%s(dir=%lu, %lu \"%pd\")\n", __func__, dir->i_ino, 31062306a36Sopenharmony_ci d_inode(dentry)->i_ino, dentry); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci return affs_remove_header(dentry); 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ciint 31662306a36Sopenharmony_ciaffs_symlink(struct mnt_idmap *idmap, struct inode *dir, 31762306a36Sopenharmony_ci struct dentry *dentry, const char *symname) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci struct super_block *sb = dir->i_sb; 32062306a36Sopenharmony_ci struct buffer_head *bh; 32162306a36Sopenharmony_ci struct inode *inode; 32262306a36Sopenharmony_ci char *p; 32362306a36Sopenharmony_ci int i, maxlen, error; 32462306a36Sopenharmony_ci char c, lc; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci pr_debug("%s(%lu,\"%pd\" -> \"%s\")\n", 32762306a36Sopenharmony_ci __func__, dir->i_ino, dentry, symname); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci maxlen = AFFS_SB(sb)->s_hashsize * sizeof(u32) - 1; 33062306a36Sopenharmony_ci inode = affs_new_inode(dir); 33162306a36Sopenharmony_ci if (!inode) 33262306a36Sopenharmony_ci return -ENOSPC; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci inode->i_op = &affs_symlink_inode_operations; 33562306a36Sopenharmony_ci inode_nohighmem(inode); 33662306a36Sopenharmony_ci inode->i_data.a_ops = &affs_symlink_aops; 33762306a36Sopenharmony_ci inode->i_mode = S_IFLNK | 0777; 33862306a36Sopenharmony_ci affs_mode_to_prot(inode); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci error = -EIO; 34162306a36Sopenharmony_ci bh = affs_bread(sb, inode->i_ino); 34262306a36Sopenharmony_ci if (!bh) 34362306a36Sopenharmony_ci goto err; 34462306a36Sopenharmony_ci i = 0; 34562306a36Sopenharmony_ci p = (char *)AFFS_HEAD(bh)->table; 34662306a36Sopenharmony_ci lc = '/'; 34762306a36Sopenharmony_ci if (*symname == '/') { 34862306a36Sopenharmony_ci struct affs_sb_info *sbi = AFFS_SB(sb); 34962306a36Sopenharmony_ci while (*symname == '/') 35062306a36Sopenharmony_ci symname++; 35162306a36Sopenharmony_ci spin_lock(&sbi->symlink_lock); 35262306a36Sopenharmony_ci while (sbi->s_volume[i]) /* Cannot overflow */ 35362306a36Sopenharmony_ci *p++ = sbi->s_volume[i++]; 35462306a36Sopenharmony_ci spin_unlock(&sbi->symlink_lock); 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci while (i < maxlen && (c = *symname++)) { 35762306a36Sopenharmony_ci if (c == '.' && lc == '/' && *symname == '.' && symname[1] == '/') { 35862306a36Sopenharmony_ci *p++ = '/'; 35962306a36Sopenharmony_ci i++; 36062306a36Sopenharmony_ci symname += 2; 36162306a36Sopenharmony_ci lc = '/'; 36262306a36Sopenharmony_ci } else if (c == '.' && lc == '/' && *symname == '/') { 36362306a36Sopenharmony_ci symname++; 36462306a36Sopenharmony_ci lc = '/'; 36562306a36Sopenharmony_ci } else { 36662306a36Sopenharmony_ci *p++ = c; 36762306a36Sopenharmony_ci lc = c; 36862306a36Sopenharmony_ci i++; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci if (lc == '/') 37162306a36Sopenharmony_ci while (*symname == '/') 37262306a36Sopenharmony_ci symname++; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci *p = 0; 37562306a36Sopenharmony_ci inode->i_size = i + 1; 37662306a36Sopenharmony_ci mark_buffer_dirty_inode(bh, inode); 37762306a36Sopenharmony_ci affs_brelse(bh); 37862306a36Sopenharmony_ci mark_inode_dirty(inode); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci error = affs_add_entry(dir, inode, dentry, ST_SOFTLINK); 38162306a36Sopenharmony_ci if (error) 38262306a36Sopenharmony_ci goto err; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci return 0; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_cierr: 38762306a36Sopenharmony_ci clear_nlink(inode); 38862306a36Sopenharmony_ci mark_inode_dirty(inode); 38962306a36Sopenharmony_ci iput(inode); 39062306a36Sopenharmony_ci return error; 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ciint 39462306a36Sopenharmony_ciaffs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci struct inode *inode = d_inode(old_dentry); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci pr_debug("%s(%lu, %lu, \"%pd\")\n", __func__, inode->i_ino, dir->i_ino, 39962306a36Sopenharmony_ci dentry); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci return affs_add_entry(dir, inode, dentry, ST_LINKFILE); 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic int 40562306a36Sopenharmony_ciaffs_rename(struct inode *old_dir, struct dentry *old_dentry, 40662306a36Sopenharmony_ci struct inode *new_dir, struct dentry *new_dentry) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci struct super_block *sb = old_dir->i_sb; 40962306a36Sopenharmony_ci struct buffer_head *bh = NULL; 41062306a36Sopenharmony_ci int retval; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci retval = affs_check_name(new_dentry->d_name.name, 41362306a36Sopenharmony_ci new_dentry->d_name.len, 41462306a36Sopenharmony_ci affs_nofilenametruncate(old_dentry)); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci if (retval) 41762306a36Sopenharmony_ci return retval; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci /* Unlink destination if it already exists */ 42062306a36Sopenharmony_ci if (d_really_is_positive(new_dentry)) { 42162306a36Sopenharmony_ci retval = affs_remove_header(new_dentry); 42262306a36Sopenharmony_ci if (retval) 42362306a36Sopenharmony_ci return retval; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci bh = affs_bread(sb, d_inode(old_dentry)->i_ino); 42762306a36Sopenharmony_ci if (!bh) 42862306a36Sopenharmony_ci return -EIO; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci /* Remove header from its parent directory. */ 43162306a36Sopenharmony_ci affs_lock_dir(old_dir); 43262306a36Sopenharmony_ci retval = affs_remove_hash(old_dir, bh); 43362306a36Sopenharmony_ci affs_unlock_dir(old_dir); 43462306a36Sopenharmony_ci if (retval) 43562306a36Sopenharmony_ci goto done; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci /* And insert it into the new directory with the new name. */ 43862306a36Sopenharmony_ci affs_copy_name(AFFS_TAIL(sb, bh)->name, new_dentry); 43962306a36Sopenharmony_ci affs_fix_checksum(sb, bh); 44062306a36Sopenharmony_ci affs_lock_dir(new_dir); 44162306a36Sopenharmony_ci retval = affs_insert_hash(new_dir, bh); 44262306a36Sopenharmony_ci affs_unlock_dir(new_dir); 44362306a36Sopenharmony_ci /* TODO: move it back to old_dir, if error? */ 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cidone: 44662306a36Sopenharmony_ci mark_buffer_dirty_inode(bh, retval ? old_dir : new_dir); 44762306a36Sopenharmony_ci affs_brelse(bh); 44862306a36Sopenharmony_ci return retval; 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic int 45262306a36Sopenharmony_ciaffs_xrename(struct inode *old_dir, struct dentry *old_dentry, 45362306a36Sopenharmony_ci struct inode *new_dir, struct dentry *new_dentry) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci struct super_block *sb = old_dir->i_sb; 45762306a36Sopenharmony_ci struct buffer_head *bh_old = NULL; 45862306a36Sopenharmony_ci struct buffer_head *bh_new = NULL; 45962306a36Sopenharmony_ci int retval; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci bh_old = affs_bread(sb, d_inode(old_dentry)->i_ino); 46262306a36Sopenharmony_ci if (!bh_old) 46362306a36Sopenharmony_ci return -EIO; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci bh_new = affs_bread(sb, d_inode(new_dentry)->i_ino); 46662306a36Sopenharmony_ci if (!bh_new) { 46762306a36Sopenharmony_ci affs_brelse(bh_old); 46862306a36Sopenharmony_ci return -EIO; 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci /* Remove old header from its parent directory. */ 47262306a36Sopenharmony_ci affs_lock_dir(old_dir); 47362306a36Sopenharmony_ci retval = affs_remove_hash(old_dir, bh_old); 47462306a36Sopenharmony_ci affs_unlock_dir(old_dir); 47562306a36Sopenharmony_ci if (retval) 47662306a36Sopenharmony_ci goto done; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci /* Remove new header from its parent directory. */ 47962306a36Sopenharmony_ci affs_lock_dir(new_dir); 48062306a36Sopenharmony_ci retval = affs_remove_hash(new_dir, bh_new); 48162306a36Sopenharmony_ci affs_unlock_dir(new_dir); 48262306a36Sopenharmony_ci if (retval) 48362306a36Sopenharmony_ci goto done; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci /* Insert old into the new directory with the new name. */ 48662306a36Sopenharmony_ci affs_copy_name(AFFS_TAIL(sb, bh_old)->name, new_dentry); 48762306a36Sopenharmony_ci affs_fix_checksum(sb, bh_old); 48862306a36Sopenharmony_ci affs_lock_dir(new_dir); 48962306a36Sopenharmony_ci retval = affs_insert_hash(new_dir, bh_old); 49062306a36Sopenharmony_ci affs_unlock_dir(new_dir); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci /* Insert new into the old directory with the old name. */ 49362306a36Sopenharmony_ci affs_copy_name(AFFS_TAIL(sb, bh_new)->name, old_dentry); 49462306a36Sopenharmony_ci affs_fix_checksum(sb, bh_new); 49562306a36Sopenharmony_ci affs_lock_dir(old_dir); 49662306a36Sopenharmony_ci retval = affs_insert_hash(old_dir, bh_new); 49762306a36Sopenharmony_ci affs_unlock_dir(old_dir); 49862306a36Sopenharmony_cidone: 49962306a36Sopenharmony_ci mark_buffer_dirty_inode(bh_old, new_dir); 50062306a36Sopenharmony_ci mark_buffer_dirty_inode(bh_new, old_dir); 50162306a36Sopenharmony_ci affs_brelse(bh_old); 50262306a36Sopenharmony_ci affs_brelse(bh_new); 50362306a36Sopenharmony_ci return retval; 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ciint affs_rename2(struct mnt_idmap *idmap, struct inode *old_dir, 50762306a36Sopenharmony_ci struct dentry *old_dentry, struct inode *new_dir, 50862306a36Sopenharmony_ci struct dentry *new_dentry, unsigned int flags) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE)) 51262306a36Sopenharmony_ci return -EINVAL; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci pr_debug("%s(old=%lu,\"%pd\" to new=%lu,\"%pd\")\n", __func__, 51562306a36Sopenharmony_ci old_dir->i_ino, old_dentry, new_dir->i_ino, new_dentry); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci if (flags & RENAME_EXCHANGE) 51862306a36Sopenharmony_ci return affs_xrename(old_dir, old_dentry, new_dir, new_dentry); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci return affs_rename(old_dir, old_dentry, new_dir, new_dentry); 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic struct dentry *affs_get_parent(struct dentry *child) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci struct inode *parent; 52662306a36Sopenharmony_ci struct buffer_head *bh; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci bh = affs_bread(child->d_sb, d_inode(child)->i_ino); 52962306a36Sopenharmony_ci if (!bh) 53062306a36Sopenharmony_ci return ERR_PTR(-EIO); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci parent = affs_iget(child->d_sb, 53362306a36Sopenharmony_ci be32_to_cpu(AFFS_TAIL(child->d_sb, bh)->parent)); 53462306a36Sopenharmony_ci brelse(bh); 53562306a36Sopenharmony_ci if (IS_ERR(parent)) 53662306a36Sopenharmony_ci return ERR_CAST(parent); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci return d_obtain_alias(parent); 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cistatic struct inode *affs_nfs_get_inode(struct super_block *sb, u64 ino, 54262306a36Sopenharmony_ci u32 generation) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci struct inode *inode; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci if (!affs_validblock(sb, ino)) 54762306a36Sopenharmony_ci return ERR_PTR(-ESTALE); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci inode = affs_iget(sb, ino); 55062306a36Sopenharmony_ci if (IS_ERR(inode)) 55162306a36Sopenharmony_ci return ERR_CAST(inode); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci return inode; 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_cistatic struct dentry *affs_fh_to_dentry(struct super_block *sb, struct fid *fid, 55762306a36Sopenharmony_ci int fh_len, int fh_type) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci return generic_fh_to_dentry(sb, fid, fh_len, fh_type, 56062306a36Sopenharmony_ci affs_nfs_get_inode); 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_cistatic struct dentry *affs_fh_to_parent(struct super_block *sb, struct fid *fid, 56462306a36Sopenharmony_ci int fh_len, int fh_type) 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci return generic_fh_to_parent(sb, fid, fh_len, fh_type, 56762306a36Sopenharmony_ci affs_nfs_get_inode); 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ciconst struct export_operations affs_export_ops = { 57162306a36Sopenharmony_ci .fh_to_dentry = affs_fh_to_dentry, 57262306a36Sopenharmony_ci .fh_to_parent = affs_fh_to_parent, 57362306a36Sopenharmony_ci .get_parent = affs_get_parent, 57462306a36Sopenharmony_ci}; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ciconst struct dentry_operations affs_dentry_operations = { 57762306a36Sopenharmony_ci .d_hash = affs_hash_dentry, 57862306a36Sopenharmony_ci .d_compare = affs_compare_dentry, 57962306a36Sopenharmony_ci}; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ciconst struct dentry_operations affs_intl_dentry_operations = { 58262306a36Sopenharmony_ci .d_hash = affs_intl_hash_dentry, 58362306a36Sopenharmony_ci .d_compare = affs_intl_compare_dentry, 58462306a36Sopenharmony_ci}; 585