0001
0002
0003
0004
0005
0006
0007 #include "internal.h"
0008
0009 static void debug_one_dentry(unsigned char d_type, const char *de_name,
0010 unsigned int de_namelen)
0011 {
0012 #ifdef CONFIG_EROFS_FS_DEBUG
0013
0014 unsigned char dbg_namebuf[EROFS_NAME_LEN + 1];
0015
0016 memcpy(dbg_namebuf, de_name, de_namelen);
0017 dbg_namebuf[de_namelen] = '\0';
0018
0019 erofs_dbg("found dirent %s de_len %u d_type %d", dbg_namebuf,
0020 de_namelen, d_type);
0021 #endif
0022 }
0023
0024 static int erofs_fill_dentries(struct inode *dir, struct dir_context *ctx,
0025 void *dentry_blk, struct erofs_dirent *de,
0026 unsigned int nameoff, unsigned int maxsize)
0027 {
0028 const struct erofs_dirent *end = dentry_blk + nameoff;
0029
0030 while (de < end) {
0031 const char *de_name;
0032 unsigned int de_namelen;
0033 unsigned char d_type;
0034
0035 d_type = fs_ftype_to_dtype(de->file_type);
0036
0037 nameoff = le16_to_cpu(de->nameoff);
0038 de_name = (char *)dentry_blk + nameoff;
0039
0040
0041 if (de + 1 >= end)
0042 de_namelen = strnlen(de_name, maxsize - nameoff);
0043 else
0044 de_namelen = le16_to_cpu(de[1].nameoff) - nameoff;
0045
0046
0047 if (nameoff + de_namelen > maxsize ||
0048 de_namelen > EROFS_NAME_LEN) {
0049 erofs_err(dir->i_sb, "bogus dirent @ nid %llu",
0050 EROFS_I(dir)->nid);
0051 DBG_BUGON(1);
0052 return -EFSCORRUPTED;
0053 }
0054
0055 debug_one_dentry(d_type, de_name, de_namelen);
0056 if (!dir_emit(ctx, de_name, de_namelen,
0057 le64_to_cpu(de->nid), d_type))
0058
0059 return 1;
0060 ++de;
0061 ctx->pos += sizeof(struct erofs_dirent);
0062 }
0063 return 0;
0064 }
0065
0066 static int erofs_readdir(struct file *f, struct dir_context *ctx)
0067 {
0068 struct inode *dir = file_inode(f);
0069 struct erofs_buf buf = __EROFS_BUF_INITIALIZER;
0070 const size_t dirsize = i_size_read(dir);
0071 unsigned int i = ctx->pos / EROFS_BLKSIZ;
0072 unsigned int ofs = ctx->pos % EROFS_BLKSIZ;
0073 int err = 0;
0074 bool initial = true;
0075
0076 while (ctx->pos < dirsize) {
0077 struct erofs_dirent *de;
0078 unsigned int nameoff, maxsize;
0079
0080 de = erofs_bread(&buf, dir, i, EROFS_KMAP);
0081 if (IS_ERR(de)) {
0082 erofs_err(dir->i_sb,
0083 "fail to readdir of logical block %u of nid %llu",
0084 i, EROFS_I(dir)->nid);
0085 err = PTR_ERR(de);
0086 break;
0087 }
0088
0089 nameoff = le16_to_cpu(de->nameoff);
0090 if (nameoff < sizeof(struct erofs_dirent) ||
0091 nameoff >= EROFS_BLKSIZ) {
0092 erofs_err(dir->i_sb,
0093 "invalid de[0].nameoff %u @ nid %llu",
0094 nameoff, EROFS_I(dir)->nid);
0095 err = -EFSCORRUPTED;
0096 break;
0097 }
0098
0099 maxsize = min_t(unsigned int,
0100 dirsize - ctx->pos + ofs, EROFS_BLKSIZ);
0101
0102
0103 if (initial) {
0104 initial = false;
0105
0106 ofs = roundup(ofs, sizeof(struct erofs_dirent));
0107 ctx->pos = blknr_to_addr(i) + ofs;
0108 if (ofs >= nameoff)
0109 goto skip_this;
0110 }
0111
0112 err = erofs_fill_dentries(dir, ctx, de, (void *)de + ofs,
0113 nameoff, maxsize);
0114 if (err)
0115 break;
0116 skip_this:
0117 ctx->pos = blknr_to_addr(i) + maxsize;
0118 ++i;
0119 ofs = 0;
0120 }
0121 erofs_put_metabuf(&buf);
0122 return err < 0 ? err : 0;
0123 }
0124
0125 const struct file_operations erofs_dir_fops = {
0126 .llseek = generic_file_llseek,
0127 .read = generic_read_dir,
0128 .iterate_shared = erofs_readdir,
0129 };