b24413180f560 (Greg Kroah-Hartman 2017-11-01 15:07:57 +0100 1) // SPDX-License-Identifier: GPL-2.0
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 3) * dir.c
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 4) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 5) * Copyright (c) 1999 Al Smith
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 6) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 7)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 8) #include <linux/buffer_head.h>
45254b4fb2aef (Christoph Hellwig 2008-02-23 15:23:51 -0800 9) #include "efs.h"
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 10)
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 11) static int efs_readdir(struct file *, struct dir_context *);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 12)
4b6f5d20b04dc (Arjan van de Ven 2006-03-28 01:56:42 -0800 13) const struct file_operations efs_dir_operations = {
e7ec952f6aa6a (Al Viro 2009-06-16 23:35:46 -0400 14) .llseek = generic_file_llseek,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 15) .read = generic_read_dir,
c51da20c48b76 (Al Viro 2016-04-30 22:37:34 -0400 16) .iterate_shared = efs_readdir,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 17) };
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 18)
754661f143e70 (Arjan van de Ven 2007-02-12 00:55:38 -0800 19) const struct inode_operations efs_dir_inode_operations = {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 20) .lookup = efs_lookup,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 21) };
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 22)
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 23) static int efs_readdir(struct file *file, struct dir_context *ctx)
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 24) {
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 25) struct inode *inode = file_inode(file);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 26) efs_block_t block;
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 27) int slot;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 28)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 29) if (inode->i_size & (EFS_DIRBSIZE-1))
f403d1dbac6d1 (Fabian Frederick 2014-06-04 16:12:12 -0700 30) pr_warn("%s(): directory size not a multiple of EFS_DIRBSIZE\n",
f403d1dbac6d1 (Fabian Frederick 2014-06-04 16:12:12 -0700 31) __func__);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 32)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 33) /* work out where this entry can be found */
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 34) block = ctx->pos >> EFS_DIRBSIZE_BITS;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 35)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 36) /* each block contains at most 256 slots */
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 37) slot = ctx->pos & 0xff;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 38)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 39) /* look at all blocks */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 40) while (block < inode->i_blocks) {
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 41) struct efs_dir *dirblock;
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 42) struct buffer_head *bh;
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 43)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 44) /* read the dir block */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 45) bh = sb_bread(inode->i_sb, efs_bmap(inode, block));
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 46)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 47) if (!bh) {
f403d1dbac6d1 (Fabian Frederick 2014-06-04 16:12:12 -0700 48) pr_err("%s(): failed to read dir block %d\n",
f403d1dbac6d1 (Fabian Frederick 2014-06-04 16:12:12 -0700 49) __func__, block);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 50) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 51) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 52)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 53) dirblock = (struct efs_dir *) bh->b_data;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 54)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 55) if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) {
f403d1dbac6d1 (Fabian Frederick 2014-06-04 16:12:12 -0700 56) pr_err("%s(): invalid directory block\n", __func__);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 57) brelse(bh);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 58) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 59) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 60)
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 61) for (; slot < dirblock->slots; slot++) {
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 62) struct efs_dentry *dirslot;
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 63) efs_ino_t inodenum;
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 64) const char *nameptr;
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 65) int namelen;
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 66)
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 67) if (dirblock->space[slot] == 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 68) continue;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 69)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 70) dirslot = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot));
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 71)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 72) inodenum = be32_to_cpu(dirslot->inode);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 73) namelen = dirslot->namelen;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 74) nameptr = dirslot->name;
d1826f2a3d64f (Fabian Frederick 2014-06-04 16:12:13 -0700 75) pr_debug("%s(): block %d slot %d/%d: inode %u, name \"%s\", namelen %u\n",
d1826f2a3d64f (Fabian Frederick 2014-06-04 16:12:13 -0700 76) __func__, block, slot, dirblock->slots-1,
d1826f2a3d64f (Fabian Frederick 2014-06-04 16:12:13 -0700 77) inodenum, nameptr, namelen);
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 78) if (!namelen)
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 79) continue;
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 80) /* found the next entry */
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 81) ctx->pos = (block << EFS_DIRBSIZE_BITS) | slot;
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 82)
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 83) /* sanity check */
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 84) if (nameptr - (char *) dirblock + namelen > EFS_DIRBSIZE) {
f403d1dbac6d1 (Fabian Frederick 2014-06-04 16:12:12 -0700 85) pr_warn("directory entry %d exceeds directory block\n",
f403d1dbac6d1 (Fabian Frederick 2014-06-04 16:12:12 -0700 86) slot);
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 87) continue;
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 88) }
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 89)
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 90) /* copy filename and data in dirslot */
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 91) if (!dir_emit(ctx, nameptr, namelen, inodenum, DT_UNKNOWN)) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 92) brelse(bh);
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 93) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 94) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 95) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 96) brelse(bh);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 97)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 98) slot = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 99) block++;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 100) }
7aa123a0dc3a8 (Al Viro 2013-05-16 01:41:10 -0400 101) ctx->pos = (block << EFS_DIRBSIZE_BITS) | slot;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 102) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 103) }