diff options
Diffstat (limited to 'fs/efs/dir.c')
-rw-r--r-- | fs/efs/dir.c | 221 |
1 files changed, 97 insertions, 124 deletions
diff --git a/fs/efs/dir.c b/fs/efs/dir.c index a31f6784a..483efd85a 100644 --- a/fs/efs/dir.c +++ b/fs/efs/dir.c @@ -1,146 +1,119 @@ /* - * linux/fs/efs/dir.c + * dir.c * - * Copyright (C) 1998 Mike Shaver + * Copyright (c) 1999 Al Smith * - * Portions derived from work (C) 1995,1996 Christian Vogelgsang. - * ``Inspired by'' fs/minix/dir.c. + * Portions derived from work (c) 1995,1996 Christian Vogelgsang. */ -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/efs_fs.h> -#include <asm/uaccess.h> +#include <linux/efs.h> 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, /* lseek */ - efs_dir_read, - NULL, /* write */ - efs_readdir, - NULL, /* poll */ - NULL, /* ioctl */ - NULL, /* mmap */ - NULL, /* open */ - NULL, /* flush */ - NULL, /* release */ - NULL /* fsync */ +static struct file_operations efs_dir_operations = { + NULL, /* lseek */ + NULL, /* read */ + NULL, /* write */ + efs_readdir, + NULL, /* poll */ + NULL, /* ioctl */ + NULL, /* no special open code */ + NULL, /* flush */ + NULL, /* no special release code */ + NULL /* fsync */ }; 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 */ + &efs_dir_operations, + 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; - } +/* read the next entry for a given directory */ + +static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) { + struct inode *inode = filp->f_dentry->d_inode; + struct efs_in_info *ini = (struct efs_in_info *) &inode->u.generic_ip; + struct buffer_head *bh; + + struct efs_dir *dirblock; + struct efs_dentry *dirslot; + efs_ino_t inodenum; + efs_block_t block; + int slot, namelen, numslots; + char *nameptr; + + if (!inode || !S_ISDIR(inode->i_mode)) + return -EBADF; + + if (ini->numextents != 1) + printk("EFS: WARNING: readdir(): more than one extent\n"); + + if (inode->i_size & (EFS_BLOCKSIZE-1)) + printk("EFS: WARNING: readdir(): directory size not a multiple of EFS_BLOCKSIZE\n"); + + /* work out the block where this entry can be found */ + block = filp->f_pos >> EFS_BLOCKSIZE_BITS; + + /* don't read past last entry */ + if (block > inode->i_blocks) return 0; + + /* read the dir block */ + bh = bread(inode->i_dev, efs_bmap(inode, block), EFS_BLOCKSIZE); + + if (!bh) { + printk("EFS: readdir(): failed to read dir block %d\n", block); + return 0; + } - dirblk = (struct efs_dirblk *)bh->b_data; + dirblock = (struct efs_dir *) bh->b_data; - /* 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) { + if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) { + printk("EFS: readdir(): invalid directory block\n"); brelse(bh); - goto start_block; - } + return(0); } - } 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 - { - __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))); - } + + slot = filp->f_pos & 0xff; + + dirslot = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot)); + + numslots = dirblock->slots; + inodenum = be32_to_cpu(dirslot->inode); + namelen = dirslot->namelen; + nameptr = dirslot->name; + +#ifdef DEBUG + printk("EFS: dent #%d: inode %u, name \"%s\", namelen %u\n", slot, inodenum, nameptr, namelen); #endif - 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); + /* copy filename and data in dirslot */ + filldir(dirent, nameptr, namelen, filp->f_pos, inodenum); - filp->f_pos = (block << EFS_BLOCK_SIZE_BITS) | item; - UPDATE_ATIME(in); + brelse(bh); - return 0; + /* store position of next slot */ + if (++slot == numslots) { + slot = 0; + block++; + } + + filp->f_pos = (block << EFS_BLOCKSIZE_BITS) | slot; + + return 0; } + |