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 user_namespace *mnt_userns, struct inode *dir,
 246            struct dentry *dentry, umode_t mode, bool excl)
 247{
 248        struct super_block *sb = dir->i_sb;
 249        struct inode    *inode;
 250        int              error;
 251
 252        pr_debug("%s(%lu,\"%pd\",0%ho)\n",
 253                 __func__, dir->i_ino, dentry, mode);
 254
 255        inode = affs_new_inode(dir);
 256        if (!inode)
 257                return -ENOSPC;
 258
 259        inode->i_mode = mode;
 260        affs_mode_to_prot(inode);
 261        mark_inode_dirty(inode);
 262
 263        inode->i_op = &affs_file_inode_operations;
 264        inode->i_fop = &affs_file_operations;
 265        inode->i_mapping->a_ops = affs_test_opt(AFFS_SB(sb)->s_flags, SF_OFS) ?
 266                                  &affs_aops_ofs : &affs_aops;
 267        error = affs_add_entry(dir, inode, dentry, ST_FILE);
 268        if (error) {
 269                clear_nlink(inode);
 270                iput(inode);
 271                return error;
 272        }
 273        return 0;
 274}
 275
 276int
 277affs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
 278           struct dentry *dentry, umode_t mode)
 279{
 280        struct inode            *inode;
 281        int                      error;
 282
 283        pr_debug("%s(%lu,\"%pd\",0%ho)\n",
 284                 __func__, dir->i_ino, dentry, mode);
 285
 286        inode = affs_new_inode(dir);
 287        if (!inode)
 288                return -ENOSPC;
 289
 290        inode->i_mode = S_IFDIR | mode;
 291        affs_mode_to_prot(inode);
 292
 293        inode->i_op = &affs_dir_inode_operations;
 294        inode->i_fop = &affs_dir_operations;
 295
 296        error = affs_add_entry(dir, inode, dentry, ST_USERDIR);
 297        if (error) {
 298                clear_nlink(inode);
 299                mark_inode_dirty(inode);
 300                iput(inode);
 301                return error;
 302        }
 303        return 0;
 304}
 305
 306int
 307affs_rmdir(struct inode *dir, struct dentry *dentry)
 308{
 309        pr_debug("%s(dir=%lu, %lu \"%pd\")\n", __func__, dir->i_ino,
 310                 d_inode(dentry)->i_ino, dentry);
 311
 312        return affs_remove_header(dentry);
 313}
 314
 315int
 316affs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
 317             struct dentry *dentry, const char *symname)
 318{
 319        struct super_block      *sb = dir->i_sb;
 320        struct buffer_head      *bh;
 321        struct inode            *inode;
 322        char                    *p;
 323        int                      i, maxlen, error;
 324        char                     c, lc;
 325
 326        pr_debug("%s(%lu,\"%pd\" -> \"%s\")\n",
 327                 __func__, dir->i_ino, dentry, symname);
 328
 329        maxlen = AFFS_SB(sb)->s_hashsize * sizeof(u32) - 1;
 330        inode  = affs_new_inode(dir);
 331        if (!inode)
 332                return -ENOSPC;
 333
 334        inode->i_op = &affs_symlink_inode_operations;
 335        inode_nohighmem(inode);
 336        inode->i_data.a_ops = &affs_symlink_aops;
 337        inode->i_mode = S_IFLNK | 0777;
 338        affs_mode_to_prot(inode);
 339
 340        error = -EIO;
 341        bh = affs_bread(sb, inode->i_ino);
 342        if (!bh)
 343                goto err;
 344        i  = 0;
 345        p  = (char *)AFFS_HEAD(bh)->table;
 346        lc = '/';
 347        if (*symname == '/') {
 348                struct affs_sb_info *sbi = AFFS_SB(sb);
 349                while (*symname == '/')
 350                        symname++;
 351                spin_lock(&sbi->symlink_lock);
 352                while (sbi->s_volume[i])        /* Cannot overflow */
 353                        *p++ = sbi->s_volume[i++];
 354                spin_unlock(&sbi->symlink_lock);
 355        }
 356        while (i < maxlen && (c = *symname++)) {
 357                if (c == '.' && lc == '/' && *symname == '.' && symname[1] == '/') {
 358                        *p++ = '/';
 359                        i++;
 360                        symname += 2;
 361                        lc = '/';
 362                } else if (c == '.' && lc == '/' && *symname == '/') {
 363                        symname++;
 364                        lc = '/';
 365                } else {
 366                        *p++ = c;
 367                        lc   = c;
 368                        i++;
 369                }
 370                if (lc == '/')
 371                        while (*symname == '/')
 372                                symname++;
 373        }
 374        *p = 0;
 375        inode->i_size = i + 1;
 376        mark_buffer_dirty_inode(bh, inode);
 377        affs_brelse(bh);
 378        mark_inode_dirty(inode);
 379
 380        error = affs_add_entry(dir, inode, dentry, ST_SOFTLINK);
 381        if (error)
 382                goto err;
 383
 384        return 0;
 385
 386err:
 387        clear_nlink(inode);
 388        mark_inode_dirty(inode);
 389        iput(inode);
 390        return error;
 391}
 392
 393int
 394affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
 395{
 396        struct inode *inode = d_inode(old_dentry);
 397
 398        pr_debug("%s(%lu, %lu, \"%pd\")\n", __func__, inode->i_ino, dir->i_ino,
 399                 dentry);
 400
 401        return affs_add_entry(dir, inode, dentry, ST_LINKFILE);
 402}
 403
 404static int
 405affs_rename(struct inode *old_dir, struct dentry *old_dentry,
 406            struct inode *new_dir, struct dentry *new_dentry)
 407{
 408        struct super_block *sb = old_dir->i_sb;
 409        struct buffer_head *bh = NULL;
 410        int retval;
 411
 412        retval = affs_check_name(new_dentry->d_name.name,
 413                                 new_dentry->d_name.len,
 414                                 affs_nofilenametruncate(old_dentry));
 415
 416        if (retval)
 417                return retval;
 418
 419        /* Unlink destination if it already exists */
 420        if (d_really_is_positive(new_dentry)) {
 421                retval = affs_remove_header(new_dentry);
 422                if (retval)
 423                        return retval;
 424        }
 425
 426        bh = affs_bread(sb, d_inode(old_dentry)->i_ino);
 427        if (!bh)
 428                return -EIO;
 429
 430        /* Remove header from its parent directory. */
 431        affs_lock_dir(old_dir);
 432        retval = affs_remove_hash(old_dir, bh);
 433        affs_unlock_dir(old_dir);
 434        if (retval)
 435                goto done;
 436
 437        /* And insert it into the new directory with the new name. */
 438        affs_copy_name(AFFS_TAIL(sb, bh)->name, new_dentry);
 439        affs_fix_checksum(sb, bh);
 440        affs_lock_dir(new_dir);
 441        retval = affs_insert_hash(new_dir, bh);
 442        affs_unlock_dir(new_dir);
 443        /* TODO: move it back to old_dir, if error? */
 444
 445done:
 446        mark_buffer_dirty_inode(bh, retval ? old_dir : new_dir);
 447        affs_brelse(bh);
 448        return retval;
 449}
 450
 451static int
 452affs_xrename(struct inode *old_dir, struct dentry *old_dentry,
 453             struct inode *new_dir, struct dentry *new_dentry)
 454{
 455
 456        struct super_block *sb = old_dir->i_sb;
 457        struct buffer_head *bh_old = NULL;
 458        struct buffer_head *bh_new = NULL;
 459        int retval;
 460
 461        bh_old = affs_bread(sb, d_inode(old_dentry)->i_ino);
 462        if (!bh_old)
 463                return -EIO;
 464
 465        bh_new = affs_bread(sb, d_inode(new_dentry)->i_ino);
 466        if (!bh_new) {
 467                affs_brelse(bh_old);
 468                return -EIO;
 469        }
 470
 471        /* Remove old header from its parent directory. */
 472        affs_lock_dir(old_dir);
 473        retval = affs_remove_hash(old_dir, bh_old);
 474        affs_unlock_dir(old_dir);
 475        if (retval)
 476                goto done;
 477
 478        /* Remove new header from its parent directory. */
 479        affs_lock_dir(new_dir);
 480        retval = affs_remove_hash(new_dir, bh_new);
 481        affs_unlock_dir(new_dir);
 482        if (retval)
 483                goto done;
 484
 485        /* Insert old into the new directory with the new name. */
 486        affs_copy_name(AFFS_TAIL(sb, bh_old)->name, new_dentry);
 487        affs_fix_checksum(sb, bh_old);
 488        affs_lock_dir(new_dir);
 489        retval = affs_insert_hash(new_dir, bh_old);
 490        affs_unlock_dir(new_dir);
 491
 492        /* Insert new into the old directory with the old name. */
 493        affs_copy_name(AFFS_TAIL(sb, bh_new)->name, old_dentry);
 494        affs_fix_checksum(sb, bh_new);
 495        affs_lock_dir(old_dir);
 496        retval = affs_insert_hash(old_dir, bh_new);
 497        affs_unlock_dir(old_dir);
 498done:
 499        mark_buffer_dirty_inode(bh_old, new_dir);
 500        mark_buffer_dirty_inode(bh_new, old_dir);
 501        affs_brelse(bh_old);
 502        affs_brelse(bh_new);
 503        return retval;
 504}
 505
 506int affs_rename2(struct user_namespace *mnt_userns, struct inode *old_dir,
 507                 struct dentry *old_dentry, struct inode *new_dir,
 508                 struct dentry *new_dentry, unsigned int flags)
 509{
 510
 511        if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
 512                return -EINVAL;
 513
 514        pr_debug("%s(old=%lu,\"%pd\" to new=%lu,\"%pd\")\n", __func__,
 515                 old_dir->i_ino, old_dentry, new_dir->i_ino, new_dentry);
 516
 517        if (flags & RENAME_EXCHANGE)
 518                return affs_xrename(old_dir, old_dentry, new_dir, new_dentry);
 519
 520        return affs_rename(old_dir, old_dentry, new_dir, new_dentry);
 521}
 522
 523static struct dentry *affs_get_parent(struct dentry *child)
 524{
 525        struct inode *parent;
 526        struct buffer_head *bh;
 527
 528        bh = affs_bread(child->d_sb, d_inode(child)->i_ino);
 529        if (!bh)
 530                return ERR_PTR(-EIO);
 531
 532        parent = affs_iget(child->d_sb,
 533                           be32_to_cpu(AFFS_TAIL(child->d_sb, bh)->parent));
 534        brelse(bh);
 535        if (IS_ERR(parent))
 536                return ERR_CAST(parent);
 537
 538        return d_obtain_alias(parent);
 539}
 540
 541static struct inode *affs_nfs_get_inode(struct super_block *sb, u64 ino,
 542                                        u32 generation)
 543{
 544        struct inode *inode;
 545
 546        if (!affs_validblock(sb, ino))
 547                return ERR_PTR(-ESTALE);
 548
 549        inode = affs_iget(sb, ino);
 550        if (IS_ERR(inode))
 551                return ERR_CAST(inode);
 552
 553        return inode;
 554}
 555
 556static struct dentry *affs_fh_to_dentry(struct super_block *sb, struct fid *fid,
 557                                        int fh_len, int fh_type)
 558{
 559        return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
 560                                    affs_nfs_get_inode);
 561}
 562
 563static struct dentry *affs_fh_to_parent(struct super_block *sb, struct fid *fid,
 564                                        int fh_len, int fh_type)
 565{
 566        return generic_fh_to_parent(sb, fid, fh_len, fh_type,
 567                                    affs_nfs_get_inode);
 568}
 569
 570const struct export_operations affs_export_ops = {
 571        .fh_to_dentry = affs_fh_to_dentry,
 572        .fh_to_parent = affs_fh_to_parent,
 573        .get_parent = affs_get_parent,
 574};
 575
 576const struct dentry_operations affs_dentry_operations = {
 577        .d_hash         = affs_hash_dentry,
 578        .d_compare      = affs_compare_dentry,
 579};
 580
 581const struct dentry_operations affs_intl_dentry_operations = {
 582        .d_hash         = affs_intl_hash_dentry,
 583        .d_compare      = affs_intl_compare_dentry,
 584};
 585