Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/fs/efs/dir.c
26288 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* dir.c
4
*
5
* Copyright (c) 1999 Al Smith
6
*/
7
8
#include <linux/buffer_head.h>
9
#include "efs.h"
10
11
static int efs_readdir(struct file *, struct dir_context *);
12
13
const struct file_operations efs_dir_operations = {
14
.llseek = generic_file_llseek,
15
.read = generic_read_dir,
16
.iterate_shared = efs_readdir,
17
};
18
19
const struct inode_operations efs_dir_inode_operations = {
20
.lookup = efs_lookup,
21
};
22
23
static int efs_readdir(struct file *file, struct dir_context *ctx)
24
{
25
struct inode *inode = file_inode(file);
26
efs_block_t block;
27
int slot;
28
29
if (inode->i_size & (EFS_DIRBSIZE-1))
30
pr_warn("%s(): directory size not a multiple of EFS_DIRBSIZE\n",
31
__func__);
32
33
/* work out where this entry can be found */
34
block = ctx->pos >> EFS_DIRBSIZE_BITS;
35
36
/* each block contains at most 256 slots */
37
slot = ctx->pos & 0xff;
38
39
/* look at all blocks */
40
while (block < inode->i_blocks) {
41
struct efs_dir *dirblock;
42
struct buffer_head *bh;
43
44
/* read the dir block */
45
bh = sb_bread(inode->i_sb, efs_bmap(inode, block));
46
47
if (!bh) {
48
pr_err("%s(): failed to read dir block %d\n",
49
__func__, block);
50
break;
51
}
52
53
dirblock = (struct efs_dir *) bh->b_data;
54
55
if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) {
56
pr_err("%s(): invalid directory block\n", __func__);
57
brelse(bh);
58
break;
59
}
60
61
for (; slot < dirblock->slots; slot++) {
62
struct efs_dentry *dirslot;
63
efs_ino_t inodenum;
64
const char *nameptr;
65
int namelen;
66
67
if (dirblock->space[slot] == 0)
68
continue;
69
70
dirslot = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot));
71
72
inodenum = be32_to_cpu(dirslot->inode);
73
namelen = dirslot->namelen;
74
nameptr = dirslot->name;
75
pr_debug("%s(): block %d slot %d/%d: inode %u, name \"%s\", namelen %u\n",
76
__func__, block, slot, dirblock->slots-1,
77
inodenum, nameptr, namelen);
78
if (!namelen)
79
continue;
80
/* found the next entry */
81
ctx->pos = (block << EFS_DIRBSIZE_BITS) | slot;
82
83
/* sanity check */
84
if (nameptr - (char *) dirblock + namelen > EFS_DIRBSIZE) {
85
pr_warn("directory entry %d exceeds directory block\n",
86
slot);
87
continue;
88
}
89
90
/* copy filename and data in dirslot */
91
if (!dir_emit(ctx, nameptr, namelen, inodenum, DT_UNKNOWN)) {
92
brelse(bh);
93
return 0;
94
}
95
}
96
brelse(bh);
97
98
slot = 0;
99
block++;
100
}
101
ctx->pos = (block << EFS_DIRBSIZE_BITS) | slot;
102
return 0;
103
}
104
105