linux/fs/affs/namei.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 *  linux/fs/affs/namei.c
   4 *
   5 *  (c) 1996  Hans-Joachim Widmaier - Rewritten
   6 *
   7 *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
   8 *
   9 *  (C) 1991  Linus Torvalds - minix filesystem
  10 */
  11
  12#include "affs.h"
  13#include <linux/exportfs.h>
  14
  15typedef int (*toupper_t)(int);
  16
  17/* Simple toupper() for DOS\1 */
  18
  19static int
  20affs_toupper(int ch)
  21{
  22        return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch;
  23}
  24
  25/* International toupper() for DOS\3 ("international") */
  26
  27static int
  28affs_intl_toupper(int ch)
  29{
  30        return (ch >= 'a' && ch <= 'z') || (ch >= 0xE0
  31                && ch <= 0xFE && ch != 0xF7) ?
  32                ch - ('a' - 'A') : ch;
  33}
  34
  35static inline toupper_t
  36affs_get_toupper(struct super_block *sb)
  37{
  38        return affs_test_opt(AFFS_SB(sb)->s_flags, SF_INTL) ?
  39               affs_intl_toupper : affs_toupper;
  40}
  41
  42/*
  43 * Note: the dentry argument is the parent dentry.
  44 */
  45static inline int
  46__affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr, toupper_t toupper, bool notruncate)
  47{
  48        const u8 *name = qstr->name;
  49        unsigned long hash;
  50        int retval;
  51        u32 len;
  52
  53        retval = affs_check_name(qstr->name, qstr->len, notruncate);
  54        if (retval)
  55                return retval;
  56
  57        hash = init_name_hash(dentry);
  58        len = min(qstr->len, AFFSNAMEMAX);
  59        for (; len > 0; name++, len--)
  60                hash = partial_name_hash(toupper(*name), hash);
  61        qstr->hash = end_name_hash(hash);
  62
  63        return 0;
  64}
  65
  66static int
  67affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
  68{
  69        return __affs_hash_dentry(dentry, qstr, affs_toupper,
  70                                  affs_nofilenametruncate(dentry));
  71
  72}
  73
  74static int
  75affs_intl_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
  76{
  77        return __affs_hash_dentry(dentry, qstr, affs_intl_toupper,
  78                                  affs_nofilenametruncate(dentry));
  79
  80}
  81
  82static inline int __affs_compare_dentry(unsigned int len,
  83                const char *str, const struct qstr *name, toupper_t toupper,
  84                bool notruncate)
  85{
  86        const u8 *aname = str;
  87        const u8 *bname = name->name;
  88
  89        /*
  90         * 'str' is the name of an already existing dentry, so the name
  91         * must be valid. 'name' must be validated first.
  92         */
  93
  94        if (affs_check_name(name->name, name->len, notruncate))
  95                return 1;
  96
  97        /*
  98         * If the names are longer than the allowed 30 chars,
  99         * the excess is ignored, so their length may differ.
 100         */
 101        if (len >= AFFSNAMEMAX) {
 102                if (name->len < AFFSNAMEMAX)
 103                        return 1;
 104                len = AFFSNAMEMAX;
 105        } else if (len != name->len)
 106                return 1;
 107
 108        for (; len > 0; len--)
 109                if (toupper(*aname++) != toupper(*bname++))
 110                        return 1;
 111
 112        return 0;
 113}
 114
 115static int
 116affs_compare_dentry(const struct dentry *dentry,
 117                unsigned int len, const char *str, const struct qstr *name)
 118{
 119
 120        return __affs_compare_dentry(len, str, name, affs_toupper,
 121                                     affs_nofilenametruncate(dentry));
 122}
 123
 124static int
 125affs_intl_compare_dentry(const struct dentry *dentry,
 126                unsigned int len, const char *str, const struct qstr *name)
 127{
 128        return __affs_compare_dentry(len, str, name, affs_intl_toupper,
 129                                     affs_nofilenametruncate(dentry));
 130
 131}
 132
 133/*
 134 * NOTE! unlike strncmp, affs_match returns 1 for success, 0 for failure.
 135 */
 136
 137static inline int
 138affs_match(struct dentry *dentry, const u8 *name2, toupper_t toupper)
 139{
 140        const u8 *name = dentry->d_name.name;
 141        int len = dentry->d_name.len;
 142
 143        if (len >= AFFSNAMEMAX) {
 144                if (*name2 < AFFSNAMEMAX)
 145                        return 0;
 146                len = AFFSNAMEMAX;
 147        } else if (len != *name2)
 148                return 0;
 149
 150        for (name2++; len > 0; len--)
 151                if (toupper(*name++) != toupper(*name2++))
 152                        return 0;
 153        return 1;
 154}
 155
 156int
 157affs_hash_name(struct super_block *sb, const u8 *name, unsigned int len)
 158{
 159        toupper_t toupper = affs_get_toupper(sb);
 160        u32 hash;
 161
 162        hash = len = min(len, AFFSNAMEMAX);
 163        for (; len > 0; len--)
 164                hash = (hash * 13 + toupper(*name++)) & 0x7ff;
 165
 166        return hash % AFFS_SB(sb)->s_hashsize;
 167}
 168
 169static struct buffer_head *
 170affs_find_entry(struct inode *dir, struct dentry *dentry)
 171{
 172        struct super_block *sb = dir->i_sb;
 173        struct buffer_head *bh;
 174        toupper_t toupper = affs_get_toupper(sb);
 175        u32 key;
 176
 177        pr_debug("%s(\"%pd\")\n", __func__, dentry);
 178
 179        bh = affs_bread(sb, dir->i_ino);
 180        if (!bh)
 181                return ERR_PTR(-EIO);
 182
 183        key = be32_to_cpu(AFFS_HEAD(bh)->table[affs_hash_name(sb, dentry->d_name.name, dentry->d_name.len)]);
 184
 185        for (;;) {
 186                affs_brelse(bh);
 187                if (key == 0)
 188                        return NULL;
 189                bh = affs_bread(sb, key);
 190                if (!bh)
 191                        return ERR_PTR(-EIO);
 192                if (affs_match(dentry, AFFS_TAIL(sb, bh)->name, toupper))
 193                        return bh;
 194                key = be32_to_cpu(AFFS_TAIL(sb, bh)->hash_chain);
 195        }
 196}
 197
 198struct dentry *
 199affs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 200{
 201        struct super_block *sb = dir->i_sb;
 202        struct buffer_head *bh;
 203        struct inode *inode = NULL;
 204        struct dentry *res;
 205
 206        pr_debug("%s(\"%pd\")\n", __func__, dentry);
 207
 208        affs_lock_dir(dir);
 209        bh = affs_find_entry(dir, dentry);
 210        if (IS_ERR(bh)) {
 211                affs_unlock_dir(dir);
 212                return ERR_CAST(bh);
 213        }
 214        if (bh) {
 215                u32 ino = bh->b_blocknr;
 216
 217                /* store the real header ino in d_fsdata for faster lookups */
 218                dentry->d_fsdata = (void *)(long)ino;
 219                switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
 220                //link to dirs disabled
 221                //case ST_LINKDIR:
 222                case ST_LINKFILE:
 223                        ino = be32_to_cpu(AFFS_TAIL(sb, bh)->original);
 224                }
 225                affs_brelse(bh);
 226                inode = affs_iget(sb, ino);
 227        }
 228        res = d_splice_alias(inode, dentry);
 229        if (!IS_ERR_OR_NULL(res))
 230                res->d_fsdata = dentry->d_fsdata;
 231        affs_unlock_dir(dir);
 232        return res;
 233}
 234
 235int
 236affs_unlink(struct inode *dir, struct dentry *dentry)
 237{
 238        pr_debug("%s(dir=%lu, %lu \"%pd\")\n", __func__, dir->i_ino,
 239                 d_inode(dentry)->i_ino, dentry);
 240
 241        return affs_remove_header(dentry);
 242}
 243
 244int
 245affs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl)
 246{
 247        struct super_block *sb = dir->i_sb;
 248        struct inode    *inode;
 249        int              error;
 250
 251        pr_debug("%s(%lu,\"%pd\",0%ho)\n",
 252                 __func__, dir->i_ino, dentry, mode);
 253
 254        inode = affs_new_inode(dir);
 255        if (!inode)
 256                return -ENOSPC;
 257
 258        inode->i_mode = mode;
 259        affs_mode_to_prot(inode);
 260        mark_inode_dirty(inode);
 261
 262        inode->i_op = &affs_file_inode_operations;
 263        inode->i_fop = &affs_file_operations;
 264        inode->i_mapping->a_ops = affs_test_opt(AFFS_SB(sb)->s_flags, SF_OFS) ?
 265                                  &affs_aops_ofs : &affs_aops;
 266        error = affs_add_entry(dir, inode, dentry, ST_FILE);
 267        if (error) {
 268                clear_nlink(inode);
 269                iput(inode);
 270                return error;
 271        }
 272        return 0;
 273}
 274
 275int
 276affs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 277{
 278        struct inode            *inode;
 279        int                      error;
 280
 281        pr_debug("%s(%lu,\"%pd\",0%ho)\n",
 282                 __func__, dir->i_ino, dentry, mode);
 283
 284        inode = affs_new_inode(dir);
 285        if (!inode)
 286                return -ENOSPC;
 287
 288        inode->i_mode = S_IFDIR | mode;
 289        affs_mode_to_prot(inode);
 290
 291        inode->i_op = &affs_dir_inode_operations;
 292        inode->i_fop = &affs_dir_operations;
 293
 294        error = affs_add_entry(dir, inode, dentry, ST_USERDIR);
 295        if (error) {
 296                clear_nlink(inode);
 297                mark_inode_dirty(inode);
 298                iput(inode);
 299                return error;
 300        }
 301        return 0;
 302}
 303
 304int
 305affs_rmdir(struct inode *dir, struct dentry *dentry)
 306{
 307        pr_debug("%s(dir=%lu, %lu \"%pd\")\n", __func__, dir->i_ino,
 308                 d_inode(dentry)->i_ino, dentry);
 309
 310        return affs_remove_header(dentry);
 311}
 312
 313int
 314affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
 315{
 316        struct super_block      *sb = dir->i_sb;
 317        struct buffer_head      *bh;
 318        struct inode            *inode;
 319        char                    *p;
 320        int                      i, maxlen, error;
 321        char                     c, lc;
 322
 323        pr_debug("%s(%lu,\"%pd\" -> \"%s\")\n",
 324                 __func__, dir->i_ino, dentry, symname);
 325
 326        maxlen = AFFS_SB(sb)->s_hashsize * sizeof(u32) - 1;
 327        inode  = affs_new_inode(dir);
 328        if (!inode)
 329                return -ENOSPC;
 330
 331        inode->i_op = &affs_symlink_inode_operations;
 332        inode_nohighmem(inode);
 333        inode->i_data.a_ops = &affs_symlink_aops;
 334        inode->i_mode = S_IFLNK | 0777;
 335        affs_mode_to_prot(inode);
 336
 337        error = -EIO;
 338        bh = affs_bread(sb, inode->i_ino);
 339        if (!bh)
 340                goto err;
 341        i  = 0;
 342        p  = (char *)AFFS_HEAD(bh)->table;
 343        lc = '/';
 344        if (*symname == '/') {
 345                struct affs_sb_info *sbi = AFFS_SB(sb);
 346                while (*symname == '/')
 347                        symname++;
 348                spin_lock(&sbi->symlink_lock);
 349                while (sbi->s_volume[i])        /* Cannot overflow */
 350                        *p++ = sbi->s_volume[i++];
 351                spin_unlock(&sbi->symlink_lock);
 352        }
 353        while (i < maxlen && (c = *symname++)) {
 354                if (c == '.' && lc == '/' && *symname == '.' && symname[1] == '/') {
 355                        *p++ = '/';
 356                        i++;
 357                        symname += 2;
 358                        lc = '/';
 359                } else if (c == '.' && lc == '/' && *symname == '/') {
 360                        symname++;
 361                        lc = '/';
 362                } else {
 363                        *p++ = c;
 364                        lc   = c;
 365                        i++;
 366                }
 367                if (lc == '/')
 368                        while (*symname == '/')
 369                                symname++;
 370        }
 371        *p = 0;
 372        inode->i_size = i + 1;
 373        mark_buffer_dirty_inode(bh, inode);
 374        affs_brelse(bh);
 375        mark_inode_dirty(inode);
 376
 377        error = affs_add_entry(dir, inode, dentry, ST_SOFTLINK);
 378        if (error)
 379                goto err;
 380
 381        return 0;
 382
 383err:
 384        clear_nlink(inode);
 385        mark_inode_dirty(inode);
 386        iput(inode);
 387        return error;
 388}
 389
 390int
 391affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
 392{
 393        struct inode *inode = d_inode(old_dentry);
 394
 395        pr_debug("%s(%lu, %lu, \"%pd\")\n", __func__, inode->i_ino, dir->i_ino,
 396                 dentry);
 397
 398        return affs_add_entry(dir, inode, dentry, ST_LINKFILE);
 399}
 400
 401static int
 402affs_rename(struct inode *old_dir, struct dentry *old_dentry,
 403            struct inode *new_dir, struct dentry *new_dentry)
 404{
 405        struct super_block *sb = old_dir->i_sb;
 406        struct buffer_head *bh = NULL;
 407        int retval;
 408
 409        retval = affs_check_name(new_dentry->d_name.name,
 410                                 new_dentry->d_name.len,
 411                                 affs_nofilenametruncate(old_dentry));
 412
 413        if (retval)
 414                return retval;
 415
 416        /* Unlink destination if it already exists */
 417        if (d_really_is_positive(new_dentry)) {
 418                retval = affs_remove_header(new_dentry);
 419                if (retval)
 420                        return retval;
 421        }
 422
 423        bh = affs_bread(sb, d_inode(old_dentry)->i_ino);
 424        if (!bh)
 425                return -EIO;
 426
 427        /* Remove header from its parent directory. */
 428        affs_lock_dir(old_dir);
 429        retval = affs_remove_hash(old_dir, bh);
 430        affs_unlock_dir(old_dir);
 431        if (retval)
 432                goto done;
 433
 434        /* And insert it into the new directory with the new name. */
 435        affs_copy_name(AFFS_TAIL(sb, bh)->name, new_dentry);
 436        affs_fix_checksum(sb, bh);
 437        affs_lock_dir(new_dir);
 438        retval = affs_insert_hash(new_dir, bh);
 439        affs_unlock_dir(new_dir);
 440        /* TODO: move it back to old_dir, if error? */
 441
 442done:
 443        mark_buffer_dirty_inode(bh, retval ? old_dir : new_dir);
 444        affs_brelse(bh);
 445        return retval;
 446}
 447
 448static int
 449affs_xrename(struct inode *old_dir, struct dentry *old_dentry,
 450             struct inode *new_dir, struct dentry *new_dentry)
 451{
 452
 453        struct super_block *sb = old_dir->i_sb;
 454        struct buffer_head *bh_old = NULL;
 455        struct buffer_head *bh_new = NULL;
 456        int retval;
 457
 458        bh_old = affs_bread(sb, d_inode(old_dentry)->i_ino);
 459        if (!bh_old)
 460                return -EIO;
 461
 462        bh_new = affs_bread(sb, d_inode(new_dentry)->i_ino);
 463        if (!bh_new)
 464                return -EIO;
 465
 466        /* Remove old header from its parent directory. */
 467        affs_lock_dir(old_dir);
 468        retval = affs_remove_hash(old_dir, bh_old);
 469        affs_unlock_dir(old_dir);
 470        if (retval)
 471                goto done;
 472
 473        /* Remove new header from its parent directory. */
 474        affs_lock_dir(new_dir);
 475        retval = affs_remove_hash(new_dir, bh_new);
 476        affs_unlock_dir(new_dir);
 477        if (retval)
 478                goto done;
 479
 480        /* Insert old into the new directory with the new name. */
 481        affs_copy_name(AFFS_TAIL(sb, bh_old)->name, new_dentry);
 482        affs_fix_checksum(sb, bh_old);
 483        affs_lock_dir(new_dir);
 484        retval = affs_insert_hash(new_dir, bh_old);
 485        affs_unlock_dir(new_dir);
 486
 487        /* Insert new into the old directory with the old name. */
 488        affs_copy_name(AFFS_TAIL(sb, bh_new)->name, old_dentry);
 489        affs_fix_checksum(sb, bh_new);
 490        affs_lock_dir(old_dir);
 491        retval = affs_insert_hash(old_dir, bh_new);
 492        affs_unlock_dir(old_dir);
 493done:
 494        mark_buffer_dirty_inode(bh_old, new_dir);
 495        mark_buffer_dirty_inode(bh_new, old_dir);
 496        affs_brelse(bh_old);
 497        affs_brelse(bh_new);
 498        return retval;
 499}
 500
 501int affs_rename2(struct inode *old_dir, struct dentry *old_dentry,
 502                        struct inode *new_dir, struct dentry *new_dentry,
 503                        unsigned int flags)
 504{
 505
 506        if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
 507                return -EINVAL;
 508
 509        pr_debug("%s(old=%lu,\"%pd\" to new=%lu,\"%pd\")\n", __func__,
 510                 old_dir->i_ino, old_dentry, new_dir->i_ino, new_dentry);
 511
 512        if (flags & RENAME_EXCHANGE)
 513                return affs_xrename(old_dir, old_dentry, new_dir, new_dentry);
 514
 515        return affs_rename(old_dir, old_dentry, new_dir, new_dentry);
 516}
 517
 518static struct dentry *affs_get_parent(struct dentry *child)
 519{
 520        struct inode *parent;
 521        struct buffer_head *bh;
 522
 523        bh = affs_bread(child->d_sb, d_inode(child)->i_ino);
 524        if (!bh)
 525                return ERR_PTR(-EIO);
 526
 527        parent = affs_iget(child->d_sb,
 528                           be32_to_cpu(AFFS_TAIL(child->d_sb, bh)->parent));
 529        brelse(bh);
 530        if (IS_ERR(parent))
 531                return ERR_CAST(parent);
 532
 533        return d_obtain_alias(parent);
 534}
 535
 536static struct inode *affs_nfs_get_inode(struct super_block *sb, u64 ino,
 537                                        u32 generation)
 538{
 539        struct inode *inode;
 540
 541        if (!affs_validblock(sb, ino))
 542                return ERR_PTR(-ESTALE);
 543
 544        inode = affs_iget(sb, ino);
 545        if (IS_ERR(inode))
 546                return ERR_CAST(inode);
 547
 548        return inode;
 549}
 550
 551static struct dentry *affs_fh_to_dentry(struct super_block *sb, struct fid *fid,
 552                                        int fh_len, int fh_type)
 553{
 554        return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
 555                                    affs_nfs_get_inode);
 556}
 557
 558static struct dentry *affs_fh_to_parent(struct super_block *sb, struct fid *fid,
 559                                        int fh_len, int fh_type)
 560{
 561        return generic_fh_to_parent(sb, fid, fh_len, fh_type,
 562                                    affs_nfs_get_inode);
 563}
 564
 565const struct export_operations affs_export_ops = {
 566        .fh_to_dentry = affs_fh_to_dentry,
 567        .fh_to_parent = affs_fh_to_parent,
 568        .get_parent = affs_get_parent,
 569};
 570
 571const struct dentry_operations affs_dentry_operations = {
 572        .d_hash         = affs_hash_dentry,
 573        .d_compare      = affs_compare_dentry,
 574};
 575
 576const struct dentry_operations affs_intl_dentry_operations = {
 577        .d_hash         = affs_intl_hash_dentry,
 578        .d_compare      = affs_intl_compare_dentry,
 579};
 580