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 107aa123a0SAl 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, 157aa123a0SAl 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 227aa123a0SAl Viro static int efs_readdir(struct file *file, struct dir_context *ctx) 237aa123a0SAl Viro { 247aa123a0SAl Viro struct inode *inode = file_inode(file); 251da177e4SLinus Torvalds efs_block_t block; 267aa123a0SAl Viro int slot; 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds if (inode->i_size & (EFS_DIRBSIZE-1)) 29f403d1dbSFabian Frederick pr_warn("%s(): directory size not a multiple of EFS_DIRBSIZE\n", 30f403d1dbSFabian Frederick __func__); 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds /* work out where this entry can be found */ 337aa123a0SAl Viro block = ctx->pos >> EFS_DIRBSIZE_BITS; 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds /* each block contains at most 256 slots */ 367aa123a0SAl Viro slot = ctx->pos & 0xff; 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds /* look at all blocks */ 391da177e4SLinus Torvalds while (block < inode->i_blocks) { 407aa123a0SAl Viro struct efs_dir *dirblock; 417aa123a0SAl Viro struct buffer_head *bh; 427aa123a0SAl Viro 431da177e4SLinus Torvalds /* read the dir block */ 441da177e4SLinus Torvalds bh = sb_bread(inode->i_sb, efs_bmap(inode, block)); 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds if (!bh) { 47f403d1dbSFabian Frederick pr_err("%s(): failed to read dir block %d\n", 48f403d1dbSFabian Frederick __func__, 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) { 55f403d1dbSFabian Frederick pr_err("%s(): invalid directory block\n", __func__); 561da177e4SLinus Torvalds brelse(bh); 571da177e4SLinus Torvalds break; 581da177e4SLinus Torvalds } 591da177e4SLinus Torvalds 607aa123a0SAl Viro for (; slot < dirblock->slots; slot++) { 617aa123a0SAl Viro struct efs_dentry *dirslot; 627aa123a0SAl Viro efs_ino_t inodenum; 637aa123a0SAl Viro const char *nameptr; 647aa123a0SAl Viro int namelen; 657aa123a0SAl Viro 667aa123a0SAl Viro if (dirblock->space[slot] == 0) 671da177e4SLinus Torvalds continue; 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds dirslot = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot)); 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds inodenum = be32_to_cpu(dirslot->inode); 721da177e4SLinus Torvalds namelen = dirslot->namelen; 731da177e4SLinus Torvalds nameptr = dirslot->name; 74*d1826f2aSFabian Frederick pr_debug("%s(): block %d slot %d/%d: inode %u, name \"%s\", namelen %u\n", 75*d1826f2aSFabian Frederick __func__, block, slot, dirblock->slots-1, 76*d1826f2aSFabian Frederick inodenum, nameptr, namelen); 777aa123a0SAl Viro if (!namelen) 787aa123a0SAl Viro continue; 791da177e4SLinus Torvalds /* found the next entry */ 807aa123a0SAl Viro ctx->pos = (block << EFS_DIRBSIZE_BITS) | slot; 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds /* sanity check */ 831da177e4SLinus Torvalds if (nameptr - (char *) dirblock + namelen > EFS_DIRBSIZE) { 84f403d1dbSFabian Frederick pr_warn("directory entry %d exceeds directory block\n", 85f403d1dbSFabian Frederick slot); 861da177e4SLinus Torvalds continue; 871da177e4SLinus Torvalds } 881da177e4SLinus Torvalds 897aa123a0SAl Viro /* copy filename and data in dirslot */ 907aa123a0SAl Viro if (!dir_emit(ctx, nameptr, namelen, inodenum, DT_UNKNOWN)) { 911da177e4SLinus Torvalds brelse(bh); 927aa123a0SAl Viro return 0; 931da177e4SLinus Torvalds } 941da177e4SLinus Torvalds } 951da177e4SLinus Torvalds brelse(bh); 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds slot = 0; 981da177e4SLinus Torvalds block++; 991da177e4SLinus Torvalds } 1007aa123a0SAl Viro ctx->pos = (block << EFS_DIRBSIZE_BITS) | slot; 1011da177e4SLinus Torvalds return 0; 1021da177e4SLinus Torvalds } 1031da177e4SLinus Torvalds 104