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> 845254b4fSChristoph Hellwig #include "efs.h" 91da177e4SLinus Torvalds 101da177e4SLinus Torvalds static int efs_readdir(struct file *, void *, filldir_t); 111da177e4SLinus Torvalds 124b6f5d20SArjan van de Ven const struct file_operations efs_dir_operations = { 13*e7ec952fSAl Viro .llseek = generic_file_llseek, 141da177e4SLinus Torvalds .read = generic_read_dir, 151da177e4SLinus Torvalds .readdir = efs_readdir, 161da177e4SLinus Torvalds }; 171da177e4SLinus Torvalds 18754661f1SArjan van de Ven const 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) { 230191f205SJosef 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 /* work out where this entry can be found */ 371da177e4SLinus Torvalds block = filp->f_pos >> EFS_DIRBSIZE_BITS; 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds /* each block contains at most 256 slots */ 401da177e4SLinus Torvalds slot = filp->f_pos & 0xff; 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds /* look at all blocks */ 431da177e4SLinus Torvalds while (block < inode->i_blocks) { 441da177e4SLinus Torvalds /* read the dir block */ 451da177e4SLinus Torvalds bh = sb_bread(inode->i_sb, efs_bmap(inode, block)); 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds if (!bh) { 481da177e4SLinus Torvalds printk(KERN_ERR "EFS: readdir(): failed to read dir block %d\n", block); 491da177e4SLinus Torvalds break; 501da177e4SLinus Torvalds } 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds dirblock = (struct efs_dir *) bh->b_data; 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) { 551da177e4SLinus Torvalds printk(KERN_ERR "EFS: readdir(): invalid directory block\n"); 561da177e4SLinus Torvalds brelse(bh); 571da177e4SLinus Torvalds break; 581da177e4SLinus Torvalds } 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds while (slot < dirblock->slots) { 611da177e4SLinus Torvalds if (dirblock->space[slot] == 0) { 621da177e4SLinus Torvalds slot++; 631da177e4SLinus Torvalds continue; 641da177e4SLinus Torvalds } 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds dirslot = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot)); 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds inodenum = be32_to_cpu(dirslot->inode); 691da177e4SLinus Torvalds namelen = dirslot->namelen; 701da177e4SLinus Torvalds nameptr = dirslot->name; 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds #ifdef DEBUG 731da177e4SLinus 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); 741da177e4SLinus Torvalds #endif 751da177e4SLinus Torvalds if (namelen > 0) { 761da177e4SLinus Torvalds /* found the next entry */ 771da177e4SLinus Torvalds filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot; 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds /* copy filename and data in dirslot */ 801da177e4SLinus Torvalds filldir(dirent, nameptr, namelen, filp->f_pos, inodenum, DT_UNKNOWN); 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds /* sanity check */ 831da177e4SLinus Torvalds if (nameptr - (char *) dirblock + namelen > EFS_DIRBSIZE) { 841da177e4SLinus Torvalds printk(KERN_WARNING "EFS: directory entry %d exceeds directory block\n", slot); 851da177e4SLinus Torvalds slot++; 861da177e4SLinus Torvalds continue; 871da177e4SLinus Torvalds } 881da177e4SLinus Torvalds 891da177e4SLinus Torvalds /* store position of next slot */ 901da177e4SLinus Torvalds if (++slot == dirblock->slots) { 911da177e4SLinus Torvalds slot = 0; 921da177e4SLinus Torvalds block++; 931da177e4SLinus Torvalds } 941da177e4SLinus Torvalds brelse(bh); 951da177e4SLinus Torvalds filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot; 961da177e4SLinus Torvalds goto out; 971da177e4SLinus Torvalds } 981da177e4SLinus Torvalds slot++; 991da177e4SLinus Torvalds } 1001da177e4SLinus Torvalds brelse(bh); 1011da177e4SLinus Torvalds 1021da177e4SLinus Torvalds slot = 0; 1031da177e4SLinus Torvalds block++; 1041da177e4SLinus Torvalds } 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot; 1071da177e4SLinus Torvalds out: 1081da177e4SLinus Torvalds return 0; 1091da177e4SLinus Torvalds } 1101da177e4SLinus Torvalds 111