1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * linux/fs/affs/amigaffs.c 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * (c) 1996 Hans-Joachim Widmaier - Rewritten 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * (C) 1993 Ray Burr - Amiga FFS filesystem. 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * Please send bug reports to: hjw@zvw.de 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 12db39c167SDengChao #include <linux/math64.h> 139dffe569SJeff Layton #include <linux/iversion.h> 141da177e4SLinus Torvalds #include "affs.h" 151da177e4SLinus Torvalds 161da177e4SLinus Torvalds /* 171da177e4SLinus Torvalds * Functions for accessing Amiga-FFS structures. 181da177e4SLinus Torvalds */ 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds 211da177e4SLinus Torvalds /* Insert a header block bh into the directory dir 221da177e4SLinus Torvalds * caller must hold AFFS_DIR->i_hash_lock! 231da177e4SLinus Torvalds */ 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds int 261da177e4SLinus Torvalds affs_insert_hash(struct inode *dir, struct buffer_head *bh) 271da177e4SLinus Torvalds { 281da177e4SLinus Torvalds struct super_block *sb = dir->i_sb; 291da177e4SLinus Torvalds struct buffer_head *dir_bh; 301da177e4SLinus Torvalds u32 ino, hash_ino; 311da177e4SLinus Torvalds int offset; 321da177e4SLinus Torvalds 331da177e4SLinus Torvalds ino = bh->b_blocknr; 341da177e4SLinus Torvalds offset = affs_hash_name(sb, AFFS_TAIL(sb, bh)->name + 1, AFFS_TAIL(sb, bh)->name[0]); 351da177e4SLinus Torvalds 3608fe100dSGeert Uytterhoeven pr_debug("%s(dir=%lu, ino=%d)\n", __func__, dir->i_ino, ino); 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds dir_bh = affs_bread(sb, dir->i_ino); 391da177e4SLinus Torvalds if (!dir_bh) 401da177e4SLinus Torvalds return -EIO; 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds hash_ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[offset]); 431da177e4SLinus Torvalds while (hash_ino) { 441da177e4SLinus Torvalds affs_brelse(dir_bh); 451da177e4SLinus Torvalds dir_bh = affs_bread(sb, hash_ino); 461da177e4SLinus Torvalds if (!dir_bh) 471da177e4SLinus Torvalds return -EIO; 481da177e4SLinus Torvalds hash_ino = be32_to_cpu(AFFS_TAIL(sb, dir_bh)->hash_chain); 491da177e4SLinus Torvalds } 501da177e4SLinus Torvalds AFFS_TAIL(sb, bh)->parent = cpu_to_be32(dir->i_ino); 511da177e4SLinus Torvalds AFFS_TAIL(sb, bh)->hash_chain = 0; 521da177e4SLinus Torvalds affs_fix_checksum(sb, bh); 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds if (dir->i_ino == dir_bh->b_blocknr) 551da177e4SLinus Torvalds AFFS_HEAD(dir_bh)->table[offset] = cpu_to_be32(ino); 561da177e4SLinus Torvalds else 571da177e4SLinus Torvalds AFFS_TAIL(sb, dir_bh)->hash_chain = cpu_to_be32(ino); 581da177e4SLinus Torvalds 591da177e4SLinus Torvalds affs_adjust_checksum(dir_bh, ino); 601da177e4SLinus Torvalds mark_buffer_dirty_inode(dir_bh, dir); 611da177e4SLinus Torvalds affs_brelse(dir_bh); 621da177e4SLinus Torvalds 6302027d42SDeepa Dinamani dir->i_mtime = dir->i_ctime = current_time(dir); 649dffe569SJeff Layton inode_inc_iversion(dir); 651da177e4SLinus Torvalds mark_inode_dirty(dir); 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds return 0; 681da177e4SLinus Torvalds } 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds /* Remove a header block from its directory. 711da177e4SLinus Torvalds * caller must hold AFFS_DIR->i_hash_lock! 721da177e4SLinus Torvalds */ 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds int 751da177e4SLinus Torvalds affs_remove_hash(struct inode *dir, struct buffer_head *rem_bh) 761da177e4SLinus Torvalds { 771da177e4SLinus Torvalds struct super_block *sb; 781da177e4SLinus Torvalds struct buffer_head *bh; 791da177e4SLinus Torvalds u32 rem_ino, hash_ino; 801da177e4SLinus Torvalds __be32 ino; 811da177e4SLinus Torvalds int offset, retval; 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds sb = dir->i_sb; 841da177e4SLinus Torvalds rem_ino = rem_bh->b_blocknr; 851da177e4SLinus Torvalds offset = affs_hash_name(sb, AFFS_TAIL(sb, rem_bh)->name+1, AFFS_TAIL(sb, rem_bh)->name[0]); 8608fe100dSGeert Uytterhoeven pr_debug("%s(dir=%lu, ino=%d, hashval=%d)\n", __func__, dir->i_ino, 8708fe100dSGeert Uytterhoeven rem_ino, offset); 881da177e4SLinus Torvalds 891da177e4SLinus Torvalds bh = affs_bread(sb, dir->i_ino); 901da177e4SLinus Torvalds if (!bh) 911da177e4SLinus Torvalds return -EIO; 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds retval = -ENOENT; 941da177e4SLinus Torvalds hash_ino = be32_to_cpu(AFFS_HEAD(bh)->table[offset]); 951da177e4SLinus Torvalds while (hash_ino) { 961da177e4SLinus Torvalds if (hash_ino == rem_ino) { 971da177e4SLinus Torvalds ino = AFFS_TAIL(sb, rem_bh)->hash_chain; 981da177e4SLinus Torvalds if (dir->i_ino == bh->b_blocknr) 991da177e4SLinus Torvalds AFFS_HEAD(bh)->table[offset] = ino; 1001da177e4SLinus Torvalds else 1011da177e4SLinus Torvalds AFFS_TAIL(sb, bh)->hash_chain = ino; 1021da177e4SLinus Torvalds affs_adjust_checksum(bh, be32_to_cpu(ino) - hash_ino); 1031da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, dir); 1041da177e4SLinus Torvalds AFFS_TAIL(sb, rem_bh)->parent = 0; 1051da177e4SLinus Torvalds retval = 0; 1061da177e4SLinus Torvalds break; 1071da177e4SLinus Torvalds } 1081da177e4SLinus Torvalds affs_brelse(bh); 1091da177e4SLinus Torvalds bh = affs_bread(sb, hash_ino); 1101da177e4SLinus Torvalds if (!bh) 1111da177e4SLinus Torvalds return -EIO; 1121da177e4SLinus Torvalds hash_ino = be32_to_cpu(AFFS_TAIL(sb, bh)->hash_chain); 1131da177e4SLinus Torvalds } 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds affs_brelse(bh); 1161da177e4SLinus Torvalds 11702027d42SDeepa Dinamani dir->i_mtime = dir->i_ctime = current_time(dir); 1189dffe569SJeff Layton inode_inc_iversion(dir); 1191da177e4SLinus Torvalds mark_inode_dirty(dir); 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds return retval; 1221da177e4SLinus Torvalds } 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds static void 12512447c40SAl Viro affs_fix_dcache(struct inode *inode, u32 entry_ino) 1261da177e4SLinus Torvalds { 12712447c40SAl Viro struct dentry *dentry; 128873feea0SNick Piggin spin_lock(&inode->i_lock); 129946e51f2SAl Viro hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) { 1301da177e4SLinus Torvalds if (entry_ino == (u32)(long)dentry->d_fsdata) { 13112447c40SAl Viro dentry->d_fsdata = (void *)inode->i_ino; 1321da177e4SLinus Torvalds break; 1331da177e4SLinus Torvalds } 1341da177e4SLinus Torvalds } 135873feea0SNick Piggin spin_unlock(&inode->i_lock); 1361da177e4SLinus Torvalds } 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds /* Remove header from link chain */ 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds static int 1421da177e4SLinus Torvalds affs_remove_link(struct dentry *dentry) 1431da177e4SLinus Torvalds { 1442b0143b5SDavid Howells struct inode *dir, *inode = d_inode(dentry); 1451da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 1464709187eSFabian Frederick struct buffer_head *bh, *link_bh = NULL; 1471da177e4SLinus Torvalds u32 link_ino, ino; 1481da177e4SLinus Torvalds int retval; 1491da177e4SLinus Torvalds 1509606d9aaSFabian Frederick pr_debug("%s(key=%ld)\n", __func__, inode->i_ino); 1511da177e4SLinus Torvalds retval = -EIO; 1521da177e4SLinus Torvalds bh = affs_bread(sb, inode->i_ino); 1531da177e4SLinus Torvalds if (!bh) 1541da177e4SLinus Torvalds goto done; 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds link_ino = (u32)(long)dentry->d_fsdata; 1571da177e4SLinus Torvalds if (inode->i_ino == link_ino) { 1581da177e4SLinus Torvalds /* we can't remove the head of the link, as its blocknr is still used as ino, 1591da177e4SLinus Torvalds * so we remove the block of the first link instead. 1601da177e4SLinus Torvalds */ 1611da177e4SLinus Torvalds link_ino = be32_to_cpu(AFFS_TAIL(sb, bh)->link_chain); 1621da177e4SLinus Torvalds link_bh = affs_bread(sb, link_ino); 1631da177e4SLinus Torvalds if (!link_bh) 1641da177e4SLinus Torvalds goto done; 1651da177e4SLinus Torvalds 166210f8559SDavid Howells dir = affs_iget(sb, be32_to_cpu(AFFS_TAIL(sb, link_bh)->parent)); 167210f8559SDavid Howells if (IS_ERR(dir)) { 168210f8559SDavid Howells retval = PTR_ERR(dir); 1691da177e4SLinus Torvalds goto done; 170210f8559SDavid Howells } 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds affs_lock_dir(dir); 17312447c40SAl Viro /* 17412447c40SAl Viro * if there's a dentry for that block, make it 17512447c40SAl Viro * refer to inode itself. 17612447c40SAl Viro */ 17712447c40SAl Viro affs_fix_dcache(inode, link_ino); 1781da177e4SLinus Torvalds retval = affs_remove_hash(dir, link_bh); 179ec1ab0abSChristoph Hellwig if (retval) { 180ec1ab0abSChristoph Hellwig affs_unlock_dir(dir); 1811da177e4SLinus Torvalds goto done; 182ec1ab0abSChristoph Hellwig } 1831da177e4SLinus Torvalds mark_buffer_dirty_inode(link_bh, inode); 1841da177e4SLinus Torvalds 1851da177e4SLinus Torvalds memcpy(AFFS_TAIL(sb, bh)->name, AFFS_TAIL(sb, link_bh)->name, 32); 1861da177e4SLinus Torvalds retval = affs_insert_hash(dir, bh); 187ec1ab0abSChristoph Hellwig if (retval) { 188ec1ab0abSChristoph Hellwig affs_unlock_dir(dir); 1891da177e4SLinus Torvalds goto done; 190ec1ab0abSChristoph Hellwig } 1911da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 1921da177e4SLinus Torvalds 1931da177e4SLinus Torvalds affs_unlock_dir(dir); 1941da177e4SLinus Torvalds iput(dir); 1951da177e4SLinus Torvalds } else { 1961da177e4SLinus Torvalds link_bh = affs_bread(sb, link_ino); 1971da177e4SLinus Torvalds if (!link_bh) 1981da177e4SLinus Torvalds goto done; 1991da177e4SLinus Torvalds } 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds while ((ino = be32_to_cpu(AFFS_TAIL(sb, bh)->link_chain)) != 0) { 2021da177e4SLinus Torvalds if (ino == link_ino) { 2031da177e4SLinus Torvalds __be32 ino2 = AFFS_TAIL(sb, link_bh)->link_chain; 2041da177e4SLinus Torvalds AFFS_TAIL(sb, bh)->link_chain = ino2; 2051da177e4SLinus Torvalds affs_adjust_checksum(bh, be32_to_cpu(ino2) - link_ino); 2061da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 2071da177e4SLinus Torvalds retval = 0; 2081da177e4SLinus Torvalds /* Fix the link count, if bh is a normal header block without links */ 2091da177e4SLinus Torvalds switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) { 2101da177e4SLinus Torvalds case ST_LINKDIR: 2111da177e4SLinus Torvalds case ST_LINKFILE: 2121da177e4SLinus Torvalds break; 2131da177e4SLinus Torvalds default: 2141da177e4SLinus Torvalds if (!AFFS_TAIL(sb, bh)->link_chain) 215bfe86848SMiklos Szeredi set_nlink(inode, 1); 2161da177e4SLinus Torvalds } 2171da177e4SLinus Torvalds affs_free_block(sb, link_ino); 2181da177e4SLinus Torvalds goto done; 2191da177e4SLinus Torvalds } 2201da177e4SLinus Torvalds affs_brelse(bh); 2211da177e4SLinus Torvalds bh = affs_bread(sb, ino); 2221da177e4SLinus Torvalds if (!bh) 2231da177e4SLinus Torvalds goto done; 2241da177e4SLinus Torvalds } 2251da177e4SLinus Torvalds retval = -ENOENT; 2261da177e4SLinus Torvalds done: 2271da177e4SLinus Torvalds affs_brelse(link_bh); 2281da177e4SLinus Torvalds affs_brelse(bh); 2291da177e4SLinus Torvalds return retval; 2301da177e4SLinus Torvalds } 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds 2331da177e4SLinus Torvalds static int 2341da177e4SLinus Torvalds affs_empty_dir(struct inode *inode) 2351da177e4SLinus Torvalds { 2361da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 2371da177e4SLinus Torvalds struct buffer_head *bh; 2381da177e4SLinus Torvalds int retval, size; 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds retval = -EIO; 2411da177e4SLinus Torvalds bh = affs_bread(sb, inode->i_ino); 2421da177e4SLinus Torvalds if (!bh) 2431da177e4SLinus Torvalds goto done; 2441da177e4SLinus Torvalds 2451da177e4SLinus Torvalds retval = -ENOTEMPTY; 2461da177e4SLinus Torvalds for (size = AFFS_SB(sb)->s_hashsize - 1; size >= 0; size--) 2471da177e4SLinus Torvalds if (AFFS_HEAD(bh)->table[size]) 2481da177e4SLinus Torvalds goto not_empty; 2491da177e4SLinus Torvalds retval = 0; 2501da177e4SLinus Torvalds not_empty: 2511da177e4SLinus Torvalds affs_brelse(bh); 2521da177e4SLinus Torvalds done: 2531da177e4SLinus Torvalds return retval; 2541da177e4SLinus Torvalds } 2551da177e4SLinus Torvalds 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds /* Remove a filesystem object. If the object to be removed has 2581da177e4SLinus Torvalds * links to it, one of the links must be changed to inherit 2591da177e4SLinus Torvalds * the file or directory. As above, any inode will do. 2601da177e4SLinus Torvalds * The buffer will not be freed. If the header is a link, the 2611da177e4SLinus Torvalds * block will be marked as free. 2621da177e4SLinus Torvalds * This function returns a negative error number in case of 2631da177e4SLinus Torvalds * an error, else 0 if the inode is to be deleted or 1 if not. 2641da177e4SLinus Torvalds */ 2651da177e4SLinus Torvalds 2661da177e4SLinus Torvalds int 2671da177e4SLinus Torvalds affs_remove_header(struct dentry *dentry) 2681da177e4SLinus Torvalds { 2691da177e4SLinus Torvalds struct super_block *sb; 2701da177e4SLinus Torvalds struct inode *inode, *dir; 2711da177e4SLinus Torvalds struct buffer_head *bh = NULL; 2721da177e4SLinus Torvalds int retval; 2731da177e4SLinus Torvalds 2742b0143b5SDavid Howells dir = d_inode(dentry->d_parent); 2751da177e4SLinus Torvalds sb = dir->i_sb; 2761da177e4SLinus Torvalds 2771da177e4SLinus Torvalds retval = -ENOENT; 2782b0143b5SDavid Howells inode = d_inode(dentry); 2791da177e4SLinus Torvalds if (!inode) 2801da177e4SLinus Torvalds goto done; 2811da177e4SLinus Torvalds 2829606d9aaSFabian Frederick pr_debug("%s(key=%ld)\n", __func__, inode->i_ino); 2831da177e4SLinus Torvalds retval = -EIO; 2841da177e4SLinus Torvalds bh = affs_bread(sb, (u32)(long)dentry->d_fsdata); 2851da177e4SLinus Torvalds if (!bh) 2861da177e4SLinus Torvalds goto done; 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds affs_lock_link(inode); 2891da177e4SLinus Torvalds affs_lock_dir(dir); 2901da177e4SLinus Torvalds switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) { 2911da177e4SLinus Torvalds case ST_USERDIR: 2921da177e4SLinus Torvalds /* if we ever want to support links to dirs 2931da177e4SLinus Torvalds * i_hash_lock of the inode must only be 2941da177e4SLinus Torvalds * taken after some checks 2951da177e4SLinus Torvalds */ 2961da177e4SLinus Torvalds affs_lock_dir(inode); 2971da177e4SLinus Torvalds retval = affs_empty_dir(inode); 2981da177e4SLinus Torvalds affs_unlock_dir(inode); 2991da177e4SLinus Torvalds if (retval) 3001da177e4SLinus Torvalds goto done_unlock; 3011da177e4SLinus Torvalds break; 3021da177e4SLinus Torvalds default: 3031da177e4SLinus Torvalds break; 3041da177e4SLinus Torvalds } 3051da177e4SLinus Torvalds 3061da177e4SLinus Torvalds retval = affs_remove_hash(dir, bh); 3071da177e4SLinus Torvalds if (retval) 3081da177e4SLinus Torvalds goto done_unlock; 3091da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds affs_unlock_dir(dir); 3121da177e4SLinus Torvalds 3131da177e4SLinus Torvalds if (inode->i_nlink > 1) 3141da177e4SLinus Torvalds retval = affs_remove_link(dentry); 3151da177e4SLinus Torvalds else 3166d6b77f1SMiklos Szeredi clear_nlink(inode); 3171da177e4SLinus Torvalds affs_unlock_link(inode); 31802027d42SDeepa Dinamani inode->i_ctime = current_time(inode); 3191da177e4SLinus Torvalds mark_inode_dirty(inode); 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds done: 3221da177e4SLinus Torvalds affs_brelse(bh); 3231da177e4SLinus Torvalds return retval; 3241da177e4SLinus Torvalds 3251da177e4SLinus Torvalds done_unlock: 3261da177e4SLinus Torvalds affs_unlock_dir(dir); 3271da177e4SLinus Torvalds affs_unlock_link(inode); 3281da177e4SLinus Torvalds goto done; 3291da177e4SLinus Torvalds } 3301da177e4SLinus Torvalds 3311da177e4SLinus Torvalds /* Checksum a block, do various consistency checks and optionally return 3321da177e4SLinus Torvalds the blocks type number. DATA points to the block. If their pointers 3331da177e4SLinus Torvalds are non-null, *PTYPE and *STYPE are set to the primary and secondary 3341da177e4SLinus Torvalds block types respectively, *HASHSIZE is set to the size of the hashtable 3351da177e4SLinus Torvalds (which lets us calculate the block size). 3361da177e4SLinus Torvalds Returns non-zero if the block is not consistent. */ 3371da177e4SLinus Torvalds 3381da177e4SLinus Torvalds u32 3391da177e4SLinus Torvalds affs_checksum_block(struct super_block *sb, struct buffer_head *bh) 3401da177e4SLinus Torvalds { 3411da177e4SLinus Torvalds __be32 *ptr = (__be32 *)bh->b_data; 3421da177e4SLinus Torvalds u32 sum; 3431da177e4SLinus Torvalds int bsize; 3441da177e4SLinus Torvalds 3451da177e4SLinus Torvalds sum = 0; 3461da177e4SLinus Torvalds for (bsize = sb->s_blocksize / sizeof(__be32); bsize > 0; bsize--) 3471da177e4SLinus Torvalds sum += be32_to_cpu(*ptr++); 3481da177e4SLinus Torvalds return sum; 3491da177e4SLinus Torvalds } 3501da177e4SLinus Torvalds 3511da177e4SLinus Torvalds /* 3521da177e4SLinus Torvalds * Calculate the checksum of a disk block and store it 3531da177e4SLinus Torvalds * at the indicated position. 3541da177e4SLinus Torvalds */ 3551da177e4SLinus Torvalds 3561da177e4SLinus Torvalds void 3571da177e4SLinus Torvalds affs_fix_checksum(struct super_block *sb, struct buffer_head *bh) 3581da177e4SLinus Torvalds { 3591da177e4SLinus Torvalds int cnt = sb->s_blocksize / sizeof(__be32); 3601da177e4SLinus Torvalds __be32 *ptr = (__be32 *)bh->b_data; 3611da177e4SLinus Torvalds u32 checksum; 3621da177e4SLinus Torvalds __be32 *checksumptr; 3631da177e4SLinus Torvalds 3641da177e4SLinus Torvalds checksumptr = ptr + 5; 3651da177e4SLinus Torvalds *checksumptr = 0; 3661da177e4SLinus Torvalds for (checksum = 0; cnt > 0; ptr++, cnt--) 3671da177e4SLinus Torvalds checksum += be32_to_cpu(*ptr); 3681da177e4SLinus Torvalds *checksumptr = cpu_to_be32(-checksum); 3691da177e4SLinus Torvalds } 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds void 372c1618208SFabian Frederick affs_secs_to_datestamp(time64_t secs, struct affs_date *ds) 3731da177e4SLinus Torvalds { 3741da177e4SLinus Torvalds u32 days; 3751da177e4SLinus Torvalds u32 minute; 376db39c167SDengChao s32 rem; 3771da177e4SLinus Torvalds 378487b25bcSDeepa Dinamani secs -= sys_tz.tz_minuteswest * 60 + AFFS_EPOCH_DELTA; 3791da177e4SLinus Torvalds if (secs < 0) 3801da177e4SLinus Torvalds secs = 0; 381db39c167SDengChao days = div_s64_rem(secs, 86400, &rem); 382db39c167SDengChao minute = rem / 60; 383db39c167SDengChao rem -= minute * 60; 3841da177e4SLinus Torvalds 3851da177e4SLinus Torvalds ds->days = cpu_to_be32(days); 3861da177e4SLinus Torvalds ds->mins = cpu_to_be32(minute); 387db39c167SDengChao ds->ticks = cpu_to_be32(rem * 50); 3881da177e4SLinus Torvalds } 3891da177e4SLinus Torvalds 390a760b03dSAl Viro umode_t 391c1618208SFabian Frederick affs_prot_to_mode(u32 prot) 3921da177e4SLinus Torvalds { 393a760b03dSAl Viro umode_t mode = 0; 3941da177e4SLinus Torvalds 3951da177e4SLinus Torvalds if (!(prot & FIBF_NOWRITE)) 3961bafd6f1SFabian Frederick mode |= 0200; 3971da177e4SLinus Torvalds if (!(prot & FIBF_NOREAD)) 3981bafd6f1SFabian Frederick mode |= 0400; 3991da177e4SLinus Torvalds if (!(prot & FIBF_NOEXECUTE)) 4001bafd6f1SFabian Frederick mode |= 0100; 4011da177e4SLinus Torvalds if (prot & FIBF_GRP_WRITE) 4021bafd6f1SFabian Frederick mode |= 0020; 4031da177e4SLinus Torvalds if (prot & FIBF_GRP_READ) 4041bafd6f1SFabian Frederick mode |= 0040; 4051da177e4SLinus Torvalds if (prot & FIBF_GRP_EXECUTE) 4061bafd6f1SFabian Frederick mode |= 0010; 4071da177e4SLinus Torvalds if (prot & FIBF_OTR_WRITE) 4081bafd6f1SFabian Frederick mode |= 0002; 4091da177e4SLinus Torvalds if (prot & FIBF_OTR_READ) 4101bafd6f1SFabian Frederick mode |= 0004; 4111da177e4SLinus Torvalds if (prot & FIBF_OTR_EXECUTE) 4121bafd6f1SFabian Frederick mode |= 0001; 4131da177e4SLinus Torvalds 4141da177e4SLinus Torvalds return mode; 4151da177e4SLinus Torvalds } 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds void 418c1618208SFabian Frederick affs_mode_to_prot(struct inode *inode) 4191da177e4SLinus Torvalds { 4201da177e4SLinus Torvalds u32 prot = AFFS_I(inode)->i_protect; 421a760b03dSAl Viro umode_t mode = inode->i_mode; 4221da177e4SLinus Torvalds 423*d3a84a8dSMax Staudt /* 424*d3a84a8dSMax Staudt * First, clear all RWED bits for owner, group, other. 425*d3a84a8dSMax Staudt * Then, recalculate them afresh. 426*d3a84a8dSMax Staudt * 427*d3a84a8dSMax Staudt * We'll always clear the delete-inhibit bit for the owner, as that is 428*d3a84a8dSMax Staudt * the classic single-user mode AmigaOS protection bit and we need to 429*d3a84a8dSMax Staudt * stay compatible with all scenarios. 430*d3a84a8dSMax Staudt * 431*d3a84a8dSMax Staudt * Since multi-user AmigaOS is an extension, we'll only set the 432*d3a84a8dSMax Staudt * delete-allow bit if any of the other bits in the same user class 433*d3a84a8dSMax Staudt * (group/other) are used. 434*d3a84a8dSMax Staudt */ 435*d3a84a8dSMax Staudt prot &= ~(FIBF_NOEXECUTE | FIBF_NOREAD 436*d3a84a8dSMax Staudt | FIBF_NOWRITE | FIBF_NODELETE 437*d3a84a8dSMax Staudt | FIBF_GRP_EXECUTE | FIBF_GRP_READ 438*d3a84a8dSMax Staudt | FIBF_GRP_WRITE | FIBF_GRP_DELETE 439*d3a84a8dSMax Staudt | FIBF_OTR_EXECUTE | FIBF_OTR_READ 440*d3a84a8dSMax Staudt | FIBF_OTR_WRITE | FIBF_OTR_DELETE); 441*d3a84a8dSMax Staudt 442*d3a84a8dSMax Staudt /* Classic single-user AmigaOS flags. These are inverted. */ 4431bafd6f1SFabian Frederick if (!(mode & 0100)) 4441da177e4SLinus Torvalds prot |= FIBF_NOEXECUTE; 4451bafd6f1SFabian Frederick if (!(mode & 0400)) 4461da177e4SLinus Torvalds prot |= FIBF_NOREAD; 4471bafd6f1SFabian Frederick if (!(mode & 0200)) 4481da177e4SLinus Torvalds prot |= FIBF_NOWRITE; 449*d3a84a8dSMax Staudt 450*d3a84a8dSMax Staudt /* Multi-user extended flags. Not inverted. */ 4511bafd6f1SFabian Frederick if (mode & 0010) 4521da177e4SLinus Torvalds prot |= FIBF_GRP_EXECUTE; 4531bafd6f1SFabian Frederick if (mode & 0040) 4541da177e4SLinus Torvalds prot |= FIBF_GRP_READ; 4551bafd6f1SFabian Frederick if (mode & 0020) 4561da177e4SLinus Torvalds prot |= FIBF_GRP_WRITE; 457*d3a84a8dSMax Staudt if (mode & 0070) 458*d3a84a8dSMax Staudt prot |= FIBF_GRP_DELETE; 459*d3a84a8dSMax Staudt 4601bafd6f1SFabian Frederick if (mode & 0001) 4611da177e4SLinus Torvalds prot |= FIBF_OTR_EXECUTE; 4621bafd6f1SFabian Frederick if (mode & 0004) 4631da177e4SLinus Torvalds prot |= FIBF_OTR_READ; 4641bafd6f1SFabian Frederick if (mode & 0002) 4651da177e4SLinus Torvalds prot |= FIBF_OTR_WRITE; 466*d3a84a8dSMax Staudt if (mode & 0007) 467*d3a84a8dSMax Staudt prot |= FIBF_OTR_DELETE; 4681da177e4SLinus Torvalds 4691da177e4SLinus Torvalds AFFS_I(inode)->i_protect = prot; 4701da177e4SLinus Torvalds } 4711da177e4SLinus Torvalds 4721da177e4SLinus Torvalds void 4731da177e4SLinus Torvalds affs_error(struct super_block *sb, const char *function, const char *fmt, ...) 4741da177e4SLinus Torvalds { 4751ee54b09SFabian Frederick struct va_format vaf; 4761da177e4SLinus Torvalds va_list args; 4771da177e4SLinus Torvalds 4781da177e4SLinus Torvalds va_start(args, fmt); 4791ee54b09SFabian Frederick vaf.fmt = fmt; 4801ee54b09SFabian Frederick vaf.va = &args; 4811ee54b09SFabian Frederick pr_crit("error (device %s): %s(): %pV\n", sb->s_id, function, &vaf); 482bc98a42cSDavid Howells if (!sb_rdonly(sb)) 4830158de12SFabian Frederick pr_warn("Remounting filesystem read-only\n"); 4841751e8a6SLinus Torvalds sb->s_flags |= SB_RDONLY; 4851ee54b09SFabian Frederick va_end(args); 4861da177e4SLinus Torvalds } 4871da177e4SLinus Torvalds 4881da177e4SLinus Torvalds void 4891da177e4SLinus Torvalds affs_warning(struct super_block *sb, const char *function, const char *fmt, ...) 4901da177e4SLinus Torvalds { 4911ee54b09SFabian Frederick struct va_format vaf; 4921da177e4SLinus Torvalds va_list args; 4931da177e4SLinus Torvalds 4941da177e4SLinus Torvalds va_start(args, fmt); 4951ee54b09SFabian Frederick vaf.fmt = fmt; 4961ee54b09SFabian Frederick vaf.va = &args; 4971ee54b09SFabian Frederick pr_warn("(device %s): %s(): %pV\n", sb->s_id, function, &vaf); 4981da177e4SLinus Torvalds va_end(args); 4991da177e4SLinus Torvalds } 5001da177e4SLinus Torvalds 5018ca57722SFabian Frederick bool 5028ca57722SFabian Frederick affs_nofilenametruncate(const struct dentry *dentry) 5038ca57722SFabian Frederick { 504e0b3f595SAl Viro return affs_test_opt(AFFS_SB(dentry->d_sb)->s_flags, SF_NO_TRUNCATE); 5058ca57722SFabian Frederick } 5068ca57722SFabian Frederick 5071da177e4SLinus Torvalds /* Check if the name is valid for a affs object. */ 5081da177e4SLinus Torvalds 5091da177e4SLinus Torvalds int 5108ca57722SFabian Frederick affs_check_name(const unsigned char *name, int len, bool notruncate) 5111da177e4SLinus Torvalds { 5121da177e4SLinus Torvalds int i; 5131da177e4SLinus Torvalds 514f157853eSFabian Frederick if (len > AFFSNAMEMAX) { 5158ca57722SFabian Frederick if (notruncate) 5161da177e4SLinus Torvalds return -ENAMETOOLONG; 517f157853eSFabian Frederick len = AFFSNAMEMAX; 5188ca57722SFabian Frederick } 5191da177e4SLinus Torvalds for (i = 0; i < len; i++) { 5201da177e4SLinus Torvalds if (name[i] < ' ' || name[i] == ':' 5211da177e4SLinus Torvalds || (name[i] > 0x7e && name[i] < 0xa0)) 5221da177e4SLinus Torvalds return -EINVAL; 5231da177e4SLinus Torvalds } 5241da177e4SLinus Torvalds 5251da177e4SLinus Torvalds return 0; 5261da177e4SLinus Torvalds } 5271da177e4SLinus Torvalds 5281da177e4SLinus Torvalds /* This function copies name to bstr, with at most 30 5291da177e4SLinus Torvalds * characters length. The bstr will be prepended by 5301da177e4SLinus Torvalds * a length byte. 5311da177e4SLinus Torvalds * NOTE: The name will must be already checked by 5321da177e4SLinus Torvalds * affs_check_name()! 5331da177e4SLinus Torvalds */ 5341da177e4SLinus Torvalds 5351da177e4SLinus Torvalds int 5361da177e4SLinus Torvalds affs_copy_name(unsigned char *bstr, struct dentry *dentry) 5371da177e4SLinus Torvalds { 538f157853eSFabian Frederick u32 len = min(dentry->d_name.len, AFFSNAMEMAX); 5391da177e4SLinus Torvalds 5401da177e4SLinus Torvalds *bstr++ = len; 5411da177e4SLinus Torvalds memcpy(bstr, dentry->d_name.name, len); 5421da177e4SLinus Torvalds return len; 5431da177e4SLinus Torvalds } 544