1*b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * dir.c 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (c) 1999 Al Smith 61da177e4SLinus Torvalds */ 71da177e4SLinus Torvalds 81da177e4SLinus Torvalds #include <linux/buffer_head.h> 945254b4fSChristoph Hellwig #include "efs.h" 101da177e4SLinus Torvalds 117aa123a0SAl Viro static int efs_readdir(struct file *, struct dir_context *); 121da177e4SLinus Torvalds 134b6f5d20SArjan van de Ven const struct file_operations efs_dir_operations = { 14e7ec952fSAl Viro .llseek = generic_file_llseek, 151da177e4SLinus Torvalds .read = generic_read_dir, 16c51da20cSAl Viro .iterate_shared = efs_readdir, 171da177e4SLinus Torvalds }; 181da177e4SLinus Torvalds 19754661f1SArjan van de Ven const struct inode_operations efs_dir_inode_operations = { 201da177e4SLinus Torvalds .lookup = efs_lookup, 211da177e4SLinus Torvalds }; 221da177e4SLinus Torvalds 237aa123a0SAl Viro static int efs_readdir(struct file *file, struct dir_context *ctx) 247aa123a0SAl Viro { 257aa123a0SAl Viro struct inode *inode = file_inode(file); 261da177e4SLinus Torvalds efs_block_t block; 277aa123a0SAl Viro int slot; 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds if (inode->i_size & (EFS_DIRBSIZE-1)) 30f403d1dbSFabian Frederick pr_warn("%s(): directory size not a multiple of EFS_DIRBSIZE\n", 31f403d1dbSFabian Frederick __func__); 321da177e4SLinus Torvalds 331da177e4SLinus Torvalds /* work out where this entry can be found */ 347aa123a0SAl Viro block = ctx->pos >> EFS_DIRBSIZE_BITS; 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds /* each block contains at most 256 slots */ 377aa123a0SAl Viro slot = ctx->pos & 0xff; 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds /* look at all blocks */ 401da177e4SLinus Torvalds while (block < inode->i_blocks) { 417aa123a0SAl Viro struct efs_dir *dirblock; 427aa123a0SAl Viro struct buffer_head *bh; 437aa123a0SAl Viro 441da177e4SLinus Torvalds /* read the dir block */ 451da177e4SLinus Torvalds bh = sb_bread(inode->i_sb, efs_bmap(inode, block)); 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds if (!bh) { 48f403d1dbSFabian Frederick pr_err("%s(): failed to read dir block %d\n", 49f403d1dbSFabian Frederick __func__, block); 501da177e4SLinus Torvalds break; 511da177e4SLinus Torvalds } 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds dirblock = (struct efs_dir *) bh->b_data; 541da177e4SLinus Torvalds 551da177e4SLinus Torvalds if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) { 56f403d1dbSFabian Frederick pr_err("%s(): invalid directory block\n", __func__); 571da177e4SLinus Torvalds brelse(bh); 581da177e4SLinus Torvalds break; 591da177e4SLinus Torvalds } 601da177e4SLinus Torvalds 617aa123a0SAl Viro for (; slot < dirblock->slots; slot++) { 627aa123a0SAl Viro struct efs_dentry *dirslot; 637aa123a0SAl Viro efs_ino_t inodenum; 647aa123a0SAl Viro const char *nameptr; 657aa123a0SAl Viro int namelen; 667aa123a0SAl Viro 677aa123a0SAl Viro if (dirblock->space[slot] == 0) 681da177e4SLinus Torvalds continue; 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds dirslot = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot)); 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds inodenum = be32_to_cpu(dirslot->inode); 731da177e4SLinus Torvalds namelen = dirslot->namelen; 741da177e4SLinus Torvalds nameptr = dirslot->name; 75d1826f2aSFabian Frederick pr_debug("%s(): block %d slot %d/%d: inode %u, name \"%s\", namelen %u\n", 76d1826f2aSFabian Frederick __func__, block, slot, dirblock->slots-1, 77d1826f2aSFabian Frederick inodenum, nameptr, namelen); 787aa123a0SAl Viro if (!namelen) 797aa123a0SAl Viro continue; 801da177e4SLinus Torvalds /* found the next entry */ 817aa123a0SAl Viro ctx->pos = (block << EFS_DIRBSIZE_BITS) | slot; 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds /* sanity check */ 841da177e4SLinus Torvalds if (nameptr - (char *) dirblock + namelen > EFS_DIRBSIZE) { 85f403d1dbSFabian Frederick pr_warn("directory entry %d exceeds directory block\n", 86f403d1dbSFabian Frederick slot); 871da177e4SLinus Torvalds continue; 881da177e4SLinus Torvalds } 891da177e4SLinus Torvalds 907aa123a0SAl Viro /* copy filename and data in dirslot */ 917aa123a0SAl Viro if (!dir_emit(ctx, nameptr, namelen, inodenum, DT_UNKNOWN)) { 921da177e4SLinus Torvalds brelse(bh); 937aa123a0SAl Viro return 0; 941da177e4SLinus Torvalds } 951da177e4SLinus Torvalds } 961da177e4SLinus Torvalds brelse(bh); 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds slot = 0; 991da177e4SLinus Torvalds block++; 1001da177e4SLinus Torvalds } 1017aa123a0SAl Viro ctx->pos = (block << EFS_DIRBSIZE_BITS) | slot; 1021da177e4SLinus Torvalds return 0; 1031da177e4SLinus Torvalds } 104