1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * linux/fs/affs/amigaffs.c 3*1da177e4SLinus Torvalds * 4*1da177e4SLinus Torvalds * (c) 1996 Hans-Joachim Widmaier - Rewritten 5*1da177e4SLinus Torvalds * 6*1da177e4SLinus Torvalds * (C) 1993 Ray Burr - Amiga FFS filesystem. 7*1da177e4SLinus Torvalds * 8*1da177e4SLinus Torvalds * Please send bug reports to: hjw@zvw.de 9*1da177e4SLinus Torvalds */ 10*1da177e4SLinus Torvalds 11*1da177e4SLinus Torvalds #include "affs.h" 12*1da177e4SLinus Torvalds 13*1da177e4SLinus Torvalds extern struct timezone sys_tz; 14*1da177e4SLinus Torvalds 15*1da177e4SLinus Torvalds static char ErrorBuffer[256]; 16*1da177e4SLinus Torvalds 17*1da177e4SLinus Torvalds /* 18*1da177e4SLinus Torvalds * Functions for accessing Amiga-FFS structures. 19*1da177e4SLinus Torvalds */ 20*1da177e4SLinus Torvalds 21*1da177e4SLinus Torvalds 22*1da177e4SLinus Torvalds /* Insert a header block bh into the directory dir 23*1da177e4SLinus Torvalds * caller must hold AFFS_DIR->i_hash_lock! 24*1da177e4SLinus Torvalds */ 25*1da177e4SLinus Torvalds 26*1da177e4SLinus Torvalds int 27*1da177e4SLinus Torvalds affs_insert_hash(struct inode *dir, struct buffer_head *bh) 28*1da177e4SLinus Torvalds { 29*1da177e4SLinus Torvalds struct super_block *sb = dir->i_sb; 30*1da177e4SLinus Torvalds struct buffer_head *dir_bh; 31*1da177e4SLinus Torvalds u32 ino, hash_ino; 32*1da177e4SLinus Torvalds int offset; 33*1da177e4SLinus Torvalds 34*1da177e4SLinus Torvalds ino = bh->b_blocknr; 35*1da177e4SLinus Torvalds offset = affs_hash_name(sb, AFFS_TAIL(sb, bh)->name + 1, AFFS_TAIL(sb, bh)->name[0]); 36*1da177e4SLinus Torvalds 37*1da177e4SLinus Torvalds pr_debug("AFFS: insert_hash(dir=%u, ino=%d)\n", (u32)dir->i_ino, ino); 38*1da177e4SLinus Torvalds 39*1da177e4SLinus Torvalds dir_bh = affs_bread(sb, dir->i_ino); 40*1da177e4SLinus Torvalds if (!dir_bh) 41*1da177e4SLinus Torvalds return -EIO; 42*1da177e4SLinus Torvalds 43*1da177e4SLinus Torvalds hash_ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[offset]); 44*1da177e4SLinus Torvalds while (hash_ino) { 45*1da177e4SLinus Torvalds affs_brelse(dir_bh); 46*1da177e4SLinus Torvalds dir_bh = affs_bread(sb, hash_ino); 47*1da177e4SLinus Torvalds if (!dir_bh) 48*1da177e4SLinus Torvalds return -EIO; 49*1da177e4SLinus Torvalds hash_ino = be32_to_cpu(AFFS_TAIL(sb, dir_bh)->hash_chain); 50*1da177e4SLinus Torvalds } 51*1da177e4SLinus Torvalds AFFS_TAIL(sb, bh)->parent = cpu_to_be32(dir->i_ino); 52*1da177e4SLinus Torvalds AFFS_TAIL(sb, bh)->hash_chain = 0; 53*1da177e4SLinus Torvalds affs_fix_checksum(sb, bh); 54*1da177e4SLinus Torvalds 55*1da177e4SLinus Torvalds if (dir->i_ino == dir_bh->b_blocknr) 56*1da177e4SLinus Torvalds AFFS_HEAD(dir_bh)->table[offset] = cpu_to_be32(ino); 57*1da177e4SLinus Torvalds else 58*1da177e4SLinus Torvalds AFFS_TAIL(sb, dir_bh)->hash_chain = cpu_to_be32(ino); 59*1da177e4SLinus Torvalds 60*1da177e4SLinus Torvalds affs_adjust_checksum(dir_bh, ino); 61*1da177e4SLinus Torvalds mark_buffer_dirty_inode(dir_bh, dir); 62*1da177e4SLinus Torvalds affs_brelse(dir_bh); 63*1da177e4SLinus Torvalds 64*1da177e4SLinus Torvalds dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; 65*1da177e4SLinus Torvalds dir->i_version++; 66*1da177e4SLinus Torvalds mark_inode_dirty(dir); 67*1da177e4SLinus Torvalds 68*1da177e4SLinus Torvalds return 0; 69*1da177e4SLinus Torvalds } 70*1da177e4SLinus Torvalds 71*1da177e4SLinus Torvalds /* Remove a header block from its directory. 72*1da177e4SLinus Torvalds * caller must hold AFFS_DIR->i_hash_lock! 73*1da177e4SLinus Torvalds */ 74*1da177e4SLinus Torvalds 75*1da177e4SLinus Torvalds int 76*1da177e4SLinus Torvalds affs_remove_hash(struct inode *dir, struct buffer_head *rem_bh) 77*1da177e4SLinus Torvalds { 78*1da177e4SLinus Torvalds struct super_block *sb; 79*1da177e4SLinus Torvalds struct buffer_head *bh; 80*1da177e4SLinus Torvalds u32 rem_ino, hash_ino; 81*1da177e4SLinus Torvalds __be32 ino; 82*1da177e4SLinus Torvalds int offset, retval; 83*1da177e4SLinus Torvalds 84*1da177e4SLinus Torvalds sb = dir->i_sb; 85*1da177e4SLinus Torvalds rem_ino = rem_bh->b_blocknr; 86*1da177e4SLinus Torvalds offset = affs_hash_name(sb, AFFS_TAIL(sb, rem_bh)->name+1, AFFS_TAIL(sb, rem_bh)->name[0]); 87*1da177e4SLinus Torvalds pr_debug("AFFS: remove_hash(dir=%d, ino=%d, hashval=%d)\n", (u32)dir->i_ino, rem_ino, offset); 88*1da177e4SLinus Torvalds 89*1da177e4SLinus Torvalds bh = affs_bread(sb, dir->i_ino); 90*1da177e4SLinus Torvalds if (!bh) 91*1da177e4SLinus Torvalds return -EIO; 92*1da177e4SLinus Torvalds 93*1da177e4SLinus Torvalds retval = -ENOENT; 94*1da177e4SLinus Torvalds hash_ino = be32_to_cpu(AFFS_HEAD(bh)->table[offset]); 95*1da177e4SLinus Torvalds while (hash_ino) { 96*1da177e4SLinus Torvalds if (hash_ino == rem_ino) { 97*1da177e4SLinus Torvalds ino = AFFS_TAIL(sb, rem_bh)->hash_chain; 98*1da177e4SLinus Torvalds if (dir->i_ino == bh->b_blocknr) 99*1da177e4SLinus Torvalds AFFS_HEAD(bh)->table[offset] = ino; 100*1da177e4SLinus Torvalds else 101*1da177e4SLinus Torvalds AFFS_TAIL(sb, bh)->hash_chain = ino; 102*1da177e4SLinus Torvalds affs_adjust_checksum(bh, be32_to_cpu(ino) - hash_ino); 103*1da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, dir); 104*1da177e4SLinus Torvalds AFFS_TAIL(sb, rem_bh)->parent = 0; 105*1da177e4SLinus Torvalds retval = 0; 106*1da177e4SLinus Torvalds break; 107*1da177e4SLinus Torvalds } 108*1da177e4SLinus Torvalds affs_brelse(bh); 109*1da177e4SLinus Torvalds bh = affs_bread(sb, hash_ino); 110*1da177e4SLinus Torvalds if (!bh) 111*1da177e4SLinus Torvalds return -EIO; 112*1da177e4SLinus Torvalds hash_ino = be32_to_cpu(AFFS_TAIL(sb, bh)->hash_chain); 113*1da177e4SLinus Torvalds } 114*1da177e4SLinus Torvalds 115*1da177e4SLinus Torvalds affs_brelse(bh); 116*1da177e4SLinus Torvalds 117*1da177e4SLinus Torvalds dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; 118*1da177e4SLinus Torvalds dir->i_version++; 119*1da177e4SLinus Torvalds mark_inode_dirty(dir); 120*1da177e4SLinus Torvalds 121*1da177e4SLinus Torvalds return retval; 122*1da177e4SLinus Torvalds } 123*1da177e4SLinus Torvalds 124*1da177e4SLinus Torvalds static void 125*1da177e4SLinus Torvalds affs_fix_dcache(struct dentry *dentry, u32 entry_ino) 126*1da177e4SLinus Torvalds { 127*1da177e4SLinus Torvalds struct inode *inode = dentry->d_inode; 128*1da177e4SLinus Torvalds void *data = dentry->d_fsdata; 129*1da177e4SLinus Torvalds struct list_head *head, *next; 130*1da177e4SLinus Torvalds 131*1da177e4SLinus Torvalds spin_lock(&dcache_lock); 132*1da177e4SLinus Torvalds head = &inode->i_dentry; 133*1da177e4SLinus Torvalds next = head->next; 134*1da177e4SLinus Torvalds while (next != head) { 135*1da177e4SLinus Torvalds dentry = list_entry(next, struct dentry, d_alias); 136*1da177e4SLinus Torvalds if (entry_ino == (u32)(long)dentry->d_fsdata) { 137*1da177e4SLinus Torvalds dentry->d_fsdata = data; 138*1da177e4SLinus Torvalds break; 139*1da177e4SLinus Torvalds } 140*1da177e4SLinus Torvalds next = next->next; 141*1da177e4SLinus Torvalds } 142*1da177e4SLinus Torvalds spin_unlock(&dcache_lock); 143*1da177e4SLinus Torvalds } 144*1da177e4SLinus Torvalds 145*1da177e4SLinus Torvalds 146*1da177e4SLinus Torvalds /* Remove header from link chain */ 147*1da177e4SLinus Torvalds 148*1da177e4SLinus Torvalds static int 149*1da177e4SLinus Torvalds affs_remove_link(struct dentry *dentry) 150*1da177e4SLinus Torvalds { 151*1da177e4SLinus Torvalds struct inode *dir, *inode = dentry->d_inode; 152*1da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 153*1da177e4SLinus Torvalds struct buffer_head *bh = NULL, *link_bh = NULL; 154*1da177e4SLinus Torvalds u32 link_ino, ino; 155*1da177e4SLinus Torvalds int retval; 156*1da177e4SLinus Torvalds 157*1da177e4SLinus Torvalds pr_debug("AFFS: remove_link(key=%ld)\n", inode->i_ino); 158*1da177e4SLinus Torvalds retval = -EIO; 159*1da177e4SLinus Torvalds bh = affs_bread(sb, inode->i_ino); 160*1da177e4SLinus Torvalds if (!bh) 161*1da177e4SLinus Torvalds goto done; 162*1da177e4SLinus Torvalds 163*1da177e4SLinus Torvalds link_ino = (u32)(long)dentry->d_fsdata; 164*1da177e4SLinus Torvalds if (inode->i_ino == link_ino) { 165*1da177e4SLinus Torvalds /* we can't remove the head of the link, as its blocknr is still used as ino, 166*1da177e4SLinus Torvalds * so we remove the block of the first link instead. 167*1da177e4SLinus Torvalds */ 168*1da177e4SLinus Torvalds link_ino = be32_to_cpu(AFFS_TAIL(sb, bh)->link_chain); 169*1da177e4SLinus Torvalds link_bh = affs_bread(sb, link_ino); 170*1da177e4SLinus Torvalds if (!link_bh) 171*1da177e4SLinus Torvalds goto done; 172*1da177e4SLinus Torvalds 173*1da177e4SLinus Torvalds dir = iget(sb, be32_to_cpu(AFFS_TAIL(sb, link_bh)->parent)); 174*1da177e4SLinus Torvalds if (!dir) 175*1da177e4SLinus Torvalds goto done; 176*1da177e4SLinus Torvalds 177*1da177e4SLinus Torvalds affs_lock_dir(dir); 178*1da177e4SLinus Torvalds affs_fix_dcache(dentry, link_ino); 179*1da177e4SLinus Torvalds retval = affs_remove_hash(dir, link_bh); 180*1da177e4SLinus Torvalds if (retval) 181*1da177e4SLinus Torvalds goto done; 182*1da177e4SLinus Torvalds mark_buffer_dirty_inode(link_bh, inode); 183*1da177e4SLinus Torvalds 184*1da177e4SLinus Torvalds memcpy(AFFS_TAIL(sb, bh)->name, AFFS_TAIL(sb, link_bh)->name, 32); 185*1da177e4SLinus Torvalds retval = affs_insert_hash(dir, bh); 186*1da177e4SLinus Torvalds if (retval) 187*1da177e4SLinus Torvalds goto done; 188*1da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 189*1da177e4SLinus Torvalds 190*1da177e4SLinus Torvalds affs_unlock_dir(dir); 191*1da177e4SLinus Torvalds iput(dir); 192*1da177e4SLinus Torvalds } else { 193*1da177e4SLinus Torvalds link_bh = affs_bread(sb, link_ino); 194*1da177e4SLinus Torvalds if (!link_bh) 195*1da177e4SLinus Torvalds goto done; 196*1da177e4SLinus Torvalds } 197*1da177e4SLinus Torvalds 198*1da177e4SLinus Torvalds while ((ino = be32_to_cpu(AFFS_TAIL(sb, bh)->link_chain)) != 0) { 199*1da177e4SLinus Torvalds if (ino == link_ino) { 200*1da177e4SLinus Torvalds __be32 ino2 = AFFS_TAIL(sb, link_bh)->link_chain; 201*1da177e4SLinus Torvalds AFFS_TAIL(sb, bh)->link_chain = ino2; 202*1da177e4SLinus Torvalds affs_adjust_checksum(bh, be32_to_cpu(ino2) - link_ino); 203*1da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 204*1da177e4SLinus Torvalds retval = 0; 205*1da177e4SLinus Torvalds /* Fix the link count, if bh is a normal header block without links */ 206*1da177e4SLinus Torvalds switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) { 207*1da177e4SLinus Torvalds case ST_LINKDIR: 208*1da177e4SLinus Torvalds case ST_LINKFILE: 209*1da177e4SLinus Torvalds break; 210*1da177e4SLinus Torvalds default: 211*1da177e4SLinus Torvalds if (!AFFS_TAIL(sb, bh)->link_chain) 212*1da177e4SLinus Torvalds inode->i_nlink = 1; 213*1da177e4SLinus Torvalds } 214*1da177e4SLinus Torvalds affs_free_block(sb, link_ino); 215*1da177e4SLinus Torvalds goto done; 216*1da177e4SLinus Torvalds } 217*1da177e4SLinus Torvalds affs_brelse(bh); 218*1da177e4SLinus Torvalds bh = affs_bread(sb, ino); 219*1da177e4SLinus Torvalds if (!bh) 220*1da177e4SLinus Torvalds goto done; 221*1da177e4SLinus Torvalds } 222*1da177e4SLinus Torvalds retval = -ENOENT; 223*1da177e4SLinus Torvalds done: 224*1da177e4SLinus Torvalds affs_brelse(link_bh); 225*1da177e4SLinus Torvalds affs_brelse(bh); 226*1da177e4SLinus Torvalds return retval; 227*1da177e4SLinus Torvalds } 228*1da177e4SLinus Torvalds 229*1da177e4SLinus Torvalds 230*1da177e4SLinus Torvalds static int 231*1da177e4SLinus Torvalds affs_empty_dir(struct inode *inode) 232*1da177e4SLinus Torvalds { 233*1da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 234*1da177e4SLinus Torvalds struct buffer_head *bh; 235*1da177e4SLinus Torvalds int retval, size; 236*1da177e4SLinus Torvalds 237*1da177e4SLinus Torvalds retval = -EIO; 238*1da177e4SLinus Torvalds bh = affs_bread(sb, inode->i_ino); 239*1da177e4SLinus Torvalds if (!bh) 240*1da177e4SLinus Torvalds goto done; 241*1da177e4SLinus Torvalds 242*1da177e4SLinus Torvalds retval = -ENOTEMPTY; 243*1da177e4SLinus Torvalds for (size = AFFS_SB(sb)->s_hashsize - 1; size >= 0; size--) 244*1da177e4SLinus Torvalds if (AFFS_HEAD(bh)->table[size]) 245*1da177e4SLinus Torvalds goto not_empty; 246*1da177e4SLinus Torvalds retval = 0; 247*1da177e4SLinus Torvalds not_empty: 248*1da177e4SLinus Torvalds affs_brelse(bh); 249*1da177e4SLinus Torvalds done: 250*1da177e4SLinus Torvalds return retval; 251*1da177e4SLinus Torvalds } 252*1da177e4SLinus Torvalds 253*1da177e4SLinus Torvalds 254*1da177e4SLinus Torvalds /* Remove a filesystem object. If the object to be removed has 255*1da177e4SLinus Torvalds * links to it, one of the links must be changed to inherit 256*1da177e4SLinus Torvalds * the file or directory. As above, any inode will do. 257*1da177e4SLinus Torvalds * The buffer will not be freed. If the header is a link, the 258*1da177e4SLinus Torvalds * block will be marked as free. 259*1da177e4SLinus Torvalds * This function returns a negative error number in case of 260*1da177e4SLinus Torvalds * an error, else 0 if the inode is to be deleted or 1 if not. 261*1da177e4SLinus Torvalds */ 262*1da177e4SLinus Torvalds 263*1da177e4SLinus Torvalds int 264*1da177e4SLinus Torvalds affs_remove_header(struct dentry *dentry) 265*1da177e4SLinus Torvalds { 266*1da177e4SLinus Torvalds struct super_block *sb; 267*1da177e4SLinus Torvalds struct inode *inode, *dir; 268*1da177e4SLinus Torvalds struct buffer_head *bh = NULL; 269*1da177e4SLinus Torvalds int retval; 270*1da177e4SLinus Torvalds 271*1da177e4SLinus Torvalds dir = dentry->d_parent->d_inode; 272*1da177e4SLinus Torvalds sb = dir->i_sb; 273*1da177e4SLinus Torvalds 274*1da177e4SLinus Torvalds retval = -ENOENT; 275*1da177e4SLinus Torvalds inode = dentry->d_inode; 276*1da177e4SLinus Torvalds if (!inode) 277*1da177e4SLinus Torvalds goto done; 278*1da177e4SLinus Torvalds 279*1da177e4SLinus Torvalds pr_debug("AFFS: remove_header(key=%ld)\n", inode->i_ino); 280*1da177e4SLinus Torvalds retval = -EIO; 281*1da177e4SLinus Torvalds bh = affs_bread(sb, (u32)(long)dentry->d_fsdata); 282*1da177e4SLinus Torvalds if (!bh) 283*1da177e4SLinus Torvalds goto done; 284*1da177e4SLinus Torvalds 285*1da177e4SLinus Torvalds affs_lock_link(inode); 286*1da177e4SLinus Torvalds affs_lock_dir(dir); 287*1da177e4SLinus Torvalds switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) { 288*1da177e4SLinus Torvalds case ST_USERDIR: 289*1da177e4SLinus Torvalds /* if we ever want to support links to dirs 290*1da177e4SLinus Torvalds * i_hash_lock of the inode must only be 291*1da177e4SLinus Torvalds * taken after some checks 292*1da177e4SLinus Torvalds */ 293*1da177e4SLinus Torvalds affs_lock_dir(inode); 294*1da177e4SLinus Torvalds retval = affs_empty_dir(inode); 295*1da177e4SLinus Torvalds affs_unlock_dir(inode); 296*1da177e4SLinus Torvalds if (retval) 297*1da177e4SLinus Torvalds goto done_unlock; 298*1da177e4SLinus Torvalds break; 299*1da177e4SLinus Torvalds default: 300*1da177e4SLinus Torvalds break; 301*1da177e4SLinus Torvalds } 302*1da177e4SLinus Torvalds 303*1da177e4SLinus Torvalds retval = affs_remove_hash(dir, bh); 304*1da177e4SLinus Torvalds if (retval) 305*1da177e4SLinus Torvalds goto done_unlock; 306*1da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 307*1da177e4SLinus Torvalds 308*1da177e4SLinus Torvalds affs_unlock_dir(dir); 309*1da177e4SLinus Torvalds 310*1da177e4SLinus Torvalds if (inode->i_nlink > 1) 311*1da177e4SLinus Torvalds retval = affs_remove_link(dentry); 312*1da177e4SLinus Torvalds else 313*1da177e4SLinus Torvalds inode->i_nlink = 0; 314*1da177e4SLinus Torvalds affs_unlock_link(inode); 315*1da177e4SLinus Torvalds inode->i_ctime = CURRENT_TIME_SEC; 316*1da177e4SLinus Torvalds mark_inode_dirty(inode); 317*1da177e4SLinus Torvalds 318*1da177e4SLinus Torvalds done: 319*1da177e4SLinus Torvalds affs_brelse(bh); 320*1da177e4SLinus Torvalds return retval; 321*1da177e4SLinus Torvalds 322*1da177e4SLinus Torvalds done_unlock: 323*1da177e4SLinus Torvalds affs_unlock_dir(dir); 324*1da177e4SLinus Torvalds affs_unlock_link(inode); 325*1da177e4SLinus Torvalds goto done; 326*1da177e4SLinus Torvalds } 327*1da177e4SLinus Torvalds 328*1da177e4SLinus Torvalds /* Checksum a block, do various consistency checks and optionally return 329*1da177e4SLinus Torvalds the blocks type number. DATA points to the block. If their pointers 330*1da177e4SLinus Torvalds are non-null, *PTYPE and *STYPE are set to the primary and secondary 331*1da177e4SLinus Torvalds block types respectively, *HASHSIZE is set to the size of the hashtable 332*1da177e4SLinus Torvalds (which lets us calculate the block size). 333*1da177e4SLinus Torvalds Returns non-zero if the block is not consistent. */ 334*1da177e4SLinus Torvalds 335*1da177e4SLinus Torvalds u32 336*1da177e4SLinus Torvalds affs_checksum_block(struct super_block *sb, struct buffer_head *bh) 337*1da177e4SLinus Torvalds { 338*1da177e4SLinus Torvalds __be32 *ptr = (__be32 *)bh->b_data; 339*1da177e4SLinus Torvalds u32 sum; 340*1da177e4SLinus Torvalds int bsize; 341*1da177e4SLinus Torvalds 342*1da177e4SLinus Torvalds sum = 0; 343*1da177e4SLinus Torvalds for (bsize = sb->s_blocksize / sizeof(__be32); bsize > 0; bsize--) 344*1da177e4SLinus Torvalds sum += be32_to_cpu(*ptr++); 345*1da177e4SLinus Torvalds return sum; 346*1da177e4SLinus Torvalds } 347*1da177e4SLinus Torvalds 348*1da177e4SLinus Torvalds /* 349*1da177e4SLinus Torvalds * Calculate the checksum of a disk block and store it 350*1da177e4SLinus Torvalds * at the indicated position. 351*1da177e4SLinus Torvalds */ 352*1da177e4SLinus Torvalds 353*1da177e4SLinus Torvalds void 354*1da177e4SLinus Torvalds affs_fix_checksum(struct super_block *sb, struct buffer_head *bh) 355*1da177e4SLinus Torvalds { 356*1da177e4SLinus Torvalds int cnt = sb->s_blocksize / sizeof(__be32); 357*1da177e4SLinus Torvalds __be32 *ptr = (__be32 *)bh->b_data; 358*1da177e4SLinus Torvalds u32 checksum; 359*1da177e4SLinus Torvalds __be32 *checksumptr; 360*1da177e4SLinus Torvalds 361*1da177e4SLinus Torvalds checksumptr = ptr + 5; 362*1da177e4SLinus Torvalds *checksumptr = 0; 363*1da177e4SLinus Torvalds for (checksum = 0; cnt > 0; ptr++, cnt--) 364*1da177e4SLinus Torvalds checksum += be32_to_cpu(*ptr); 365*1da177e4SLinus Torvalds *checksumptr = cpu_to_be32(-checksum); 366*1da177e4SLinus Torvalds } 367*1da177e4SLinus Torvalds 368*1da177e4SLinus Torvalds void 369*1da177e4SLinus Torvalds secs_to_datestamp(time_t secs, struct affs_date *ds) 370*1da177e4SLinus Torvalds { 371*1da177e4SLinus Torvalds u32 days; 372*1da177e4SLinus Torvalds u32 minute; 373*1da177e4SLinus Torvalds 374*1da177e4SLinus Torvalds secs -= sys_tz.tz_minuteswest * 60 + ((8 * 365 + 2) * 24 * 60 * 60); 375*1da177e4SLinus Torvalds if (secs < 0) 376*1da177e4SLinus Torvalds secs = 0; 377*1da177e4SLinus Torvalds days = secs / 86400; 378*1da177e4SLinus Torvalds secs -= days * 86400; 379*1da177e4SLinus Torvalds minute = secs / 60; 380*1da177e4SLinus Torvalds secs -= minute * 60; 381*1da177e4SLinus Torvalds 382*1da177e4SLinus Torvalds ds->days = cpu_to_be32(days); 383*1da177e4SLinus Torvalds ds->mins = cpu_to_be32(minute); 384*1da177e4SLinus Torvalds ds->ticks = cpu_to_be32(secs * 50); 385*1da177e4SLinus Torvalds } 386*1da177e4SLinus Torvalds 387*1da177e4SLinus Torvalds mode_t 388*1da177e4SLinus Torvalds prot_to_mode(u32 prot) 389*1da177e4SLinus Torvalds { 390*1da177e4SLinus Torvalds int mode = 0; 391*1da177e4SLinus Torvalds 392*1da177e4SLinus Torvalds if (!(prot & FIBF_NOWRITE)) 393*1da177e4SLinus Torvalds mode |= S_IWUSR; 394*1da177e4SLinus Torvalds if (!(prot & FIBF_NOREAD)) 395*1da177e4SLinus Torvalds mode |= S_IRUSR; 396*1da177e4SLinus Torvalds if (!(prot & FIBF_NOEXECUTE)) 397*1da177e4SLinus Torvalds mode |= S_IXUSR; 398*1da177e4SLinus Torvalds if (prot & FIBF_GRP_WRITE) 399*1da177e4SLinus Torvalds mode |= S_IWGRP; 400*1da177e4SLinus Torvalds if (prot & FIBF_GRP_READ) 401*1da177e4SLinus Torvalds mode |= S_IRGRP; 402*1da177e4SLinus Torvalds if (prot & FIBF_GRP_EXECUTE) 403*1da177e4SLinus Torvalds mode |= S_IXGRP; 404*1da177e4SLinus Torvalds if (prot & FIBF_OTR_WRITE) 405*1da177e4SLinus Torvalds mode |= S_IWOTH; 406*1da177e4SLinus Torvalds if (prot & FIBF_OTR_READ) 407*1da177e4SLinus Torvalds mode |= S_IROTH; 408*1da177e4SLinus Torvalds if (prot & FIBF_OTR_EXECUTE) 409*1da177e4SLinus Torvalds mode |= S_IXOTH; 410*1da177e4SLinus Torvalds 411*1da177e4SLinus Torvalds return mode; 412*1da177e4SLinus Torvalds } 413*1da177e4SLinus Torvalds 414*1da177e4SLinus Torvalds void 415*1da177e4SLinus Torvalds mode_to_prot(struct inode *inode) 416*1da177e4SLinus Torvalds { 417*1da177e4SLinus Torvalds u32 prot = AFFS_I(inode)->i_protect; 418*1da177e4SLinus Torvalds mode_t mode = inode->i_mode; 419*1da177e4SLinus Torvalds 420*1da177e4SLinus Torvalds if (!(mode & S_IXUSR)) 421*1da177e4SLinus Torvalds prot |= FIBF_NOEXECUTE; 422*1da177e4SLinus Torvalds if (!(mode & S_IRUSR)) 423*1da177e4SLinus Torvalds prot |= FIBF_NOREAD; 424*1da177e4SLinus Torvalds if (!(mode & S_IWUSR)) 425*1da177e4SLinus Torvalds prot |= FIBF_NOWRITE; 426*1da177e4SLinus Torvalds if (mode & S_IXGRP) 427*1da177e4SLinus Torvalds prot |= FIBF_GRP_EXECUTE; 428*1da177e4SLinus Torvalds if (mode & S_IRGRP) 429*1da177e4SLinus Torvalds prot |= FIBF_GRP_READ; 430*1da177e4SLinus Torvalds if (mode & S_IWGRP) 431*1da177e4SLinus Torvalds prot |= FIBF_GRP_WRITE; 432*1da177e4SLinus Torvalds if (mode & S_IXOTH) 433*1da177e4SLinus Torvalds prot |= FIBF_OTR_EXECUTE; 434*1da177e4SLinus Torvalds if (mode & S_IROTH) 435*1da177e4SLinus Torvalds prot |= FIBF_OTR_READ; 436*1da177e4SLinus Torvalds if (mode & S_IWOTH) 437*1da177e4SLinus Torvalds prot |= FIBF_OTR_WRITE; 438*1da177e4SLinus Torvalds 439*1da177e4SLinus Torvalds AFFS_I(inode)->i_protect = prot; 440*1da177e4SLinus Torvalds } 441*1da177e4SLinus Torvalds 442*1da177e4SLinus Torvalds void 443*1da177e4SLinus Torvalds affs_error(struct super_block *sb, const char *function, const char *fmt, ...) 444*1da177e4SLinus Torvalds { 445*1da177e4SLinus Torvalds va_list args; 446*1da177e4SLinus Torvalds 447*1da177e4SLinus Torvalds va_start(args,fmt); 448*1da177e4SLinus Torvalds vsprintf(ErrorBuffer,fmt,args); 449*1da177e4SLinus Torvalds va_end(args); 450*1da177e4SLinus Torvalds 451*1da177e4SLinus Torvalds printk(KERN_CRIT "AFFS error (device %s): %s(): %s\n", sb->s_id, 452*1da177e4SLinus Torvalds function,ErrorBuffer); 453*1da177e4SLinus Torvalds if (!(sb->s_flags & MS_RDONLY)) 454*1da177e4SLinus Torvalds printk(KERN_WARNING "AFFS: Remounting filesystem read-only\n"); 455*1da177e4SLinus Torvalds sb->s_flags |= MS_RDONLY; 456*1da177e4SLinus Torvalds } 457*1da177e4SLinus Torvalds 458*1da177e4SLinus Torvalds void 459*1da177e4SLinus Torvalds affs_warning(struct super_block *sb, const char *function, const char *fmt, ...) 460*1da177e4SLinus Torvalds { 461*1da177e4SLinus Torvalds va_list args; 462*1da177e4SLinus Torvalds 463*1da177e4SLinus Torvalds va_start(args,fmt); 464*1da177e4SLinus Torvalds vsprintf(ErrorBuffer,fmt,args); 465*1da177e4SLinus Torvalds va_end(args); 466*1da177e4SLinus Torvalds 467*1da177e4SLinus Torvalds printk(KERN_WARNING "AFFS warning (device %s): %s(): %s\n", sb->s_id, 468*1da177e4SLinus Torvalds function,ErrorBuffer); 469*1da177e4SLinus Torvalds } 470*1da177e4SLinus Torvalds 471*1da177e4SLinus Torvalds /* Check if the name is valid for a affs object. */ 472*1da177e4SLinus Torvalds 473*1da177e4SLinus Torvalds int 474*1da177e4SLinus Torvalds affs_check_name(const unsigned char *name, int len) 475*1da177e4SLinus Torvalds { 476*1da177e4SLinus Torvalds int i; 477*1da177e4SLinus Torvalds 478*1da177e4SLinus Torvalds if (len > 30) 479*1da177e4SLinus Torvalds #ifdef AFFS_NO_TRUNCATE 480*1da177e4SLinus Torvalds return -ENAMETOOLONG; 481*1da177e4SLinus Torvalds #else 482*1da177e4SLinus Torvalds len = 30; 483*1da177e4SLinus Torvalds #endif 484*1da177e4SLinus Torvalds 485*1da177e4SLinus Torvalds for (i = 0; i < len; i++) { 486*1da177e4SLinus Torvalds if (name[i] < ' ' || name[i] == ':' 487*1da177e4SLinus Torvalds || (name[i] > 0x7e && name[i] < 0xa0)) 488*1da177e4SLinus Torvalds return -EINVAL; 489*1da177e4SLinus Torvalds } 490*1da177e4SLinus Torvalds 491*1da177e4SLinus Torvalds return 0; 492*1da177e4SLinus Torvalds } 493*1da177e4SLinus Torvalds 494*1da177e4SLinus Torvalds /* This function copies name to bstr, with at most 30 495*1da177e4SLinus Torvalds * characters length. The bstr will be prepended by 496*1da177e4SLinus Torvalds * a length byte. 497*1da177e4SLinus Torvalds * NOTE: The name will must be already checked by 498*1da177e4SLinus Torvalds * affs_check_name()! 499*1da177e4SLinus Torvalds */ 500*1da177e4SLinus Torvalds 501*1da177e4SLinus Torvalds int 502*1da177e4SLinus Torvalds affs_copy_name(unsigned char *bstr, struct dentry *dentry) 503*1da177e4SLinus Torvalds { 504*1da177e4SLinus Torvalds int len = min(dentry->d_name.len, 30u); 505*1da177e4SLinus Torvalds 506*1da177e4SLinus Torvalds *bstr++ = len; 507*1da177e4SLinus Torvalds memcpy(bstr, dentry->d_name.name, len); 508*1da177e4SLinus Torvalds return len; 509*1da177e4SLinus Torvalds } 510