1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * dir.c 3*1da177e4SLinus Torvalds * 4*1da177e4SLinus Torvalds * Copyright (c) 1999 Al Smith 5*1da177e4SLinus Torvalds */ 6*1da177e4SLinus Torvalds 7*1da177e4SLinus Torvalds #include <linux/buffer_head.h> 8*1da177e4SLinus Torvalds #include <linux/efs_fs.h> 9*1da177e4SLinus Torvalds #include <linux/smp_lock.h> 10*1da177e4SLinus Torvalds 11*1da177e4SLinus Torvalds static int efs_readdir(struct file *, void *, filldir_t); 12*1da177e4SLinus Torvalds 13*1da177e4SLinus Torvalds struct file_operations efs_dir_operations = { 14*1da177e4SLinus Torvalds .read = generic_read_dir, 15*1da177e4SLinus Torvalds .readdir = efs_readdir, 16*1da177e4SLinus Torvalds }; 17*1da177e4SLinus Torvalds 18*1da177e4SLinus Torvalds struct inode_operations efs_dir_inode_operations = { 19*1da177e4SLinus Torvalds .lookup = efs_lookup, 20*1da177e4SLinus Torvalds }; 21*1da177e4SLinus Torvalds 22*1da177e4SLinus Torvalds static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) { 23*1da177e4SLinus Torvalds struct inode *inode = filp->f_dentry->d_inode; 24*1da177e4SLinus Torvalds struct buffer_head *bh; 25*1da177e4SLinus Torvalds 26*1da177e4SLinus Torvalds struct efs_dir *dirblock; 27*1da177e4SLinus Torvalds struct efs_dentry *dirslot; 28*1da177e4SLinus Torvalds efs_ino_t inodenum; 29*1da177e4SLinus Torvalds efs_block_t block; 30*1da177e4SLinus Torvalds int slot, namelen; 31*1da177e4SLinus Torvalds char *nameptr; 32*1da177e4SLinus Torvalds 33*1da177e4SLinus Torvalds if (inode->i_size & (EFS_DIRBSIZE-1)) 34*1da177e4SLinus Torvalds printk(KERN_WARNING "EFS: WARNING: readdir(): directory size not a multiple of EFS_DIRBSIZE\n"); 35*1da177e4SLinus Torvalds 36*1da177e4SLinus Torvalds lock_kernel(); 37*1da177e4SLinus Torvalds 38*1da177e4SLinus Torvalds /* work out where this entry can be found */ 39*1da177e4SLinus Torvalds block = filp->f_pos >> EFS_DIRBSIZE_BITS; 40*1da177e4SLinus Torvalds 41*1da177e4SLinus Torvalds /* each block contains at most 256 slots */ 42*1da177e4SLinus Torvalds slot = filp->f_pos & 0xff; 43*1da177e4SLinus Torvalds 44*1da177e4SLinus Torvalds /* look at all blocks */ 45*1da177e4SLinus Torvalds while (block < inode->i_blocks) { 46*1da177e4SLinus Torvalds /* read the dir block */ 47*1da177e4SLinus Torvalds bh = sb_bread(inode->i_sb, efs_bmap(inode, block)); 48*1da177e4SLinus Torvalds 49*1da177e4SLinus Torvalds if (!bh) { 50*1da177e4SLinus Torvalds printk(KERN_ERR "EFS: readdir(): failed to read dir block %d\n", block); 51*1da177e4SLinus Torvalds break; 52*1da177e4SLinus Torvalds } 53*1da177e4SLinus Torvalds 54*1da177e4SLinus Torvalds dirblock = (struct efs_dir *) bh->b_data; 55*1da177e4SLinus Torvalds 56*1da177e4SLinus Torvalds if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) { 57*1da177e4SLinus Torvalds printk(KERN_ERR "EFS: readdir(): invalid directory block\n"); 58*1da177e4SLinus Torvalds brelse(bh); 59*1da177e4SLinus Torvalds break; 60*1da177e4SLinus Torvalds } 61*1da177e4SLinus Torvalds 62*1da177e4SLinus Torvalds while (slot < dirblock->slots) { 63*1da177e4SLinus Torvalds if (dirblock->space[slot] == 0) { 64*1da177e4SLinus Torvalds slot++; 65*1da177e4SLinus Torvalds continue; 66*1da177e4SLinus Torvalds } 67*1da177e4SLinus Torvalds 68*1da177e4SLinus Torvalds dirslot = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot)); 69*1da177e4SLinus Torvalds 70*1da177e4SLinus Torvalds inodenum = be32_to_cpu(dirslot->inode); 71*1da177e4SLinus Torvalds namelen = dirslot->namelen; 72*1da177e4SLinus Torvalds nameptr = dirslot->name; 73*1da177e4SLinus Torvalds 74*1da177e4SLinus Torvalds #ifdef DEBUG 75*1da177e4SLinus Torvalds printk(KERN_DEBUG "EFS: readdir(): block %d slot %d/%d: inode %u, name \"%s\", namelen %u\n", block, slot, dirblock->slots-1, inodenum, nameptr, namelen); 76*1da177e4SLinus Torvalds #endif 77*1da177e4SLinus Torvalds if (namelen > 0) { 78*1da177e4SLinus Torvalds /* found the next entry */ 79*1da177e4SLinus Torvalds filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot; 80*1da177e4SLinus Torvalds 81*1da177e4SLinus Torvalds /* copy filename and data in dirslot */ 82*1da177e4SLinus Torvalds filldir(dirent, nameptr, namelen, filp->f_pos, inodenum, DT_UNKNOWN); 83*1da177e4SLinus Torvalds 84*1da177e4SLinus Torvalds /* sanity check */ 85*1da177e4SLinus Torvalds if (nameptr - (char *) dirblock + namelen > EFS_DIRBSIZE) { 86*1da177e4SLinus Torvalds printk(KERN_WARNING "EFS: directory entry %d exceeds directory block\n", slot); 87*1da177e4SLinus Torvalds slot++; 88*1da177e4SLinus Torvalds continue; 89*1da177e4SLinus Torvalds } 90*1da177e4SLinus Torvalds 91*1da177e4SLinus Torvalds /* store position of next slot */ 92*1da177e4SLinus Torvalds if (++slot == dirblock->slots) { 93*1da177e4SLinus Torvalds slot = 0; 94*1da177e4SLinus Torvalds block++; 95*1da177e4SLinus Torvalds } 96*1da177e4SLinus Torvalds brelse(bh); 97*1da177e4SLinus Torvalds filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot; 98*1da177e4SLinus Torvalds goto out; 99*1da177e4SLinus Torvalds } 100*1da177e4SLinus Torvalds slot++; 101*1da177e4SLinus Torvalds } 102*1da177e4SLinus Torvalds brelse(bh); 103*1da177e4SLinus Torvalds 104*1da177e4SLinus Torvalds slot = 0; 105*1da177e4SLinus Torvalds block++; 106*1da177e4SLinus Torvalds } 107*1da177e4SLinus Torvalds 108*1da177e4SLinus Torvalds filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot; 109*1da177e4SLinus Torvalds out: 110*1da177e4SLinus Torvalds unlock_kernel(); 111*1da177e4SLinus Torvalds return 0; 112*1da177e4SLinus Torvalds } 113*1da177e4SLinus Torvalds 114