linux/fs/affs/amigaffs.c
<<
>>
Prefs
   1/*
   2 *  linux/fs/affs/amigaffs.c
   3 *
   4 *  (c) 1996  Hans-Joachim Widmaier - Rewritten
   5 *
   6 *  (C) 1993  Ray Burr - Amiga FFS filesystem.
   7 *
   8 *  Please send bug reports to: hjw@zvw.de
   9 */
  10
  11#include <linux/math64.h>
  12#include "affs.h"
  13
  14/*
  15 * Functions for accessing Amiga-FFS structures.
  16 */
  17
  18
  19/* Insert a header block bh into the directory dir
  20 * caller must hold AFFS_DIR->i_hash_lock!
  21 */
  22
  23int
  24affs_insert_hash(struct inode *dir, struct buffer_head *bh)
  25{
  26        struct super_block *sb = dir->i_sb;
  27        struct buffer_head *dir_bh;
  28        u32 ino, hash_ino;
  29        int offset;
  30
  31        ino = bh->b_blocknr;
  32        offset = affs_hash_name(sb, AFFS_TAIL(sb, bh)->name + 1, AFFS_TAIL(sb, bh)->name[0]);
  33
  34        pr_debug("%s(dir=%lu, ino=%d)\n", __func__, dir->i_ino, ino);
  35
  36        dir_bh = affs_bread(sb, dir->i_ino);
  37        if (!dir_bh)
  38                return -EIO;
  39
  40        hash_ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[offset]);
  41        while (hash_ino) {
  42                affs_brelse(dir_bh);
  43                dir_bh = affs_bread(sb, hash_ino);
  44                if (!dir_bh)
  45                        return -EIO;
  46                hash_ino = be32_to_cpu(AFFS_TAIL(sb, dir_bh)->hash_chain);
  47        }
  48        AFFS_TAIL(sb, bh)->parent = cpu_to_be32(dir->i_ino);
  49        AFFS_TAIL(sb, bh)->hash_chain = 0;
  50        affs_fix_checksum(sb, bh);
  51
  52        if (dir->i_ino == dir_bh->b_blocknr)
  53                AFFS_HEAD(dir_bh)->table[offset] = cpu_to_be32(ino);
  54        else
  55                AFFS_TAIL(sb, dir_bh)->hash_chain = cpu_to_be32(ino);
  56
  57        affs_adjust_checksum(dir_bh, ino);
  58        mark_buffer_dirty_inode(dir_bh, dir);
  59        affs_brelse(dir_bh);
  60
  61        dir->i_mtime = dir->i_ctime = current_time(dir);
  62        dir->i_version++;
  63        mark_inode_dirty(dir);
  64
  65        return 0;
  66}
  67
  68/* Remove a header block from its directory.
  69 * caller must hold AFFS_DIR->i_hash_lock!
  70 */
  71
  72int
  73affs_remove_hash(struct inode *dir, struct buffer_head *rem_bh)
  74{
  75        struct super_block *sb;
  76        struct buffer_head *bh;
  77        u32 rem_ino, hash_ino;
  78        __be32 ino;
  79        int offset, retval;
  80
  81        sb = dir->i_sb;
  82        rem_ino = rem_bh->b_blocknr;
  83        offset = affs_hash_name(sb, AFFS_TAIL(sb, rem_bh)->name+1, AFFS_TAIL(sb, rem_bh)->name[0]);
  84        pr_debug("%s(dir=%lu, ino=%d, hashval=%d)\n", __func__, dir->i_ino,
  85                 rem_ino, offset);
  86
  87        bh = affs_bread(sb, dir->i_ino);
  88        if (!bh)
  89                return -EIO;
  90
  91        retval = -ENOENT;
  92        hash_ino = be32_to_cpu(AFFS_HEAD(bh)->table[offset]);
  93        while (hash_ino) {
  94                if (hash_ino == rem_ino) {
  95                        ino = AFFS_TAIL(sb, rem_bh)->hash_chain;
  96                        if (dir->i_ino == bh->b_blocknr)
  97                                AFFS_HEAD(bh)->table[offset] = ino;
  98                        else
  99                                AFFS_TAIL(sb, bh)->hash_chain = ino;
 100                        affs_adjust_checksum(bh, be32_to_cpu(ino) - hash_ino);
 101                        mark_buffer_dirty_inode(bh, dir);
 102                        AFFS_TAIL(sb, rem_bh)->parent = 0;
 103                        retval = 0;
 104                        break;
 105                }
 106                affs_brelse(bh);
 107                bh = affs_bread(sb, hash_ino);
 108                if (!bh)
 109                        return -EIO;
 110                hash_ino = be32_to_cpu(AFFS_TAIL(sb, bh)->hash_chain);
 111        }
 112
 113        affs_brelse(bh);
 114
 115        dir->i_mtime = dir->i_ctime = current_time(dir);
 116        dir->i_version++;
 117        mark_inode_dirty(dir);
 118
 119        return retval;
 120}
 121
 122static void
 123affs_fix_dcache(struct inode *inode, u32 entry_ino)
 124{
 125        struct dentry *dentry;
 126        spin_lock(&inode->i_lock);
 127        hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
 128                if (entry_ino == (u32)(long)dentry->d_fsdata) {
 129                        dentry->d_fsdata = (void *)inode->i_ino;
 130                        break;
 131                }
 132        }
 133        spin_unlock(&inode->i_lock);
 134}
 135
 136
 137/* Remove header from link chain */
 138
 139static int
 140affs_remove_link(struct dentry *dentry)
 141{
 142        struct inode *dir, *inode = d_inode(dentry);
 143        struct super_block *sb = inode->i_sb;
 144        struct buffer_head *bh, *link_bh = NULL;
 145        u32 link_ino, ino;
 146        int retval;
 147
 148        pr_debug("%s(key=%ld)\n", __func__, inode->i_ino);
 149        retval = -EIO;
 150        bh = affs_bread(sb, inode->i_ino);
 151        if (!bh)
 152                goto done;
 153
 154        link_ino = (u32)(long)dentry->d_fsdata;
 155        if (inode->i_ino == link_ino) {
 156                /* we can't remove the head of the link, as its blocknr is still used as ino,
 157                 * so we remove the block of the first link instead.
 158                 */ 
 159                link_ino = be32_to_cpu(AFFS_TAIL(sb, bh)->link_chain);
 160                link_bh = affs_bread(sb, link_ino);
 161                if (!link_bh)
 162                        goto done;
 163
 164                dir = affs_iget(sb, be32_to_cpu(AFFS_TAIL(sb, link_bh)->parent));
 165                if (IS_ERR(dir)) {
 166                        retval = PTR_ERR(dir);
 167                        goto done;
 168                }
 169
 170                affs_lock_dir(dir);
 171                /*
 172                 * if there's a dentry for that block, make it
 173                 * refer to inode itself.
 174                 */
 175                affs_fix_dcache(inode, link_ino);
 176                retval = affs_remove_hash(dir, link_bh);
 177                if (retval) {
 178                        affs_unlock_dir(dir);
 179                        goto done;
 180                }
 181                mark_buffer_dirty_inode(link_bh, inode);
 182
 183                memcpy(AFFS_TAIL(sb, bh)->name, AFFS_TAIL(sb, link_bh)->name, 32);
 184                retval = affs_insert_hash(dir, bh);
 185                if (retval) {
 186                        affs_unlock_dir(dir);
 187                        goto done;
 188                }
 189                mark_buffer_dirty_inode(bh, inode);
 190
 191                affs_unlock_dir(dir);
 192                iput(dir);
 193        } else {
 194                link_bh = affs_bread(sb, link_ino);
 195                if (!link_bh)
 196                        goto done;
 197        }
 198
 199        while ((ino = be32_to_cpu(AFFS_TAIL(sb, bh)->link_chain)) != 0) {
 200                if (ino == link_ino) {
 201                        __be32 ino2 = AFFS_TAIL(sb, link_bh)->link_chain;
 202                        AFFS_TAIL(sb, bh)->link_chain = ino2;
 203                        affs_adjust_checksum(bh, be32_to_cpu(ino2) - link_ino);
 204                        mark_buffer_dirty_inode(bh, inode);
 205                        retval = 0;
 206                        /* Fix the link count, if bh is a normal header block without links */
 207                        switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
 208                        case ST_LINKDIR:
 209                        case ST_LINKFILE:
 210                                break;
 211                        default:
 212                                if (!AFFS_TAIL(sb, bh)->link_chain)
 213                                        set_nlink(inode, 1);
 214                        }
 215                        affs_free_block(sb, link_ino);
 216                        goto done;
 217                }
 218                affs_brelse(bh);
 219                bh = affs_bread(sb, ino);
 220                if (!bh)
 221                        goto done;
 222        }
 223        retval = -ENOENT;
 224done:
 225        affs_brelse(link_bh);
 226        affs_brelse(bh);
 227        return retval;
 228}
 229
 230
 231static int
 232affs_empty_dir(struct inode *inode)
 233{
 234        struct super_block *sb = inode->i_sb;
 235        struct buffer_head *bh;
 236        int retval, size;
 237
 238        retval = -EIO;
 239        bh = affs_bread(sb, inode->i_ino);
 240        if (!bh)
 241                goto done;
 242
 243        retval = -ENOTEMPTY;
 244        for (size = AFFS_SB(sb)->s_hashsize - 1; size >= 0; size--)
 245                if (AFFS_HEAD(bh)->table[size])
 246                        goto not_empty;
 247        retval = 0;
 248not_empty:
 249        affs_brelse(bh);
 250done:
 251        return retval;
 252}
 253
 254
 255/* Remove a filesystem object. If the object to be removed has
 256 * links to it, one of the links must be changed to inherit
 257 * the file or directory. As above, any inode will do.
 258 * The buffer will not be freed. If the header is a link, the
 259 * block will be marked as free.
 260 * This function returns a negative error number in case of
 261 * an error, else 0 if the inode is to be deleted or 1 if not.
 262 */
 263
 264int
 265affs_remove_header(struct dentry *dentry)
 266{
 267        struct super_block *sb;
 268        struct inode *inode, *dir;
 269        struct buffer_head *bh = NULL;
 270        int retval;
 271
 272        dir = d_inode(dentry->d_parent);
 273        sb = dir->i_sb;
 274
 275        retval = -ENOENT;
 276        inode = d_inode(dentry);
 277        if (!inode)
 278                goto done;
 279
 280        pr_debug("%s(key=%ld)\n", __func__, inode->i_ino);
 281        retval = -EIO;
 282        bh = affs_bread(sb, (u32)(long)dentry->d_fsdata);
 283        if (!bh)
 284                goto done;
 285
 286        affs_lock_link(inode);
 287        affs_lock_dir(dir);
 288        switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
 289        case ST_USERDIR:
 290                /* if we ever want to support links to dirs
 291                 * i_hash_lock of the inode must only be
 292                 * taken after some checks
 293                 */
 294                affs_lock_dir(inode);
 295                retval = affs_empty_dir(inode);
 296                affs_unlock_dir(inode);
 297                if (retval)
 298                        goto done_unlock;
 299                break;
 300        default:
 301                break;
 302        }
 303
 304        retval = affs_remove_hash(dir, bh);
 305        if (retval)
 306                goto done_unlock;
 307        mark_buffer_dirty_inode(bh, inode);
 308
 309        affs_unlock_dir(dir);
 310
 311        if (inode->i_nlink > 1)
 312                retval = affs_remove_link(dentry);
 313        else
 314                clear_nlink(inode);
 315        affs_unlock_link(inode);
 316        inode->i_ctime = current_time(inode);
 317        mark_inode_dirty(inode);
 318
 319done:
 320        affs_brelse(bh);
 321        return retval;
 322
 323done_unlock:
 324        affs_unlock_dir(dir);
 325        affs_unlock_link(inode);
 326        goto done;
 327}
 328
 329/* Checksum a block, do various consistency checks and optionally return
 330   the blocks type number.  DATA points to the block.  If their pointers
 331   are non-null, *PTYPE and *STYPE are set to the primary and secondary
 332   block types respectively, *HASHSIZE is set to the size of the hashtable
 333   (which lets us calculate the block size).
 334   Returns non-zero if the block is not consistent. */
 335
 336u32
 337affs_checksum_block(struct super_block *sb, struct buffer_head *bh)
 338{
 339        __be32 *ptr = (__be32 *)bh->b_data;
 340        u32 sum;
 341        int bsize;
 342
 343        sum = 0;
 344        for (bsize = sb->s_blocksize / sizeof(__be32); bsize > 0; bsize--)
 345                sum += be32_to_cpu(*ptr++);
 346        return sum;
 347}
 348
 349/*
 350 * Calculate the checksum of a disk block and store it
 351 * at the indicated position.
 352 */
 353
 354void
 355affs_fix_checksum(struct super_block *sb, struct buffer_head *bh)
 356{
 357        int cnt = sb->s_blocksize / sizeof(__be32);
 358        __be32 *ptr = (__be32 *)bh->b_data;
 359        u32 checksum;
 360        __be32 *checksumptr;
 361
 362        checksumptr = ptr + 5;
 363        *checksumptr = 0;
 364        for (checksum = 0; cnt > 0; ptr++, cnt--)
 365                checksum += be32_to_cpu(*ptr);
 366        *checksumptr = cpu_to_be32(-checksum);
 367}
 368
 369void
 370secs_to_datestamp(time64_t secs, struct affs_date *ds)
 371{
 372        u32      days;
 373        u32      minute;
 374        s32      rem;
 375
 376        secs -= sys_tz.tz_minuteswest * 60 + ((8 * 365 + 2) * 24 * 60 * 60);
 377        if (secs < 0)
 378                secs = 0;
 379        days    = div_s64_rem(secs, 86400, &rem);
 380        minute  = rem / 60;
 381        rem    -= minute * 60;
 382
 383        ds->days = cpu_to_be32(days);
 384        ds->mins = cpu_to_be32(minute);
 385        ds->ticks = cpu_to_be32(rem * 50);
 386}
 387
 388umode_t
 389prot_to_mode(u32 prot)
 390{
 391        umode_t mode = 0;
 392
 393        if (!(prot & FIBF_NOWRITE))
 394                mode |= S_IWUSR;
 395        if (!(prot & FIBF_NOREAD))
 396                mode |= S_IRUSR;
 397        if (!(prot & FIBF_NOEXECUTE))
 398                mode |= S_IXUSR;
 399        if (prot & FIBF_GRP_WRITE)
 400                mode |= S_IWGRP;
 401        if (prot & FIBF_GRP_READ)
 402                mode |= S_IRGRP;
 403        if (prot & FIBF_GRP_EXECUTE)
 404                mode |= S_IXGRP;
 405        if (prot & FIBF_OTR_WRITE)
 406                mode |= S_IWOTH;
 407        if (prot & FIBF_OTR_READ)
 408                mode |= S_IROTH;
 409        if (prot & FIBF_OTR_EXECUTE)
 410                mode |= S_IXOTH;
 411
 412        return mode;
 413}
 414
 415void
 416mode_to_prot(struct inode *inode)
 417{
 418        u32 prot = AFFS_I(inode)->i_protect;
 419        umode_t mode = inode->i_mode;
 420
 421        if (!(mode & S_IXUSR))
 422                prot |= FIBF_NOEXECUTE;
 423        if (!(mode & S_IRUSR))
 424                prot |= FIBF_NOREAD;
 425        if (!(mode & S_IWUSR))
 426                prot |= FIBF_NOWRITE;
 427        if (mode & S_IXGRP)
 428                prot |= FIBF_GRP_EXECUTE;
 429        if (mode & S_IRGRP)
 430                prot |= FIBF_GRP_READ;
 431        if (mode & S_IWGRP)
 432                prot |= FIBF_GRP_WRITE;
 433        if (mode & S_IXOTH)
 434                prot |= FIBF_OTR_EXECUTE;
 435        if (mode & S_IROTH)
 436                prot |= FIBF_OTR_READ;
 437        if (mode & S_IWOTH)
 438                prot |= FIBF_OTR_WRITE;
 439
 440        AFFS_I(inode)->i_protect = prot;
 441}
 442
 443void
 444affs_error(struct super_block *sb, const char *function, const char *fmt, ...)
 445{
 446        struct va_format vaf;
 447        va_list args;
 448
 449        va_start(args, fmt);
 450        vaf.fmt = fmt;
 451        vaf.va = &args;
 452        pr_crit("error (device %s): %s(): %pV\n", sb->s_id, function, &vaf);
 453        if (!(sb->s_flags & MS_RDONLY))
 454                pr_warn("Remounting filesystem read-only\n");
 455        sb->s_flags |= MS_RDONLY;
 456        va_end(args);
 457}
 458
 459void
 460affs_warning(struct super_block *sb, const char *function, const char *fmt, ...)
 461{
 462        struct va_format vaf;
 463        va_list args;
 464
 465        va_start(args, fmt);
 466        vaf.fmt = fmt;
 467        vaf.va = &args;
 468        pr_warn("(device %s): %s(): %pV\n", sb->s_id, function, &vaf);
 469        va_end(args);
 470}
 471
 472bool
 473affs_nofilenametruncate(const struct dentry *dentry)
 474{
 475        return affs_test_opt(AFFS_SB(dentry->d_sb)->s_flags, SF_NO_TRUNCATE);
 476}
 477
 478/* Check if the name is valid for a affs object. */
 479
 480int
 481affs_check_name(const unsigned char *name, int len, bool notruncate)
 482{
 483        int      i;
 484
 485        if (len > AFFSNAMEMAX) {
 486                if (notruncate)
 487                        return -ENAMETOOLONG;
 488                len = AFFSNAMEMAX;
 489        }
 490        for (i = 0; i < len; i++) {
 491                if (name[i] < ' ' || name[i] == ':'
 492                    || (name[i] > 0x7e && name[i] < 0xa0))
 493                        return -EINVAL;
 494        }
 495
 496        return 0;
 497}
 498
 499/* This function copies name to bstr, with at most 30
 500 * characters length. The bstr will be prepended by
 501 * a length byte.
 502 * NOTE: The name will must be already checked by
 503 *       affs_check_name()!
 504 */
 505
 506int
 507affs_copy_name(unsigned char *bstr, struct dentry *dentry)
 508{
 509        u32 len = min(dentry->d_name.len, AFFSNAMEMAX);
 510
 511        *bstr++ = len;
 512        memcpy(bstr, dentry->d_name.name, len);
 513        return len;
 514}
 515