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 extern struct timezone sys_tz; 141da177e4SLinus Torvalds 151da177e4SLinus Torvalds static char ErrorBuffer[256]; 161da177e4SLinus Torvalds 171da177e4SLinus Torvalds /* 181da177e4SLinus Torvalds * Functions for accessing Amiga-FFS structures. 191da177e4SLinus Torvalds */ 201da177e4SLinus Torvalds 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds /* Insert a header block bh into the directory dir 231da177e4SLinus Torvalds * caller must hold AFFS_DIR->i_hash_lock! 241da177e4SLinus Torvalds */ 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds int 271da177e4SLinus Torvalds affs_insert_hash(struct inode *dir, struct buffer_head *bh) 281da177e4SLinus Torvalds { 291da177e4SLinus Torvalds struct super_block *sb = dir->i_sb; 301da177e4SLinus Torvalds struct buffer_head *dir_bh; 311da177e4SLinus Torvalds u32 ino, hash_ino; 321da177e4SLinus Torvalds int offset; 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds ino = bh->b_blocknr; 351da177e4SLinus Torvalds offset = affs_hash_name(sb, AFFS_TAIL(sb, bh)->name + 1, AFFS_TAIL(sb, bh)->name[0]); 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds pr_debug("AFFS: insert_hash(dir=%u, ino=%d)\n", (u32)dir->i_ino, ino); 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds dir_bh = affs_bread(sb, dir->i_ino); 401da177e4SLinus Torvalds if (!dir_bh) 411da177e4SLinus Torvalds return -EIO; 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds hash_ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[offset]); 441da177e4SLinus Torvalds while (hash_ino) { 451da177e4SLinus Torvalds affs_brelse(dir_bh); 461da177e4SLinus Torvalds dir_bh = affs_bread(sb, hash_ino); 471da177e4SLinus Torvalds if (!dir_bh) 481da177e4SLinus Torvalds return -EIO; 491da177e4SLinus Torvalds hash_ino = be32_to_cpu(AFFS_TAIL(sb, dir_bh)->hash_chain); 501da177e4SLinus Torvalds } 511da177e4SLinus Torvalds AFFS_TAIL(sb, bh)->parent = cpu_to_be32(dir->i_ino); 521da177e4SLinus Torvalds AFFS_TAIL(sb, bh)->hash_chain = 0; 531da177e4SLinus Torvalds affs_fix_checksum(sb, bh); 541da177e4SLinus Torvalds 551da177e4SLinus Torvalds if (dir->i_ino == dir_bh->b_blocknr) 561da177e4SLinus Torvalds AFFS_HEAD(dir_bh)->table[offset] = cpu_to_be32(ino); 571da177e4SLinus Torvalds else 581da177e4SLinus Torvalds AFFS_TAIL(sb, dir_bh)->hash_chain = cpu_to_be32(ino); 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds affs_adjust_checksum(dir_bh, ino); 611da177e4SLinus Torvalds mark_buffer_dirty_inode(dir_bh, dir); 621da177e4SLinus Torvalds affs_brelse(dir_bh); 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; 651da177e4SLinus Torvalds dir->i_version++; 661da177e4SLinus Torvalds mark_inode_dirty(dir); 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds return 0; 691da177e4SLinus Torvalds } 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds /* Remove a header block from its directory. 721da177e4SLinus Torvalds * caller must hold AFFS_DIR->i_hash_lock! 731da177e4SLinus Torvalds */ 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds int 761da177e4SLinus Torvalds affs_remove_hash(struct inode *dir, struct buffer_head *rem_bh) 771da177e4SLinus Torvalds { 781da177e4SLinus Torvalds struct super_block *sb; 791da177e4SLinus Torvalds struct buffer_head *bh; 801da177e4SLinus Torvalds u32 rem_ino, hash_ino; 811da177e4SLinus Torvalds __be32 ino; 821da177e4SLinus Torvalds int offset, retval; 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds sb = dir->i_sb; 851da177e4SLinus Torvalds rem_ino = rem_bh->b_blocknr; 861da177e4SLinus Torvalds offset = affs_hash_name(sb, AFFS_TAIL(sb, rem_bh)->name+1, AFFS_TAIL(sb, rem_bh)->name[0]); 871da177e4SLinus Torvalds pr_debug("AFFS: remove_hash(dir=%d, ino=%d, hashval=%d)\n", (u32)dir->i_ino, 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 1171da177e4SLinus Torvalds dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; 1181da177e4SLinus Torvalds dir->i_version++; 1191da177e4SLinus Torvalds mark_inode_dirty(dir); 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds return retval; 1221da177e4SLinus Torvalds } 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds static void 1251da177e4SLinus Torvalds affs_fix_dcache(struct dentry *dentry, u32 entry_ino) 1261da177e4SLinus Torvalds { 1271da177e4SLinus Torvalds struct inode *inode = dentry->d_inode; 1281da177e4SLinus Torvalds void *data = dentry->d_fsdata; 1291da177e4SLinus Torvalds struct list_head *head, *next; 1301da177e4SLinus Torvalds 131873feea0SNick Piggin spin_lock(&inode->i_lock); 1321da177e4SLinus Torvalds head = &inode->i_dentry; 1331da177e4SLinus Torvalds next = head->next; 1341da177e4SLinus Torvalds while (next != head) { 1351da177e4SLinus Torvalds dentry = list_entry(next, struct dentry, d_alias); 1361da177e4SLinus Torvalds if (entry_ino == (u32)(long)dentry->d_fsdata) { 1371da177e4SLinus Torvalds dentry->d_fsdata = data; 1381da177e4SLinus Torvalds break; 1391da177e4SLinus Torvalds } 1401da177e4SLinus Torvalds next = next->next; 1411da177e4SLinus Torvalds } 142873feea0SNick Piggin spin_unlock(&inode->i_lock); 1431da177e4SLinus Torvalds } 1441da177e4SLinus Torvalds 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds /* Remove header from link chain */ 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds static int 1491da177e4SLinus Torvalds affs_remove_link(struct dentry *dentry) 1501da177e4SLinus Torvalds { 1511da177e4SLinus Torvalds struct inode *dir, *inode = dentry->d_inode; 1521da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 1531da177e4SLinus Torvalds struct buffer_head *bh = NULL, *link_bh = NULL; 1541da177e4SLinus Torvalds u32 link_ino, ino; 1551da177e4SLinus Torvalds int retval; 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds pr_debug("AFFS: remove_link(key=%ld)\n", inode->i_ino); 1581da177e4SLinus Torvalds retval = -EIO; 1591da177e4SLinus Torvalds bh = affs_bread(sb, inode->i_ino); 1601da177e4SLinus Torvalds if (!bh) 1611da177e4SLinus Torvalds goto done; 1621da177e4SLinus Torvalds 1631da177e4SLinus Torvalds link_ino = (u32)(long)dentry->d_fsdata; 1641da177e4SLinus Torvalds if (inode->i_ino == link_ino) { 1651da177e4SLinus Torvalds /* we can't remove the head of the link, as its blocknr is still used as ino, 1661da177e4SLinus Torvalds * so we remove the block of the first link instead. 1671da177e4SLinus Torvalds */ 1681da177e4SLinus Torvalds link_ino = be32_to_cpu(AFFS_TAIL(sb, bh)->link_chain); 1691da177e4SLinus Torvalds link_bh = affs_bread(sb, link_ino); 1701da177e4SLinus Torvalds if (!link_bh) 1711da177e4SLinus Torvalds goto done; 1721da177e4SLinus Torvalds 173210f8559SDavid Howells dir = affs_iget(sb, be32_to_cpu(AFFS_TAIL(sb, link_bh)->parent)); 174210f8559SDavid Howells if (IS_ERR(dir)) { 175210f8559SDavid Howells retval = PTR_ERR(dir); 1761da177e4SLinus Torvalds goto done; 177210f8559SDavid Howells } 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds affs_lock_dir(dir); 1801da177e4SLinus Torvalds affs_fix_dcache(dentry, link_ino); 1811da177e4SLinus Torvalds retval = affs_remove_hash(dir, link_bh); 182ec1ab0abSChristoph Hellwig if (retval) { 183ec1ab0abSChristoph Hellwig affs_unlock_dir(dir); 1841da177e4SLinus Torvalds goto done; 185ec1ab0abSChristoph Hellwig } 1861da177e4SLinus Torvalds mark_buffer_dirty_inode(link_bh, inode); 1871da177e4SLinus Torvalds 1881da177e4SLinus Torvalds memcpy(AFFS_TAIL(sb, bh)->name, AFFS_TAIL(sb, link_bh)->name, 32); 1891da177e4SLinus Torvalds retval = affs_insert_hash(dir, bh); 190ec1ab0abSChristoph Hellwig if (retval) { 191ec1ab0abSChristoph Hellwig affs_unlock_dir(dir); 1921da177e4SLinus Torvalds goto done; 193ec1ab0abSChristoph Hellwig } 1941da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds affs_unlock_dir(dir); 1971da177e4SLinus Torvalds iput(dir); 1981da177e4SLinus Torvalds } else { 1991da177e4SLinus Torvalds link_bh = affs_bread(sb, link_ino); 2001da177e4SLinus Torvalds if (!link_bh) 2011da177e4SLinus Torvalds goto done; 2021da177e4SLinus Torvalds } 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds while ((ino = be32_to_cpu(AFFS_TAIL(sb, bh)->link_chain)) != 0) { 2051da177e4SLinus Torvalds if (ino == link_ino) { 2061da177e4SLinus Torvalds __be32 ino2 = AFFS_TAIL(sb, link_bh)->link_chain; 2071da177e4SLinus Torvalds AFFS_TAIL(sb, bh)->link_chain = ino2; 2081da177e4SLinus Torvalds affs_adjust_checksum(bh, be32_to_cpu(ino2) - link_ino); 2091da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 2101da177e4SLinus Torvalds retval = 0; 2111da177e4SLinus Torvalds /* Fix the link count, if bh is a normal header block without links */ 2121da177e4SLinus Torvalds switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) { 2131da177e4SLinus Torvalds case ST_LINKDIR: 2141da177e4SLinus Torvalds case ST_LINKFILE: 2151da177e4SLinus Torvalds break; 2161da177e4SLinus Torvalds default: 2171da177e4SLinus Torvalds if (!AFFS_TAIL(sb, bh)->link_chain) 218*bfe86848SMiklos Szeredi set_nlink(inode, 1); 2191da177e4SLinus Torvalds } 2201da177e4SLinus Torvalds affs_free_block(sb, link_ino); 2211da177e4SLinus Torvalds goto done; 2221da177e4SLinus Torvalds } 2231da177e4SLinus Torvalds affs_brelse(bh); 2241da177e4SLinus Torvalds bh = affs_bread(sb, ino); 2251da177e4SLinus Torvalds if (!bh) 2261da177e4SLinus Torvalds goto done; 2271da177e4SLinus Torvalds } 2281da177e4SLinus Torvalds retval = -ENOENT; 2291da177e4SLinus Torvalds done: 2301da177e4SLinus Torvalds affs_brelse(link_bh); 2311da177e4SLinus Torvalds affs_brelse(bh); 2321da177e4SLinus Torvalds return retval; 2331da177e4SLinus Torvalds } 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds 2361da177e4SLinus Torvalds static int 2371da177e4SLinus Torvalds affs_empty_dir(struct inode *inode) 2381da177e4SLinus Torvalds { 2391da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 2401da177e4SLinus Torvalds struct buffer_head *bh; 2411da177e4SLinus Torvalds int retval, size; 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds retval = -EIO; 2441da177e4SLinus Torvalds bh = affs_bread(sb, inode->i_ino); 2451da177e4SLinus Torvalds if (!bh) 2461da177e4SLinus Torvalds goto done; 2471da177e4SLinus Torvalds 2481da177e4SLinus Torvalds retval = -ENOTEMPTY; 2491da177e4SLinus Torvalds for (size = AFFS_SB(sb)->s_hashsize - 1; size >= 0; size--) 2501da177e4SLinus Torvalds if (AFFS_HEAD(bh)->table[size]) 2511da177e4SLinus Torvalds goto not_empty; 2521da177e4SLinus Torvalds retval = 0; 2531da177e4SLinus Torvalds not_empty: 2541da177e4SLinus Torvalds affs_brelse(bh); 2551da177e4SLinus Torvalds done: 2561da177e4SLinus Torvalds return retval; 2571da177e4SLinus Torvalds } 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds /* Remove a filesystem object. If the object to be removed has 2611da177e4SLinus Torvalds * links to it, one of the links must be changed to inherit 2621da177e4SLinus Torvalds * the file or directory. As above, any inode will do. 2631da177e4SLinus Torvalds * The buffer will not be freed. If the header is a link, the 2641da177e4SLinus Torvalds * block will be marked as free. 2651da177e4SLinus Torvalds * This function returns a negative error number in case of 2661da177e4SLinus Torvalds * an error, else 0 if the inode is to be deleted or 1 if not. 2671da177e4SLinus Torvalds */ 2681da177e4SLinus Torvalds 2691da177e4SLinus Torvalds int 2701da177e4SLinus Torvalds affs_remove_header(struct dentry *dentry) 2711da177e4SLinus Torvalds { 2721da177e4SLinus Torvalds struct super_block *sb; 2731da177e4SLinus Torvalds struct inode *inode, *dir; 2741da177e4SLinus Torvalds struct buffer_head *bh = NULL; 2751da177e4SLinus Torvalds int retval; 2761da177e4SLinus Torvalds 2771da177e4SLinus Torvalds dir = dentry->d_parent->d_inode; 2781da177e4SLinus Torvalds sb = dir->i_sb; 2791da177e4SLinus Torvalds 2801da177e4SLinus Torvalds retval = -ENOENT; 2811da177e4SLinus Torvalds inode = dentry->d_inode; 2821da177e4SLinus Torvalds if (!inode) 2831da177e4SLinus Torvalds goto done; 2841da177e4SLinus Torvalds 2851da177e4SLinus Torvalds pr_debug("AFFS: remove_header(key=%ld)\n", inode->i_ino); 2861da177e4SLinus Torvalds retval = -EIO; 2871da177e4SLinus Torvalds bh = affs_bread(sb, (u32)(long)dentry->d_fsdata); 2881da177e4SLinus Torvalds if (!bh) 2891da177e4SLinus Torvalds goto done; 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds affs_lock_link(inode); 2921da177e4SLinus Torvalds affs_lock_dir(dir); 2931da177e4SLinus Torvalds switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) { 2941da177e4SLinus Torvalds case ST_USERDIR: 2951da177e4SLinus Torvalds /* if we ever want to support links to dirs 2961da177e4SLinus Torvalds * i_hash_lock of the inode must only be 2971da177e4SLinus Torvalds * taken after some checks 2981da177e4SLinus Torvalds */ 2991da177e4SLinus Torvalds affs_lock_dir(inode); 3001da177e4SLinus Torvalds retval = affs_empty_dir(inode); 3011da177e4SLinus Torvalds affs_unlock_dir(inode); 3021da177e4SLinus Torvalds if (retval) 3031da177e4SLinus Torvalds goto done_unlock; 3041da177e4SLinus Torvalds break; 3051da177e4SLinus Torvalds default: 3061da177e4SLinus Torvalds break; 3071da177e4SLinus Torvalds } 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds retval = affs_remove_hash(dir, bh); 3101da177e4SLinus Torvalds if (retval) 3111da177e4SLinus Torvalds goto done_unlock; 3121da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 3131da177e4SLinus Torvalds 3141da177e4SLinus Torvalds affs_unlock_dir(dir); 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds if (inode->i_nlink > 1) 3171da177e4SLinus Torvalds retval = affs_remove_link(dentry); 3181da177e4SLinus Torvalds else 3196d6b77f1SMiklos Szeredi clear_nlink(inode); 3201da177e4SLinus Torvalds affs_unlock_link(inode); 3211da177e4SLinus Torvalds inode->i_ctime = CURRENT_TIME_SEC; 3221da177e4SLinus Torvalds mark_inode_dirty(inode); 3231da177e4SLinus Torvalds 3241da177e4SLinus Torvalds done: 3251da177e4SLinus Torvalds affs_brelse(bh); 3261da177e4SLinus Torvalds return retval; 3271da177e4SLinus Torvalds 3281da177e4SLinus Torvalds done_unlock: 3291da177e4SLinus Torvalds affs_unlock_dir(dir); 3301da177e4SLinus Torvalds affs_unlock_link(inode); 3311da177e4SLinus Torvalds goto done; 3321da177e4SLinus Torvalds } 3331da177e4SLinus Torvalds 3341da177e4SLinus Torvalds /* Checksum a block, do various consistency checks and optionally return 3351da177e4SLinus Torvalds the blocks type number. DATA points to the block. If their pointers 3361da177e4SLinus Torvalds are non-null, *PTYPE and *STYPE are set to the primary and secondary 3371da177e4SLinus Torvalds block types respectively, *HASHSIZE is set to the size of the hashtable 3381da177e4SLinus Torvalds (which lets us calculate the block size). 3391da177e4SLinus Torvalds Returns non-zero if the block is not consistent. */ 3401da177e4SLinus Torvalds 3411da177e4SLinus Torvalds u32 3421da177e4SLinus Torvalds affs_checksum_block(struct super_block *sb, struct buffer_head *bh) 3431da177e4SLinus Torvalds { 3441da177e4SLinus Torvalds __be32 *ptr = (__be32 *)bh->b_data; 3451da177e4SLinus Torvalds u32 sum; 3461da177e4SLinus Torvalds int bsize; 3471da177e4SLinus Torvalds 3481da177e4SLinus Torvalds sum = 0; 3491da177e4SLinus Torvalds for (bsize = sb->s_blocksize / sizeof(__be32); bsize > 0; bsize--) 3501da177e4SLinus Torvalds sum += be32_to_cpu(*ptr++); 3511da177e4SLinus Torvalds return sum; 3521da177e4SLinus Torvalds } 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds /* 3551da177e4SLinus Torvalds * Calculate the checksum of a disk block and store it 3561da177e4SLinus Torvalds * at the indicated position. 3571da177e4SLinus Torvalds */ 3581da177e4SLinus Torvalds 3591da177e4SLinus Torvalds void 3601da177e4SLinus Torvalds affs_fix_checksum(struct super_block *sb, struct buffer_head *bh) 3611da177e4SLinus Torvalds { 3621da177e4SLinus Torvalds int cnt = sb->s_blocksize / sizeof(__be32); 3631da177e4SLinus Torvalds __be32 *ptr = (__be32 *)bh->b_data; 3641da177e4SLinus Torvalds u32 checksum; 3651da177e4SLinus Torvalds __be32 *checksumptr; 3661da177e4SLinus Torvalds 3671da177e4SLinus Torvalds checksumptr = ptr + 5; 3681da177e4SLinus Torvalds *checksumptr = 0; 3691da177e4SLinus Torvalds for (checksum = 0; cnt > 0; ptr++, cnt--) 3701da177e4SLinus Torvalds checksum += be32_to_cpu(*ptr); 3711da177e4SLinus Torvalds *checksumptr = cpu_to_be32(-checksum); 3721da177e4SLinus Torvalds } 3731da177e4SLinus Torvalds 3741da177e4SLinus Torvalds void 3751da177e4SLinus Torvalds secs_to_datestamp(time_t secs, struct affs_date *ds) 3761da177e4SLinus Torvalds { 3771da177e4SLinus Torvalds u32 days; 3781da177e4SLinus Torvalds u32 minute; 3791da177e4SLinus Torvalds 3801da177e4SLinus Torvalds secs -= sys_tz.tz_minuteswest * 60 + ((8 * 365 + 2) * 24 * 60 * 60); 3811da177e4SLinus Torvalds if (secs < 0) 3821da177e4SLinus Torvalds secs = 0; 3831da177e4SLinus Torvalds days = secs / 86400; 3841da177e4SLinus Torvalds secs -= days * 86400; 3851da177e4SLinus Torvalds minute = secs / 60; 3861da177e4SLinus Torvalds secs -= minute * 60; 3871da177e4SLinus Torvalds 3881da177e4SLinus Torvalds ds->days = cpu_to_be32(days); 3891da177e4SLinus Torvalds ds->mins = cpu_to_be32(minute); 3901da177e4SLinus Torvalds ds->ticks = cpu_to_be32(secs * 50); 3911da177e4SLinus Torvalds } 3921da177e4SLinus Torvalds 3931da177e4SLinus Torvalds mode_t 3941da177e4SLinus Torvalds prot_to_mode(u32 prot) 3951da177e4SLinus Torvalds { 3961da177e4SLinus Torvalds int mode = 0; 3971da177e4SLinus Torvalds 3981da177e4SLinus Torvalds if (!(prot & FIBF_NOWRITE)) 3991da177e4SLinus Torvalds mode |= S_IWUSR; 4001da177e4SLinus Torvalds if (!(prot & FIBF_NOREAD)) 4011da177e4SLinus Torvalds mode |= S_IRUSR; 4021da177e4SLinus Torvalds if (!(prot & FIBF_NOEXECUTE)) 4031da177e4SLinus Torvalds mode |= S_IXUSR; 4041da177e4SLinus Torvalds if (prot & FIBF_GRP_WRITE) 4051da177e4SLinus Torvalds mode |= S_IWGRP; 4061da177e4SLinus Torvalds if (prot & FIBF_GRP_READ) 4071da177e4SLinus Torvalds mode |= S_IRGRP; 4081da177e4SLinus Torvalds if (prot & FIBF_GRP_EXECUTE) 4091da177e4SLinus Torvalds mode |= S_IXGRP; 4101da177e4SLinus Torvalds if (prot & FIBF_OTR_WRITE) 4111da177e4SLinus Torvalds mode |= S_IWOTH; 4121da177e4SLinus Torvalds if (prot & FIBF_OTR_READ) 4131da177e4SLinus Torvalds mode |= S_IROTH; 4141da177e4SLinus Torvalds if (prot & FIBF_OTR_EXECUTE) 4151da177e4SLinus Torvalds mode |= S_IXOTH; 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds return mode; 4181da177e4SLinus Torvalds } 4191da177e4SLinus Torvalds 4201da177e4SLinus Torvalds void 4211da177e4SLinus Torvalds mode_to_prot(struct inode *inode) 4221da177e4SLinus Torvalds { 4231da177e4SLinus Torvalds u32 prot = AFFS_I(inode)->i_protect; 4241da177e4SLinus Torvalds mode_t mode = inode->i_mode; 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds if (!(mode & S_IXUSR)) 4271da177e4SLinus Torvalds prot |= FIBF_NOEXECUTE; 4281da177e4SLinus Torvalds if (!(mode & S_IRUSR)) 4291da177e4SLinus Torvalds prot |= FIBF_NOREAD; 4301da177e4SLinus Torvalds if (!(mode & S_IWUSR)) 4311da177e4SLinus Torvalds prot |= FIBF_NOWRITE; 4321da177e4SLinus Torvalds if (mode & S_IXGRP) 4331da177e4SLinus Torvalds prot |= FIBF_GRP_EXECUTE; 4341da177e4SLinus Torvalds if (mode & S_IRGRP) 4351da177e4SLinus Torvalds prot |= FIBF_GRP_READ; 4361da177e4SLinus Torvalds if (mode & S_IWGRP) 4371da177e4SLinus Torvalds prot |= FIBF_GRP_WRITE; 4381da177e4SLinus Torvalds if (mode & S_IXOTH) 4391da177e4SLinus Torvalds prot |= FIBF_OTR_EXECUTE; 4401da177e4SLinus Torvalds if (mode & S_IROTH) 4411da177e4SLinus Torvalds prot |= FIBF_OTR_READ; 4421da177e4SLinus Torvalds if (mode & S_IWOTH) 4431da177e4SLinus Torvalds prot |= FIBF_OTR_WRITE; 4441da177e4SLinus Torvalds 4451da177e4SLinus Torvalds AFFS_I(inode)->i_protect = prot; 4461da177e4SLinus Torvalds } 4471da177e4SLinus Torvalds 4481da177e4SLinus Torvalds void 4491da177e4SLinus Torvalds affs_error(struct super_block *sb, const char *function, const char *fmt, ...) 4501da177e4SLinus Torvalds { 4511da177e4SLinus Torvalds va_list args; 4521da177e4SLinus Torvalds 4531da177e4SLinus Torvalds va_start(args,fmt); 4544a6e617aSAlexey Dobriyan vsnprintf(ErrorBuffer,sizeof(ErrorBuffer),fmt,args); 4551da177e4SLinus Torvalds va_end(args); 4561da177e4SLinus Torvalds 4571da177e4SLinus Torvalds printk(KERN_CRIT "AFFS error (device %s): %s(): %s\n", sb->s_id, 4581da177e4SLinus Torvalds function,ErrorBuffer); 4591da177e4SLinus Torvalds if (!(sb->s_flags & MS_RDONLY)) 4601da177e4SLinus Torvalds printk(KERN_WARNING "AFFS: Remounting filesystem read-only\n"); 4611da177e4SLinus Torvalds sb->s_flags |= MS_RDONLY; 4621da177e4SLinus Torvalds } 4631da177e4SLinus Torvalds 4641da177e4SLinus Torvalds void 4651da177e4SLinus Torvalds affs_warning(struct super_block *sb, const char *function, const char *fmt, ...) 4661da177e4SLinus Torvalds { 4671da177e4SLinus Torvalds va_list args; 4681da177e4SLinus Torvalds 4691da177e4SLinus Torvalds va_start(args,fmt); 4704a6e617aSAlexey Dobriyan vsnprintf(ErrorBuffer,sizeof(ErrorBuffer),fmt,args); 4711da177e4SLinus Torvalds va_end(args); 4721da177e4SLinus Torvalds 4731da177e4SLinus Torvalds printk(KERN_WARNING "AFFS warning (device %s): %s(): %s\n", sb->s_id, 4741da177e4SLinus Torvalds function,ErrorBuffer); 4751da177e4SLinus Torvalds } 4761da177e4SLinus Torvalds 4771da177e4SLinus Torvalds /* Check if the name is valid for a affs object. */ 4781da177e4SLinus Torvalds 4791da177e4SLinus Torvalds int 4801da177e4SLinus Torvalds affs_check_name(const unsigned char *name, int len) 4811da177e4SLinus Torvalds { 4821da177e4SLinus Torvalds int i; 4831da177e4SLinus Torvalds 4841da177e4SLinus Torvalds if (len > 30) 4851da177e4SLinus Torvalds #ifdef AFFS_NO_TRUNCATE 4861da177e4SLinus Torvalds return -ENAMETOOLONG; 4871da177e4SLinus Torvalds #else 4881da177e4SLinus Torvalds len = 30; 4891da177e4SLinus Torvalds #endif 4901da177e4SLinus Torvalds 4911da177e4SLinus Torvalds for (i = 0; i < len; i++) { 4921da177e4SLinus Torvalds if (name[i] < ' ' || name[i] == ':' 4931da177e4SLinus Torvalds || (name[i] > 0x7e && name[i] < 0xa0)) 4941da177e4SLinus Torvalds return -EINVAL; 4951da177e4SLinus Torvalds } 4961da177e4SLinus Torvalds 4971da177e4SLinus Torvalds return 0; 4981da177e4SLinus Torvalds } 4991da177e4SLinus Torvalds 5001da177e4SLinus Torvalds /* This function copies name to bstr, with at most 30 5011da177e4SLinus Torvalds * characters length. The bstr will be prepended by 5021da177e4SLinus Torvalds * a length byte. 5031da177e4SLinus Torvalds * NOTE: The name will must be already checked by 5041da177e4SLinus Torvalds * affs_check_name()! 5051da177e4SLinus Torvalds */ 5061da177e4SLinus Torvalds 5071da177e4SLinus Torvalds int 5081da177e4SLinus Torvalds affs_copy_name(unsigned char *bstr, struct dentry *dentry) 5091da177e4SLinus Torvalds { 5101da177e4SLinus Torvalds int len = min(dentry->d_name.len, 30u); 5111da177e4SLinus Torvalds 5121da177e4SLinus Torvalds *bstr++ = len; 5131da177e4SLinus Torvalds memcpy(bstr, dentry->d_name.name, len); 5141da177e4SLinus Torvalds return len; 5151da177e4SLinus Torvalds } 516