11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/fs/affs/amigaffs.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * (c) 1996 Hans-Joachim Widmaier - Rewritten 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * (C) 1993 Ray Burr - Amiga FFS filesystem. 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Please send bug reports to: hjw@zvw.de 91da177e4SLinus Torvalds */ 101da177e4SLinus Torvalds 11db39c167SDengChao #include <linux/math64.h> 121da177e4SLinus Torvalds #include "affs.h" 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds /* 151da177e4SLinus Torvalds * Functions for accessing Amiga-FFS structures. 161da177e4SLinus Torvalds */ 171da177e4SLinus Torvalds 181da177e4SLinus Torvalds 191da177e4SLinus Torvalds /* Insert a header block bh into the directory dir 201da177e4SLinus Torvalds * caller must hold AFFS_DIR->i_hash_lock! 211da177e4SLinus Torvalds */ 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds int 241da177e4SLinus Torvalds affs_insert_hash(struct inode *dir, struct buffer_head *bh) 251da177e4SLinus Torvalds { 261da177e4SLinus Torvalds struct super_block *sb = dir->i_sb; 271da177e4SLinus Torvalds struct buffer_head *dir_bh; 281da177e4SLinus Torvalds u32 ino, hash_ino; 291da177e4SLinus Torvalds int offset; 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds ino = bh->b_blocknr; 321da177e4SLinus Torvalds offset = affs_hash_name(sb, AFFS_TAIL(sb, bh)->name + 1, AFFS_TAIL(sb, bh)->name[0]); 331da177e4SLinus Torvalds 3408fe100dSGeert Uytterhoeven pr_debug("%s(dir=%lu, ino=%d)\n", __func__, dir->i_ino, ino); 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds dir_bh = affs_bread(sb, dir->i_ino); 371da177e4SLinus Torvalds if (!dir_bh) 381da177e4SLinus Torvalds return -EIO; 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds hash_ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[offset]); 411da177e4SLinus Torvalds while (hash_ino) { 421da177e4SLinus Torvalds affs_brelse(dir_bh); 431da177e4SLinus Torvalds dir_bh = affs_bread(sb, hash_ino); 441da177e4SLinus Torvalds if (!dir_bh) 451da177e4SLinus Torvalds return -EIO; 461da177e4SLinus Torvalds hash_ino = be32_to_cpu(AFFS_TAIL(sb, dir_bh)->hash_chain); 471da177e4SLinus Torvalds } 481da177e4SLinus Torvalds AFFS_TAIL(sb, bh)->parent = cpu_to_be32(dir->i_ino); 491da177e4SLinus Torvalds AFFS_TAIL(sb, bh)->hash_chain = 0; 501da177e4SLinus Torvalds affs_fix_checksum(sb, bh); 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds if (dir->i_ino == dir_bh->b_blocknr) 531da177e4SLinus Torvalds AFFS_HEAD(dir_bh)->table[offset] = cpu_to_be32(ino); 541da177e4SLinus Torvalds else 551da177e4SLinus Torvalds AFFS_TAIL(sb, dir_bh)->hash_chain = cpu_to_be32(ino); 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds affs_adjust_checksum(dir_bh, ino); 581da177e4SLinus Torvalds mark_buffer_dirty_inode(dir_bh, dir); 591da177e4SLinus Torvalds affs_brelse(dir_bh); 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; 621da177e4SLinus Torvalds dir->i_version++; 631da177e4SLinus Torvalds mark_inode_dirty(dir); 641da177e4SLinus Torvalds 651da177e4SLinus Torvalds return 0; 661da177e4SLinus Torvalds } 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds /* Remove a header block from its directory. 691da177e4SLinus Torvalds * caller must hold AFFS_DIR->i_hash_lock! 701da177e4SLinus Torvalds */ 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds int 731da177e4SLinus Torvalds affs_remove_hash(struct inode *dir, struct buffer_head *rem_bh) 741da177e4SLinus Torvalds { 751da177e4SLinus Torvalds struct super_block *sb; 761da177e4SLinus Torvalds struct buffer_head *bh; 771da177e4SLinus Torvalds u32 rem_ino, hash_ino; 781da177e4SLinus Torvalds __be32 ino; 791da177e4SLinus Torvalds int offset, retval; 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds sb = dir->i_sb; 821da177e4SLinus Torvalds rem_ino = rem_bh->b_blocknr; 831da177e4SLinus Torvalds offset = affs_hash_name(sb, AFFS_TAIL(sb, rem_bh)->name+1, AFFS_TAIL(sb, rem_bh)->name[0]); 8408fe100dSGeert Uytterhoeven pr_debug("%s(dir=%lu, ino=%d, hashval=%d)\n", __func__, dir->i_ino, 8508fe100dSGeert Uytterhoeven rem_ino, offset); 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds bh = affs_bread(sb, dir->i_ino); 881da177e4SLinus Torvalds if (!bh) 891da177e4SLinus Torvalds return -EIO; 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds retval = -ENOENT; 921da177e4SLinus Torvalds hash_ino = be32_to_cpu(AFFS_HEAD(bh)->table[offset]); 931da177e4SLinus Torvalds while (hash_ino) { 941da177e4SLinus Torvalds if (hash_ino == rem_ino) { 951da177e4SLinus Torvalds ino = AFFS_TAIL(sb, rem_bh)->hash_chain; 961da177e4SLinus Torvalds if (dir->i_ino == bh->b_blocknr) 971da177e4SLinus Torvalds AFFS_HEAD(bh)->table[offset] = ino; 981da177e4SLinus Torvalds else 991da177e4SLinus Torvalds AFFS_TAIL(sb, bh)->hash_chain = ino; 1001da177e4SLinus Torvalds affs_adjust_checksum(bh, be32_to_cpu(ino) - hash_ino); 1011da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, dir); 1021da177e4SLinus Torvalds AFFS_TAIL(sb, rem_bh)->parent = 0; 1031da177e4SLinus Torvalds retval = 0; 1041da177e4SLinus Torvalds break; 1051da177e4SLinus Torvalds } 1061da177e4SLinus Torvalds affs_brelse(bh); 1071da177e4SLinus Torvalds bh = affs_bread(sb, hash_ino); 1081da177e4SLinus Torvalds if (!bh) 1091da177e4SLinus Torvalds return -EIO; 1101da177e4SLinus Torvalds hash_ino = be32_to_cpu(AFFS_TAIL(sb, bh)->hash_chain); 1111da177e4SLinus Torvalds } 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds affs_brelse(bh); 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; 1161da177e4SLinus Torvalds dir->i_version++; 1171da177e4SLinus Torvalds mark_inode_dirty(dir); 1181da177e4SLinus Torvalds 1191da177e4SLinus Torvalds return retval; 1201da177e4SLinus Torvalds } 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds static void 12312447c40SAl Viro affs_fix_dcache(struct inode *inode, u32 entry_ino) 1241da177e4SLinus Torvalds { 12512447c40SAl Viro struct dentry *dentry; 126873feea0SNick Piggin spin_lock(&inode->i_lock); 127946e51f2SAl Viro hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) { 1281da177e4SLinus Torvalds if (entry_ino == (u32)(long)dentry->d_fsdata) { 12912447c40SAl Viro dentry->d_fsdata = (void *)inode->i_ino; 1301da177e4SLinus Torvalds break; 1311da177e4SLinus Torvalds } 1321da177e4SLinus Torvalds } 133873feea0SNick Piggin spin_unlock(&inode->i_lock); 1341da177e4SLinus Torvalds } 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds 1371da177e4SLinus Torvalds /* Remove header from link chain */ 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds static int 1401da177e4SLinus Torvalds affs_remove_link(struct dentry *dentry) 1411da177e4SLinus Torvalds { 1422b0143b5SDavid Howells struct inode *dir, *inode = d_inode(dentry); 1431da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 1444709187eSFabian Frederick struct buffer_head *bh, *link_bh = NULL; 1451da177e4SLinus Torvalds u32 link_ino, ino; 1461da177e4SLinus Torvalds int retval; 1471da177e4SLinus Torvalds 1489606d9aaSFabian Frederick pr_debug("%s(key=%ld)\n", __func__, inode->i_ino); 1491da177e4SLinus Torvalds retval = -EIO; 1501da177e4SLinus Torvalds bh = affs_bread(sb, inode->i_ino); 1511da177e4SLinus Torvalds if (!bh) 1521da177e4SLinus Torvalds goto done; 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds link_ino = (u32)(long)dentry->d_fsdata; 1551da177e4SLinus Torvalds if (inode->i_ino == link_ino) { 1561da177e4SLinus Torvalds /* we can't remove the head of the link, as its blocknr is still used as ino, 1571da177e4SLinus Torvalds * so we remove the block of the first link instead. 1581da177e4SLinus Torvalds */ 1591da177e4SLinus Torvalds link_ino = be32_to_cpu(AFFS_TAIL(sb, bh)->link_chain); 1601da177e4SLinus Torvalds link_bh = affs_bread(sb, link_ino); 1611da177e4SLinus Torvalds if (!link_bh) 1621da177e4SLinus Torvalds goto done; 1631da177e4SLinus Torvalds 164210f8559SDavid Howells dir = affs_iget(sb, be32_to_cpu(AFFS_TAIL(sb, link_bh)->parent)); 165210f8559SDavid Howells if (IS_ERR(dir)) { 166210f8559SDavid Howells retval = PTR_ERR(dir); 1671da177e4SLinus Torvalds goto done; 168210f8559SDavid Howells } 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds affs_lock_dir(dir); 17112447c40SAl Viro /* 17212447c40SAl Viro * if there's a dentry for that block, make it 17312447c40SAl Viro * refer to inode itself. 17412447c40SAl Viro */ 17512447c40SAl Viro affs_fix_dcache(inode, link_ino); 1761da177e4SLinus Torvalds retval = affs_remove_hash(dir, link_bh); 177ec1ab0abSChristoph Hellwig if (retval) { 178ec1ab0abSChristoph Hellwig affs_unlock_dir(dir); 1791da177e4SLinus Torvalds goto done; 180ec1ab0abSChristoph Hellwig } 1811da177e4SLinus Torvalds mark_buffer_dirty_inode(link_bh, inode); 1821da177e4SLinus Torvalds 1831da177e4SLinus Torvalds memcpy(AFFS_TAIL(sb, bh)->name, AFFS_TAIL(sb, link_bh)->name, 32); 1841da177e4SLinus Torvalds retval = affs_insert_hash(dir, bh); 185ec1ab0abSChristoph Hellwig if (retval) { 186ec1ab0abSChristoph Hellwig affs_unlock_dir(dir); 1871da177e4SLinus Torvalds goto done; 188ec1ab0abSChristoph Hellwig } 1891da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 1901da177e4SLinus Torvalds 1911da177e4SLinus Torvalds affs_unlock_dir(dir); 1921da177e4SLinus Torvalds iput(dir); 1931da177e4SLinus Torvalds } else { 1941da177e4SLinus Torvalds link_bh = affs_bread(sb, link_ino); 1951da177e4SLinus Torvalds if (!link_bh) 1961da177e4SLinus Torvalds goto done; 1971da177e4SLinus Torvalds } 1981da177e4SLinus Torvalds 1991da177e4SLinus Torvalds while ((ino = be32_to_cpu(AFFS_TAIL(sb, bh)->link_chain)) != 0) { 2001da177e4SLinus Torvalds if (ino == link_ino) { 2011da177e4SLinus Torvalds __be32 ino2 = AFFS_TAIL(sb, link_bh)->link_chain; 2021da177e4SLinus Torvalds AFFS_TAIL(sb, bh)->link_chain = ino2; 2031da177e4SLinus Torvalds affs_adjust_checksum(bh, be32_to_cpu(ino2) - link_ino); 2041da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 2051da177e4SLinus Torvalds retval = 0; 2061da177e4SLinus Torvalds /* Fix the link count, if bh is a normal header block without links */ 2071da177e4SLinus Torvalds switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) { 2081da177e4SLinus Torvalds case ST_LINKDIR: 2091da177e4SLinus Torvalds case ST_LINKFILE: 2101da177e4SLinus Torvalds break; 2111da177e4SLinus Torvalds default: 2121da177e4SLinus Torvalds if (!AFFS_TAIL(sb, bh)->link_chain) 213bfe86848SMiklos Szeredi set_nlink(inode, 1); 2141da177e4SLinus Torvalds } 2151da177e4SLinus Torvalds affs_free_block(sb, link_ino); 2161da177e4SLinus Torvalds goto done; 2171da177e4SLinus Torvalds } 2181da177e4SLinus Torvalds affs_brelse(bh); 2191da177e4SLinus Torvalds bh = affs_bread(sb, ino); 2201da177e4SLinus Torvalds if (!bh) 2211da177e4SLinus Torvalds goto done; 2221da177e4SLinus Torvalds } 2231da177e4SLinus Torvalds retval = -ENOENT; 2241da177e4SLinus Torvalds done: 2251da177e4SLinus Torvalds affs_brelse(link_bh); 2261da177e4SLinus Torvalds affs_brelse(bh); 2271da177e4SLinus Torvalds return retval; 2281da177e4SLinus Torvalds } 2291da177e4SLinus Torvalds 2301da177e4SLinus Torvalds 2311da177e4SLinus Torvalds static int 2321da177e4SLinus Torvalds affs_empty_dir(struct inode *inode) 2331da177e4SLinus Torvalds { 2341da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 2351da177e4SLinus Torvalds struct buffer_head *bh; 2361da177e4SLinus Torvalds int retval, size; 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds retval = -EIO; 2391da177e4SLinus Torvalds bh = affs_bread(sb, inode->i_ino); 2401da177e4SLinus Torvalds if (!bh) 2411da177e4SLinus Torvalds goto done; 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds retval = -ENOTEMPTY; 2441da177e4SLinus Torvalds for (size = AFFS_SB(sb)->s_hashsize - 1; size >= 0; size--) 2451da177e4SLinus Torvalds if (AFFS_HEAD(bh)->table[size]) 2461da177e4SLinus Torvalds goto not_empty; 2471da177e4SLinus Torvalds retval = 0; 2481da177e4SLinus Torvalds not_empty: 2491da177e4SLinus Torvalds affs_brelse(bh); 2501da177e4SLinus Torvalds done: 2511da177e4SLinus Torvalds return retval; 2521da177e4SLinus Torvalds } 2531da177e4SLinus Torvalds 2541da177e4SLinus Torvalds 2551da177e4SLinus Torvalds /* Remove a filesystem object. If the object to be removed has 2561da177e4SLinus Torvalds * links to it, one of the links must be changed to inherit 2571da177e4SLinus Torvalds * the file or directory. As above, any inode will do. 2581da177e4SLinus Torvalds * The buffer will not be freed. If the header is a link, the 2591da177e4SLinus Torvalds * block will be marked as free. 2601da177e4SLinus Torvalds * This function returns a negative error number in case of 2611da177e4SLinus Torvalds * an error, else 0 if the inode is to be deleted or 1 if not. 2621da177e4SLinus Torvalds */ 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvalds int 2651da177e4SLinus Torvalds affs_remove_header(struct dentry *dentry) 2661da177e4SLinus Torvalds { 2671da177e4SLinus Torvalds struct super_block *sb; 2681da177e4SLinus Torvalds struct inode *inode, *dir; 2691da177e4SLinus Torvalds struct buffer_head *bh = NULL; 2701da177e4SLinus Torvalds int retval; 2711da177e4SLinus Torvalds 2722b0143b5SDavid Howells dir = d_inode(dentry->d_parent); 2731da177e4SLinus Torvalds sb = dir->i_sb; 2741da177e4SLinus Torvalds 2751da177e4SLinus Torvalds retval = -ENOENT; 2762b0143b5SDavid Howells inode = d_inode(dentry); 2771da177e4SLinus Torvalds if (!inode) 2781da177e4SLinus Torvalds goto done; 2791da177e4SLinus Torvalds 2809606d9aaSFabian Frederick pr_debug("%s(key=%ld)\n", __func__, inode->i_ino); 2811da177e4SLinus Torvalds retval = -EIO; 2821da177e4SLinus Torvalds bh = affs_bread(sb, (u32)(long)dentry->d_fsdata); 2831da177e4SLinus Torvalds if (!bh) 2841da177e4SLinus Torvalds goto done; 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds affs_lock_link(inode); 2871da177e4SLinus Torvalds affs_lock_dir(dir); 2881da177e4SLinus Torvalds switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) { 2891da177e4SLinus Torvalds case ST_USERDIR: 2901da177e4SLinus Torvalds /* if we ever want to support links to dirs 2911da177e4SLinus Torvalds * i_hash_lock of the inode must only be 2921da177e4SLinus Torvalds * taken after some checks 2931da177e4SLinus Torvalds */ 2941da177e4SLinus Torvalds affs_lock_dir(inode); 2951da177e4SLinus Torvalds retval = affs_empty_dir(inode); 2961da177e4SLinus Torvalds affs_unlock_dir(inode); 2971da177e4SLinus Torvalds if (retval) 2981da177e4SLinus Torvalds goto done_unlock; 2991da177e4SLinus Torvalds break; 3001da177e4SLinus Torvalds default: 3011da177e4SLinus Torvalds break; 3021da177e4SLinus Torvalds } 3031da177e4SLinus Torvalds 3041da177e4SLinus Torvalds retval = affs_remove_hash(dir, bh); 3051da177e4SLinus Torvalds if (retval) 3061da177e4SLinus Torvalds goto done_unlock; 3071da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds affs_unlock_dir(dir); 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds if (inode->i_nlink > 1) 3121da177e4SLinus Torvalds retval = affs_remove_link(dentry); 3131da177e4SLinus Torvalds else 3146d6b77f1SMiklos Szeredi clear_nlink(inode); 3151da177e4SLinus Torvalds affs_unlock_link(inode); 3161da177e4SLinus Torvalds inode->i_ctime = CURRENT_TIME_SEC; 3171da177e4SLinus Torvalds mark_inode_dirty(inode); 3181da177e4SLinus Torvalds 3191da177e4SLinus Torvalds done: 3201da177e4SLinus Torvalds affs_brelse(bh); 3211da177e4SLinus Torvalds return retval; 3221da177e4SLinus Torvalds 3231da177e4SLinus Torvalds done_unlock: 3241da177e4SLinus Torvalds affs_unlock_dir(dir); 3251da177e4SLinus Torvalds affs_unlock_link(inode); 3261da177e4SLinus Torvalds goto done; 3271da177e4SLinus Torvalds } 3281da177e4SLinus Torvalds 3291da177e4SLinus Torvalds /* Checksum a block, do various consistency checks and optionally return 3301da177e4SLinus Torvalds the blocks type number. DATA points to the block. If their pointers 3311da177e4SLinus Torvalds are non-null, *PTYPE and *STYPE are set to the primary and secondary 3321da177e4SLinus Torvalds block types respectively, *HASHSIZE is set to the size of the hashtable 3331da177e4SLinus Torvalds (which lets us calculate the block size). 3341da177e4SLinus Torvalds Returns non-zero if the block is not consistent. */ 3351da177e4SLinus Torvalds 3361da177e4SLinus Torvalds u32 3371da177e4SLinus Torvalds affs_checksum_block(struct super_block *sb, struct buffer_head *bh) 3381da177e4SLinus Torvalds { 3391da177e4SLinus Torvalds __be32 *ptr = (__be32 *)bh->b_data; 3401da177e4SLinus Torvalds u32 sum; 3411da177e4SLinus Torvalds int bsize; 3421da177e4SLinus Torvalds 3431da177e4SLinus Torvalds sum = 0; 3441da177e4SLinus Torvalds for (bsize = sb->s_blocksize / sizeof(__be32); bsize > 0; bsize--) 3451da177e4SLinus Torvalds sum += be32_to_cpu(*ptr++); 3461da177e4SLinus Torvalds return sum; 3471da177e4SLinus Torvalds } 3481da177e4SLinus Torvalds 3491da177e4SLinus Torvalds /* 3501da177e4SLinus Torvalds * Calculate the checksum of a disk block and store it 3511da177e4SLinus Torvalds * at the indicated position. 3521da177e4SLinus Torvalds */ 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds void 3551da177e4SLinus Torvalds affs_fix_checksum(struct super_block *sb, struct buffer_head *bh) 3561da177e4SLinus Torvalds { 3571da177e4SLinus Torvalds int cnt = sb->s_blocksize / sizeof(__be32); 3581da177e4SLinus Torvalds __be32 *ptr = (__be32 *)bh->b_data; 3591da177e4SLinus Torvalds u32 checksum; 3601da177e4SLinus Torvalds __be32 *checksumptr; 3611da177e4SLinus Torvalds 3621da177e4SLinus Torvalds checksumptr = ptr + 5; 3631da177e4SLinus Torvalds *checksumptr = 0; 3641da177e4SLinus Torvalds for (checksum = 0; cnt > 0; ptr++, cnt--) 3651da177e4SLinus Torvalds checksum += be32_to_cpu(*ptr); 3661da177e4SLinus Torvalds *checksumptr = cpu_to_be32(-checksum); 3671da177e4SLinus Torvalds } 3681da177e4SLinus Torvalds 3691da177e4SLinus Torvalds void 370db39c167SDengChao secs_to_datestamp(time64_t secs, struct affs_date *ds) 3711da177e4SLinus Torvalds { 3721da177e4SLinus Torvalds u32 days; 3731da177e4SLinus Torvalds u32 minute; 374db39c167SDengChao s32 rem; 3751da177e4SLinus Torvalds 3761da177e4SLinus Torvalds secs -= sys_tz.tz_minuteswest * 60 + ((8 * 365 + 2) * 24 * 60 * 60); 3771da177e4SLinus Torvalds if (secs < 0) 3781da177e4SLinus Torvalds secs = 0; 379db39c167SDengChao days = div_s64_rem(secs, 86400, &rem); 380db39c167SDengChao minute = rem / 60; 381db39c167SDengChao rem -= minute * 60; 3821da177e4SLinus Torvalds 3831da177e4SLinus Torvalds ds->days = cpu_to_be32(days); 3841da177e4SLinus Torvalds ds->mins = cpu_to_be32(minute); 385db39c167SDengChao ds->ticks = cpu_to_be32(rem * 50); 3861da177e4SLinus Torvalds } 3871da177e4SLinus Torvalds 388a760b03dSAl Viro umode_t 3891da177e4SLinus Torvalds prot_to_mode(u32 prot) 3901da177e4SLinus Torvalds { 391a760b03dSAl Viro umode_t mode = 0; 3921da177e4SLinus Torvalds 3931da177e4SLinus Torvalds if (!(prot & FIBF_NOWRITE)) 3941da177e4SLinus Torvalds mode |= S_IWUSR; 3951da177e4SLinus Torvalds if (!(prot & FIBF_NOREAD)) 3961da177e4SLinus Torvalds mode |= S_IRUSR; 3971da177e4SLinus Torvalds if (!(prot & FIBF_NOEXECUTE)) 3981da177e4SLinus Torvalds mode |= S_IXUSR; 3991da177e4SLinus Torvalds if (prot & FIBF_GRP_WRITE) 4001da177e4SLinus Torvalds mode |= S_IWGRP; 4011da177e4SLinus Torvalds if (prot & FIBF_GRP_READ) 4021da177e4SLinus Torvalds mode |= S_IRGRP; 4031da177e4SLinus Torvalds if (prot & FIBF_GRP_EXECUTE) 4041da177e4SLinus Torvalds mode |= S_IXGRP; 4051da177e4SLinus Torvalds if (prot & FIBF_OTR_WRITE) 4061da177e4SLinus Torvalds mode |= S_IWOTH; 4071da177e4SLinus Torvalds if (prot & FIBF_OTR_READ) 4081da177e4SLinus Torvalds mode |= S_IROTH; 4091da177e4SLinus Torvalds if (prot & FIBF_OTR_EXECUTE) 4101da177e4SLinus Torvalds mode |= S_IXOTH; 4111da177e4SLinus Torvalds 4121da177e4SLinus Torvalds return mode; 4131da177e4SLinus Torvalds } 4141da177e4SLinus Torvalds 4151da177e4SLinus Torvalds void 4161da177e4SLinus Torvalds mode_to_prot(struct inode *inode) 4171da177e4SLinus Torvalds { 4181da177e4SLinus Torvalds u32 prot = AFFS_I(inode)->i_protect; 419a760b03dSAl Viro umode_t mode = inode->i_mode; 4201da177e4SLinus Torvalds 4211da177e4SLinus Torvalds if (!(mode & S_IXUSR)) 4221da177e4SLinus Torvalds prot |= FIBF_NOEXECUTE; 4231da177e4SLinus Torvalds if (!(mode & S_IRUSR)) 4241da177e4SLinus Torvalds prot |= FIBF_NOREAD; 4251da177e4SLinus Torvalds if (!(mode & S_IWUSR)) 4261da177e4SLinus Torvalds prot |= FIBF_NOWRITE; 4271da177e4SLinus Torvalds if (mode & S_IXGRP) 4281da177e4SLinus Torvalds prot |= FIBF_GRP_EXECUTE; 4291da177e4SLinus Torvalds if (mode & S_IRGRP) 4301da177e4SLinus Torvalds prot |= FIBF_GRP_READ; 4311da177e4SLinus Torvalds if (mode & S_IWGRP) 4321da177e4SLinus Torvalds prot |= FIBF_GRP_WRITE; 4331da177e4SLinus Torvalds if (mode & S_IXOTH) 4341da177e4SLinus Torvalds prot |= FIBF_OTR_EXECUTE; 4351da177e4SLinus Torvalds if (mode & S_IROTH) 4361da177e4SLinus Torvalds prot |= FIBF_OTR_READ; 4371da177e4SLinus Torvalds if (mode & S_IWOTH) 4381da177e4SLinus Torvalds prot |= FIBF_OTR_WRITE; 4391da177e4SLinus Torvalds 4401da177e4SLinus Torvalds AFFS_I(inode)->i_protect = prot; 4411da177e4SLinus Torvalds } 4421da177e4SLinus Torvalds 4431da177e4SLinus Torvalds void 4441da177e4SLinus Torvalds affs_error(struct super_block *sb, const char *function, const char *fmt, ...) 4451da177e4SLinus Torvalds { 4461ee54b09SFabian Frederick struct va_format vaf; 4471da177e4SLinus Torvalds va_list args; 4481da177e4SLinus Torvalds 4491da177e4SLinus Torvalds va_start(args, fmt); 4501ee54b09SFabian Frederick vaf.fmt = fmt; 4511ee54b09SFabian Frederick vaf.va = &args; 4521ee54b09SFabian Frederick pr_crit("error (device %s): %s(): %pV\n", sb->s_id, function, &vaf); 4531da177e4SLinus Torvalds if (!(sb->s_flags & MS_RDONLY)) 4540158de12SFabian Frederick pr_warn("Remounting filesystem read-only\n"); 4551da177e4SLinus Torvalds sb->s_flags |= MS_RDONLY; 4561ee54b09SFabian Frederick va_end(args); 4571da177e4SLinus Torvalds } 4581da177e4SLinus Torvalds 4591da177e4SLinus Torvalds void 4601da177e4SLinus Torvalds affs_warning(struct super_block *sb, const char *function, const char *fmt, ...) 4611da177e4SLinus Torvalds { 4621ee54b09SFabian Frederick struct va_format vaf; 4631da177e4SLinus Torvalds va_list args; 4641da177e4SLinus Torvalds 4651da177e4SLinus Torvalds va_start(args, fmt); 4661ee54b09SFabian Frederick vaf.fmt = fmt; 4671ee54b09SFabian Frederick vaf.va = &args; 4681ee54b09SFabian Frederick pr_warn("(device %s): %s(): %pV\n", sb->s_id, function, &vaf); 4691da177e4SLinus Torvalds va_end(args); 4701da177e4SLinus Torvalds } 4711da177e4SLinus Torvalds 4728ca57722SFabian Frederick bool 4738ca57722SFabian Frederick affs_nofilenametruncate(const struct dentry *dentry) 4748ca57722SFabian Frederick { 475*e0b3f595SAl Viro return affs_test_opt(AFFS_SB(dentry->d_sb)->s_flags, SF_NO_TRUNCATE); 4768ca57722SFabian Frederick } 4778ca57722SFabian Frederick 4781da177e4SLinus Torvalds /* Check if the name is valid for a affs object. */ 4791da177e4SLinus Torvalds 4801da177e4SLinus Torvalds int 4818ca57722SFabian Frederick affs_check_name(const unsigned char *name, int len, bool notruncate) 4821da177e4SLinus Torvalds { 4831da177e4SLinus Torvalds int i; 4841da177e4SLinus Torvalds 485f157853eSFabian Frederick if (len > AFFSNAMEMAX) { 4868ca57722SFabian Frederick if (notruncate) 4871da177e4SLinus Torvalds return -ENAMETOOLONG; 488f157853eSFabian Frederick len = AFFSNAMEMAX; 4898ca57722SFabian Frederick } 4901da177e4SLinus Torvalds for (i = 0; i < len; i++) { 4911da177e4SLinus Torvalds if (name[i] < ' ' || name[i] == ':' 4921da177e4SLinus Torvalds || (name[i] > 0x7e && name[i] < 0xa0)) 4931da177e4SLinus Torvalds return -EINVAL; 4941da177e4SLinus Torvalds } 4951da177e4SLinus Torvalds 4961da177e4SLinus Torvalds return 0; 4971da177e4SLinus Torvalds } 4981da177e4SLinus Torvalds 4991da177e4SLinus Torvalds /* This function copies name to bstr, with at most 30 5001da177e4SLinus Torvalds * characters length. The bstr will be prepended by 5011da177e4SLinus Torvalds * a length byte. 5021da177e4SLinus Torvalds * NOTE: The name will must be already checked by 5031da177e4SLinus Torvalds * affs_check_name()! 5041da177e4SLinus Torvalds */ 5051da177e4SLinus Torvalds 5061da177e4SLinus Torvalds int 5071da177e4SLinus Torvalds affs_copy_name(unsigned char *bstr, struct dentry *dentry) 5081da177e4SLinus Torvalds { 509f157853eSFabian Frederick u32 len = min(dentry->d_name.len, AFFSNAMEMAX); 5101da177e4SLinus Torvalds 5111da177e4SLinus Torvalds *bstr++ = len; 5121da177e4SLinus Torvalds memcpy(bstr, dentry->d_name.name, len); 5131da177e4SLinus Torvalds return len; 5141da177e4SLinus Torvalds } 515