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