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 const size_t dirsize = i_size_read(dir); 54 unsigned int i = ctx->pos / EROFS_BLKSIZ; 55 unsigned int ofs = ctx->pos % EROFS_BLKSIZ; 56 int err = 0; 57 bool initial = true; 58 59 while (ctx->pos < dirsize) { 60 struct erofs_dirent *de; 61 unsigned int nameoff, maxsize; 62 63 de = erofs_bread(&buf, dir, i, EROFS_KMAP); 64 if (IS_ERR(de)) { 65 erofs_err(dir->i_sb, 66 "fail to readdir of logical block %u of nid %llu", 67 i, EROFS_I(dir)->nid); 68 err = PTR_ERR(de); 69 break; 70 } 71 72 nameoff = le16_to_cpu(de->nameoff); 73 if (nameoff < sizeof(struct erofs_dirent) || 74 nameoff >= EROFS_BLKSIZ) { 75 erofs_err(dir->i_sb, 76 "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, 83 dirsize - ctx->pos + ofs, EROFS_BLKSIZ); 84 85 /* search dirents at the arbitrary position */ 86 if (initial) { 87 initial = false; 88 89 ofs = roundup(ofs, sizeof(struct erofs_dirent)); 90 ctx->pos = blknr_to_addr(i) + ofs; 91 if (ofs >= nameoff) 92 goto skip_this; 93 } 94 95 err = erofs_fill_dentries(dir, ctx, de, (void *)de + ofs, 96 nameoff, maxsize); 97 if (err) 98 break; 99 skip_this: 100 ctx->pos = blknr_to_addr(i) + maxsize; 101 ++i; 102 ofs = 0; 103 } 104 erofs_put_metabuf(&buf); 105 return err < 0 ? err : 0; 106 } 107 108 const struct file_operations erofs_dir_fops = { 109 .llseek = generic_file_llseek, 110 .read = generic_read_dir, 111 .iterate_shared = erofs_readdir, 112 }; 113