]> Git Repo - linux.git/blob - fs/erofs/dir.c
ravb: Remove setting of RX software timestamp
[linux.git] / fs / erofs / dir.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2017-2018 HUAWEI, Inc.
4  *             https://www.huawei.com/
5  * Copyright (C) 2022, Alibaba Cloud
6  */
7 #include "internal.h"
8
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)
12 {
13         const struct erofs_dirent *end = dentry_blk + nameoff0;
14
15         while (de < end) {
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;
20
21                 /* the last dirent in the block? */
22                 if (de + 1 >= end)
23                         de_namelen = strnlen(de_name, maxsize - nameoff);
24                 else
25                         de_namelen = le16_to_cpu(de[1].nameoff) - nameoff;
26
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",
31                                   EROFS_I(dir)->nid);
32                         DBG_BUGON(1);
33                         return -EFSCORRUPTED;
34                 }
35
36                 if (!dir_emit(ctx, de_name, de_namelen,
37                               le64_to_cpu(de->nid), d_type))
38                         return 1;
39                 ++de;
40                 ctx->pos += sizeof(struct erofs_dirent);
41         }
42         return 0;
43 }
44
45 static int erofs_readdir(struct file *f, struct dir_context *ctx)
46 {
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);
52         int err = 0;
53         bool initial = true;
54
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;
60
61                 de = erofs_bread(&buf, dbstart, EROFS_KMAP);
62                 if (IS_ERR(de)) {
63                         erofs_err(sb, "fail to readdir of logical block %u of nid %llu",
64                                   erofs_blknr(sb, dbstart), EROFS_I(dir)->nid);
65                         err = PTR_ERR(de);
66                         break;
67                 }
68
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);
73                         err = -EFSCORRUPTED;
74                         break;
75                 }
76
77                 maxsize = min_t(unsigned int, dir->i_size - dbstart, bsz);
78                 /* search dirents at the arbitrary position */
79                 if (initial) {
80                         initial = false;
81                         ofs = roundup(ofs, sizeof(struct erofs_dirent));
82                         ctx->pos = dbstart + ofs;
83                 }
84
85                 err = erofs_fill_dentries(dir, ctx, de, (void *)de + ofs,
86                                           nameoff, maxsize);
87                 if (err)
88                         break;
89                 ctx->pos = dbstart + maxsize;
90                 ofs = 0;
91         }
92         erofs_put_metabuf(&buf);
93         return err < 0 ? err : 0;
94 }
95
96 const struct file_operations erofs_dir_fops = {
97         .llseek         = generic_file_llseek,
98         .read           = generic_read_dir,
99         .iterate_shared = erofs_readdir,
100 };
This page took 0.037253 seconds and 4 git commands to generate.