11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * dir.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (c) 1999 Al Smith 51da177e4SLinus Torvalds */ 61da177e4SLinus Torvalds 71da177e4SLinus Torvalds #include <linux/buffer_head.h> 81da177e4SLinus Torvalds #include <linux/efs_fs.h> 91da177e4SLinus Torvalds #include <linux/smp_lock.h> 101da177e4SLinus Torvalds 111da177e4SLinus Torvalds static int efs_readdir(struct file *, void *, filldir_t); 121da177e4SLinus Torvalds 134b6f5d20SArjan van de Ven const struct file_operations efs_dir_operations = { 141da177e4SLinus Torvalds .read = generic_read_dir, 151da177e4SLinus Torvalds .readdir = efs_readdir, 161da177e4SLinus Torvalds }; 171da177e4SLinus Torvalds 181da177e4SLinus Torvalds struct inode_operations efs_dir_inode_operations = { 191da177e4SLinus Torvalds .lookup = efs_lookup, 201da177e4SLinus Torvalds }; 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) { 23*0191f205SJosef Sipek struct inode *inode = filp->f_path.dentry->d_inode; 241da177e4SLinus Torvalds struct buffer_head *bh; 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds struct efs_dir *dirblock; 271da177e4SLinus Torvalds struct efs_dentry *dirslot; 281da177e4SLinus Torvalds efs_ino_t inodenum; 291da177e4SLinus Torvalds efs_block_t block; 301da177e4SLinus Torvalds int slot, namelen; 311da177e4SLinus Torvalds char *nameptr; 321da177e4SLinus Torvalds 331da177e4SLinus Torvalds if (inode->i_size & (EFS_DIRBSIZE-1)) 341da177e4SLinus Torvalds printk(KERN_WARNING "EFS: WARNING: readdir(): directory size not a multiple of EFS_DIRBSIZE\n"); 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds lock_kernel(); 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds /* work out where this entry can be found */ 391da177e4SLinus Torvalds block = filp->f_pos >> EFS_DIRBSIZE_BITS; 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds /* each block contains at most 256 slots */ 421da177e4SLinus Torvalds slot = filp->f_pos & 0xff; 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds /* look at all blocks */ 451da177e4SLinus Torvalds while (block < inode->i_blocks) { 461da177e4SLinus Torvalds /* read the dir block */ 471da177e4SLinus Torvalds bh = sb_bread(inode->i_sb, efs_bmap(inode, block)); 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds if (!bh) { 501da177e4SLinus Torvalds printk(KERN_ERR "EFS: readdir(): failed to read dir block %d\n", block); 511da177e4SLinus Torvalds break; 521da177e4SLinus Torvalds } 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds dirblock = (struct efs_dir *) bh->b_data; 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) { 571da177e4SLinus Torvalds printk(KERN_ERR "EFS: readdir(): invalid directory block\n"); 581da177e4SLinus Torvalds brelse(bh); 591da177e4SLinus Torvalds break; 601da177e4SLinus Torvalds } 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds while (slot < dirblock->slots) { 631da177e4SLinus Torvalds if (dirblock->space[slot] == 0) { 641da177e4SLinus Torvalds slot++; 651da177e4SLinus Torvalds continue; 661da177e4SLinus Torvalds } 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds dirslot = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot)); 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds inodenum = be32_to_cpu(dirslot->inode); 711da177e4SLinus Torvalds namelen = dirslot->namelen; 721da177e4SLinus Torvalds nameptr = dirslot->name; 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds #ifdef DEBUG 751da177e4SLinus 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); 761da177e4SLinus Torvalds #endif 771da177e4SLinus Torvalds if (namelen > 0) { 781da177e4SLinus Torvalds /* found the next entry */ 791da177e4SLinus Torvalds filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot; 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds /* copy filename and data in dirslot */ 821da177e4SLinus Torvalds filldir(dirent, nameptr, namelen, filp->f_pos, inodenum, DT_UNKNOWN); 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds /* sanity check */ 851da177e4SLinus Torvalds if (nameptr - (char *) dirblock + namelen > EFS_DIRBSIZE) { 861da177e4SLinus Torvalds printk(KERN_WARNING "EFS: directory entry %d exceeds directory block\n", slot); 871da177e4SLinus Torvalds slot++; 881da177e4SLinus Torvalds continue; 891da177e4SLinus Torvalds } 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds /* store position of next slot */ 921da177e4SLinus Torvalds if (++slot == dirblock->slots) { 931da177e4SLinus Torvalds slot = 0; 941da177e4SLinus Torvalds block++; 951da177e4SLinus Torvalds } 961da177e4SLinus Torvalds brelse(bh); 971da177e4SLinus Torvalds filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot; 981da177e4SLinus Torvalds goto out; 991da177e4SLinus Torvalds } 1001da177e4SLinus Torvalds slot++; 1011da177e4SLinus Torvalds } 1021da177e4SLinus Torvalds brelse(bh); 1031da177e4SLinus Torvalds 1041da177e4SLinus Torvalds slot = 0; 1051da177e4SLinus Torvalds block++; 1061da177e4SLinus Torvalds } 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot; 1091da177e4SLinus Torvalds out: 1101da177e4SLinus Torvalds unlock_kernel(); 1111da177e4SLinus Torvalds return 0; 1121da177e4SLinus Torvalds } 1131da177e4SLinus Torvalds 114