1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2017-2018 HUAWEI, Inc.
4 * https://www.huawei.com/
5 * Copyright (C) 2022, Alibaba Cloud
9 static int erofs_fill_dentries(struct inode
*dir
, struct dir_context
*ctx
,
10 void *dentry_blk
, struct erofs_dirent
*de
,
11 unsigned int nameoff0
, unsigned int maxsize
)
13 const struct erofs_dirent
*end
= dentry_blk
+ nameoff0
;
16 unsigned char d_type
= fs_ftype_to_dtype(de
->file_type
);
17 unsigned int nameoff
= le16_to_cpu(de
->nameoff
);
18 const char *de_name
= (char *)dentry_blk
+ nameoff
;
19 unsigned int de_namelen
;
21 /* the last dirent in the block? */
23 de_namelen
= strnlen(de_name
, maxsize
- nameoff
);
25 de_namelen
= le16_to_cpu(de
[1].nameoff
) - nameoff
;
27 /* a corrupted entry is found */
28 if (nameoff
+ de_namelen
> maxsize
||
29 de_namelen
> EROFS_NAME_LEN
) {
30 erofs_err(dir
->i_sb
, "bogus dirent @ nid %llu",
36 if (!dir_emit(ctx
, de_name
, de_namelen
,
37 le64_to_cpu(de
->nid
), d_type
))
40 ctx
->pos
+= sizeof(struct erofs_dirent
);
45 static int erofs_readdir(struct file
*f
, struct dir_context
*ctx
)
47 struct inode
*dir
= file_inode(f
);
48 struct erofs_buf buf
= __EROFS_BUF_INITIALIZER
;
49 struct super_block
*sb
= dir
->i_sb
;
50 unsigned long bsz
= sb
->s_blocksize
;
51 unsigned int ofs
= erofs_blkoff(sb
, ctx
->pos
);
55 buf
.mapping
= dir
->i_mapping
;
56 while (ctx
->pos
< dir
->i_size
) {
57 erofs_off_t dbstart
= ctx
->pos
- ofs
;
58 struct erofs_dirent
*de
;
59 unsigned int nameoff
, maxsize
;
61 de
= erofs_bread(&buf
, dbstart
, EROFS_KMAP
);
63 erofs_err(sb
, "fail to readdir of logical block %u of nid %llu",
64 erofs_blknr(sb
, dbstart
), EROFS_I(dir
)->nid
);
69 nameoff
= le16_to_cpu(de
->nameoff
);
70 if (nameoff
< sizeof(struct erofs_dirent
) || nameoff
>= bsz
) {
71 erofs_err(sb
, "invalid de[0].nameoff %u @ nid %llu",
72 nameoff
, EROFS_I(dir
)->nid
);
77 maxsize
= min_t(unsigned int, dir
->i_size
- dbstart
, bsz
);
78 /* search dirents at the arbitrary position */
81 ofs
= roundup(ofs
, sizeof(struct erofs_dirent
));
82 ctx
->pos
= dbstart
+ ofs
;
85 err
= erofs_fill_dentries(dir
, ctx
, de
, (void *)de
+ ofs
,
89 ctx
->pos
= dbstart
+ maxsize
;
92 erofs_put_metabuf(&buf
);
93 return err
< 0 ? err
: 0;
96 const struct file_operations erofs_dir_fops
= {
97 .llseek
= generic_file_llseek
,
98 .read
= generic_read_dir
,
99 .iterate_shared
= erofs_readdir
,