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 10*7aa123a0SAl Viro static int efs_readdir(struct file *, struct dir_context *); 111da177e4SLinus Torvalds 124b6f5d20SArjan van de Ven const struct file_operations efs_dir_operations = { 13e7ec952fSAl Viro .llseek = generic_file_llseek, 141da177e4SLinus Torvalds .read = generic_read_dir, 15*7aa123a0SAl Viro .iterate = 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 22*7aa123a0SAl Viro static int efs_readdir(struct file *file, struct dir_context *ctx) 23*7aa123a0SAl Viro { 24*7aa123a0SAl Viro struct inode *inode = file_inode(file); 251da177e4SLinus Torvalds efs_block_t block; 26*7aa123a0SAl Viro int slot; 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds if (inode->i_size & (EFS_DIRBSIZE-1)) 291da177e4SLinus Torvalds printk(KERN_WARNING "EFS: WARNING: readdir(): directory size not a multiple of EFS_DIRBSIZE\n"); 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds /* work out where this entry can be found */ 32*7aa123a0SAl Viro block = ctx->pos >> EFS_DIRBSIZE_BITS; 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds /* each block contains at most 256 slots */ 35*7aa123a0SAl Viro slot = ctx->pos & 0xff; 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds /* look at all blocks */ 381da177e4SLinus Torvalds while (block < inode->i_blocks) { 39*7aa123a0SAl Viro struct efs_dir *dirblock; 40*7aa123a0SAl Viro struct buffer_head *bh; 41*7aa123a0SAl Viro 421da177e4SLinus Torvalds /* read the dir block */ 431da177e4SLinus Torvalds bh = sb_bread(inode->i_sb, efs_bmap(inode, block)); 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds if (!bh) { 461da177e4SLinus Torvalds printk(KERN_ERR "EFS: readdir(): failed to read dir block %d\n", block); 471da177e4SLinus Torvalds break; 481da177e4SLinus Torvalds } 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds dirblock = (struct efs_dir *) bh->b_data; 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) { 531da177e4SLinus Torvalds printk(KERN_ERR "EFS: readdir(): invalid directory block\n"); 541da177e4SLinus Torvalds brelse(bh); 551da177e4SLinus Torvalds break; 561da177e4SLinus Torvalds } 571da177e4SLinus Torvalds 58*7aa123a0SAl Viro for (; slot < dirblock->slots; slot++) { 59*7aa123a0SAl Viro struct efs_dentry *dirslot; 60*7aa123a0SAl Viro efs_ino_t inodenum; 61*7aa123a0SAl Viro const char *nameptr; 62*7aa123a0SAl Viro int namelen; 63*7aa123a0SAl Viro 64*7aa123a0SAl Viro if (dirblock->space[slot] == 0) 651da177e4SLinus Torvalds continue; 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds dirslot = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot)); 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds inodenum = be32_to_cpu(dirslot->inode); 701da177e4SLinus Torvalds namelen = dirslot->namelen; 711da177e4SLinus Torvalds nameptr = dirslot->name; 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds #ifdef DEBUG 741da177e4SLinus 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); 751da177e4SLinus Torvalds #endif 76*7aa123a0SAl Viro if (!namelen) 77*7aa123a0SAl Viro continue; 781da177e4SLinus Torvalds /* found the next entry */ 79*7aa123a0SAl Viro ctx->pos = (block << EFS_DIRBSIZE_BITS) | slot; 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds /* sanity check */ 821da177e4SLinus Torvalds if (nameptr - (char *) dirblock + namelen > EFS_DIRBSIZE) { 831da177e4SLinus Torvalds printk(KERN_WARNING "EFS: directory entry %d exceeds directory block\n", slot); 841da177e4SLinus Torvalds continue; 851da177e4SLinus Torvalds } 861da177e4SLinus Torvalds 87*7aa123a0SAl Viro /* copy filename and data in dirslot */ 88*7aa123a0SAl Viro if (!dir_emit(ctx, nameptr, namelen, inodenum, DT_UNKNOWN)) { 891da177e4SLinus Torvalds brelse(bh); 90*7aa123a0SAl Viro return 0; 911da177e4SLinus Torvalds } 921da177e4SLinus Torvalds } 931da177e4SLinus Torvalds brelse(bh); 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds slot = 0; 961da177e4SLinus Torvalds block++; 971da177e4SLinus Torvalds } 98*7aa123a0SAl Viro ctx->pos = (block << EFS_DIRBSIZE_BITS) | slot; 991da177e4SLinus Torvalds return 0; 1001da177e4SLinus Torvalds } 1011da177e4SLinus Torvalds 102