Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2017-2018 HUAWEI, Inc.
0004  *             https://www.huawei.com/
0005  * Copyright (C) 2022, Alibaba Cloud
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     /* since the on-disk name could not have the trailing '\0' */
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         /* the last dirent in the block? */
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         /* a corrupted entry is found */
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             /* stopped by some reason */
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         /* search dirents at the arbitrary position */
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 };