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 1311da177e4SLinus Torvalds spin_lock(&dcache_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 } 1421da177e4SLinus Torvalds spin_unlock(&dcache_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 173*210f8559SDavid Howells dir = affs_iget(sb, be32_to_cpu(AFFS_TAIL(sb, link_bh)->parent)); 174*210f8559SDavid Howells if (IS_ERR(dir)) { 175*210f8559SDavid Howells retval = PTR_ERR(dir); 1761da177e4SLinus Torvalds goto done; 177*210f8559SDavid 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); 1821da177e4SLinus Torvalds if (retval) 1831da177e4SLinus Torvalds goto done; 1841da177e4SLinus Torvalds mark_buffer_dirty_inode(link_bh, inode); 1851da177e4SLinus Torvalds 1861da177e4SLinus Torvalds memcpy(AFFS_TAIL(sb, bh)->name, AFFS_TAIL(sb, link_bh)->name, 32); 1871da177e4SLinus Torvalds retval = affs_insert_hash(dir, bh); 1881da177e4SLinus Torvalds if (retval) 1891da177e4SLinus Torvalds goto done; 1901da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds affs_unlock_dir(dir); 1931da177e4SLinus Torvalds iput(dir); 1941da177e4SLinus Torvalds } else { 1951da177e4SLinus Torvalds link_bh = affs_bread(sb, link_ino); 1961da177e4SLinus Torvalds if (!link_bh) 1971da177e4SLinus Torvalds goto done; 1981da177e4SLinus Torvalds } 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds while ((ino = be32_to_cpu(AFFS_TAIL(sb, bh)->link_chain)) != 0) { 2011da177e4SLinus Torvalds if (ino == link_ino) { 2021da177e4SLinus Torvalds __be32 ino2 = AFFS_TAIL(sb, link_bh)->link_chain; 2031da177e4SLinus Torvalds AFFS_TAIL(sb, bh)->link_chain = ino2; 2041da177e4SLinus Torvalds affs_adjust_checksum(bh, be32_to_cpu(ino2) - link_ino); 2051da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 2061da177e4SLinus Torvalds retval = 0; 2071da177e4SLinus Torvalds /* Fix the link count, if bh is a normal header block without links */ 2081da177e4SLinus Torvalds switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) { 2091da177e4SLinus Torvalds case ST_LINKDIR: 2101da177e4SLinus Torvalds case ST_LINKFILE: 2111da177e4SLinus Torvalds break; 2121da177e4SLinus Torvalds default: 2131da177e4SLinus Torvalds if (!AFFS_TAIL(sb, bh)->link_chain) 2141da177e4SLinus Torvalds inode->i_nlink = 1; 2151da177e4SLinus Torvalds } 2161da177e4SLinus Torvalds affs_free_block(sb, link_ino); 2171da177e4SLinus Torvalds goto done; 2181da177e4SLinus Torvalds } 2191da177e4SLinus Torvalds affs_brelse(bh); 2201da177e4SLinus Torvalds bh = affs_bread(sb, ino); 2211da177e4SLinus Torvalds if (!bh) 2221da177e4SLinus Torvalds goto done; 2231da177e4SLinus Torvalds } 2241da177e4SLinus Torvalds retval = -ENOENT; 2251da177e4SLinus Torvalds done: 2261da177e4SLinus Torvalds affs_brelse(link_bh); 2271da177e4SLinus Torvalds affs_brelse(bh); 2281da177e4SLinus Torvalds return retval; 2291da177e4SLinus Torvalds } 2301da177e4SLinus Torvalds 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds static int 2331da177e4SLinus Torvalds affs_empty_dir(struct inode *inode) 2341da177e4SLinus Torvalds { 2351da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 2361da177e4SLinus Torvalds struct buffer_head *bh; 2371da177e4SLinus Torvalds int retval, size; 2381da177e4SLinus Torvalds 2391da177e4SLinus Torvalds retval = -EIO; 2401da177e4SLinus Torvalds bh = affs_bread(sb, inode->i_ino); 2411da177e4SLinus Torvalds if (!bh) 2421da177e4SLinus Torvalds goto done; 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvalds retval = -ENOTEMPTY; 2451da177e4SLinus Torvalds for (size = AFFS_SB(sb)->s_hashsize - 1; size >= 0; size--) 2461da177e4SLinus Torvalds if (AFFS_HEAD(bh)->table[size]) 2471da177e4SLinus Torvalds goto not_empty; 2481da177e4SLinus Torvalds retval = 0; 2491da177e4SLinus Torvalds not_empty: 2501da177e4SLinus Torvalds affs_brelse(bh); 2511da177e4SLinus Torvalds done: 2521da177e4SLinus Torvalds return retval; 2531da177e4SLinus Torvalds } 2541da177e4SLinus Torvalds 2551da177e4SLinus Torvalds 2561da177e4SLinus Torvalds /* Remove a filesystem object. If the object to be removed has 2571da177e4SLinus Torvalds * links to it, one of the links must be changed to inherit 2581da177e4SLinus Torvalds * the file or directory. As above, any inode will do. 2591da177e4SLinus Torvalds * The buffer will not be freed. If the header is a link, the 2601da177e4SLinus Torvalds * block will be marked as free. 2611da177e4SLinus Torvalds * This function returns a negative error number in case of 2621da177e4SLinus Torvalds * an error, else 0 if the inode is to be deleted or 1 if not. 2631da177e4SLinus Torvalds */ 2641da177e4SLinus Torvalds 2651da177e4SLinus Torvalds int 2661da177e4SLinus Torvalds affs_remove_header(struct dentry *dentry) 2671da177e4SLinus Torvalds { 2681da177e4SLinus Torvalds struct super_block *sb; 2691da177e4SLinus Torvalds struct inode *inode, *dir; 2701da177e4SLinus Torvalds struct buffer_head *bh = NULL; 2711da177e4SLinus Torvalds int retval; 2721da177e4SLinus Torvalds 2731da177e4SLinus Torvalds dir = dentry->d_parent->d_inode; 2741da177e4SLinus Torvalds sb = dir->i_sb; 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds retval = -ENOENT; 2771da177e4SLinus Torvalds inode = dentry->d_inode; 2781da177e4SLinus Torvalds if (!inode) 2791da177e4SLinus Torvalds goto done; 2801da177e4SLinus Torvalds 2811da177e4SLinus Torvalds pr_debug("AFFS: remove_header(key=%ld)\n", inode->i_ino); 2821da177e4SLinus Torvalds retval = -EIO; 2831da177e4SLinus Torvalds bh = affs_bread(sb, (u32)(long)dentry->d_fsdata); 2841da177e4SLinus Torvalds if (!bh) 2851da177e4SLinus Torvalds goto done; 2861da177e4SLinus Torvalds 2871da177e4SLinus Torvalds affs_lock_link(inode); 2881da177e4SLinus Torvalds affs_lock_dir(dir); 2891da177e4SLinus Torvalds switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) { 2901da177e4SLinus Torvalds case ST_USERDIR: 2911da177e4SLinus Torvalds /* if we ever want to support links to dirs 2921da177e4SLinus Torvalds * i_hash_lock of the inode must only be 2931da177e4SLinus Torvalds * taken after some checks 2941da177e4SLinus Torvalds */ 2951da177e4SLinus Torvalds affs_lock_dir(inode); 2961da177e4SLinus Torvalds retval = affs_empty_dir(inode); 2971da177e4SLinus Torvalds affs_unlock_dir(inode); 2981da177e4SLinus Torvalds if (retval) 2991da177e4SLinus Torvalds goto done_unlock; 3001da177e4SLinus Torvalds break; 3011da177e4SLinus Torvalds default: 3021da177e4SLinus Torvalds break; 3031da177e4SLinus Torvalds } 3041da177e4SLinus Torvalds 3051da177e4SLinus Torvalds retval = affs_remove_hash(dir, bh); 3061da177e4SLinus Torvalds if (retval) 3071da177e4SLinus Torvalds goto done_unlock; 3081da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 3091da177e4SLinus Torvalds 3101da177e4SLinus Torvalds affs_unlock_dir(dir); 3111da177e4SLinus Torvalds 3121da177e4SLinus Torvalds if (inode->i_nlink > 1) 3131da177e4SLinus Torvalds retval = affs_remove_link(dentry); 3141da177e4SLinus Torvalds else 3151da177e4SLinus Torvalds inode->i_nlink = 0; 3161da177e4SLinus Torvalds affs_unlock_link(inode); 3171da177e4SLinus Torvalds inode->i_ctime = CURRENT_TIME_SEC; 3181da177e4SLinus Torvalds mark_inode_dirty(inode); 3191da177e4SLinus Torvalds 3201da177e4SLinus Torvalds done: 3211da177e4SLinus Torvalds affs_brelse(bh); 3221da177e4SLinus Torvalds return retval; 3231da177e4SLinus Torvalds 3241da177e4SLinus Torvalds done_unlock: 3251da177e4SLinus Torvalds affs_unlock_dir(dir); 3261da177e4SLinus Torvalds affs_unlock_link(inode); 3271da177e4SLinus Torvalds goto done; 3281da177e4SLinus Torvalds } 3291da177e4SLinus Torvalds 3301da177e4SLinus Torvalds /* Checksum a block, do various consistency checks and optionally return 3311da177e4SLinus Torvalds the blocks type number. DATA points to the block. If their pointers 3321da177e4SLinus Torvalds are non-null, *PTYPE and *STYPE are set to the primary and secondary 3331da177e4SLinus Torvalds block types respectively, *HASHSIZE is set to the size of the hashtable 3341da177e4SLinus Torvalds (which lets us calculate the block size). 3351da177e4SLinus Torvalds Returns non-zero if the block is not consistent. */ 3361da177e4SLinus Torvalds 3371da177e4SLinus Torvalds u32 3381da177e4SLinus Torvalds affs_checksum_block(struct super_block *sb, struct buffer_head *bh) 3391da177e4SLinus Torvalds { 3401da177e4SLinus Torvalds __be32 *ptr = (__be32 *)bh->b_data; 3411da177e4SLinus Torvalds u32 sum; 3421da177e4SLinus Torvalds int bsize; 3431da177e4SLinus Torvalds 3441da177e4SLinus Torvalds sum = 0; 3451da177e4SLinus Torvalds for (bsize = sb->s_blocksize / sizeof(__be32); bsize > 0; bsize--) 3461da177e4SLinus Torvalds sum += be32_to_cpu(*ptr++); 3471da177e4SLinus Torvalds return sum; 3481da177e4SLinus Torvalds } 3491da177e4SLinus Torvalds 3501da177e4SLinus Torvalds /* 3511da177e4SLinus Torvalds * Calculate the checksum of a disk block and store it 3521da177e4SLinus Torvalds * at the indicated position. 3531da177e4SLinus Torvalds */ 3541da177e4SLinus Torvalds 3551da177e4SLinus Torvalds void 3561da177e4SLinus Torvalds affs_fix_checksum(struct super_block *sb, struct buffer_head *bh) 3571da177e4SLinus Torvalds { 3581da177e4SLinus Torvalds int cnt = sb->s_blocksize / sizeof(__be32); 3591da177e4SLinus Torvalds __be32 *ptr = (__be32 *)bh->b_data; 3601da177e4SLinus Torvalds u32 checksum; 3611da177e4SLinus Torvalds __be32 *checksumptr; 3621da177e4SLinus Torvalds 3631da177e4SLinus Torvalds checksumptr = ptr + 5; 3641da177e4SLinus Torvalds *checksumptr = 0; 3651da177e4SLinus Torvalds for (checksum = 0; cnt > 0; ptr++, cnt--) 3661da177e4SLinus Torvalds checksum += be32_to_cpu(*ptr); 3671da177e4SLinus Torvalds *checksumptr = cpu_to_be32(-checksum); 3681da177e4SLinus Torvalds } 3691da177e4SLinus Torvalds 3701da177e4SLinus Torvalds void 3711da177e4SLinus Torvalds secs_to_datestamp(time_t secs, struct affs_date *ds) 3721da177e4SLinus Torvalds { 3731da177e4SLinus Torvalds u32 days; 3741da177e4SLinus Torvalds u32 minute; 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; 3791da177e4SLinus Torvalds days = secs / 86400; 3801da177e4SLinus Torvalds secs -= days * 86400; 3811da177e4SLinus Torvalds minute = secs / 60; 3821da177e4SLinus Torvalds secs -= minute * 60; 3831da177e4SLinus Torvalds 3841da177e4SLinus Torvalds ds->days = cpu_to_be32(days); 3851da177e4SLinus Torvalds ds->mins = cpu_to_be32(minute); 3861da177e4SLinus Torvalds ds->ticks = cpu_to_be32(secs * 50); 3871da177e4SLinus Torvalds } 3881da177e4SLinus Torvalds 3891da177e4SLinus Torvalds mode_t 3901da177e4SLinus Torvalds prot_to_mode(u32 prot) 3911da177e4SLinus Torvalds { 3921da177e4SLinus Torvalds int mode = 0; 3931da177e4SLinus Torvalds 3941da177e4SLinus Torvalds if (!(prot & FIBF_NOWRITE)) 3951da177e4SLinus Torvalds mode |= S_IWUSR; 3961da177e4SLinus Torvalds if (!(prot & FIBF_NOREAD)) 3971da177e4SLinus Torvalds mode |= S_IRUSR; 3981da177e4SLinus Torvalds if (!(prot & FIBF_NOEXECUTE)) 3991da177e4SLinus Torvalds mode |= S_IXUSR; 4001da177e4SLinus Torvalds if (prot & FIBF_GRP_WRITE) 4011da177e4SLinus Torvalds mode |= S_IWGRP; 4021da177e4SLinus Torvalds if (prot & FIBF_GRP_READ) 4031da177e4SLinus Torvalds mode |= S_IRGRP; 4041da177e4SLinus Torvalds if (prot & FIBF_GRP_EXECUTE) 4051da177e4SLinus Torvalds mode |= S_IXGRP; 4061da177e4SLinus Torvalds if (prot & FIBF_OTR_WRITE) 4071da177e4SLinus Torvalds mode |= S_IWOTH; 4081da177e4SLinus Torvalds if (prot & FIBF_OTR_READ) 4091da177e4SLinus Torvalds mode |= S_IROTH; 4101da177e4SLinus Torvalds if (prot & FIBF_OTR_EXECUTE) 4111da177e4SLinus Torvalds mode |= S_IXOTH; 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds return mode; 4141da177e4SLinus Torvalds } 4151da177e4SLinus Torvalds 4161da177e4SLinus Torvalds void 4171da177e4SLinus Torvalds mode_to_prot(struct inode *inode) 4181da177e4SLinus Torvalds { 4191da177e4SLinus Torvalds u32 prot = AFFS_I(inode)->i_protect; 4201da177e4SLinus Torvalds mode_t mode = inode->i_mode; 4211da177e4SLinus Torvalds 4221da177e4SLinus Torvalds if (!(mode & S_IXUSR)) 4231da177e4SLinus Torvalds prot |= FIBF_NOEXECUTE; 4241da177e4SLinus Torvalds if (!(mode & S_IRUSR)) 4251da177e4SLinus Torvalds prot |= FIBF_NOREAD; 4261da177e4SLinus Torvalds if (!(mode & S_IWUSR)) 4271da177e4SLinus Torvalds prot |= FIBF_NOWRITE; 4281da177e4SLinus Torvalds if (mode & S_IXGRP) 4291da177e4SLinus Torvalds prot |= FIBF_GRP_EXECUTE; 4301da177e4SLinus Torvalds if (mode & S_IRGRP) 4311da177e4SLinus Torvalds prot |= FIBF_GRP_READ; 4321da177e4SLinus Torvalds if (mode & S_IWGRP) 4331da177e4SLinus Torvalds prot |= FIBF_GRP_WRITE; 4341da177e4SLinus Torvalds if (mode & S_IXOTH) 4351da177e4SLinus Torvalds prot |= FIBF_OTR_EXECUTE; 4361da177e4SLinus Torvalds if (mode & S_IROTH) 4371da177e4SLinus Torvalds prot |= FIBF_OTR_READ; 4381da177e4SLinus Torvalds if (mode & S_IWOTH) 4391da177e4SLinus Torvalds prot |= FIBF_OTR_WRITE; 4401da177e4SLinus Torvalds 4411da177e4SLinus Torvalds AFFS_I(inode)->i_protect = prot; 4421da177e4SLinus Torvalds } 4431da177e4SLinus Torvalds 4441da177e4SLinus Torvalds void 4451da177e4SLinus Torvalds affs_error(struct super_block *sb, const char *function, const char *fmt, ...) 4461da177e4SLinus Torvalds { 4471da177e4SLinus Torvalds va_list args; 4481da177e4SLinus Torvalds 4491da177e4SLinus Torvalds va_start(args,fmt); 4504a6e617aSAlexey Dobriyan vsnprintf(ErrorBuffer,sizeof(ErrorBuffer),fmt,args); 4511da177e4SLinus Torvalds va_end(args); 4521da177e4SLinus Torvalds 4531da177e4SLinus Torvalds printk(KERN_CRIT "AFFS error (device %s): %s(): %s\n", sb->s_id, 4541da177e4SLinus Torvalds function,ErrorBuffer); 4551da177e4SLinus Torvalds if (!(sb->s_flags & MS_RDONLY)) 4561da177e4SLinus Torvalds printk(KERN_WARNING "AFFS: Remounting filesystem read-only\n"); 4571da177e4SLinus Torvalds sb->s_flags |= MS_RDONLY; 4581da177e4SLinus Torvalds } 4591da177e4SLinus Torvalds 4601da177e4SLinus Torvalds void 4611da177e4SLinus Torvalds affs_warning(struct super_block *sb, const char *function, const char *fmt, ...) 4621da177e4SLinus Torvalds { 4631da177e4SLinus Torvalds va_list args; 4641da177e4SLinus Torvalds 4651da177e4SLinus Torvalds va_start(args,fmt); 4664a6e617aSAlexey Dobriyan vsnprintf(ErrorBuffer,sizeof(ErrorBuffer),fmt,args); 4671da177e4SLinus Torvalds va_end(args); 4681da177e4SLinus Torvalds 4691da177e4SLinus Torvalds printk(KERN_WARNING "AFFS warning (device %s): %s(): %s\n", sb->s_id, 4701da177e4SLinus Torvalds function,ErrorBuffer); 4711da177e4SLinus Torvalds } 4721da177e4SLinus Torvalds 4731da177e4SLinus Torvalds /* Check if the name is valid for a affs object. */ 4741da177e4SLinus Torvalds 4751da177e4SLinus Torvalds int 4761da177e4SLinus Torvalds affs_check_name(const unsigned char *name, int len) 4771da177e4SLinus Torvalds { 4781da177e4SLinus Torvalds int i; 4791da177e4SLinus Torvalds 4801da177e4SLinus Torvalds if (len > 30) 4811da177e4SLinus Torvalds #ifdef AFFS_NO_TRUNCATE 4821da177e4SLinus Torvalds return -ENAMETOOLONG; 4831da177e4SLinus Torvalds #else 4841da177e4SLinus Torvalds len = 30; 4851da177e4SLinus Torvalds #endif 4861da177e4SLinus Torvalds 4871da177e4SLinus Torvalds for (i = 0; i < len; i++) { 4881da177e4SLinus Torvalds if (name[i] < ' ' || name[i] == ':' 4891da177e4SLinus Torvalds || (name[i] > 0x7e && name[i] < 0xa0)) 4901da177e4SLinus Torvalds return -EINVAL; 4911da177e4SLinus Torvalds } 4921da177e4SLinus Torvalds 4931da177e4SLinus Torvalds return 0; 4941da177e4SLinus Torvalds } 4951da177e4SLinus Torvalds 4961da177e4SLinus Torvalds /* This function copies name to bstr, with at most 30 4971da177e4SLinus Torvalds * characters length. The bstr will be prepended by 4981da177e4SLinus Torvalds * a length byte. 4991da177e4SLinus Torvalds * NOTE: The name will must be already checked by 5001da177e4SLinus Torvalds * affs_check_name()! 5011da177e4SLinus Torvalds */ 5021da177e4SLinus Torvalds 5031da177e4SLinus Torvalds int 5041da177e4SLinus Torvalds affs_copy_name(unsigned char *bstr, struct dentry *dentry) 5051da177e4SLinus Torvalds { 5061da177e4SLinus Torvalds int len = min(dentry->d_name.len, 30u); 5071da177e4SLinus Torvalds 5081da177e4SLinus Torvalds *bstr++ = len; 5091da177e4SLinus Torvalds memcpy(bstr, dentry->d_name.name, len); 5101da177e4SLinus Torvalds return len; 5111da177e4SLinus Torvalds } 512