1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2017-2018 HUAWEI, Inc.
4 * https://www.huawei.com/
8 static void debug_one_dentry(unsigned char d_type
, const char *de_name
,
9 unsigned int de_namelen
)
11 #ifdef CONFIG_EROFS_FS_DEBUG
12 /* since the on-disk name could not have the trailing '\0' */
13 unsigned char dbg_namebuf
[EROFS_NAME_LEN
+ 1];
15 memcpy(dbg_namebuf
, de_name
, de_namelen
);
16 dbg_namebuf
[de_namelen
] = '\0';
18 erofs_dbg("found dirent %s de_len %u d_type %d", dbg_namebuf
,
23 static int erofs_fill_dentries(struct inode
*dir
, struct dir_context
*ctx
,
24 void *dentry_blk
, unsigned int *ofs
,
25 unsigned int nameoff
, unsigned int maxsize
)
27 struct erofs_dirent
*de
= dentry_blk
+ *ofs
;
28 const struct erofs_dirent
*end
= dentry_blk
+ nameoff
;
32 unsigned int de_namelen
;
35 d_type
= fs_ftype_to_dtype(de
->file_type
);
37 nameoff
= le16_to_cpu(de
->nameoff
);
38 de_name
= (char *)dentry_blk
+ nameoff
;
40 /* the last dirent in the block? */
42 de_namelen
= strnlen(de_name
, maxsize
- nameoff
);
44 de_namelen
= le16_to_cpu(de
[1].nameoff
) - nameoff
;
46 /* a corrupted entry is found */
47 if (nameoff
+ de_namelen
> maxsize
||
48 de_namelen
> EROFS_NAME_LEN
) {
49 erofs_err(dir
->i_sb
, "bogus dirent @ nid %llu",
55 debug_one_dentry(d_type
, de_name
, de_namelen
);
56 if (!dir_emit(ctx
, de_name
, de_namelen
,
57 le64_to_cpu(de
->nid
), d_type
))
58 /* stopped by some reason */
61 *ofs
+= sizeof(struct erofs_dirent
);
67 static int erofs_readdir(struct file
*f
, struct dir_context
*ctx
)
69 struct inode
*dir
= file_inode(f
);
70 struct address_space
*mapping
= dir
->i_mapping
;
71 const size_t dirsize
= i_size_read(dir
);
72 unsigned int i
= ctx
->pos
/ EROFS_BLKSIZ
;
73 unsigned int ofs
= ctx
->pos
% EROFS_BLKSIZ
;
77 while (ctx
->pos
< dirsize
) {
78 struct page
*dentry_page
;
79 struct erofs_dirent
*de
;
80 unsigned int nameoff
, maxsize
;
82 dentry_page
= read_mapping_page(mapping
, i
, NULL
);
83 if (dentry_page
== ERR_PTR(-ENOMEM
)) {
86 } else if (IS_ERR(dentry_page
)) {
88 "fail to readdir of logical block %u of nid %llu",
89 i
, EROFS_I(dir
)->nid
);
94 de
= (struct erofs_dirent
*)kmap(dentry_page
);
96 nameoff
= le16_to_cpu(de
->nameoff
);
98 if (nameoff
< sizeof(struct erofs_dirent
) ||
99 nameoff
>= PAGE_SIZE
) {
101 "invalid de[0].nameoff %u @ nid %llu",
102 nameoff
, EROFS_I(dir
)->nid
);
107 maxsize
= min_t(unsigned int,
108 dirsize
- ctx
->pos
+ ofs
, PAGE_SIZE
);
110 /* search dirents at the arbitrary position */
114 ofs
= roundup(ofs
, sizeof(struct erofs_dirent
));
119 err
= erofs_fill_dentries(dir
, ctx
, de
, &ofs
,
124 put_page(dentry_page
);
126 ctx
->pos
= blknr_to_addr(i
) + ofs
;
133 return err
< 0 ? err
: 0;
136 const struct file_operations erofs_dir_fops
= {
137 .llseek
= generic_file_llseek
,
138 .read
= generic_read_dir
,
139 .iterate_shared
= erofs_readdir
,