diff options
author | Mike Shaver <shaver@ingenia.com> | 1999-01-18 04:16:25 +0000 |
---|---|---|
committer | Mike Shaver <shaver@ingenia.com> | 1999-01-18 04:16:25 +0000 |
commit | 6bafd683c6bd78f19df9a42aea24037137f913ce (patch) | |
tree | 7580dc3040c32da4048009721d60a7ac442962ca /fs | |
parent | 317b660279d583d4db3fc112e3ef2e56b20bec87 (diff) |
EFS mark II. Incomplete, but much cleaner.
Diffstat (limited to 'fs')
-rw-r--r-- | fs/efs/Makefile | 2 | ||||
-rw-r--r-- | fs/efs/dir.c | 239 | ||||
-rw-r--r-- | fs/efs/file.c | 349 | ||||
-rw-r--r-- | fs/efs/inode.c | 741 | ||||
-rw-r--r-- | fs/efs/namei.c | 211 | ||||
-rw-r--r-- | fs/efs/symlink.c | 178 |
6 files changed, 706 insertions, 1014 deletions
diff --git a/fs/efs/Makefile b/fs/efs/Makefile index 5a8556795..a0532be3e 100644 --- a/fs/efs/Makefile +++ b/fs/efs/Makefile @@ -7,7 +7,7 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -#CFLAGS+=-g -DDEBUG_EFS +CFLAGS+=-g -DDEBUG_EFS O_TARGET := efs.o O_OBJS := dir.o file.o inode.o namei.o \ diff --git a/fs/efs/dir.c b/fs/efs/dir.c index a89dd304e..a31f6784a 100644 --- a/fs/efs/dir.c +++ b/fs/efs/dir.c @@ -1,137 +1,146 @@ -/* dir.c - - directory inode operations for EFS filesystem - - (C)95,96 Christian Vogelgsang -*/ +/* + * linux/fs/efs/dir.c + * + * Copyright (C) 1998 Mike Shaver + * + * Portions derived from work (C) 1995,1996 Christian Vogelgsang. + * ``Inspired by'' fs/minix/dir.c. + */ #include <linux/string.h> #include <linux/errno.h> -#include <linux/fs.h> #include <linux/efs_fs.h> -#include <linux/efs_fs_i.h> -#include <linux/stat.h> #include <asm/uaccess.h> -static int efs_readdir(struct file *,void *,filldir_t); -extern int efs_lookup(struct inode *, struct dentry *); +static int efs_readdir(struct file *, void *, filldir_t); +int efs_lookup(struct inode *, struct dentry *); + +static ssize_t +efs_dir_read(struct file *filp, char *buf, size_t count, loff_t *ppos) +{ + return -EISDIR; +} static struct file_operations efs_dir_ops = { - NULL, - NULL, - NULL, - efs_readdir, - NULL, - NULL, - NULL, - NULL, - NULL + NULL, /* lseek */ + efs_dir_read, + NULL, /* write */ + efs_readdir, + NULL, /* poll */ + NULL, /* ioctl */ + NULL, /* mmap */ + NULL, /* open */ + NULL, /* flush */ + NULL, /* release */ + NULL /* fsync */ }; -struct inode_operations efs_dir_in_ops = { - &efs_dir_ops, - NULL, - efs_lookup, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - efs_bmap, - NULL, - NULL +struct inode_operations efs_dir_inode_operations = { + &efs_dir_ops, + NULL, /* create */ + efs_lookup, + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + efs_bmap, + NULL, /* truncate */ + NULL /* permission */ }; +static int +efs_readdir(struct file *filp, void *dirent, filldir_t filldir) +{ + struct inode *in = filp->f_dentry->d_inode; + struct efs_inode_info *ini = &in->u.efs_i; + struct buffer_head *bh; + __u16 item; + __u32 block; + __u16 offset; + struct efs_dirblk *dirblk; + struct efs_dir_entry *entry; + + if (!in || !in->i_sb || !S_ISDIR(in->i_mode) || !ini->tot) + return -EBADF; + + if (ini->tot > 1) { + printk("EFS: ERROR: directory %s has %d extents\n", + filp->f_dentry->d_name.name, ini->tot); + printk("EFS: ERROR: Mike is lazy, so this is NYI.\n"); + return 0; + }; + + if (in->i_size & (EFS_BLOCK_SIZE - 1)) + printk("EFS: readdir: dirsize %#lx not block multiple\n", in->i_size); + + /* filp->f_pos is (block << BLOCK_SIZE | item) */ + block = filp->f_pos >> EFS_BLOCK_SIZE_BITS; + item = filp->f_pos & 0xFF; + + start_block: + if (block == (in->i_size >> EFS_BLOCK_SIZE_BITS)) + return 0; /* all done! */ + + bh = bread(in->i_dev, efs_bmap(in, block), EFS_BLOCK_SIZE); + if (!bh) { + printk("EFS: ERROR: readdir: bread of %#lx/%#x\n", + in->i_ino, efs_bmap(in, block)); + return 0; + } -/* ----- efs_readdir ----- - readdir inode operation: - read the next directory entry of a given dir file - - inode - pointer to inode struct of directory - filp - pointer to file struct of directory inode - dirent - pointer to dirent struct that has to be filled - filldir - function to store values in the directory + dirblk = (struct efs_dirblk *)bh->b_data; - return - 0 ok, <0 error -*/ -static int efs_readdir(struct file *filp, - void *dirent, filldir_t filldir) -{ - struct inode *inode = filp->f_dentry->d_inode; - struct efs_inode_info *ini = (struct efs_inode_info *)&inode->u.efs_i; - struct buffer_head *bh; - __u8 *rawdirblk; - __u32 iteminode; - __u16 namelen; - __u8 *nameptr; - __u32 numitems; - __u16 itemnum; - __u32 block; - __u16 rawdepos; - - /* some checks */ - if(!inode || !inode->i_sb || !S_ISDIR(inode->i_mode)) - return -EBADF; - - /* Warnings */ - if(ini->tot!=1) { - printk("EFS: directory %s has more than one extent.\n", - filp->f_dentry->d_name.name); - printk("EFS: Mike is lazy, so we can't handle this yet. Sorry =(\n"); - return 0; + /* skip empty slots */ + do { + offset = EFS_SLOT2OFF(dirblk, item); + if (!offset) { + DB(("EFS: skipping empty slot %d\n", item)); + } + item++; + if (item == dirblk->db_slots) { + item = 0; + block++; + if (!offset) { + brelse(bh); + goto start_block; + } } - if(inode->i_size & (EFS_BLOCK_SIZE-1)) - printk("efs_readdir: dirsize != blocksize*n\n"); - - /* f_pos contains: dirblock<<BLOCK_SIZE | # of item in dirblock */ - block = filp->f_pos >> EFS_BLOCK_SIZE_BITS; - itemnum = filp->f_pos & 0xff; - - /* We found the last entry -> ready */ - if(block == (inode->i_size>>EFS_BLOCK_SIZE_BITS)) - return 0; - - /* get disc block number from dir block num: 0..i_size/BLOCK_SIZE */ - bh = bread(inode->i_dev,efs_bmap(inode,block),EFS_BLOCK_SIZE); - if(!bh) return 0; - - /* dirblock */ - rawdirblk = (__u8 *)bh->b_data; - /* number of entries stored in this dirblock */ - numitems = rawdirblk[EFS_DB_ENTRIES]; - /* offset in block of #off diritem */ - rawdepos = (__u16)rawdirblk[EFS_DB_FIRST+itemnum]<<1; - - /* diritem first contains the inode number, the namelen and the name */ - iteminode = ConvertLong(rawdirblk,rawdepos); - namelen = (__u16)rawdirblk[rawdepos+EFS_DI_NAMELEN]; - nameptr = rawdirblk + rawdepos + EFS_DI_NAME; + } while(!offset); + entry = EFS_DENT4OFF(dirblk, offset); + /* + DB(("EFS_SLOT2OFF(%d) -> %d, EFS_DENT4OFF(%p, %d) -> %p) || ", + item-1, offset, dirblk, offset, entry)); #ifdef DEBUG_EFS - printk("efs: dir #%d @ %0#3x - inode %lx %s namelen %u\n", - itemnum,rawdepos,iteminode,nameptr,namelen); + { + __u8 *rawdirblk, nameptr; + __u32 iteminode; + __u16 namelen, rawdepos; + rawdirblk = (__u8*)bh->b_data; + rawdepos = (__u16)rawdirblk[EFS_DB_FIRST+item-1] << 1; + DB(("OLD_WAY: offset = %d, dent = %p ||", rawdepos, + (struct efs_dir_entry *)(rawdirblk + rawdepos))); + } #endif - /* copy filename and data in direntry */ - filldir(dirent,nameptr,namelen,filp->f_pos,iteminode); + DB(("EFS: filldir(dirent, \"%.*s\", %d, %d, %d)\n", + entry->d_namelen, entry->d_name, entry->d_namelen, + filp->f_pos, efs_swab32(entry->ud_inum.l))); + */ + filldir(dirent, entry->d_name, entry->d_namelen, filp->f_pos, + efs_swab32(entry->ud_inum.l)); + + brelse(bh); - brelse(bh); + filp->f_pos = (block << EFS_BLOCK_SIZE_BITS) | item; + UPDATE_ATIME(in); - /* store pos of next item */ - itemnum++; - if(itemnum==numitems) { - itemnum = 0; - block++; - } - filp->f_pos = (block<<EFS_BLOCK_SIZE_BITS) | itemnum; - UPDATE_ATIME(inode); - - return 0; + return 0; } - diff --git a/fs/efs/file.c b/fs/efs/file.c index 4c04616bb..7ffaa6a16 100644 --- a/fs/efs/file.c +++ b/fs/efs/file.c @@ -1,218 +1,165 @@ -/* file.c - - read files on EFS filesystems - now replaced by generic functions of the kernel: - leaves only mapping of file block number -> disk block number in this file - - (C)95,96 Christian Vogelgsang -*/ - -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/fs.h> +/* + * linux/fs/efs/file.c + * + * Copyright (C) 1998 Mike Shaver + * + * Portions derived from work (C) 1995,1996 Christian Vogelgsang. + * ``Inspired by'' fs/minix/file.c. + */ + #include <linux/efs_fs.h> -#include <linux/efs_fs_i.h> -#include <linux/efs_fs_sb.h> -#include <linux/stat.h> -#include <asm/uaccess.h> - -static struct file_operations efs_file_ops = { - NULL, - generic_file_read, - NULL, - NULL, - NULL, - NULL, - generic_file_mmap, - NULL, - NULL, - NULL + +static struct file_operations efs_file_operations = { + NULL, /* lseek */ + generic_file_read, + NULL, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + NULL, /* ioctl */ + generic_file_mmap, /* mmap */ + NULL, /* open */ + NULL, /* flush */ + NULL, /* release */ + NULL /* fsync */ }; -struct inode_operations efs_file_in_ops = { - &efs_file_ops, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - generic_readpage, - NULL, - efs_bmap, - NULL, - NULL +struct inode_operations efs_file_inode_operations = { + &efs_file_operations, /* default file ops */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + generic_readpage, /* readpage */ + NULL, /* writepage */ + efs_bmap, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ }; - -#define MIN(a,b) ((a)<(b)?(a):(b)) - -#define CHECK(num) \ - eblk = ini->extents[num].ex_bytes[0]; \ - epos = ini->extents[num].ex_bytes[1] & 0xffffff; \ - elen = ini->extents[num].ex_bytes[1] >> 24; \ - if((blk >= epos)&&(blk < (epos+elen))) \ - result = (blk - epos) + eblk + sbi->fs_start; - - -/* ----- efs_getblknum ----- - find the disc block number for a given logical file block number - - in - inode of file - blk - logical file block number - - return - 0 on error, or unmapped block number -*/ -static __u32 efs_getblk(struct inode *in,__u32 blk) + +static inline __u32 +check_extent(union efs_extent *ext, int blk, int fs_start) { - struct efs_sb_info *sbi = &in->i_sb->u.efs_sb; - struct efs_inode_info *ini = &in->u.efs_i; - struct buffer_head *bh; - - __u32 result = 0; - __u32 eblk,epos,elen; - int num,extnum,readahead; - __u32 extblk; - __u16 extoff,pos,cur,tot; - union efs_extent *ptr; - - - /* first check the current extend */ - cur = ini->cur; - tot = ini->tot; - CHECK(cur) - if(result) - return result; - - /* if only one extent exists and we are here the test failed */ - if(tot==1) { - printk("efs: bmap failed on one extent!\n"); - return 0; - } - - /* check the stored extents in the inode */ - num = MIN(tot,EFS_MAX_EXTENTS); - for(pos=0;pos<num;pos++) { - /* don't check the current again! */ - if(pos==cur) - continue; - - CHECK(pos) - if(result) { - ini->cur = pos; - return result; - } - } + int eblk, epos, elen; - /* If the inode has only direct extents, - the above tests must have found the block's extend! */ - if(tot<=EFS_MAX_EXTENTS) { - printk("efs: bmap failed for direct extents!\n"); - return 0; - } - - /* --- search in the indirect extensions list blocks --- */ -#ifdef DEBUG - printk("efs - indirect search for %lu\n",blk); -#endif - - /* calculate block and offset for begin of extent descr and read it */ - extblk = ini->extblk; - extoff = 0; - bh = bread(in->i_dev,extblk,EFS_BLOCK_SIZE); - if(!bh) { - printk("efs: read error in indirect extents\n"); + eblk = ext->ex_bytes[0]; /* start disk block of the extent */ + epos = ext->ex_bytes[1] & 0xFFFFFF; /* starting logical block */ + elen = ext->ex_bytes[1] >> 24; /* length of the extent */ + + if ( (blk >= epos) && (blk < epos+elen) ) + return blk - epos + eblk + fs_start; return 0; - } - ptr = (union efs_extent *)bh->b_data; - - pos = 0; /* number of extend store in the inode */ - extnum = 0; /* count the extents in the indirect blocks */ - readahead = 10; /* number of extents to read ahead */ - while(1) { - - /* skip last current extent store in the inode */ - if(pos==cur) pos++; - - /* read new extent in inode buffer */ - ini->extents[pos].ex_bytes[0] = efs_swab32(ptr[pos].ex_bytes[0]); - ini->extents[pos].ex_bytes[1] = efs_swab32(ptr[pos].ex_bytes[1]); - - /* we must still search */ - if(!result) { - CHECK(pos) - if(result) - ini->cur = pos; - } - /* we found it already and read ahead */ - else { - readahead--; - if(!readahead) - break; - } +} - /* next storage place */ - pos++; - extnum++; +#define CHECK(index) (check_extent(&ini->extents[index], blk, sbi->fs_start)) - /* last extent checked -> finished */ - if(extnum==tot) { - if(!result) - printk("efs: bmap on indirect failed!\n"); - break; - } +static __u32 +efs_getblk(struct inode *in, __u32 blk) +{ + struct efs_sb_info *sbi = &in->i_sb->u.efs_sb; + struct efs_inode_info *ini = &in->u.efs_i; + int iter; + + __u32 diskblk, total = ini->tot, current = ini->cur; + + if (total <= EFS_MAX_EXTENTS) { + diskblk = CHECK(current); + if (diskblk) + return diskblk; + + if (total == 1) + return 0; + + /* + * OPT: start with current and then wrap, to optimize for + * read-forward pattern. + */ + for (iter = 0; iter < total; iter++) { + if (iter == current) + continue; /* already checked the current extent */ + diskblk = CHECK(iter); + if (diskblk) { + ini->cur = iter; + DB(("EFS: inode %d: found block %d as %d in ext %d\n", + in->i_ino, blk, diskblk, iter)); + return diskblk; + } + } + + DB(("EFS: block %d not found in direct inode %d (size %d)\n", + blk, in->i_ino, in->i_size)); + return 0; - extoff += 8; - /* need new block */ - if(extoff==EFS_BLOCK_SIZE) { - extoff = 0; - extblk++; - - brelse(bh); - bh = bread(in->i_dev,extblk,EFS_BLOCK_SIZE); - if(!bh) { - printk("efs: read error in indirect extents\n"); + } else { + int indirext = 0, total_extents_checked = 0; + + /* indirect inode */ + DB(("EFS: inode %d is indirect (total %d, indir ", in->i_ino, total)); + total = ini->extents[0].ex_ex.ex_offset; + DB(("%d)\n", total)); + + for (indirext = 0; indirext < total; indirext++) { + struct buffer_head *extbh; + union efs_extent *ptr; + int indirblk, indirbn, indirlen; + /* + * OPT: copy the current direct extent into the inode info for a + * quick check before we start reading blocks. + * OPT: copy _10_ into the inode info, like the old code did. + */ + + indirbn = ini->extents[indirext].ex_ex.ex_bn; + indirlen = ini->extents[indirext].ex_ex.ex_length; + for (indirblk = indirbn; + indirblk < indirbn + indirlen; + indirblk++) { + extbh = bread(in->i_dev, indirblk, EFS_BLOCK_SIZE); + if (!extbh) { + printk("EFS: ERROR: inode %ld bread of extent block %d failed\n", + in->i_ino, indirblk); + return 0; + } + + for (ptr = (union efs_extent *)extbh->b_data; + ptr < (union efs_extent *)(extbh->b_data+EFS_BLOCK_SIZE); + ptr++, ++total_extents_checked) { + + diskblk = check_extent(ptr, blk, sbi->fs_start); + if (diskblk || total_extents_checked > ini->tot) { + brelse(extbh); + return diskblk; + } + } + + brelse(extbh); + } + } + DB(("EFS: inode %d: didn't find block %d (indirect search, size %d)\n", + in->i_ino, in->i_size)); return 0; - } - ptr = (union efs_extent *)bh->b_data; } - } - brelse(bh); - - return result; -} - +} -/* ----- efs_bmap ----- - bmap: map a file block number to a device block number - - in - inode owning the block - block - block number - - return - disk block -*/ int efs_bmap(struct inode *in, int block) { - /* quickly reject invalid block numbers */ - if(block<0) { -#ifdef DEBUG - printk("efs_bmap: block < 0\n"); -#endif - return 0; - } - /* since the kernel wants to read a full page of data, i.e. 8 blocks - we must check if the block number is not too large */ - if(block>((in->i_size-1)>>EFS_BLOCK_SIZE_BITS)) { -#ifdef DEBUG - printk("efs_bmap: block %d > max %d == %d\n", - block,in->i_size>>EFS_BLOCK_SIZE_BITS,in->i_blocks); -#endif - return 0; - } + if (block < 0) + return 0; + + /* + * the kernel wants a full page (== 4K == 8 EFS blocks), so be sure that + * the block number isn't too large for that. + */ + if (block > ((in->i_size - 1) >> EFS_BLOCK_SIZE_BITS)) { + DB(("EFS: wacky: block %d > max %d\n", block, + ((in->i_size - 1) >> EFS_BLOCK_SIZE_BITS))); + return 0; + } - return efs_getblk(in,block); + return efs_getblk(in, block); } diff --git a/fs/efs/inode.c b/fs/efs/inode.c index 7928e45b4..735d86d99 100644 --- a/fs/efs/inode.c +++ b/fs/efs/inode.c @@ -1,498 +1,339 @@ -/* inode.c - * - * Inode and Superblock handling for the EFS filesystem +/* + * linux/fs/efs/inode.c * - * (C) 1995,96 Christian Vogelgsang + * Copyright (C) 1998 Mike Shaver + * + * Portions derived from work (C) 1995,1996 Christian Vogelgsang. + * ``Inspired by'' fs/minix/inode.c. */ - -#include <linux/module.h> + +#include <linux/module.h> /* module apparatus */ #include <linux/init.h> /* __initfunc */ -#include <linux/fs.h> #include <linux/efs_fs.h> -#include <linux/efs_fs_i.h> -#include <linux/efs_fs_sb.h> #include <linux/locks.h> - #include <asm/uaccess.h> -/* ----- Define the operations for the Superblock ----- */ -void efs_read_inode(struct inode *); -void efs_put_super(struct super_block *); -int efs_statfs(struct super_block *, struct statfs *,int ); - -static struct super_operations efs_sops = { - efs_read_inode, - NULL, /* write_inode */ - NULL, /* put_inode */ - NULL, /* delete_inode */ - NULL, /* notify_change */ - efs_put_super, - NULL, /* write_super */ - efs_statfs, - NULL -}; - - -/* ----- Conversion utilities ----- - Get 16- and 32-bit unsigned values in big-endian format from a byte buffer -*/ -__u32 ConvertLong(__u8 *buf, int offset) -{ - return *((__u32 *)(buf + offset)); - /* return (__u32)buf[offset+3] | - ((__u32)buf[offset+2])<<8 | - ((__u32)buf[offset+1])<<16 | - ((__u32)buf[offset])<<24; - */ +#define COPY_EXTENT(from, to) \ +{ \ + to.ex_bytes[0] = efs_swab32(from.ex_bytes[0]); \ + to.ex_bytes[1] = efs_swab32(from.ex_bytes[1]); \ } -__u16 ConvertShort(__u8 *buf, int offset) +void +efs_put_super(struct super_block *sb) { - return *((__u16 *)(buf + offset)); - /* - return (__u16)buf[offset+1] | - ((__u16)buf[offset])<<8; - */ + DB(("efs_put_super ... ")); + lock_super(sb); + DB(("locked ... ")); + sb->s_dev = 0; + unlock_super(sb); + DB(("unlocked ... ")); + MOD_DEC_USE_COUNT; + DB(("MOD_DEC_USE_COUNT\n")); } +static struct super_operations efs_sops = { + efs_read_inode, + NULL, /* write_inode */ + NULL, /* put_inode */ + NULL, /* delete_inode */ + NULL, /* notify_change */ + efs_put_super, + NULL, /* write_super */ + efs_statfs, + NULL, /* remount */ +}; -/* ----- Install/Remove Module ----- - These procedures are used to install/remove our filesystem - module in the linux kernel -*/ +static const char * +efs_checkroot(struct super_block *sb, struct inode *dir) +{ + struct buffer_head *bh; -/* describe filesystem */ -struct super_block *efs_read_super(struct super_block *s, void *d, int sil); + if (!S_ISDIR(dir->i_mode)) + return "root directory is not a directory"; -static struct file_system_type efs_fs_type = { - "efs", - FS_REQUIRES_DEV, - efs_read_super, - NULL -}; + bh = bread(dir->i_dev, efs_bmap(dir, 0), EFS_BLOCK_SIZE); + if (!bh) + return "unable to read root directory"; -__initfunc(int init_efs_fs(void)) { - return register_filesystem(&efs_fs_type); + /* XXX check sanity of root directory */ + + brelse(bh); + return NULL; } -#ifdef MODULE -EXPORT_NO_SYMBOLS; - -/* install module */ -int init_module(void) +struct super_block * +efs_read_super(struct super_block *s, void *data, int silent) { - return init_efs_fs(); + struct buffer_head *bh; + struct efs_disk_sb *efs_sb; + struct efs_sb_info *sbi; + kdev_t dev = s->s_dev; + const char *errmsg; + struct inode *root; + __u32 magic; + + DB(("read_super\n")); + MOD_INC_USE_COUNT; + + lock_super(s); + set_blocksize(dev, EFS_BLOCK_SIZE); + + /* + * XXXshaver + * If this is a CDROM, then there's a volume descriptor at block + * EFS_BLK_VOLDESC. What's there if it's just a disk partition? + */ + + bh = bread(dev, EFS_BLK_SUPER, EFS_BLOCK_SIZE); + if (!bh) + goto out_bad_sb; + + efs_sb = (struct efs_disk_sb *)bh->b_data; + sbi = &s->u.efs_sb; + sbi->total_blocks = efs_sb->s_size; + sbi->first_block = efs_sb->s_firstcg; + sbi->group_size = efs_sb->s_cgfsize; + sbi->inode_blocks = efs_sb->s_cgisize; + sbi->total_groups = efs_sb->s_ncg; + magic = efs_sb->s_magic; + brelse(bh); + + if (magic == EFS_MAGIC1 || magic == EFS_MAGIC2) { + DB(("EFS: valid superblock magic\n")); + } else { + goto out_no_fs; + } + + if (efs_sb->s_dirty != EFS_CLEAN) { + switch(efs_sb->s_dirty) { + case EFS_ACTIVE: + errmsg = "Partition was not unmounted properly, but is clean"; + break; + case EFS_ACTIVEDIRT: + errmsg = "Partition was mounted dirty and not cleanly unmounted"; + break; + case EFS_DIRTY: + errmsg = "Partition was not umounted properly, and is dirty"; + break; + } + if (!silent) + printk("EFS: ERROR: %s\n", errmsg); + goto out_unlock; + } + + s->s_blocksize = EFS_BLOCK_SIZE; + s->s_blocksize_bits = EFS_BLOCK_SIZE_BITS; + s->s_magic = EFS_SUPER_MAGIC; + s->s_op = &efs_sops; + root = iget(s, EFS_ROOT_INODE); + + errmsg = efs_checkroot(s, root); + if (errmsg) + goto out_bad_root; + + s->s_root = d_alloc_root(root, NULL); + if (!s->s_root) + goto out_iput; + + /* we only do RO right now */ + if (!(s->s_flags & MS_RDONLY)) { + if (!silent) + printk("EFS: forcing read-only: RW access not supported\n"); + s->s_flags |= MS_RDONLY; + } + + unlock_super(s); + return s; + + /* error-handling exit paths */ + out_bad_root: + if (!silent) + printk("EFS: ERROR: %s\n", errmsg); + goto out_unlock; + + out_iput: + iput(root); + brelse(bh); + goto out_unlock; + + out_no_fs: + printk("EFS: ERROR: bad magic\n"); + goto out_unlock; + + out_bad_sb: + printk("EFS: unable to read superblock\n"); + + out_unlock: + s->s_dev = 0; + unlock_super(s); + MOD_DEC_USE_COUNT; + return NULL; } -/* remove module */ -void cleanup_module(void) +int +efs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz) { - unregister_filesystem(&efs_fs_type); + struct statfs tmp; + + DB(("statfs\n")); + tmp.f_type = sb->s_magic; + tmp.f_bsize = sb->s_blocksize; + tmp.f_blocks = sb->u.efs_sb.total_blocks; + tmp.f_bfree = 0; + tmp.f_bavail = 0; + tmp.f_files = 0; /* XXX? */ + tmp.f_ffree = 0; + tmp.f_namelen = NAME_MAX; + return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0; } -#endif /* MODULE */ - -#ifdef DEBUG_EFS -void efs_dump_super(struct efs_super_block *sb) { - printk("efs_super_block @ 0x%p:\n", sb); - printk("size: %0#8lX firstcg: %0#8lX\n", sb->s_size, sb->s_firstcg); - printk("cgfsize: %0#8lX cgisize: %0#8hX\n", sb->s_cgfsize,sb->s_cgisize); - printk("sectors: %0#8hX heads: %0#8hX\n", sb->s_sectors, sb->s_heads); - printk("ncg: %0#8hX dirty: %0#8hX\n", sb->s_ncg, sb->s_dirty); - printk("time: %0#8lX magic: %0#8lX\n", sb->s_time, sb->s_magic); - printk("fname: %.6s fpack: %.6s\n", sb->s_fname, sb->s_fpack); - printk("bmsize: %0#8lX tfree: %0#8lX\n", sb->s_bmsize, sb->s_tfree); - printk("tinode: %0#8lX bmblock: %0#8lX\n", sb->s_tinode, sb->s_bmblock); - printk("replsb: %0#8lX lastiall: %0#8lX\n", sb->s_replsb, - sb->s_lastialloc); - printk("checksum: %0#8lX\n", sb->s_checksum); -} - -void efs_dump_inode(struct efs_disk_inode *di) { - printk("efs_disk_inode @ 0x%p: ", di); - printk("[%o %hd %hd %u %u %u %u %u #ext=%hd %u %u]\n", - di->di_mode, di->di_nlink, di->di_uid, di->di_gid, di->di_size, - di->di_atime, di->di_mtime, di->di_ctime, di->di_gen, - di->di_numextents, di->di_version); -} -#endif -/* ----- efs_checkVolDesc ----- - Analyse the first block of a CD and check - if it's a valid efs volume descriptor - - blk - buffer with the data of first block - silent - 0 -> verbose - - return : 0 - error ; >0 - start block of filesystem -*/ -#if 0 -static __u32 efs_checkVolDesc(__u8 *blk,int silent) +void +efs_read_inode(struct inode *in) { - __u32 magic; - __u8 *ptr; - __u8 name[10]; - __u32 pos,len; - int i; - - /* is the magic cookie here? */ - magic = ConvertLong(blk,0); - if(magic!=0x0be5a941) { - printk("EFS: no magic on first block\n"); - return 0; - } - - /* Walk through the entries of the VD */ - /* Quite useless, but gives nice output ;-) */ - ptr = blk + EFS_VD_ENTRYFIRST; - name[8] = 0; - while(*ptr) { - for(i=0;i<8;i++) - name[i] = ptr[i]; - - /* start and length of entry */ - pos = ConvertLong(ptr,EFS_VD_ENTRYPOS); - len = ConvertLong(ptr,EFS_VD_ENTRYLEN); - - if(!silent) - printk("EFS: VolDesc: %8s blk: %08lx len: %08lx\n", - name,pos,len); + struct efs_sb_info *efs_sb = &in->i_sb->u.efs_sb; + struct buffer_head *bh; + struct efs_disk_inode *di; + struct efs_inode_info *ini = &in->u.efs_i; + int block, ino = in->i_ino, offset; + __u16 numext; + __u32 rdev; + + DB(("read_inode")); + + /* + * Calculate the disk block and offset for the inode. + * There are 4 inodes per block. + */ + block = ino / EFS_INODES_PER_BLOCK; + + /* + * Inodes are stored at the beginning of every cylinder group. + * + * We find the block containing the inode like so: + * - block is set above to the ``logical'' block number + * - first_block is the start of the FS + * - (block / inode_blocks) is the cylinder group that the inode is in. + * - (block % inode_blocks) is the block offset within the cg + * + */ + block = efs_sb->first_block + + (efs_sb->group_size * (block / efs_sb->inode_blocks)) + + (block % efs_sb->inode_blocks); - ptr+=EFS_VD_ENTRYSIZE; - } + /* find the offset */ + offset = (ino % EFS_INODES_PER_BLOCK) << 7; - pos = ConvertLong(blk,EFS_VD_FS_START); - printk("EFS: FS start: %08lx\n",pos); - return pos; -} -#endif + DB(("EFS: looking for inode #%xl\n", ino)); -/* ----- efs_checkSuper ----- - Check if the given block is a valid EFS-superblock - - sbi - my EFS superblock info - block - block that must be examined - - return - 0 ok, -1 error -*/ -static int efs_verify_super(struct efs_super_block *sb, - struct efs_sb_info *sbi, - int silent) -{ - __u32 magic; - - magic = sb->s_magic; - /* check if the magic cookie is here */ - if((magic!=EFS_MAGIC1)&&(magic!=EFS_MAGIC2)) { - printk("EFS: magic %#X doesn't match %#X or %#X!\n", - magic, EFS_MAGIC1, EFS_MAGIC2); - return -1; - } + bh = bread(in->i_dev, block, EFS_BLOCK_SIZE); - /* XXX should check csum */ - - sbi->total_blocks = sb->s_size; - sbi->first_block = sb->s_firstcg; - sbi->group_size = sb->s_cgfsize; - sbi->inode_blocks = sb->s_cgisize; - sbi->total_groups = sb->s_ncg; - - return 0; -} + if (!bh) { + printk("EFS: failed to bread blk #%xl for inode %#xl\n", block, ino); + goto error; + } + di = (struct efs_disk_inode *)(bh->b_data + offset); -/* ----- efs_read_super ----- - read_super: if the fs gets mounted this procedure is called to - check if the filesystem is valid and to fill the superblock struct - - s - superblock struct - d - options for fs (unused) - sil - flag to be silent - - return - filled s struct or NULL on error - */ + /* standard inode info */ + in->i_mtime = efs_swab32(di->di_mtime); + in->i_ctime = efs_swab32(di->di_ctime); + in->i_atime = efs_swab32(di->di_atime); + in->i_size = efs_swab32(di->di_size); + in->i_nlink = efs_swab16(di->di_nlink); + in->i_uid = efs_swab16(di->di_uid); + in->i_gid = efs_swab16(di->di_gid); + in->i_mode = efs_swab16(di->di_mode); -struct super_block *efs_read_super(struct super_block *s, void *d, int silent) -{ - struct buffer_head *bh; - struct efs_sb_info *sb_info = (struct efs_sb_info *)&s->u.efs_sb; - struct efs_super_block *es; - int error = 0; - int dev = s->s_dev; - struct inode *root_inode = NULL; - - MOD_INC_USE_COUNT; - - /* say hello to my log file! */ -#ifdef EFS_DEBUG - if(!silent) - printk("EFS: --- Filesystem ---\n"); -#endif - /* set blocksize to 512 */ - set_blocksize(dev, EFS_BLOCK_SIZE); - - lock_super(s); - -#if 0 - /* Read first block of CD: the Volume Descriptor */ - bh = bread(dev, 0, EFS_BLOCK_SIZE); - if(bh) { - sb_info->fs_start = efs_checkVolDesc((__u8 *)bh->b_data,silent); - if(sb_info->fs_start==0) { - printk("EFS: failed checking Volume Descriptor\n"); - /* error++; */ - } - brelse(bh); - } else { - printk("EFS: cannot read the first block\n"); - error++; - } -#endif 0 + rdev = efs_swab32(*(__u32 *) &di->di_u.di_dev); + numext = efs_swab16(di->di_numextents); - /* Read the Superblock */ - if(!error) { -#ifdef DEBUG_EFS - if (!silent) - printk("EFS: reading superblock.\n"); -#endif - bh = bread(dev, EFS_BLK_SUPER, EFS_BLOCK_SIZE ); - if(bh) { - es = (struct efs_super_block *)(bh->b_data); -#ifdef DEBUG_EFS - if(!silent) - efs_dump_super(es); -#endif - if(efs_verify_super(es, sb_info, silent)) { - printk("EFS: failed checking Superblock\n"); - error++; - } - brelse(bh); - } else { - printk("EFS: cannot read the superblock\n"); - error++; - } - } - - if(!error) { - s->s_blocksize = EFS_BLOCK_SIZE; - s->s_blocksize_bits = EFS_BLOCK_SIZE_BITS; - - s->s_magic = EFS_SUPER_MAGIC; - s->s_flags = MS_RDONLY; - s->s_op = &efs_sops; - s->s_dev = dev; - root_inode = iget(s, EFS_ROOT_INODE); - s->s_root = d_alloc_root(root_inode, NULL); - if (!s->s_root) { - error++; - printk("EFS: couldn't allocate root inode!\n"); - } - } + if (numext > EFS_MAX_EXTENTS) { + DB(("EFS: inode #%lx is indirect (%d)\n", ino, numext)); + + /* + * OPT: copy the first 10 extents in here? + */ + } else { + int i; - unlock_super(s); - - if(check_disk_change(s->s_dev)) { - printk("EFS: Device changed!\n"); - error++; + DB(("EFS: inode %#lx is direct. Happy day!\n", in->i_ino)); + ini->extblk = block; + + /* copy extents into inode_info */ + for (i = 0; i < numext; i++) { + COPY_EXTENT(di->di_u.di_extents[i], ini->extents[i]); } - /* We found errors -> say goodbye! */ - if(error) { - s->s_dev = 0; - d_delete(s->s_root); /* XXX is this enough? */ - printk("EFS: init failed with %d errors\n", error); - brelse(bh); - MOD_DEC_USE_COUNT; - return NULL; - } - - return s; + } + ini->tot = numext; + ini->cur = 0; + brelse(bh); + + switch(in->i_mode & S_IFMT) { + case S_IFDIR: + in->i_op = &efs_dir_inode_operations; + break; + case S_IFREG: + in->i_op = &efs_file_inode_operations; + break; + case S_IFLNK: + in->i_op = &efs_symlink_inode_operations; + break; + case S_IFCHR: + in->i_rdev = rdev; + in->i_op = &chrdev_inode_operations; + break; + case S_IFBLK: + in->i_rdev = rdev; + in->i_op = &blkdev_inode_operations; + break; + case S_IFIFO: + init_fifo(in); + break; + default: + printk("EFS: ERROR: unsupported inode mode %lo\n", + (in->i_mode & S_IFMT)); + goto error; + } + + return; + + error: + in->i_mtime = in->i_atime = in->i_ctime = 0; + in->i_size = 0; + in->i_nlink = 1; + in->i_uid = in->i_gid = 0; + in->i_mode = S_IFREG; + in->i_op = NULL; } +static struct file_system_type efs_fs_type = { + "efs", + FS_REQUIRES_DEV, + efs_read_super, + NULL +}; -/* ----- efs_put_super ----- - put_super: remove the filesystem and the module use count - - s - superblock -*/ -void efs_put_super(struct super_block *s) +__initfunc(int +init_efs_fs(void)) { - lock_super(s); - s->s_dev = 0; - unlock_super(s); - MOD_DEC_USE_COUNT; + return register_filesystem(&efs_fs_type); } +#ifdef MODULE +EXPORT_NO_SYMBOLS; -/* ----- efs_statfs ----- - statfs: get informatio on the filesystem - - s - superblock of fs - buf - statfs struct that has to be filled -*/ -int efs_statfs(struct super_block *s, struct statfs *buf,int bufsize) +int +init_module(void) { - struct efs_sb_info *sbi = (struct efs_sb_info *)&s->u.generic_sbp; - struct statfs tmp; - - tmp.f_type = EFS_SUPER_MAGIC; - tmp.f_bsize = EFS_BLOCK_SIZE; - tmp.f_blocks = sbi->total_blocks; - tmp.f_bfree = 0; - tmp.f_bavail = 0; - tmp.f_files = 100; /* don't know how to calculate the correct value */ - tmp.f_ffree = 0; - tmp.f_namelen = NAME_MAX; - - return copy_to_user(buf,&tmp,bufsize) ? -EFAULT : 0; + return init_efs_fs(); } - -/* ----- efs_read_inode ----- - read an inode specified by in->i_ino from disk, fill the inode - structure and install the correct handler for the file type - - in - inode struct -*/ -void efs_read_inode(struct inode *in) +void +cleanup_module(void) { - struct buffer_head *bh; - struct efs_sb_info *sbi = (struct efs_sb_info *)&in->i_sb->u.generic_sbp; - __u32 blk,off; - int error = 0; - - /* Calc the discblock and the offset for inode (4 Nodes fit in one block) */ - blk = in->i_ino >> 2; - blk = sbi->fs_start + sbi->first_block + - (sbi->group_size * (blk / sbi->inode_blocks)) + - (blk % sbi->inode_blocks); - off = (in->i_ino&3)<<7; - - /* Read the block with the inode from disk */ -#ifdef DEBUG_EFS - printk("EFS: looking for inode %#xl\n", in->i_ino); -#endif - bh = bread(in->i_dev,blk,EFS_BLOCK_SIZE); - if(bh) { - - struct efs_disk_inode *di = (struct efs_disk_inode *)(bh->b_data + off); - __u16 numext; - struct efs_inode_info *ini = &in->u.efs_i; - __u32 rdev; - int i; - - /* fill in standard inode infos */ - in->i_mtime = efs_swab32(di->di_mtime); - in->i_ctime = efs_swab32(di->di_ctime); - in->i_atime = efs_swab32(di->di_atime); - in->i_size = efs_swab32(di->di_size); - in->i_nlink = efs_swab16(di->di_nlink); - in->i_uid = efs_swab16(di->di_uid); - in->i_gid = efs_swab16(di->di_gid); - in->i_mode = efs_swab16(di->di_mode); - - /* Special files store their rdev value where the extends of - a regular file are found */ - /* rdev = ConvertLong(rawnode,EFS_IN_EXTENTS);*/ - /* XXX this isn't right */ - rdev = efs_swab32(*(__u32 *)&di->di_u.di_dev); - - /* ----------------------------------------------------------------- - The following values are stored in my private part of the Inode. - They are necessary for further operations with the file */ - - /* get the number of extends the inode posseses */ - numext = efs_swab16(di->di_numextents); - - /* if this inode has more than EFS_MAX_EXTENDS then the extends are - stored not directly in the inode but indirect on an extra block. - The address of the extends-block is stored in the inode */ - if(numext>EFS_MAX_EXTENTS) { - struct buffer_head *bh2; - printk("EFS: inode #%lx has > EFS_MAX_EXTENTS (%d)\n", - in->i_ino, numext); - - /* Store the discblock and offset of extend-list in Inode info */ - ini->extblk = sbi->fs_start + efs_swab32((__u32)(di->di_u.di_extents)); - - /* read INI_MAX_EXT extents from the indirect block */ - printk("EFS: "); - bh2 = bread(in->i_dev,ini->extblk,EFS_BLOCK_SIZE); - if(bh2) { - union efs_extent *ptr = - (union efs_extent *)bh2->b_data; - for(i=0;i<EFS_MAX_EXTENTS;i++) { - ini->extents[i].ex_bytes[0] = efs_swab32(ptr[i].ex_bytes[0]); - ini->extents[i].ex_bytes[1] = efs_swab32(ptr[i].ex_bytes[1]); - } - brelse(bh2); - } else - printk("efs: failed reading indirect extents!\n"); - - } else { -#ifdef DEBUG_EFS - printk("EFS: inode %#Xl is direct (woohoo!)\n", - in->i_ino); -#endif - /* The extends are found in the inode block */ - ini->extblk = blk; - - /* copy extends directly from rawinode */ - for(i=0;i<numext;i++) { - ini->extents[i].ex_bytes[0] = efs_swab32(di->di_u.di_extents[i].ex_bytes[0]); - ini->extents[i].ex_bytes[1] = efs_swab32(di->di_u.di_extents[i].ex_bytes[1]); - } - } - ini->tot = numext; - ini->cur = 0; - - brelse(bh); - -#ifdef DEBUG_EFS - printk("%lx inode: blk %lx numext %x\n",in->i_ino,ini->extblk,numext); - efs_dump_inode(di); -#endif - - /* Install the filetype Handler */ - switch(in->i_mode & S_IFMT) { - case S_IFDIR: - in->i_op = &efs_dir_in_ops; - break; - case S_IFREG: - in->i_op = &efs_file_in_ops; - break; - case S_IFLNK: - in->i_op = &efs_symlink_in_ops; - break; - case S_IFCHR: - in->i_rdev = rdev; - in->i_op = &chrdev_inode_operations; - break; - case S_IFBLK: - in->i_rdev = rdev; - in->i_op = &blkdev_inode_operations; - break; - case S_IFIFO: - init_fifo(in); - break; - default: - printk("EFS: Unsupported inode Mode %o\n",(unsigned int)(in->i_mode)); - error++; - break; - } - - } else { - printk("EFS: Inode: failed bread!\n"); - error++; - } - - /* failed inode */ - if(error) { - printk("EFS: read inode failed with %d errors\n",error); - in->i_mtime = in->i_atime = in->i_ctime = 0; - in->i_size = 0; - in->i_nlink = 1; - in->i_uid = in->i_gid = 0; - in->i_mode = S_IFREG; - in->i_op = NULL; - } + unregister_filesystem(&efs_fs_type); } + +#endif diff --git a/fs/efs/namei.c b/fs/efs/namei.c index 752aa5fe1..eba441e5a 100644 --- a/fs/efs/namei.c +++ b/fs/efs/namei.c @@ -1,141 +1,96 @@ -/* namei.c - - name lookup for EFS filesystem - - (C)95,96 Christian Vogelgsang -*/ +/* + * linux/fs/efs/namei.c + * + * Copyright (C) 1998 Mike Shaver + * + * Portions derived from work (C) 1995,1996 Christian Vogelgsang. + * ``Inspired by'' fs/minix/namei.c. + */ -#include <linux/sched.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/fs.h> #include <linux/efs_fs.h> -#include <linux/efs_fs_i.h> -#include <linux/efs_fs_sb.h> -#include <linux/stat.h> -#include <asm/uaccess.h> +#include <linux/errno.h> -/* ----- efs_find_entry ----- - search a raw efs dir entry for the given name - - dir - inode of directory - oname - name to search for - onamelen- length of name - - return - inode number of the found entry or 0 on error -*/ -static struct buffer_head * efs_find_entry(struct inode *dir, - const char *oname, - int onamelen, - struct efs_dir_entry *res_dir) +static struct buffer_head * +efs_find_entry(struct inode *dir, const char *oname, int onamelen, + struct efs_dir_entry **res_dir) { - struct efs_inode_info *ini = &dir->u.efs_i; - struct buffer_head *bh = NULL; - __u32 inode; - __u16 i; - __u8 *name; - __u16 namelen; - __u32 blknum,b; - struct efs_dirblk *db; - - /* Warnings */ - if(ini->tot!=1) - printk("efs_find: More than one extent!\n"); - if(dir->i_size & (EFS_BLOCK_SIZE-1)) - printk("efs_find: dirsize != blocklen * n\n"); + struct buffer_head *bh; + struct efs_sb_info *sbi; + struct efs_dirblk *dirblk; + __u32 offset, block, maxblk; + __u16 i, namelen; + char *name; - /* Search in every dirblock */ - inode = 0; - blknum = dir->i_size >> EFS_BLOCK_SIZE_BITS; -#ifdef DEBUG_EFS - printk("EFS: directory with inode %#xd has %d blocks\n", - dir->i_ino, blknum); -#endif - for(b=0;b<blknum;b++) { - int db_offset; -#ifdef DEBUG_EFS - printk("EFS: trying block %d\n", b); -#endif - /* Read a raw dirblock */ - bh = bread(dir->i_dev,efs_bmap(dir,b),EFS_BLOCK_SIZE); - if(!bh) { - printk("EFS: efs_bmap returned NULL!\n"); - return 0; - } - - db = (struct efs_dirblk *)bh->b_data; - if (db->db_magic != EFS_DIRBLK_MAGIC) { - printk("EFS: dirblk has bad magic (%#xl)!\n", - db->db_magic); - return NULL; - } -#ifdef DEBUG_EFS - printk("EFS: db %d has %d entries, starting at offset %#x\n", - b, db->db_slots, (__u16)db->db_firstused << 1); -#endif - for(i = 0 ; i < db->db_slots ; i++) { - struct efs_dent * de; - int entry_inode; - db_offset = ((__u16)db->db_space[i] << 1) - - EFS_DIRBLK_HEADERSIZE; - de = (struct efs_dent *)(&db->db_space[db_offset]); + *res_dir = NULL; + if (!dir || !dir->i_sb) + return NULL; + sbi = &dir->i_sb->u.efs_sb; + bh = NULL; + block = offset = 0; + maxblk = dir->i_size >> EFS_BLOCK_SIZE_BITS; + DB(("EFS: dir has %d blocks\n", maxblk)); + for (block = 0; block < maxblk; block++) { - /* inode, namelen and name of direntry */ - entry_inode = efs_swab32(de->ud_inum.l); - namelen = de->d_namelen; - name = de->d_name; -#ifdef 0 - printk("EFS: entry %d @ %#x has inode %#x, %s/%d\n", - i, db_offset, entry_inode, name, namelen); -#endif - /* we found the name! */ - if((namelen==onamelen)&& - (!memcmp(oname,name,onamelen))) { - res_dir->inode = entry_inode; -#ifdef DEBUG_EFS - printk("EFS: found inode %d\n", - entry_inode); -#endif - return bh; - } - } + bh = bread(dir->i_dev, efs_bmap(dir, block), EFS_BLOCK_SIZE); + if (!bh) { + DB(("EFS: find_entry: skip blk %d (ino %#lx): bread\n", + block, dir->i_ino)); + continue; } -#ifdef DEBUG_EFS - printk("EFS: efs_find_entry didn't find inode for \"%s\"/%d!\n", - oname, onamelen); -#endif - return NULL; - /* not reached */ -} + dirblk = (struct efs_dirblk *)bh->b_data; + + if (efs_swab32(dirblk->db_magic) != EFS_DIRBLK_MAGIC) { + printk("EFS: dirblk %d (ino %#lx) has bad magic (%#x)!\n", + block, dir->i_ino, efs_swab32(dirblk->db_magic)); + brelse(bh); + continue; + } + + DB(("EFS: db %d has %d entries\n", block, dirblk->db_slots)); + + for (i = 0; i < dirblk->db_slots; i++) { + struct efs_dir_entry *dent; + __u16 off = EFS_SLOT2OFF(dirblk, i); + if (!off) { + DB(("skipping empty slot %d\n", i)); + continue; /* skip empty slot */ + } + dent = EFS_DENT4OFF(dirblk, off); + namelen = dent->d_namelen; + name = dent->d_name; + + if ((namelen == onamelen) && + !memcmp(oname, name, onamelen)) { + *res_dir = dent; + return bh; + } + } -/* ----- efs_lookup ----- - lookup inode operation: - check if a given name is in the dir directory - - dir - pointer to inode of directory - name - name we must search for - len - length of name - result - pointer to inode struct if we found it or NULL on error - - return - 0 everything is ok or <0 on error -*/ -int efs_lookup(struct inode *dir, struct dentry *dentry) + brelse(bh); + } + DB(("EFS: find_entry didn't find inode for \"%s\"/%d\n", + oname, onamelen)); + return NULL; +} + +int +efs_lookup(struct inode *dir, struct dentry *dentry) { - struct inode *inode = NULL; - struct buffer_head *bh; - struct efs_dir_entry de; - - bh = efs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); - if (bh) { - int ino = de.inode; - brelse(bh); - inode = iget(dir->i_sb, ino); + struct buffer_head *bh; + struct inode *in = NULL; + struct efs_dir_entry *dent; + + bh = efs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &dent); + if (bh) { + int ino = efs_swab32(dent->ud_inum.l); - if (!inode) - return -EACCES; - } + brelse(bh); + in = iget(dir->i_sb, ino); + if (!in) + return -EACCES; + } - d_add(dentry, inode); - return 0; + d_add(dentry, in); + return 0; } diff --git a/fs/efs/symlink.c b/fs/efs/symlink.c index 05e3c082d..95ab238a4 100644 --- a/fs/efs/symlink.c +++ b/fs/efs/symlink.c @@ -1,25 +1,64 @@ -/* symlink.c +/* + * linux/fs/efs/symlink.c * - * Symbolic link handling for EFS + * Copyright (C) 1998 Mike Shaver * - * (C)1995,96 Christian Vogelgsang - * - * Based on the symlink.c from minix-fs by Linus + * Portions derived from work (C) 1995,1996 Christian Vogelgsang. + * ``Inspired by'' fs/ext2/symlink.c. */ -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/fs.h> #include <linux/efs_fs.h> -#include <linux/stat.h> -#include <linux/mm.h> -#include <linux/slab.h> #include <asm/uaccess.h> -static int efs_readlink(struct inode *, char *, int); -static struct dentry * efs_follow_link(struct inode *, struct dentry *); +static struct dentry * +efs_follow_link(struct dentry *dentry, struct dentry *base) +{ + struct inode *in = dentry->d_inode; + struct buffer_head *bh; + + bh = bread(in->i_dev, efs_bmap(in, 0), EFS_BLOCK_SIZE); + if (!bh) { + dput(base); + return ERR_PTR(-EIO); + } + UPDATE_ATIME(in); + base = lookup_dentry(bh->b_data, base, 1); + brelse(bh); + return base; +} + +static int +efs_readlink(struct dentry *dentry, char * buffer, int buflen) +{ + int i; + struct buffer_head *bh; + struct inode *in = dentry->d_inode; + + if (buflen > 1023) + buflen = 1023; + + if (in->i_size < buflen) + buflen = in->i_size; + + bh = bread(in->i_dev, efs_bmap(in, 0), EFS_BLOCK_SIZE); + if (!bh) + return 0; + i = 0; + + /* XXX need strncpy_to_user */ + while (i < buflen && bh->b_data[i]) + i++; + + if (copy_to_user(buffer, bh->b_data, i)) + i = -EFAULT; + + UPDATE_ATIME(in); + + brelse(bh); + return i; +} -struct inode_operations efs_symlink_in_ops = { +struct inode_operations efs_symlink_inode_operations = { NULL, /* no file-operations */ NULL, /* create */ NULL, /* lookup */ @@ -30,111 +69,12 @@ struct inode_operations efs_symlink_in_ops = { NULL, /* rmdir */ NULL, /* mknod */ NULL, /* rename */ - efs_readlink, /* readlink */ - efs_follow_link, /* follow_link */ - NULL, - NULL, + efs_readlink, + efs_follow_link, + NULL, /* readpage */ + NULL, /* writepage */ NULL, /* bmap */ NULL, /* truncate */ - NULL /* permission */ + NULL, /* permission */ + NULL /* smap */ }; - - -/* ----- efs_getlinktarget ----- - read the target of the link from the data zone of the file -*/ -static char *efs_getlinktarget(struct inode *in) -{ - struct buffer_head * bh; - char *name; - __u32 size = in->i_size; - __u32 block; - - /* link data longer than 1024 not supported */ - if(size>2*EFS_BLOCK_SIZE) { - printk("efs_getlinktarget: name too long: %lu\n",in->i_size); - return NULL; - } - - /* get some memory from the kernel to store the name */ - name = kmalloc(size+1,GFP_KERNEL); - if(!name) return NULL; - - /* read first 512 bytes of target */ - block = efs_bmap(in,0); - bh = bread(in->i_dev,block,EFS_BLOCK_SIZE); - if(!bh) { - kfree(name); - return NULL; - } - memcpy(name,bh->b_data,(size>EFS_BLOCK_SIZE)?EFS_BLOCK_SIZE:size); - brelse(bh); - - /* if the linktarget is long, read the next block */ - if(size>EFS_BLOCK_SIZE) { - bh = bread(in->i_dev,block+1,EFS_BLOCK_SIZE); - if(!bh) { - kfree(name); - return NULL; - } - memcpy(name+EFS_BLOCK_SIZE,bh->b_data,size-EFS_BLOCK_SIZE); - brelse(bh); - } - - /* terminate string and return it */ - name[size]=0; - return name; -} - - -/* ----- efs_follow_link ----- - get the inode of the link target -*/ -static struct dentry * efs_follow_link(struct inode * dir, struct dentry *base) -{ - char * name; - UPDATE_ATIME(dir); - name = efs_getlinktarget(dir); -#ifdef DEBUG_EFS - printk("EFS: efs_getlinktarget(%d) returned \"%s\"\n", - dir->i_ino, name); -#endif - base = lookup_dentry(name, base, 1); - kfree(name); - return base; -} - -/* ----- efs_readlink ----- - read the target of a link and return the name -*/ -static int efs_readlink(struct inode * dir, char * buffer, int buflen) -{ - int i; - struct buffer_head * bh; - - if (buflen > 1023) - buflen = 1023; - bh = bread(dir->i_dev,efs_bmap(dir,0),EFS_BLOCK_SIZE); - if (!bh) - return 0; - /* copy the link target to the given buffer */ - i = 0; -#ifdef DEBUG_EFS - printk("EFS: efs_readlink returning "); -#endif - while (i<buflen && bh->b_data[i] && i < dir->i_size) { -#ifdef DEBUG_EFS - printk("%c", bh->b_data[i]); -#endif - i++; - } -#ifdef DEBUG_EFS - printk("\n"); -#endif - if (copy_to_user(buffer, bh->b_data, i)) - i = -EFAULT; - - brelse(bh); - return i; -} - |