1 // SPDX-License-Identifier: GPL-2.0+
3 #include <fs_internal.h>
5 struct erofs_sb_info sbi;
7 static struct erofs_ctxt {
8 struct disk_partition cur_part_info;
9 struct blk_desc *cur_dev;
12 int erofs_dev_read(int device_id, void *buf, u64 offset, size_t len)
14 lbaint_t sect = offset >> ctxt.cur_dev->log2blksz;
15 int off = offset & (ctxt.cur_dev->blksz - 1);
20 if (fs_devread(ctxt.cur_dev, &ctxt.cur_part_info, sect,
26 int erofs_blk_read(void *buf, erofs_blk_t start, u32 nblocks)
28 return erofs_dev_read(0, buf, blknr_to_addr(start),
29 blknr_to_addr(nblocks));
32 int erofs_probe(struct blk_desc *fs_dev_desc,
33 struct disk_partition *fs_partition)
37 ctxt.cur_dev = fs_dev_desc;
38 ctxt.cur_part_info = *fs_partition;
40 ret = erofs_read_superblock();
50 struct erofs_dir_stream {
51 struct fs_dir_stream fs_dirs;
52 struct fs_dirent dirent;
54 struct erofs_inode inode;
55 char dblk[EROFS_BLKSIZ];
56 unsigned int maxsize, de_end;
60 static int erofs_readlink(struct erofs_inode *vi)
62 size_t len = vi->i_size;
66 target = malloc(len + 1);
71 err = erofs_pread(vi, target, len, 0);
75 err = erofs_ilookup(target, vi);
84 int erofs_opendir(const char *filename, struct fs_dir_stream **dirsp)
86 struct erofs_dir_stream *dirs;
89 dirs = calloc(1, sizeof(*dirs));
93 err = erofs_ilookup(filename, &dirs->inode);
97 if (S_ISLNK(dirs->inode.i_mode)) {
98 err = erofs_readlink(&dirs->inode);
103 if (!S_ISDIR(dirs->inode.i_mode)) {
107 *dirsp = (struct fs_dir_stream *)dirs;
114 int erofs_readdir(struct fs_dir_stream *fs_dirs, struct fs_dirent **dentp)
116 struct erofs_dir_stream *dirs = (struct erofs_dir_stream *)fs_dirs;
117 struct fs_dirent *dent = &dirs->dirent;
118 erofs_off_t pos = dirs->pos;
119 unsigned int nameoff, de_namelen;
120 struct erofs_dirent *de;
124 if (pos >= dirs->inode.i_size)
127 if (!dirs->maxsize) {
128 dirs->maxsize = min_t(unsigned int, EROFS_BLKSIZ,
129 dirs->inode.i_size - pos);
131 err = erofs_pread(&dirs->inode, dirs->dblk,
136 de = (struct erofs_dirent *)dirs->dblk;
137 dirs->de_end = le16_to_cpu(de->nameoff);
138 if (dirs->de_end < sizeof(struct erofs_dirent) ||
139 dirs->de_end >= EROFS_BLKSIZ) {
140 erofs_err("invalid de[0].nameoff %u @ nid %llu",
141 dirs->de_end, de->nid | 0ULL);
142 return -EFSCORRUPTED;
146 de = (struct erofs_dirent *)(dirs->dblk + erofs_blkoff(pos));
147 nameoff = le16_to_cpu(de->nameoff);
148 de_name = (char *)dirs->dblk + nameoff;
150 /* the last dirent in the block? */
151 if (de + 1 >= (struct erofs_dirent *)(dirs->dblk + dirs->de_end))
152 de_namelen = strnlen(de_name, dirs->maxsize - nameoff);
154 de_namelen = le16_to_cpu(de[1].nameoff) - nameoff;
156 /* a corrupted entry is found */
157 if (nameoff + de_namelen > dirs->maxsize ||
158 de_namelen > EROFS_NAME_LEN) {
159 erofs_err("bogus dirent @ nid %llu", de->nid | 0ULL);
161 return -EFSCORRUPTED;
164 memcpy(dent->name, de_name, de_namelen);
165 dent->name[de_namelen] = '\0';
167 if (de->file_type == EROFS_FT_DIR) {
168 dent->type = FS_DT_DIR;
169 } else if (de->file_type == EROFS_FT_SYMLINK) {
170 dent->type = FS_DT_LNK;
172 struct erofs_inode vi;
174 dent->type = FS_DT_REG;
177 err = erofs_read_inode_from_disk(&vi);
180 dent->size = vi.i_size;
185 if (erofs_blkoff(pos) >= dirs->de_end) {
186 pos = blknr_to_addr(erofs_blknr(pos) + 1);
193 void erofs_closedir(struct fs_dir_stream *fs_dirs)
198 int erofs_exists(const char *filename)
200 struct erofs_inode vi;
203 err = erofs_ilookup(filename, &vi);
207 int erofs_size(const char *filename, loff_t *size)
209 struct erofs_inode vi;
212 err = erofs_ilookup(filename, &vi);
219 int erofs_read(const char *filename, void *buf, loff_t offset, loff_t len,
222 struct erofs_inode vi;
225 err = erofs_ilookup(filename, &vi);
229 if (S_ISLNK(vi.i_mode)) {
230 err = erofs_readlink(&vi);
238 err = erofs_pread(&vi, buf, len, offset);
244 if (offset >= vi.i_size)
246 else if (offset + len > vi.i_size)
247 *actread = vi.i_size - offset;
253 void erofs_close(void)
258 int erofs_uuid(char *uuid_str)
260 if (IS_ENABLED(CONFIG_LIB_UUID)) {
262 uuid_bin_to_str(sbi.uuid, uuid_str,
263 UUID_STR_FORMAT_STD);