diff options
Diffstat (limited to 'fs/affs')
-rw-r--r-- | fs/affs/Changes | 95 | ||||
-rw-r--r-- | fs/affs/amigaffs.c | 96 | ||||
-rw-r--r-- | fs/affs/bitmap.c | 52 | ||||
-rw-r--r-- | fs/affs/dir.c | 25 | ||||
-rw-r--r-- | fs/affs/file.c | 99 | ||||
-rw-r--r-- | fs/affs/inode.c | 201 | ||||
-rw-r--r-- | fs/affs/namei.c | 37 | ||||
-rw-r--r-- | fs/affs/symlink.c | 4 |
8 files changed, 400 insertions, 209 deletions
diff --git a/fs/affs/Changes b/fs/affs/Changes new file mode 100644 index 000000000..a65dc326a --- /dev/null +++ b/fs/affs/Changes @@ -0,0 +1,95 @@ +(Note: I consider version numbers as cheap. That means +that I do not like numbers like 0.1 and the like for +things that can be used since quite some time. But +then, 3.1 doesn't mean 'perfectly stable', too.) + +Known bugs: +----------- + +- Doesn't work on the alpha. The only 64/32-bit + problem that I'm aware of (pointer/int conversion + in readdir()) gives compiler warnings but is + apparently not causing the failure, as directory + reads basically work (but all files are of size 0). + Alas, I've got no alpha to debug. :-( +- If an affs mounted filesystem is exported via + nfs, it cannot be written to. No networking to + test that, either. :-( + +Please direct bug reports to: hjw@zvw.de + +Version 3.4 +----------- + +- Hash chains are now sorted by block numbers. + (Thanks to Kars de Jong for finding this.) +- Removed all unnecessary external symbols. + +Version 3.3 +----------- + +- Tried to make all types 'correct' and consistent. +- Errors and warnings are now reported via a + function. They are all prefixed by a severity + and have the same appearance: + "AFFS: <function>: <error message>" + (There's one exception to this, as in that function + is no pointer to the super block available.) +- The filesystem is remounted read-only after an + error. +- The names of newly created filesystem objects are + now checked for validity. +- Minor cleanups in comments. +- Added this Changes file. At last! + +Version 3.2 +----------- + +- Extension block cache: Reading/writing of huge files + (several MB) is much faster (of course the added + overhead slows down opening, but this is hardly + noticeable). +- The same get_block()-routine can now be used for + both OFS and FFS. +- The super block is now searched in the block that + was calculated and in the one following. This + should remedy the round-off error introduced by + the 1-k blocks that Linux uses. +- Minor changes to adhere to the new VFS interface. +- The number of used blocks is now also calculated + if the filesystem is mounted read-only. +- Prefixed some constants with AFFS_ to avoid name + clashes. +- Removed 'EXPERIMENTAL' status. + +Version 3.1 +----------- + +- Fixed a nasty bug which didn't allow read-only + mounts. +- Allow dir-cache filesystems to be mounted + read only. +- OFS support. +- Several other changes I just cannot remember + any more. + +Version 3.0 +----------- + +- Almost complete rewrite for the new VFS + interface in Linux 1.3. +- Write support. +- Support for hard and symbolic links. +- Lots of things I remeber even less ... + +Version 2.0 +----------- + +- Fixed a few things to get it compiled. +- Automatic root block calculation. +- Partition checker for genhd.c + +======================================== + +Let's just call Ray Burr's original affs +'Version 1.0'. diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c index 63d76a86e..4afd66e49 100644 --- a/fs/affs/amigaffs.c +++ b/fs/affs/amigaffs.c @@ -5,8 +5,10 @@ * * (C) 1993 Ray Burr - Amiga FFS filesystem. * + * Please send bug reports to: hjw@zvw.de */ +#include <stdarg.h> #include <linux/stat.h> #include <linux/sched.h> #include <linux/affs_fs.h> @@ -17,6 +19,8 @@ extern struct timezone sys_tz; +static char ErrorBuffer[256]; + /* * Functions for accessing Amiga-FFS structures. * @@ -28,7 +32,7 @@ extern struct timezone sys_tz; 0 is returned. Otherwise, the key number in the next used hash slot is returned. */ -int +static int affs_find_next_hash_entry(int hsize, void *dir_data, int *hash_pos) { struct dir_front *dir_front = dir_data; @@ -54,24 +58,23 @@ affs_get_file_name(int bsize, void *fh_data, char **name) file_end = GET_END_PTR(struct file_end, fh_data, bsize); if (file_end->file_name[0] == 0 || file_end->file_name[0] > 30) { - printk ("affs_get_file_name: OOPS! bad filename\n"); - printk (" file_end->file_name[0] = %d\n", + printk(KERN_WARNING "AFFS: bad filename (length=%d chars)\n", file_end->file_name[0]); *name = "***BAD_FILE***"; return 14; } - *name = (char *) &file_end->file_name[1]; + *name = (char *)&file_end->file_name[1]; return file_end->file_name[0]; } /* Find the predecessor in the hash chain */ int -affs_fix_hash_pred(struct inode *startino, int startoffset, int key, int newkey) +affs_fix_hash_pred(struct inode *startino, int startoffset, s32 key, s32 newkey) { struct buffer_head *bh = NULL; - int nextkey; - int ptype, stype; + s32 nextkey; + s32 ptype, stype; int retval; nextkey = startino->i_ino; @@ -87,14 +90,14 @@ affs_fix_hash_pred(struct inode *startino, int startoffset, int key, int newkey) || ptype != T_SHORT || (stype != ST_FILE && stype != ST_USERDIR && stype != ST_LINKFILE && stype != ST_LINKDIR && stype != ST_ROOT && stype != ST_SOFTLINK)) { - printk("AFFS: bad block found in link chain (ptype=%d, stype=%d)\n", - ptype,stype); + affs_error(startino->i_sb,"affs_fix_hash_pred", + "Bad block in link chain (ptype=%d, stype=%d)",ptype,stype); affs_brelse(bh); break; } - nextkey = htonl(((__u32 *)bh->b_data)[startoffset]); + nextkey = htonl(((s32 *)bh->b_data)[startoffset]); if (nextkey == key) { - ((__u32 *)bh->b_data)[startoffset] = newkey; + ((s32 *)bh->b_data)[startoffset] = newkey; affs_fix_checksum(AFFS_I2BSIZE(startino),bh->b_data,5); mark_buffer_dirty(bh,1); affs_brelse(bh); @@ -112,13 +115,13 @@ affs_fix_hash_pred(struct inode *startino, int startoffset, int key, int newkey) /* Remove inode from link chain */ int -affs_fix_link_pred(struct inode *startino, int key, int newkey) +affs_fix_link_pred(struct inode *startino, s32 key, s32 newkey) { struct buffer_head *bh = NULL; - int nextkey; + s32 nextkey; int offset; - int etype = 0; - int ptype, stype; + s32 etype = 0; + s32 ptype, stype; int retval; offset = AFFS_I2BSIZE(startino) / 4 - 10; @@ -150,7 +153,7 @@ affs_fix_link_pred(struct inode *startino, int key, int newkey) retval = -EPERM; break; } - nextkey = htonl(((__u32 *)bh->b_data)[offset]); + nextkey = htonl(((s32 *)bh->b_data)[offset]); if (nextkey == key) { FILE_END(bh->b_data,startino)->link_chain = newkey; affs_fix_checksum(AFFS_I2BSIZE(startino),bh->b_data,5); @@ -172,17 +175,17 @@ affs_fix_link_pred(struct inode *startino, int key, int newkey) (which lets us calculate the block size). Returns non-zero if the block is not consistent. */ -__u32 -affs_checksum_block(int bsize, void *data, int *ptype, int *stype) +u32 +affs_checksum_block(int bsize, void *data, s32 *ptype, s32 *stype) { - __u32 sum; - __u32 *p; + u32 sum; + u32 *p; bsize /= 4; if (ptype) - *ptype = htonl(((__s32 *)data)[0]); + *ptype = htonl(((s32 *)data)[0]); if (stype) - *stype = htonl(((__s32 *)data)[bsize - 1]); + *stype = htonl(((s32 *)data)[bsize - 1]); sum = 0; p = data; @@ -194,20 +197,20 @@ affs_checksum_block(int bsize, void *data, int *ptype, int *stype) void affs_fix_checksum(int bsize, void *data, int cspos) { - __u32 ocs; - __u32 cs; + u32 ocs; + u32 cs; cs = affs_checksum_block(bsize,data,NULL,NULL); - ocs = htonl (((__u32 *)data)[cspos]); + ocs = htonl (((u32 *)data)[cspos]); ocs -= cs; - ((__u32 *)data)[cspos] = htonl(ocs); + ((u32 *)data)[cspos] = htonl(ocs); } void -secs_to_datestamp(int secs, struct DateStamp *ds) +secs_to_datestamp(time_t secs, struct DateStamp *ds) { - __u32 days; - __u32 minute; + u32 days; + u32 minute; secs -= sys_tz.tz_minuteswest * 60 +((8 * 365 + 2) * 24 * 60 * 60); if (secs < 0) @@ -223,7 +226,7 @@ secs_to_datestamp(int secs, struct DateStamp *ds) } int -prot_to_mode(__u32 prot) +prot_to_mode(u32 prot) { int mode = 0; @@ -249,10 +252,10 @@ prot_to_mode(__u32 prot) return mode; } -unsigned int +u32 mode_to_prot(int mode) { - unsigned int prot = 0; + u32 prot = 0; if (mode & S_IXUSR) prot |= FIBF_SCRIPT; @@ -271,3 +274,32 @@ mode_to_prot(int mode) return prot; } + +void +affs_error(struct super_block *sb, const char *function, const char *fmt, ...) +{ + va_list args; + + va_start(args,fmt); + vsprintf(ErrorBuffer,fmt,args); + va_end(args); + + printk(KERN_CRIT "AFFS error (device %s): %s(): %s\n",kdevname(sb->s_dev), + function,ErrorBuffer); + if (!(sb->s_flags & MS_RDONLY)) + printk(KERN_WARNING "AFFS: Remounting filesystem read-only\n"); + sb->s_flags |= MS_RDONLY; +} + +void +affs_warning(struct super_block *sb, const char *function, const char *fmt, ...) +{ + va_list args; + + va_start(args,fmt); + vsprintf(ErrorBuffer,fmt,args); + va_end(args); + + printk(KERN_WARNING "AFFS error (device %s): %s(): %s\n",kdevname(sb->s_dev), + function,ErrorBuffer); +} diff --git a/fs/affs/bitmap.c b/fs/affs/bitmap.c index 1d69d5a3d..a7382db4c 100644 --- a/fs/affs/bitmap.c +++ b/fs/affs/bitmap.c @@ -3,7 +3,6 @@ * * (c) 1996 Hans-Joachim Widmaier * - * * bitmap.c contains the code that handles all bitmap related stuff - * block allocation, deallocation, calculation of free space. */ @@ -54,7 +53,7 @@ affs_count_free_blocks(struct super_block *s) } void -affs_free_block(struct super_block *sb, int block) +affs_free_block(struct super_block *sb, s32 block) { int bmap; int bit; @@ -70,7 +69,7 @@ affs_free_block(struct super_block *sb, int block) zone_no = (bmap << (sb->s_blocksize_bits - 7)) + bit / 1024; bm = &sb->u.affs_sb.s_bitmap[bmap]; if (bmap >= sb->u.affs_sb.s_bm_count) { - printk("AFFS: free_block(): block %d outside partition.\n",block); + affs_error(sb,"affs_free_block","Block %d outside partition",block); return; } blk = 0; @@ -83,15 +82,16 @@ affs_free_block(struct super_block *sb, int block) if (!bm->bm_bh) { bm->bm_count--; unlock_super(sb); - printk("AFFS: free_block(): Cannot read bitmap block %d\n",bm->bm_key); + affs_error(sb,"affs_free_block","Cannot read bitmap block %d",bm->bm_key); return; } } - if (set_bit(bit ^ BO_EXBITS,bm->bm_bh->b_data + 4)) - printk("AFFS: free_block(): block %d is already free.\n",block); + if (test_and_set_bit(bit ^ BO_EXBITS,bm->bm_bh->b_data + 4)) + affs_warning(sb,"affs_free_block","Trying to free block %d which is already free", + block); else { sb->u.affs_sb.s_alloc[zone_no].az_free++; - ((__u32 *)bm->bm_bh->b_data)[0] = ntohl(htonl(((__u32 *)bm->bm_bh->b_data)[0]) - blk); + ((u32 *)bm->bm_bh->b_data)[0] = ntohl(htonl(((u32 *)bm->bm_bh->b_data)[0]) - blk); mark_buffer_dirty(bm->bm_bh,1); sb->s_dirt = 1; } @@ -102,15 +102,15 @@ affs_free_block(struct super_block *sb, int block) unlock_super(sb); } -static int +static s32 affs_balloc(struct inode *inode, int zone_no) { - __u32 w; - __u32 *bm; + u32 w; + u32 *bm; int fb; int i; int fwb; - int block; + s32 block; struct affs_zone *zone; struct affs_alloc_zone *az; struct super_block *sb; @@ -124,7 +124,7 @@ affs_balloc(struct inode *inode, int zone_no) pr_debug("AFFS: balloc(inode=%lu,zone=%d)\n",inode->i_ino,zone_no); az = &sb->u.affs_sb.s_alloc[zone->z_az_no]; - bm = (__u32 *)zone->z_bm->bm_bh->b_data; + bm = (u32 *)zone->z_bm->bm_bh->b_data; repeat: for (i = zone->z_start; i < zone->z_end; i++) { if (bm[i]) @@ -138,9 +138,9 @@ found: zone->z_start = i; w = ~htonl(bm[i]); fb = find_first_zero_bit(&w,32); - if (fb > 31 || !clear_bit(fb ^ BO_EXBITS,&bm[i])) { + if (fb > 31 || !test_and_clear_bit(fb ^ BO_EXBITS,&bm[i])) { unlock_super(sb); - printk("AFFS: balloc(): empty block disappeared somehow\n"); + affs_warning(sb,"balloc","Empty block disappeared somehow"); goto repeat; } block = fwb + fb; @@ -153,8 +153,8 @@ found: fb = find_next_zero_bit(&w,32,fb); if (fb > 31) break; - if (!clear_bit(fb ^ BO_EXBITS,&bm[i])) { - printk("AFFS: balloc(): empty block disappeared\n"); + if (!test_and_clear_bit(fb ^ BO_EXBITS,&bm[i])) { + affs_warning(sb,"balloc","Empty block disappeared somehow"); break; } inode->u.affs_i.i_data[inode->u.affs_i.i_pa_last++] = fwb + fb; @@ -204,7 +204,7 @@ affs_find_new_zone(struct super_block *sb, int zone_no) if (az->az_count) az->az_count--; else - printk("AFFS: find_new_zone(): az_count=0, but bm used\n"); + affs_error(sb,"find_new_zone","az_count=0, but bm used"); } while (1) { @@ -247,7 +247,7 @@ affs_find_new_zone(struct super_block *sb, int zone_no) bm->bm_count--; az->az_count--; unlock_super(sb); - printk("AFFS: find_new_zone(): Cannot read bitmap\n"); + affs_error(sb,"find_new_zone","Cannot read bitmap"); return 0; } zone->z_bm = bm; @@ -261,16 +261,16 @@ affs_find_new_zone(struct super_block *sb, int zone_no) return az->az_free; } -int +s32 affs_new_header(struct inode *inode) { - int block; + s32 block; struct buffer_head *bh; pr_debug("AFFS: new_header(ino=%lu)\n",inode->i_ino); if (!(block = affs_balloc(inode,0))) { - while(affs_find_new_zone(inode->i_sb,0)) { + while (affs_find_new_zone(inode->i_sb,0)) { if ((block = affs_balloc(inode,0))) goto init_block; schedule(); @@ -279,7 +279,7 @@ affs_new_header(struct inode *inode) } init_block: if (!(bh = getblk(inode->i_dev,block,AFFS_I2BSIZE(inode)))) { - printk("AFFS: balloc(): cannot read block %d\n",block); + affs_error(inode->i_sb,"new_header","Cannot read block %d",block); return 0; } memset(bh->b_data,0,AFFS_I2BSIZE(inode)); @@ -290,7 +290,7 @@ init_block: return block; } -int +s32 affs_new_data(struct inode *inode) { int empty, old; @@ -299,7 +299,7 @@ affs_new_data(struct inode *inode) struct super_block *sb; struct buffer_head *bh; int i = 0; - int block; + s32 block; pr_debug("AFFS: new_data(ino=%lu)\n",inode->i_ino); @@ -345,7 +345,7 @@ affs_new_data(struct inode *inode) found: zone = &sb->u.affs_sb.s_zones[i]; if (!(block = affs_balloc(inode,i))) { /* No data zones left */ - while(affs_find_new_zone(sb,i)) { + while (affs_find_new_zone(sb,i)) { if ((block = affs_balloc(inode,i))) goto init_block; schedule(); @@ -357,7 +357,7 @@ found: init_block: if (!(bh = getblk(inode->i_dev,block,sb->s_blocksize))) { - printk("AFFS: balloc(): cannot read block %u\n",block); + affs_error(inode->i_sb,"new_data","Cannot read block %d",block); return 0; } memset(bh->b_data,0,sb->s_blocksize); diff --git a/fs/affs/dir.c b/fs/affs/dir.c index f7ec42ede..8ae71e5bd 100644 --- a/fs/affs/dir.c +++ b/fs/affs/dir.c @@ -64,7 +64,7 @@ struct inode_operations affs_dir_inode_operations = { }; static long -affs_dir_read(struct inode * inode, struct file * filp, char * buf, unsigned long count) +affs_dir_read(struct inode *inode, struct file *filp, char *buf, unsigned long count) { return -EISDIR; } @@ -73,19 +73,18 @@ static int affs_readdir(struct inode *inode, struct file *filp, void *dirent, filldir_t filldir) { int j, namelen; - int i; + s32 i; int hash_pos; int chain_pos; unsigned long ino; unsigned long old; - int stored; - char *name; - struct buffer_head *dir_bh; - struct buffer_head *fh_bh; - struct inode *dir; + int stored; + char *name; + struct buffer_head *dir_bh; + struct buffer_head *fh_bh; + struct inode *dir; pr_debug("AFFS: readdir(ino=%ld,f_pos=%lu)\n",inode->i_ino,filp->f_pos); - if (!inode || !S_ISDIR(inode->i_mode)) return -EBADF; @@ -122,7 +121,7 @@ affs_readdir(struct inode *inode, struct file *filp, void *dirent, filldir_t fil chain_pos = (filp->f_pos - 2) & 0xffff; hash_pos = (filp->f_pos - 2) >> 16; if (chain_pos == 0xffff) { - printk("AFFS: more than 65535 entries in chain\n"); + affs_warning(inode->i_sb,"readdir","More than 65535 entries in chain"); chain_pos = 0; hash_pos++; filp->f_pos = ((hash_pos << 16) | chain_pos) + 2; @@ -143,15 +142,15 @@ affs_readdir(struct inode *inode, struct file *filp, void *dirent, filldir_t fil * we can jump directly to where we left off. */ if (filp->private_data && filp->f_version == dir->i_version) { - i = (int)filp->private_data; + i = (s32)filp->private_data; j = 0; pr_debug("AFFS: readdir() left off=%d\n",i); } filp->f_version = dir->i_version; - pr_debug("AFFS: hash_pos=%lu chain_pos=%lu\n", hash_pos, chain_pos); + pr_debug("AFFS: hash_pos=%d chain_pos=%d\n",hash_pos,chain_pos); while (i) { if (!(fh_bh = affs_bread(inode->i_dev,i,AFFS_I2BSIZE(inode)))) { - printk("AFFS: readdir: Can't get block %d\n",i); + affs_error(inode->i_sb,"readdir","Cannot read block %d",i); goto readdir_done; } ino = i; @@ -164,7 +163,7 @@ affs_readdir(struct inode *inode, struct file *filp, void *dirent, filldir_t fil } if (fh_bh) { namelen = affs_get_file_name(AFFS_I2BSIZE(inode),fh_bh->b_data,&name); - pr_debug("AFFS: readdir(): filldir(..,\"%.*s\",ino=%lu), i=%lu\n", + pr_debug("AFFS: readdir(): filldir(..,\"%.*s\",ino=%lu), i=%d\n", namelen,name,ino,i); filp->private_data = (void *)ino; if (filldir(dirent,name,namelen,filp->f_pos,ino) < 0) diff --git a/fs/affs/file.c b/fs/affs/file.c index a450dffce..0fffbf41e 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c @@ -35,6 +35,8 @@ #error PAGE_SIZE must be at least 4096 #endif +static int affs_bmap(struct inode *inode, int block); +static struct buffer_head * affs_getblock(struct inode *inode, s32 block); static long affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf, unsigned long count); static long affs_file_write(struct inode *inode, struct file *filp, const char *buf, @@ -200,7 +202,7 @@ index_to_seqnum(int index) return 128 + 192 * 2 + 128 * 4 + 64 * 16 + 32 * 64 + 64 * 256 + (index << 9); } -static int __inline__ +static s32 __inline__ calc_key(struct inode *inode, int *ext) { int index; @@ -226,28 +228,30 @@ calc_key(struct inode *inode, int *ext) return inode->u.affs_i.i_ec->ec[index]; } -int +static int affs_bmap(struct inode *inode, int block) { struct buffer_head *bh; - int ext, key, nkey; - int ptype, stype; + s32 key, nkey; + s32 ptype, stype; + int ext; int index; int keycount; struct key_cache *kc; struct key_cache *tkc; struct timeval tv; - __s32 *keyp; + s32 *keyp; int i; pr_debug("AFFS: bmap(%lu,%d)\n",inode->i_ino,block); if (block < 0) { - printk("affs_bmap: block < 0\n"); + affs_error(inode->i_sb,"bmap","Block < 0"); return 0; } if (!inode->u.affs_i.i_ec) { - printk("affs_bmap(): No ext_cache!?\n"); + affs_error(inode->i_sb,"bmap","No extension cache for open file (inode=%lu)", + inode->i_ino); return 0; } @@ -334,14 +338,14 @@ affs_bmap(struct inode *inode, int block) return key; } -struct buffer_head * -affs_getblock(struct inode *inode, int block) +static struct buffer_head * +affs_getblock(struct inode *inode, s32 block) { struct buffer_head *bh; struct buffer_head *ebh; struct buffer_head *pbh; struct key_cache *kc; - int key, nkey; + s32 key, nkey; int ext; int cf, j, pt; int index; @@ -372,7 +376,7 @@ affs_getblock(struct inode *inode, int block) return NULL; if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&cf,&j) || cf != pt || j != ST_FILE) { - printk("AFFS: getblock(): inode %d is not a valid %s\n",key, + affs_error(inode->i_sb,"getblock","Inode %d is not a valid %s",key, pt == T_SHORT ? "file header" : "extension block"); affs_brelse(bh); return NULL; @@ -387,7 +391,8 @@ affs_getblock(struct inode *inode, int block) else pbh = affs_getblock(inode,inode->u.affs_i.i_lastblock); if (!pbh) { - printk("AFFS: getblock(): cannot get last block in file\n"); + affs_error(inode->i_sb,"getblock", + "Cannot get last block in file"); break; } } @@ -397,7 +402,7 @@ affs_getblock(struct inode *inode, int block) lock_super(inode->i_sb); if (AFFS_BLOCK(bh->b_data,inode,j)) { unlock_super(inode->i_sb); - printk("AFFS: getblock(): block already allocated\n"); + affs_warning(inode->i_sb,"getblock","Block already allocated"); affs_free_block(inode->i_sb,nkey); j++; continue; @@ -407,7 +412,8 @@ affs_getblock(struct inode *inode, int block) if (ofs) { ebh = affs_bread(inode->i_dev,nkey,AFFS_I2BSIZE(inode)); if (!ebh) { - printk("AFFS: getblock(): cannot get block %d\n",nkey); + affs_error(inode->i_sb,"getblock", + "Cannot get block %d",nkey); affs_free_block(inode->i_sb,nkey); AFFS_BLOCK(bh->b_data,inode,j) = 0; break; @@ -492,10 +498,6 @@ affs_getblock(struct inode *inode, int block) return affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)); } -/* This could be made static, regardless of what the former comment said. - * You cannot directly read affs directories. - */ - static long affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf, unsigned long count) { @@ -508,12 +510,12 @@ affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf, unsigned l pr_debug("AFFS: file_read_ofs(ino=%lu,pos=%lu,%d)\n",inode->i_ino,(long)filp->f_pos,count); if (!inode) { - printk("affs_file_read: inode = NULL\n"); + affs_error(inode->i_sb,"file_read_ofs","Inode = NULL"); return -EINVAL; } blocksize = AFFS_I2BSIZE(inode) - 24; if (!(S_ISREG(inode->i_mode))) { - pr_debug("affs_file_read: mode = %07o\n",inode->i_mode); + pr_debug("affs_file_read: mode = %07o",inode->i_mode); return -EINVAL; } if (filp->f_pos >= inode->i_size || count <= 0) @@ -524,10 +526,10 @@ affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf, unsigned l left = MIN (inode->i_size - filp->f_pos,count - (buf - start)); if (!left) break; - sector = affs_bmap(inode,(__u32)filp->f_pos / blocksize); + sector = affs_bmap(inode,(u32)filp->f_pos / blocksize); if (!sector) break; - offset = (__u32)filp->f_pos % blocksize; + offset = (u32)filp->f_pos % blocksize; bh = affs_bread(inode->i_dev,sector,AFFS_I2BSIZE(inode)); if (!bh) break; @@ -554,25 +556,31 @@ affs_file_write(struct inode *inode, struct file *filp, const char *buf, unsigne struct inode *ino; char *p; + /* Not that I wanted to be POSIX compliant ... */ + if (!count) + return 0; pr_debug("AFFS: file_write(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino, (unsigned long)filp->f_pos,count); ino = NULL; if (!inode) { - printk("AFFS: file_write(): inode=NULL\n"); + affs_error(inode->i_sb,"file_write","Inode = NULL"); return -EINVAL; } if (inode->u.affs_i.i_original) { ino = iget(inode->i_sb,inode->u.affs_i.i_original); if (!ino) { - printk("AFFS: could not follow link from inode %lu to %d\n", - inode->i_ino,inode->u.affs_i.i_original); + affs_error(inode->i_sb,"file_write", + "Could not follow link from inode %lu to %d", + inode->i_ino,inode->u.affs_i.i_original); return -EINVAL; } inode = ino; } if (!S_ISREG(inode->i_mode)) { - printk("AFFS: file_write(): mode=%07o\n",inode->i_mode); + affs_error(inode->i_sb,"file_write", + "Trying to write to non-regular file (mode=%07o)", + inode->i_mode); iput(inode); return -EINVAL; } @@ -636,22 +644,27 @@ affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, uns pr_debug("AFFS: file_write_ofs(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino, (unsigned long)filp->f_pos,count); + if (!count) + return 0; if (!inode) { - printk("AFFS: file_write_ofs(): inode=NULL\n"); + affs_error(inode->i_sb,"file_write_ofs","Inode = NULL"); return -EINVAL; } ino = NULL; if (inode->u.affs_i.i_original) { ino = iget(inode->i_sb,inode->u.affs_i.i_original); if (!ino) { - printk("AFFS: could not follow link from inode %lu to %d\n", - inode->i_ino,inode->u.affs_i.i_original); + affs_error(inode->i_sb,"file_write_ofs", + "Could not follow link from inode %lu to %d", + inode->i_ino,inode->u.affs_i.i_original); return -EINVAL; } inode = ino; } if (!S_ISREG(inode->i_mode)) { - printk("AFFS: file_write_ofs(): mode=%07o\n",inode->i_mode); + affs_error(inode->i_sb,"file_write_ofs", + "Trying to write to non-regular file (mode=%07o)", + inode->i_mode); iput(inode); return -EINVAL; } @@ -714,10 +727,10 @@ affs_truncate(struct inode *inode) struct affs_zone *zone; int first; int block; - int key; - int *keyp; - int ekey; - int ptype, stype; + s32 key; + s32 *keyp; + s32 ekey; + s32 ptype, stype; int freethis; int blocksize; int rem; @@ -729,8 +742,8 @@ affs_truncate(struct inode *inode) if (inode->u.affs_i.i_original) { ino = iget(inode->i_sb,inode->u.affs_i.i_original); if (!ino) { - printk("AFFS: truncate(): cannot follow link from %lu to %u\n", - inode->i_ino,inode->u.affs_i.i_original); + affs_error(inode->i_sb,"truncate","Cannot follow link from %lu to %d", + inode->i_ino,inode->u.affs_i.i_original); return; } inode = ino; @@ -754,7 +767,7 @@ affs_truncate(struct inode *inode) unlock_super(inode->i_sb); } if (!bh) { - printk("AFFS: truncate(): Cannot extend file\n"); + affs_error(inode->i_sb,"truncate","Cannot extend file"); inode->i_size = blocksize * (inode->u.affs_i.i_lastblock + 1); } else if (inode->i_sb->u.affs_sb.s_flags & SF_OFS) { rem = inode->i_size % blocksize; @@ -771,7 +784,7 @@ affs_truncate(struct inode *inode) while (ekey) { if (!(bh = affs_bread(inode->i_dev,ekey,AFFS_I2BSIZE(inode)))) { - printk("AFFS: truncate(): Can't read block %d\n",ekey); + affs_error(inode->i_sb,"truncate","Cannot read block %d",ekey); break; } ptype = htonl(((struct file_front *)bh->b_data)->primary_type); @@ -783,14 +796,14 @@ affs_truncate(struct inode *inode) break; } if (stype != ST_FILE || (ptype != T_SHORT && ptype != T_LIST)) { - printk("AFFS: truncate(): bad block (ptype=%d, stype=%d)\n", - ptype,stype); + affs_error(inode->i_sb,"truncate","Bad block (ptype=%d, stype=%d)", + ptype,stype); affs_brelse(bh); break; } /* Do not throw away file header */ freethis = first == 0 && ekey != inode->i_ino; - for ( block = first; block < AFFS_I2HSIZE(inode); block++) { + for (block = first; block < AFFS_I2HSIZE(inode); block++) { keyp = &AFFS_BLOCK(bh->b_data,inode,block); key = htonl(*keyp); if (key) { @@ -853,7 +866,7 @@ static int affs_open_file(struct inode *inode, struct file *filp) { int error; - int key; + u32 key; int i; pr_debug("AFFS: open_file(ino=%lu)\n",inode->i_ino); @@ -864,7 +877,7 @@ affs_open_file(struct inode *inode, struct file *filp) if (!inode->u.affs_i.i_ec) { inode->u.affs_i.i_ec = (struct ext_cache *)get_free_page(GFP_KERNEL); if (!inode->u.affs_i.i_ec) { - printk("AFFS: cache allocation failed\n"); + affs_error(inode->i_sb,"open_file","Cache allocation failed"); error = ENOMEM; } else { /* We only have to initialize non-zero values. diff --git a/fs/affs/inode.c b/fs/affs/inode.c index 9b6626f7d..654a8ca61 100644 --- a/fs/affs/inode.c +++ b/fs/affs/inode.c @@ -30,12 +30,26 @@ #include <asm/system.h> #include <asm/uaccess.h> +/* AmigaOS allows file names with up to 30 characters length. + * Names longer than that will be silently truncated. If you + * want to disallow this, comment out the following #define. + * Creating filesystem objects with longer names will then + * result in an error (ENAMETOOLONG). + */ +/*#define NO_TRUNCATE */ + extern int *blk_size[]; extern struct timezone sys_tz; #define MIN(a,b) (((a)<(b))?(a):(b)) -void +static int affs_notify_change(struct inode *inode, struct iattr *attr); +static void affs_put_inode(struct inode *inode); +static void affs_read_inode(struct inode *inode); +static void affs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz); +static void affs_write_inode(struct inode *inode); + +static void affs_put_super(struct super_block *sb) { int i; @@ -110,13 +124,13 @@ static struct super_operations affs_sops = { NULL /* remount */ }; -int +unsigned long affs_parent_ino(struct inode *dir) { int root_ino = (dir->i_sb->u.affs_sb.s_root_block); if (!S_ISDIR (dir->i_mode)) { - printk ("affs_parent_ino: argument is not a directory\n"); + affs_error(dir->i_sb,"parent_ino","Trying to get parent of non-directory"); return root_ino; } if (dir->i_ino == root_ino) @@ -125,7 +139,7 @@ affs_parent_ino(struct inode *dir) } static int -parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, int *root, +parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s32 *root, int *blocksize, char **prefix, char *volume, unsigned long *mount_opts) { char *this_char, *value; @@ -150,14 +164,14 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, i *value++ = 0; if (!strcmp(this_char,"protect")) { if (value) { - printk("AFFS: option protect does not take an argument\n"); + printk("AFFS: Option protect does not take an argument\n"); return 0; } *mount_opts |= SF_IMMUTABLE; } else if (!strcmp(this_char,"verbose")) { if (value) { - printk("AFFS: option verbose does not take an argument\n"); + printk("AFFS: Option verbose does not take an argument\n"); return 0; } *mount_opts |= SF_VERBOSE; @@ -166,7 +180,7 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, i if (!value) *uid = current->uid; else if (!*value) { - printk("AFFS: argument for uid option missing\n"); + printk("AFFS: Argument for uid option missing\n"); return 0; } else { *uid = simple_strtoul(value,&value,0); @@ -180,7 +194,7 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, i if (!value) *gid = current->gid; else if (!*value) { - printk("AFFS: argument for gid option missing\n"); + printk("AFFS: Argument for gid option missing\n"); return 0; } else { *gid = simple_strtoul(value,&value,0); @@ -248,7 +262,7 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, i return 0; if (*blocksize != 512 && *blocksize != 1024 && *blocksize != 2048 && *blocksize != 4096) { - printk ("AFFS: Invalid blocksize (512, 1024, 2048, 4096 allowed).\n"); + printk ("AFFS: Invalid blocksize (512, 1024, 2048, 4096 allowed)\n"); return 0; } } @@ -270,21 +284,21 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, i * hopefully have the guts to do so. Until then: sorry for the mess. */ -struct super_block * +static struct super_block * affs_read_super(struct super_block *s,void *data, int silent) { struct buffer_head *bh = NULL; struct buffer_head *bb; kdev_t dev = s->s_dev; - int root_block; + s32 root_block; int size; - __u32 chksum; - __u32 *bm; - int ptype, stype; + u32 chksum; + u32 *bm; + s32 ptype, stype; int mapidx; int num_bm; int i, j; - int key; + s32 key; int blocksize; uid_t uid; gid_t gid; @@ -300,7 +314,7 @@ affs_read_super(struct super_block *s,void *data, int silent) if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block, &blocksize,&s->u.affs_sb.s_prefix,s->u.affs_sb.s_volume,&mount_flags)) { s->s_dev = 0; - printk("AFFS: error parsing options.\n"); + printk(KERN_ERR "AFFS: Error parsing options\n"); MOD_DEC_USE_COUNT; return NULL; } @@ -324,13 +338,13 @@ affs_read_super(struct super_block *s,void *data, int silent) if (size == 0) { s->s_dev = 0; unlock_super(s); - printk("affs_read_super: could not determine device size\n"); + printk(KERN_ERR "AFFS: Could not determine device size\n"); goto out; } s->u.affs_sb.s_partition_size = size; s->u.affs_sb.s_reserved = reserved; - /* Try to find root block. Its location may depend on the block size. */ + /* Try to find root block. Its location depends on the block size. */ s->u.affs_sb.s_hashsize = 0; if (blocksize > 0) { @@ -358,12 +372,12 @@ affs_read_super(struct super_block *s,void *data, int silent) * block behind the calculated one. So we check this one, too. */ for (num_bm = 0; num_bm < 2; num_bm++) { - pr_debug("AFFS: Dev %s - trying bs=%d bytes, root at %d, " + pr_debug("AFFS: Dev %s - trying bs=%d bytes, root at %u, " "size=%d blocks, %d reserved\n",kdevname(dev),blocksize, s->u.affs_sb.s_root_block + num_bm,size,reserved); bh = affs_bread(dev,s->u.affs_sb.s_root_block + num_bm,blocksize); if (!bh) { - printk("AFFS: unable to read root block\n"); + printk(KERN_ERR "AFFS: Cannot read root block\n"); goto out; } if (!affs_checksum_block(blocksize,bh->b_data,&ptype,&stype) && @@ -383,7 +397,8 @@ affs_read_super(struct super_block *s,void *data, int silent) if (!key) { affs_brelse(bh); if (!silent) - printk("AFFS: Can't find a valid root block on device %s\n",kdevname(dev)); + printk(KERN_ERR "AFFS: Cannot find a valid root block on device %s\n", + kdevname(dev)); goto out; } root_block = s->u.affs_sb.s_root_block; @@ -396,7 +411,7 @@ affs_read_super(struct super_block *s,void *data, int silent) /* Find out which kind of FS we have */ bb = affs_bread(dev,0,s->s_blocksize); if (bb) { - chksum = htonl(*(__u32 *)bb->b_data); + chksum = htonl(*(u32 *)bb->b_data); /* Dircache filesystems are compatible with non-dircache ones * when reading. As long as they aren't supported, writing is @@ -404,7 +419,8 @@ affs_read_super(struct super_block *s,void *data, int silent) */ if ((chksum == FS_DCFFS || chksum == MUFS_DCFFS || chksum == FS_DCOFS || chksum == MUFS_DCOFS) && !(s->s_flags & MS_RDONLY)) { - printk("AFFS: Dircache FS - mounting %s read only.\n",kdevname(dev)); + printk(KERN_NOTICE "AFFS: Dircache FS - mounting %s read only\n", + kdevname(dev)); s->s_flags |= MS_RDONLY; } switch (chksum) { @@ -436,22 +452,22 @@ affs_read_super(struct super_block *s,void *data, int silent) s->u.affs_sb.s_flags |= SF_INTL | SF_OFS; break; default: - printk("AFFS: Unknown filesystem on device %s: %08X\n", - kdevname(dev),chksum); + printk(KERN_ERR "AFFS: Unknown filesystem on device %s: %08X\n", + kdevname(dev),chksum); affs_brelse(bb); goto out; } affs_brelse(bb); } else { - printk("AFFS: Can't get boot block.\n"); + printk(KERN_ERR "AFFS: Cannot read boot block\n"); goto out; } if (mount_flags & SF_VERBOSE) { chksum = ntohl(chksum); - printk("AFFS: Mounting volume \"%*s\": Type=%.3s\\%c, Blocksize=%d\n", - GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[0], - &GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[1], - (char *)&chksum,((char *)&chksum)[3] + '0',blocksize); + printk(KERN_NOTICE "AFFS: Mounting volume \"%*s\": Type=%.3s\\%c, Blocksize=%d\n", + GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[0], + &GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[1], + (char *)&chksum,((char *)&chksum)[3] + '0',blocksize); } s->s_magic = AFFS_SUPER_MAGIC; @@ -459,7 +475,7 @@ affs_read_super(struct super_block *s,void *data, int silent) /* Keep super block in cache */ if (!(s->u.affs_sb.s_root_bh = affs_bread(dev,root_block,s->s_blocksize))) { - printk("AFFS: Can't read root block a second time\n"); + printk(KERN_ERR "AFFS: Cannot read root block\n"); goto out; } @@ -473,7 +489,7 @@ affs_read_super(struct super_block *s,void *data, int silent) MAX_ZONES * sizeof(struct affs_zone); pr_debug("num_bm=%d, az_no=%d, sum=%d\n",num_bm,az_no,ptype); if (!(s->u.affs_sb.s_bitmap = kmalloc(ptype,GFP_KERNEL))) { - printk("AFFS: Not enough memory.\n"); + printk(KERN_ERR "AFFS: Not enough memory\n"); goto out; } memset(s->u.affs_sb.s_bitmap,0,ptype); @@ -486,7 +502,8 @@ affs_read_super(struct super_block *s,void *data, int silent) if (ROOT_END_S(bh->b_data,s)->bm_flag == 0) { if (!(s->s_flags & MS_RDONLY)) { - printk("AFFS: Bitmap invalid - mounting %s read only.\n",kdevname(dev)); + printk(KERN_NOTICE "AFFS: Bitmap invalid - mounting %s read only\n", + kdevname(dev)); s->s_flags |= MS_RDONLY; } affs_brelse(bh); @@ -504,17 +521,17 @@ affs_read_super(struct super_block *s,void *data, int silent) offset = s->u.affs_sb.s_reserved; az_no = 0; while (bh) { - bm = (__u32 *)bh->b_data; + bm = (u32 *)bh->b_data; for (i = ptype; i < stype && bm[i]; i++, mapidx++) { if (mapidx >= num_bm) { - printk("AFFS: Not enough bitmap space!?\n"); + printk(KERN_ERR "AFFS: Not enough bitmap space!?\n"); goto out; } bb = affs_bread(s->s_dev,htonl(bm[i]),s->s_blocksize); if (bb) { if (affs_checksum_block(s->s_blocksize,bb->b_data,NULL,NULL) && !(s->s_flags & MS_RDONLY)) { - printk("AFFS: Bitmap (%d,key=%lu) invalid - " + printk(KERN_WARNING "AFFS: Bitmap (%d,key=%lu) invalid - " "mounting %s read only.\n",mapidx,htonl(bm[i]), kdevname(dev)); s->s_flags |= MS_RDONLY; @@ -525,7 +542,7 @@ affs_read_super(struct super_block *s,void *data, int silent) key = size & 0x1F; /* used bits */ if (key) { chksum = ntohl(0x7FFFFFFF >> (31 - key)); - ((__u32 *)bb->b_data)[ptype] &= chksum; + ((u32 *)bb->b_data)[ptype] &= chksum; affs_fix_checksum(s->s_blocksize,bb->b_data,0); mark_buffer_dirty(bb,1); } @@ -551,7 +568,7 @@ affs_read_super(struct super_block *s,void *data, int silent) } affs_brelse(bb); } else { - printk("AFFS: Can't read bitmap.\n"); + printk(KERN_ERR "AFFS: Cannot read bitmap\n"); goto out; } } @@ -561,14 +578,14 @@ affs_read_super(struct super_block *s,void *data, int silent) affs_brelse(bh); if (key) { if (!(bh = affs_bread(s->s_dev,key,s->s_blocksize))) { - printk("AFFS: Can't read bitmap extension.\n"); + printk(KERN_ERR "AFFS: Cannot read bitmap extension\n"); goto out; } } else bh = NULL; } if (mapidx != num_bm) { - printk("AFFS: Got only %d bitmap blocks, expected %d\n",mapidx,num_bm); + printk(KERN_ERR "AFFS: Got only %d bitmap blocks, expected %d\n",mapidx,num_bm); goto out; } nobitmap: @@ -584,7 +601,7 @@ nobitmap: if (!(s->s_mounted)) { s->s_dev = 0; - printk("AFFS: get root inode failed\n"); + printk(KERN_ERR "AFFS: get root inode failed\n"); MOD_DEC_USE_COUNT; return NULL; } @@ -615,7 +632,7 @@ nobitmap: return NULL; } -void +static void affs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz) { int free; @@ -635,15 +652,15 @@ affs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz) copy_to_user(buf,&tmp,bufsiz); } -void +static void affs_read_inode(struct inode *inode) { struct buffer_head *bh, *lbh; struct file_front *file_front; struct file_end *file_end; - int block; + s32 block; unsigned long prot; - int ptype, stype; + s32 ptype, stype; unsigned short id; pr_debug("AFFS: read_inode(%lu)\n",inode->i_ino); @@ -651,12 +668,12 @@ affs_read_inode(struct inode *inode) lbh = NULL; block = inode->i_ino; if (!(bh = affs_bread(inode->i_dev,block,AFFS_I2BSIZE(inode)))) { - printk("AFFS: unable to read i-node block %d\n",block); + affs_error(inode->i_sb,"read_inode","Cannot read block %d",block); return; } if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype) || ptype != T_SHORT) { - printk("AFFS: read_inode(): checksum or type (ptype=%d) error on inode %d\n", - ptype,block); + affs_error(inode->i_sb,"read_inode", + "Checksum or type (ptype=%d) error on inode %d",ptype,block); affs_brelse(bh); return; } @@ -735,7 +752,8 @@ affs_read_inode(struct inode *inode) if (!(lbh = affs_bread(inode->i_dev,inode->u.affs_i.i_original, AFFS_I2BSIZE(inode)))) { affs_brelse(bh); - printk("AFFS: unable to read i-node block %ld\n",inode->i_ino); + affs_error(inode->i_sb,"read_inode","Cannot read block %lu", + inode->i_ino); return; } file_end = GET_END_PTR(struct file_end,lbh->b_data,AFFS_I2BSIZE(inode)); @@ -776,12 +794,13 @@ affs_read_inode(struct inode *inode) inode->i_op = &affs_symlink_inode_operations; } -void +static void affs_write_inode(struct inode *inode) { - struct buffer_head *bh; - struct file_end *file_end; - short uid, gid; + struct buffer_head *bh; + struct file_end *file_end; + uid_t uid; + gid_t gid; pr_debug("AFFS: write_inode(%lu)\n",inode->i_ino); @@ -789,8 +808,7 @@ affs_write_inode(struct inode *inode) if (!inode->i_nlink) return; if (!(bh = bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)))) { - printk("AFFS: Unable to read block of inode %ld on %s\n", - inode->i_ino,kdevname(inode->i_dev)); + affs_error(inode->i_sb,"write_inode","Cannot read block %lu",inode->i_ino); return; } file_end = GET_END_PTR(struct file_end, bh->b_data,AFFS_I2BSIZE(inode)); @@ -820,7 +838,7 @@ affs_write_inode(struct inode *inode) brelse(bh); } -int +static int affs_notify_change(struct inode *inode, struct iattr *attr) { int error; @@ -848,7 +866,7 @@ affs_notify_change(struct inode *inode, struct iattr *attr) return 0; } -void +static void affs_put_inode(struct inode *inode) { pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n",inode->i_ino,inode->i_nlink); @@ -867,7 +885,7 @@ affs_new_inode(const struct inode *dir) { struct inode *inode; struct super_block *sb; - int block; + s32 block; if (!dir || !(inode = get_empty_inode())) return NULL; @@ -918,7 +936,10 @@ affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode, struct buffer_head *dir_bh; struct buffer_head *inode_bh; struct buffer_head *link_bh; - int hash; + struct buffer_head *ibh; + int retval; + int i; + s32 next; pr_debug("AFFS: add_entry(dir=%lu,inode=%lu,\"%*s\",type=%d\n",dir->i_ino,inode->i_ino, len,name,type); @@ -926,34 +947,60 @@ affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode, dir_bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir)); inode_bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)); link_bh = NULL; - if (!dir_bh || !inode_bh) { - affs_brelse(dir_bh); - affs_brelse(inode_bh); - return -ENOSPC; - } + retval = -EIO; + if (!dir_bh || !inode_bh) + goto addentry_done; if (link) { link_bh = affs_bread(link->i_dev,link->i_ino,AFFS_I2BSIZE(link)); - if (!link_bh) { - affs_brelse(dir_bh); - affs_brelse(inode_bh); - return -EINVAL; - } + if (!link_bh) + goto addentry_done; } ((struct dir_front *)inode_bh->b_data)->primary_type = ntohl(T_SHORT); ((struct dir_front *)inode_bh->b_data)->own_key = ntohl(inode->i_ino); - if (len > 30) /* truncate name quietly */ + retval = -ENAMETOOLONG; + if (len > 30) +#ifdef NO_TRUNCATE + goto addentry_done; +#else len = 30; +#endif + + /* Check if name is valid */ + retval = -EINVAL; + for (i = 0; i < len; i++) { + if (name[i] < ' ' || name[i] == ':' + || ((unsigned char)name[i] > 0x7e && (unsigned char)name[i] < 0xa0)) + goto addentry_done; + } + retval = 0; DIR_END(inode_bh->b_data,inode)->dir_name[0] = len; strncpy(DIR_END(inode_bh->b_data,inode)->dir_name + 1,name,len); DIR_END(inode_bh->b_data,inode)->secondary_type = ntohl(type); DIR_END(inode_bh->b_data,inode)->parent = ntohl(dir->i_ino); - hash = affs_hash_name(name,len,AFFS_I2FSTYPE(dir),AFFS_I2HSIZE(dir)); + + i = affs_hash_name(name,len,AFFS_I2FSTYPE(dir),AFFS_I2HSIZE(dir)) + 6; + next = dir->i_ino; + + /* Alas, we have to search the insertion point with a locked sb */ lock_super(inode->i_sb); - DIR_END(inode_bh->b_data,inode)->hash_chain = - ((struct dir_front *)dir_bh->b_data)->hashtable[hash]; - ((struct dir_front *)dir_bh->b_data)->hashtable[hash] = ntohl(inode->i_ino); + while (1) { + if (!(ibh = affs_bread(dir->i_dev,next,AFFS_I2BSIZE(dir)))) + goto addentry_done; + next = htonl(((s32 *)ibh->b_data)[i]); + if (!next || next > inode->i_ino) + break; + i = AFFS_I2BSIZE(dir) / 4 - 4; + affs_brelse(ibh); + } + + DIR_END(inode_bh->b_data,inode)->hash_chain = next; + ((s32 *)ibh->b_data)[i] = ntohl(inode->i_ino); + affs_fix_checksum(AFFS_I2BSIZE(dir),ibh->b_data,5); + mark_buffer_dirty(ibh,1); + affs_brelse(ibh); + if (link_bh) { LINK_END(inode_bh->b_data,inode)->original = ntohl(link->i_ino); LINK_END(inode_bh->b_data,inode)->link_chain = @@ -974,11 +1021,13 @@ affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode, inode->i_dirt = 1; mark_buffer_dirty(dir_bh,1); mark_buffer_dirty(inode_bh,1); + +addentry_done: affs_brelse(dir_bh); affs_brelse(inode_bh); affs_brelse(link_bh); - return 0; + return retval; } static struct file_system_type affs_fs_type = { @@ -999,7 +1048,7 @@ EXPORT_NO_SYMBOLS; int init_module(void) { - return init_affs_fs(); + return register_filesystem(&affs_fs_type); } void diff --git a/fs/affs/namei.c b/fs/affs/namei.c index 0f4bced43..6a9b02bac 100644 --- a/fs/affs/namei.c +++ b/fs/affs/namei.c @@ -20,6 +20,8 @@ #include <linux/errno.h> +static int affs_fixup(struct buffer_head *bh, struct inode *inode); + /* Simple toupper() for DOS\1 */ static inline unsigned int @@ -100,7 +102,7 @@ affs_find_entry(struct inode *dir, const char *name, int namelen, { struct buffer_head *bh; int intl; - int key; + s32 key; pr_debug("AFFS: find_entry(%.*s)=\n",namelen,name); @@ -222,9 +224,7 @@ affs_create(struct inode *dir, const char *name, int len, int mode, struct inode pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,len,name,mode); - *result = NULL; - if (!dir || !dir->i_sb) { iput(dir); return -EINVAL; @@ -472,7 +472,7 @@ affs_link(struct inode *oldinode, struct inode *dir, const char *name, int len) iput(oldinode); oldinode = iget(dir->i_sb,i); if (!oldinode) { - printk("AFFS: link(): original does not exist.\n"); + affs_error(oldinode->i_sb,"link","Cannot get original from link"); iput(dir); return -ENOENT; } @@ -507,7 +507,7 @@ affs_link(struct inode *oldinode, struct inode *dir, const char *name, int len) } static int -subdir(struct inode * new_inode, struct inode * old_inode) +subdir(struct inode *new_inode, struct inode *old_inode) { int ino; int result; @@ -650,11 +650,11 @@ end_rename: return retval; } -int +static int affs_fixup(struct buffer_head *bh, struct inode *inode) { - int key, link_key; - int type; + s32 key, link_key; + s32 type; struct buffer_head *nbh; struct inode *ofinode; @@ -663,7 +663,8 @@ affs_fixup(struct buffer_head *bh, struct inode *inode) key = htonl(LINK_END(bh->b_data,inode)->original); LINK_END(bh->b_data,inode)->original = 0; if (!key) { - printk("AFFS: fixup(): hard link without original: ino=%lu\n",inode->i_ino); + affs_error(inode->i_sb,"fixup","Hard link without original: ino=%lu", + inode->i_ino); return -ENOENT; } if (!(ofinode = iget(inode->i_sb,key))) @@ -676,17 +677,18 @@ affs_fixup(struct buffer_head *bh, struct inode *inode) if ((key = htonl(FILE_END(bh->b_data,inode)->link_chain))) { /* Get first link, turn it to a file */ if (!(ofinode = iget(inode->i_sb,key))) { - printk("AFFS: fixup(): cannot read inode %u\n",key); + affs_error(inode->i_sb,"fixup","Cannot read block %d",key); return -ENOENT; } if (!ofinode->u.affs_i.i_hlink) { - printk("AFFS: fixup(): first link to %lu (%u) is not a link?\n", - inode->i_ino,key); + affs_error(inode->i_sb,"fixup", + "First link to %lu (%d) is not a link", + inode->i_ino,key); iput(ofinode); return -ENOENT; } if (!(nbh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) { - printk("AFFS: fixup(): cannot read block %u\n",key); + affs_error(inode->i_sb,"fixup","Cannot read block %d",key); iput(ofinode); return -ENOENT; } @@ -719,13 +721,14 @@ affs_fixup(struct buffer_head *bh, struct inode *inode) break; if ((ofinode = iget(inode->i_sb,key))) { if (!ofinode->u.affs_i.i_hlink) - printk("AFFS: fixup() inode %u in link chain is " - "not a link\n",key); + affs_error(inode->i_sb,"fixup", + "Inode %d in link chain is not a link", + key); ofinode->u.affs_i.i_original = link_key; ofinode->i_dirt = 1; FILE_END(nbh->b_data,inode)->original = htonl(link_key); } else - printk("AFFS: fixup(): cannot get inode %u\n",key); + affs_error(inode->i_sb,"fixup","Cannot read block %d",key); } /* Turn old inode to a link */ inode->u.affs_i.i_hlink = 1; @@ -735,7 +738,7 @@ affs_fixup(struct buffer_head *bh, struct inode *inode) } else if (type == ST_SOFTLINK) { return 0; } else { - printk("AFFS: fixup(): secondary type=%d\n",type); + affs_error(inode->i_sb,"fixup","Bad secondary type (%d)",type); return -EBADF; } } diff --git a/fs/affs/symlink.c b/fs/affs/symlink.c index 734df0780..de93eac5c 100644 --- a/fs/affs/symlink.c +++ b/fs/affs/symlink.c @@ -82,7 +82,7 @@ affs_follow_link(struct inode *dir, struct inode *inode, int flag, int mode, i = 0; j = 0; if (!bh) { - printk("AFFS: unable to read i-node block %lu\n",inode->i_ino); + affs_error(inode->i_sb,"follow_link","Cannot read block %lu\n",inode->i_ino); kfree(buffer); iput(inode); iput(dir); @@ -138,7 +138,7 @@ affs_readlink(struct inode *inode, char *buffer, int buflen) i = 0; j = 0; if (!bh) { - printk("AFFS: unable to read i-node block %lu\n",inode->i_ino); + affs_error(inode->i_sb,"readlink","Cannot read block %lu\n",inode->i_ino); goto symlink_end; } lf = (struct slink_front *)bh->b_data; |