Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *  linux/fs/affs/namei.c
0004  *
0005  *  (c) 1996  Hans-Joachim Widmaier - Rewritten
0006  *
0007  *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
0008  *
0009  *  (C) 1991  Linus Torvalds - minix filesystem
0010  */
0011 
0012 #include "affs.h"
0013 #include <linux/exportfs.h>
0014 
0015 typedef int (*toupper_t)(int);
0016 
0017 /* Simple toupper() for DOS\1 */
0018 
0019 static int
0020 affs_toupper(int ch)
0021 {
0022     return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch;
0023 }
0024 
0025 /* International toupper() for DOS\3 ("international") */
0026 
0027 static int
0028 affs_intl_toupper(int ch)
0029 {
0030     return (ch >= 'a' && ch <= 'z') || (ch >= 0xE0
0031         && ch <= 0xFE && ch != 0xF7) ?
0032         ch - ('a' - 'A') : ch;
0033 }
0034 
0035 static inline toupper_t
0036 affs_get_toupper(struct super_block *sb)
0037 {
0038     return affs_test_opt(AFFS_SB(sb)->s_flags, SF_INTL) ?
0039            affs_intl_toupper : affs_toupper;
0040 }
0041 
0042 /*
0043  * Note: the dentry argument is the parent dentry.
0044  */
0045 static inline int
0046 __affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr, toupper_t toupper, bool notruncate)
0047 {
0048     const u8 *name = qstr->name;
0049     unsigned long hash;
0050     int retval;
0051     u32 len;
0052 
0053     retval = affs_check_name(qstr->name, qstr->len, notruncate);
0054     if (retval)
0055         return retval;
0056 
0057     hash = init_name_hash(dentry);
0058     len = min(qstr->len, AFFSNAMEMAX);
0059     for (; len > 0; name++, len--)
0060         hash = partial_name_hash(toupper(*name), hash);
0061     qstr->hash = end_name_hash(hash);
0062 
0063     return 0;
0064 }
0065 
0066 static int
0067 affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
0068 {
0069     return __affs_hash_dentry(dentry, qstr, affs_toupper,
0070                   affs_nofilenametruncate(dentry));
0071 
0072 }
0073 
0074 static int
0075 affs_intl_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
0076 {
0077     return __affs_hash_dentry(dentry, qstr, affs_intl_toupper,
0078                   affs_nofilenametruncate(dentry));
0079 
0080 }
0081 
0082 static inline int __affs_compare_dentry(unsigned int len,
0083         const char *str, const struct qstr *name, toupper_t toupper,
0084         bool notruncate)
0085 {
0086     const u8 *aname = str;
0087     const u8 *bname = name->name;
0088 
0089     /*
0090      * 'str' is the name of an already existing dentry, so the name
0091      * must be valid. 'name' must be validated first.
0092      */
0093 
0094     if (affs_check_name(name->name, name->len, notruncate))
0095         return 1;
0096 
0097     /*
0098      * If the names are longer than the allowed 30 chars,
0099      * the excess is ignored, so their length may differ.
0100      */
0101     if (len >= AFFSNAMEMAX) {
0102         if (name->len < AFFSNAMEMAX)
0103             return 1;
0104         len = AFFSNAMEMAX;
0105     } else if (len != name->len)
0106         return 1;
0107 
0108     for (; len > 0; len--)
0109         if (toupper(*aname++) != toupper(*bname++))
0110             return 1;
0111 
0112     return 0;
0113 }
0114 
0115 static int
0116 affs_compare_dentry(const struct dentry *dentry,
0117         unsigned int len, const char *str, const struct qstr *name)
0118 {
0119 
0120     return __affs_compare_dentry(len, str, name, affs_toupper,
0121                      affs_nofilenametruncate(dentry));
0122 }
0123 
0124 static int
0125 affs_intl_compare_dentry(const struct dentry *dentry,
0126         unsigned int len, const char *str, const struct qstr *name)
0127 {
0128     return __affs_compare_dentry(len, str, name, affs_intl_toupper,
0129                      affs_nofilenametruncate(dentry));
0130 
0131 }
0132 
0133 /*
0134  * NOTE! unlike strncmp, affs_match returns 1 for success, 0 for failure.
0135  */
0136 
0137 static inline int
0138 affs_match(struct dentry *dentry, const u8 *name2, toupper_t toupper)
0139 {
0140     const u8 *name = dentry->d_name.name;
0141     int len = dentry->d_name.len;
0142 
0143     if (len >= AFFSNAMEMAX) {
0144         if (*name2 < AFFSNAMEMAX)
0145             return 0;
0146         len = AFFSNAMEMAX;
0147     } else if (len != *name2)
0148         return 0;
0149 
0150     for (name2++; len > 0; len--)
0151         if (toupper(*name++) != toupper(*name2++))
0152             return 0;
0153     return 1;
0154 }
0155 
0156 int
0157 affs_hash_name(struct super_block *sb, const u8 *name, unsigned int len)
0158 {
0159     toupper_t toupper = affs_get_toupper(sb);
0160     u32 hash;
0161 
0162     hash = len = min(len, AFFSNAMEMAX);
0163     for (; len > 0; len--)
0164         hash = (hash * 13 + toupper(*name++)) & 0x7ff;
0165 
0166     return hash % AFFS_SB(sb)->s_hashsize;
0167 }
0168 
0169 static struct buffer_head *
0170 affs_find_entry(struct inode *dir, struct dentry *dentry)
0171 {
0172     struct super_block *sb = dir->i_sb;
0173     struct buffer_head *bh;
0174     toupper_t toupper = affs_get_toupper(sb);
0175     u32 key;
0176 
0177     pr_debug("%s(\"%pd\")\n", __func__, dentry);
0178 
0179     bh = affs_bread(sb, dir->i_ino);
0180     if (!bh)
0181         return ERR_PTR(-EIO);
0182 
0183     key = be32_to_cpu(AFFS_HEAD(bh)->table[affs_hash_name(sb, dentry->d_name.name, dentry->d_name.len)]);
0184 
0185     for (;;) {
0186         affs_brelse(bh);
0187         if (key == 0)
0188             return NULL;
0189         bh = affs_bread(sb, key);
0190         if (!bh)
0191             return ERR_PTR(-EIO);
0192         if (affs_match(dentry, AFFS_TAIL(sb, bh)->name, toupper))
0193             return bh;
0194         key = be32_to_cpu(AFFS_TAIL(sb, bh)->hash_chain);
0195     }
0196 }
0197 
0198 struct dentry *
0199 affs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
0200 {
0201     struct super_block *sb = dir->i_sb;
0202     struct buffer_head *bh;
0203     struct inode *inode = NULL;
0204     struct dentry *res;
0205 
0206     pr_debug("%s(\"%pd\")\n", __func__, dentry);
0207 
0208     affs_lock_dir(dir);
0209     bh = affs_find_entry(dir, dentry);
0210     if (IS_ERR(bh)) {
0211         affs_unlock_dir(dir);
0212         return ERR_CAST(bh);
0213     }
0214     if (bh) {
0215         u32 ino = bh->b_blocknr;
0216 
0217         /* store the real header ino in d_fsdata for faster lookups */
0218         dentry->d_fsdata = (void *)(long)ino;
0219         switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
0220         //link to dirs disabled
0221         //case ST_LINKDIR:
0222         case ST_LINKFILE:
0223             ino = be32_to_cpu(AFFS_TAIL(sb, bh)->original);
0224         }
0225         affs_brelse(bh);
0226         inode = affs_iget(sb, ino);
0227     }
0228     res = d_splice_alias(inode, dentry);
0229     if (!IS_ERR_OR_NULL(res))
0230         res->d_fsdata = dentry->d_fsdata;
0231     affs_unlock_dir(dir);
0232     return res;
0233 }
0234 
0235 int
0236 affs_unlink(struct inode *dir, struct dentry *dentry)
0237 {
0238     pr_debug("%s(dir=%lu, %lu \"%pd\")\n", __func__, dir->i_ino,
0239          d_inode(dentry)->i_ino, dentry);
0240 
0241     return affs_remove_header(dentry);
0242 }
0243 
0244 int
0245 affs_create(struct user_namespace *mnt_userns, struct inode *dir,
0246         struct dentry *dentry, umode_t mode, bool excl)
0247 {
0248     struct super_block *sb = dir->i_sb;
0249     struct inode    *inode;
0250     int      error;
0251 
0252     pr_debug("%s(%lu,\"%pd\",0%ho)\n",
0253          __func__, dir->i_ino, dentry, mode);
0254 
0255     inode = affs_new_inode(dir);
0256     if (!inode)
0257         return -ENOSPC;
0258 
0259     inode->i_mode = mode;
0260     affs_mode_to_prot(inode);
0261     mark_inode_dirty(inode);
0262 
0263     inode->i_op = &affs_file_inode_operations;
0264     inode->i_fop = &affs_file_operations;
0265     inode->i_mapping->a_ops = affs_test_opt(AFFS_SB(sb)->s_flags, SF_OFS) ?
0266                   &affs_aops_ofs : &affs_aops;
0267     error = affs_add_entry(dir, inode, dentry, ST_FILE);
0268     if (error) {
0269         clear_nlink(inode);
0270         iput(inode);
0271         return error;
0272     }
0273     return 0;
0274 }
0275 
0276 int
0277 affs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
0278        struct dentry *dentry, umode_t mode)
0279 {
0280     struct inode        *inode;
0281     int          error;
0282 
0283     pr_debug("%s(%lu,\"%pd\",0%ho)\n",
0284          __func__, dir->i_ino, dentry, mode);
0285 
0286     inode = affs_new_inode(dir);
0287     if (!inode)
0288         return -ENOSPC;
0289 
0290     inode->i_mode = S_IFDIR | mode;
0291     affs_mode_to_prot(inode);
0292 
0293     inode->i_op = &affs_dir_inode_operations;
0294     inode->i_fop = &affs_dir_operations;
0295 
0296     error = affs_add_entry(dir, inode, dentry, ST_USERDIR);
0297     if (error) {
0298         clear_nlink(inode);
0299         mark_inode_dirty(inode);
0300         iput(inode);
0301         return error;
0302     }
0303     return 0;
0304 }
0305 
0306 int
0307 affs_rmdir(struct inode *dir, struct dentry *dentry)
0308 {
0309     pr_debug("%s(dir=%lu, %lu \"%pd\")\n", __func__, dir->i_ino,
0310          d_inode(dentry)->i_ino, dentry);
0311 
0312     return affs_remove_header(dentry);
0313 }
0314 
0315 int
0316 affs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
0317          struct dentry *dentry, const char *symname)
0318 {
0319     struct super_block  *sb = dir->i_sb;
0320     struct buffer_head  *bh;
0321     struct inode        *inode;
0322     char            *p;
0323     int          i, maxlen, error;
0324     char             c, lc;
0325 
0326     pr_debug("%s(%lu,\"%pd\" -> \"%s\")\n",
0327          __func__, dir->i_ino, dentry, symname);
0328 
0329     maxlen = AFFS_SB(sb)->s_hashsize * sizeof(u32) - 1;
0330     inode  = affs_new_inode(dir);
0331     if (!inode)
0332         return -ENOSPC;
0333 
0334     inode->i_op = &affs_symlink_inode_operations;
0335     inode_nohighmem(inode);
0336     inode->i_data.a_ops = &affs_symlink_aops;
0337     inode->i_mode = S_IFLNK | 0777;
0338     affs_mode_to_prot(inode);
0339 
0340     error = -EIO;
0341     bh = affs_bread(sb, inode->i_ino);
0342     if (!bh)
0343         goto err;
0344     i  = 0;
0345     p  = (char *)AFFS_HEAD(bh)->table;
0346     lc = '/';
0347     if (*symname == '/') {
0348         struct affs_sb_info *sbi = AFFS_SB(sb);
0349         while (*symname == '/')
0350             symname++;
0351         spin_lock(&sbi->symlink_lock);
0352         while (sbi->s_volume[i])    /* Cannot overflow */
0353             *p++ = sbi->s_volume[i++];
0354         spin_unlock(&sbi->symlink_lock);
0355     }
0356     while (i < maxlen && (c = *symname++)) {
0357         if (c == '.' && lc == '/' && *symname == '.' && symname[1] == '/') {
0358             *p++ = '/';
0359             i++;
0360             symname += 2;
0361             lc = '/';
0362         } else if (c == '.' && lc == '/' && *symname == '/') {
0363             symname++;
0364             lc = '/';
0365         } else {
0366             *p++ = c;
0367             lc   = c;
0368             i++;
0369         }
0370         if (lc == '/')
0371             while (*symname == '/')
0372                 symname++;
0373     }
0374     *p = 0;
0375     inode->i_size = i + 1;
0376     mark_buffer_dirty_inode(bh, inode);
0377     affs_brelse(bh);
0378     mark_inode_dirty(inode);
0379 
0380     error = affs_add_entry(dir, inode, dentry, ST_SOFTLINK);
0381     if (error)
0382         goto err;
0383 
0384     return 0;
0385 
0386 err:
0387     clear_nlink(inode);
0388     mark_inode_dirty(inode);
0389     iput(inode);
0390     return error;
0391 }
0392 
0393 int
0394 affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
0395 {
0396     struct inode *inode = d_inode(old_dentry);
0397 
0398     pr_debug("%s(%lu, %lu, \"%pd\")\n", __func__, inode->i_ino, dir->i_ino,
0399          dentry);
0400 
0401     return affs_add_entry(dir, inode, dentry, ST_LINKFILE);
0402 }
0403 
0404 static int
0405 affs_rename(struct inode *old_dir, struct dentry *old_dentry,
0406         struct inode *new_dir, struct dentry *new_dentry)
0407 {
0408     struct super_block *sb = old_dir->i_sb;
0409     struct buffer_head *bh = NULL;
0410     int retval;
0411 
0412     retval = affs_check_name(new_dentry->d_name.name,
0413                  new_dentry->d_name.len,
0414                  affs_nofilenametruncate(old_dentry));
0415 
0416     if (retval)
0417         return retval;
0418 
0419     /* Unlink destination if it already exists */
0420     if (d_really_is_positive(new_dentry)) {
0421         retval = affs_remove_header(new_dentry);
0422         if (retval)
0423             return retval;
0424     }
0425 
0426     bh = affs_bread(sb, d_inode(old_dentry)->i_ino);
0427     if (!bh)
0428         return -EIO;
0429 
0430     /* Remove header from its parent directory. */
0431     affs_lock_dir(old_dir);
0432     retval = affs_remove_hash(old_dir, bh);
0433     affs_unlock_dir(old_dir);
0434     if (retval)
0435         goto done;
0436 
0437     /* And insert it into the new directory with the new name. */
0438     affs_copy_name(AFFS_TAIL(sb, bh)->name, new_dentry);
0439     affs_fix_checksum(sb, bh);
0440     affs_lock_dir(new_dir);
0441     retval = affs_insert_hash(new_dir, bh);
0442     affs_unlock_dir(new_dir);
0443     /* TODO: move it back to old_dir, if error? */
0444 
0445 done:
0446     mark_buffer_dirty_inode(bh, retval ? old_dir : new_dir);
0447     affs_brelse(bh);
0448     return retval;
0449 }
0450 
0451 static int
0452 affs_xrename(struct inode *old_dir, struct dentry *old_dentry,
0453          struct inode *new_dir, struct dentry *new_dentry)
0454 {
0455 
0456     struct super_block *sb = old_dir->i_sb;
0457     struct buffer_head *bh_old = NULL;
0458     struct buffer_head *bh_new = NULL;
0459     int retval;
0460 
0461     bh_old = affs_bread(sb, d_inode(old_dentry)->i_ino);
0462     if (!bh_old)
0463         return -EIO;
0464 
0465     bh_new = affs_bread(sb, d_inode(new_dentry)->i_ino);
0466     if (!bh_new) {
0467         affs_brelse(bh_old);
0468         return -EIO;
0469     }
0470 
0471     /* Remove old header from its parent directory. */
0472     affs_lock_dir(old_dir);
0473     retval = affs_remove_hash(old_dir, bh_old);
0474     affs_unlock_dir(old_dir);
0475     if (retval)
0476         goto done;
0477 
0478     /* Remove new header from its parent directory. */
0479     affs_lock_dir(new_dir);
0480     retval = affs_remove_hash(new_dir, bh_new);
0481     affs_unlock_dir(new_dir);
0482     if (retval)
0483         goto done;
0484 
0485     /* Insert old into the new directory with the new name. */
0486     affs_copy_name(AFFS_TAIL(sb, bh_old)->name, new_dentry);
0487     affs_fix_checksum(sb, bh_old);
0488     affs_lock_dir(new_dir);
0489     retval = affs_insert_hash(new_dir, bh_old);
0490     affs_unlock_dir(new_dir);
0491 
0492     /* Insert new into the old directory with the old name. */
0493     affs_copy_name(AFFS_TAIL(sb, bh_new)->name, old_dentry);
0494     affs_fix_checksum(sb, bh_new);
0495     affs_lock_dir(old_dir);
0496     retval = affs_insert_hash(old_dir, bh_new);
0497     affs_unlock_dir(old_dir);
0498 done:
0499     mark_buffer_dirty_inode(bh_old, new_dir);
0500     mark_buffer_dirty_inode(bh_new, old_dir);
0501     affs_brelse(bh_old);
0502     affs_brelse(bh_new);
0503     return retval;
0504 }
0505 
0506 int affs_rename2(struct user_namespace *mnt_userns, struct inode *old_dir,
0507          struct dentry *old_dentry, struct inode *new_dir,
0508          struct dentry *new_dentry, unsigned int flags)
0509 {
0510 
0511     if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
0512         return -EINVAL;
0513 
0514     pr_debug("%s(old=%lu,\"%pd\" to new=%lu,\"%pd\")\n", __func__,
0515          old_dir->i_ino, old_dentry, new_dir->i_ino, new_dentry);
0516 
0517     if (flags & RENAME_EXCHANGE)
0518         return affs_xrename(old_dir, old_dentry, new_dir, new_dentry);
0519 
0520     return affs_rename(old_dir, old_dentry, new_dir, new_dentry);
0521 }
0522 
0523 static struct dentry *affs_get_parent(struct dentry *child)
0524 {
0525     struct inode *parent;
0526     struct buffer_head *bh;
0527 
0528     bh = affs_bread(child->d_sb, d_inode(child)->i_ino);
0529     if (!bh)
0530         return ERR_PTR(-EIO);
0531 
0532     parent = affs_iget(child->d_sb,
0533                be32_to_cpu(AFFS_TAIL(child->d_sb, bh)->parent));
0534     brelse(bh);
0535     if (IS_ERR(parent))
0536         return ERR_CAST(parent);
0537 
0538     return d_obtain_alias(parent);
0539 }
0540 
0541 static struct inode *affs_nfs_get_inode(struct super_block *sb, u64 ino,
0542                     u32 generation)
0543 {
0544     struct inode *inode;
0545 
0546     if (!affs_validblock(sb, ino))
0547         return ERR_PTR(-ESTALE);
0548 
0549     inode = affs_iget(sb, ino);
0550     if (IS_ERR(inode))
0551         return ERR_CAST(inode);
0552 
0553     return inode;
0554 }
0555 
0556 static struct dentry *affs_fh_to_dentry(struct super_block *sb, struct fid *fid,
0557                     int fh_len, int fh_type)
0558 {
0559     return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
0560                     affs_nfs_get_inode);
0561 }
0562 
0563 static struct dentry *affs_fh_to_parent(struct super_block *sb, struct fid *fid,
0564                     int fh_len, int fh_type)
0565 {
0566     return generic_fh_to_parent(sb, fid, fh_len, fh_type,
0567                     affs_nfs_get_inode);
0568 }
0569 
0570 const struct export_operations affs_export_ops = {
0571     .fh_to_dentry = affs_fh_to_dentry,
0572     .fh_to_parent = affs_fh_to_parent,
0573     .get_parent = affs_get_parent,
0574 };
0575 
0576 const struct dentry_operations affs_dentry_operations = {
0577     .d_hash     = affs_hash_dentry,
0578     .d_compare  = affs_compare_dentry,
0579 };
0580 
0581 const struct dentry_operations affs_intl_dentry_operations = {
0582     .d_hash     = affs_intl_hash_dentry,
0583     .d_compare  = affs_intl_compare_dentry,
0584 };