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 nameoff, unsigned int maxsize) 12 { 13 const struct erofs_dirent *end = dentry_blk + nameoff; 14 15 while (de < end) { 16 const char *de_name; 17 unsigned int de_namelen; 18 unsigned char d_type; 19 20 d_type = fs_ftype_to_dtype(de->file_type); 21 22 nameoff = le16_to_cpu(de->nameoff); 23 de_name = (char *)dentry_blk + nameoff; 24 25 /* the last dirent in the block? */ 26 if (de + 1 >= end) 27 de_namelen = strnlen(de_name, maxsize - nameoff); 28 else 29 de_namelen = le16_to_cpu(de[1].nameoff) - nameoff; 30 31 /* a corrupted entry is found */ 32 if (nameoff + de_namelen > maxsize || 33 de_namelen > EROFS_NAME_LEN) { 34 erofs_err(dir->i_sb, "bogus dirent @ nid %llu", 35 EROFS_I(dir)->nid); 36 DBG_BUGON(1); 37 return -EFSCORRUPTED; 38 } 39 40 if (!dir_emit(ctx, de_name, de_namelen, 41 le64_to_cpu(de->nid), d_type)) 42 return 1; 43 ++de; 44 ctx->pos += sizeof(struct erofs_dirent); 45 } 46 return 0; 47 } 48 49 static int erofs_readdir(struct file *f, struct dir_context *ctx) 50 { 51 struct inode *dir = file_inode(f); 52 struct erofs_buf buf = __EROFS_BUF_INITIALIZER; 53 struct super_block *sb = dir->i_sb; 54 unsigned long bsz = sb->s_blocksize; 55 const size_t dirsize = i_size_read(dir); 56 unsigned int i = erofs_blknr(sb, ctx->pos); 57 unsigned int ofs = erofs_blkoff(sb, ctx->pos); 58 int err = 0; 59 bool initial = true; 60 61 buf.inode = dir; 62 while (ctx->pos < dirsize) { 63 struct erofs_dirent *de; 64 unsigned int nameoff, maxsize; 65 66 de = erofs_bread(&buf, i, EROFS_KMAP); 67 if (IS_ERR(de)) { 68 erofs_err(sb, "fail to readdir of logical block %u of nid %llu", 69 i, EROFS_I(dir)->nid); 70 err = PTR_ERR(de); 71 break; 72 } 73 74 nameoff = le16_to_cpu(de->nameoff); 75 if (nameoff < sizeof(struct erofs_dirent) || nameoff >= bsz) { 76 erofs_err(sb, "invalid de[0].nameoff %u @ nid %llu", 77 nameoff, EROFS_I(dir)->nid); 78 err = -EFSCORRUPTED; 79 break; 80 } 81 82 maxsize = min_t(unsigned int, dirsize - ctx->pos + ofs, bsz); 83 84 /* search dirents at the arbitrary position */ 85 if (initial) { 86 initial = false; 87 88 ofs = roundup(ofs, sizeof(struct erofs_dirent)); 89 ctx->pos = erofs_pos(sb, i) + ofs; 90 if (ofs >= nameoff) 91 goto skip_this; 92 } 93 94 err = erofs_fill_dentries(dir, ctx, de, (void *)de + ofs, 95 nameoff, maxsize); 96 if (err) 97 break; 98 skip_this: 99 ctx->pos = erofs_pos(sb, i) + maxsize; 100 ++i; 101 ofs = 0; 102 } 103 erofs_put_metabuf(&buf); 104 return err < 0 ? err : 0; 105 } 106 107 const struct file_operations erofs_dir_fops = { 108 .llseek = generic_file_llseek, 109 .read = generic_read_dir, 110 .iterate_shared = erofs_readdir, 111 }; 112