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
efs_readdir(struct file * file,struct dir_context * ctx)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