| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267 |
- // SPDX-License-Identifier: GPL-2.0+
- #include "internal.h"
- #include <fs_internal.h>
- struct erofs_sb_info sbi;
- static struct erofs_ctxt {
- struct disk_partition cur_part_info;
- struct blk_desc *cur_dev;
- } ctxt;
- int erofs_dev_read(int device_id, void *buf, u64 offset, size_t len)
- {
- lbaint_t sect = offset >> ctxt.cur_dev->log2blksz;
- int off = offset & (ctxt.cur_dev->blksz - 1);
- if (!ctxt.cur_dev)
- return -EIO;
- if (fs_devread(ctxt.cur_dev, &ctxt.cur_part_info, sect,
- off, len, buf))
- return 0;
- return -EIO;
- }
- int erofs_blk_read(void *buf, erofs_blk_t start, u32 nblocks)
- {
- return erofs_dev_read(0, buf, erofs_pos(start),
- erofs_pos(nblocks));
- }
- int erofs_probe(struct blk_desc *fs_dev_desc,
- struct disk_partition *fs_partition)
- {
- int ret;
- ctxt.cur_dev = fs_dev_desc;
- ctxt.cur_part_info = *fs_partition;
- ret = erofs_read_superblock();
- if (ret)
- goto error;
- return 0;
- error:
- ctxt.cur_dev = NULL;
- return ret;
- }
- struct erofs_dir_stream {
- struct fs_dir_stream fs_dirs;
- struct fs_dirent dirent;
- struct erofs_inode inode;
- char dblk[EROFS_MAX_BLOCK_SIZE];
- unsigned int maxsize, de_end;
- erofs_off_t pos;
- };
- static int erofs_readlink(struct erofs_inode *vi)
- {
- size_t len = vi->i_size;
- char *target;
- int err;
- target = malloc(len + 1);
- if (!target)
- return -ENOMEM;
- target[len] = '\0';
- err = erofs_pread(vi, target, len, 0);
- if (err)
- goto err_out;
- err = erofs_ilookup(target, vi);
- if (err)
- goto err_out;
- err_out:
- free(target);
- return err;
- }
- int erofs_opendir(const char *filename, struct fs_dir_stream **dirsp)
- {
- struct erofs_dir_stream *dirs;
- int err;
- dirs = calloc(1, sizeof(*dirs));
- if (!dirs)
- return -ENOMEM;
- err = erofs_ilookup(filename, &dirs->inode);
- if (err)
- goto err_out;
- if (S_ISLNK(dirs->inode.i_mode)) {
- err = erofs_readlink(&dirs->inode);
- if (err)
- goto err_out;
- }
- if (!S_ISDIR(dirs->inode.i_mode)) {
- err = -ENOTDIR;
- goto err_out;
- }
- *dirsp = (struct fs_dir_stream *)dirs;
- return 0;
- err_out:
- free(dirs);
- return err;
- }
- int erofs_readdir(struct fs_dir_stream *fs_dirs, struct fs_dirent **dentp)
- {
- struct erofs_dir_stream *dirs = (struct erofs_dir_stream *)fs_dirs;
- struct fs_dirent *dent = &dirs->dirent;
- erofs_off_t pos = dirs->pos;
- unsigned int nameoff, de_namelen;
- struct erofs_dirent *de;
- char *de_name;
- int err;
- if (pos >= dirs->inode.i_size)
- return 1;
- if (!dirs->maxsize) {
- dirs->maxsize = min_t(unsigned int, EROFS_MAX_BLOCK_SIZE,
- dirs->inode.i_size - pos);
- err = erofs_pread(&dirs->inode, dirs->dblk,
- dirs->maxsize, pos);
- if (err)
- return err;
- de = (struct erofs_dirent *)dirs->dblk;
- dirs->de_end = le16_to_cpu(de->nameoff);
- if (dirs->de_end < sizeof(struct erofs_dirent) ||
- dirs->de_end >= EROFS_MAX_BLOCK_SIZE) {
- erofs_err("invalid de[0].nameoff %u @ nid %llu",
- dirs->de_end, de->nid | 0ULL);
- return -EFSCORRUPTED;
- }
- }
- de = (struct erofs_dirent *)(dirs->dblk + erofs_blkoff(pos));
- nameoff = le16_to_cpu(de->nameoff);
- de_name = (char *)dirs->dblk + nameoff;
- /* the last dirent in the block? */
- if (de + 1 >= (struct erofs_dirent *)(dirs->dblk + dirs->de_end))
- de_namelen = strnlen(de_name, dirs->maxsize - nameoff);
- else
- de_namelen = le16_to_cpu(de[1].nameoff) - nameoff;
- /* a corrupted entry is found */
- if (nameoff + de_namelen > dirs->maxsize ||
- de_namelen > EROFS_NAME_LEN) {
- erofs_err("bogus dirent @ nid %llu", de->nid | 0ULL);
- DBG_BUGON(1);
- return -EFSCORRUPTED;
- }
- memcpy(dent->name, de_name, de_namelen);
- dent->name[de_namelen] = '\0';
- if (de->file_type == EROFS_FT_DIR) {
- dent->type = FS_DT_DIR;
- } else if (de->file_type == EROFS_FT_SYMLINK) {
- dent->type = FS_DT_LNK;
- } else {
- struct erofs_inode vi;
- dent->type = FS_DT_REG;
- vi.nid = de->nid;
- err = erofs_read_inode_from_disk(&vi);
- if (err)
- return err;
- dent->size = vi.i_size;
- }
- *dentp = dent;
- pos += sizeof(*de);
- if (erofs_blkoff(pos) >= dirs->de_end) {
- pos = erofs_pos(erofs_blknr(pos) + 1);
- dirs->maxsize = 0;
- }
- dirs->pos = pos;
- return 0;
- }
- void erofs_closedir(struct fs_dir_stream *fs_dirs)
- {
- free(fs_dirs);
- }
- int erofs_exists(const char *filename)
- {
- struct erofs_inode vi;
- int err;
- err = erofs_ilookup(filename, &vi);
- return err == 0;
- }
- int erofs_size(const char *filename, loff_t *size)
- {
- struct erofs_inode vi;
- int err;
- err = erofs_ilookup(filename, &vi);
- if (err)
- return err;
- *size = vi.i_size;
- return 0;
- }
- int erofs_read(const char *filename, void *buf, loff_t offset, loff_t len,
- loff_t *actread)
- {
- struct erofs_inode vi;
- int err;
- err = erofs_ilookup(filename, &vi);
- if (err)
- return err;
- if (S_ISLNK(vi.i_mode)) {
- err = erofs_readlink(&vi);
- if (err)
- return err;
- }
- if (!len)
- len = vi.i_size;
- err = erofs_pread(&vi, buf, len, offset);
- if (err) {
- *actread = 0;
- return err;
- }
- if (offset >= vi.i_size)
- *actread = 0;
- else if (offset + len > vi.i_size)
- *actread = vi.i_size - offset;
- else
- *actread = len;
- return 0;
- }
- void erofs_close(void)
- {
- ctxt.cur_dev = NULL;
- }
- int erofs_uuid(char *uuid_str)
- {
- if (IS_ENABLED(CONFIG_LIB_UUID)) {
- if (ctxt.cur_dev)
- uuid_bin_to_str(sbi.uuid, uuid_str,
- UUID_STR_FORMAT_STD);
- return 0;
- }
- return -ENOSYS;
- }
|