linux/drivers/staging/erofs/dir.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * linux/drivers/staging/erofs/dir.c
   4 *
   5 * Copyright (C) 2017-2018 HUAWEI, Inc.
   6 *             http://www.huawei.com/
   7 * Created by Gao Xiang <gaoxiang25@huawei.com>
   8 *
   9 * This file is subject to the terms and conditions of the GNU General Public
  10 * License.  See the file COPYING in the main directory of the Linux
  11 * distribution for more details.
  12 */
  13#include "internal.h"
  14
  15static const unsigned char erofs_filetype_table[EROFS_FT_MAX] = {
  16        [EROFS_FT_UNKNOWN]      = DT_UNKNOWN,
  17        [EROFS_FT_REG_FILE]     = DT_REG,
  18        [EROFS_FT_DIR]          = DT_DIR,
  19        [EROFS_FT_CHRDEV]       = DT_CHR,
  20        [EROFS_FT_BLKDEV]       = DT_BLK,
  21        [EROFS_FT_FIFO]         = DT_FIFO,
  22        [EROFS_FT_SOCK]         = DT_SOCK,
  23        [EROFS_FT_SYMLINK]      = DT_LNK,
  24};
  25
  26static int erofs_fill_dentries(struct dir_context *ctx,
  27        void *dentry_blk, unsigned int *ofs,
  28        unsigned int nameoff, unsigned int maxsize)
  29{
  30        struct erofs_dirent *de = dentry_blk;
  31        const struct erofs_dirent *end = dentry_blk + nameoff;
  32
  33        de = dentry_blk + *ofs;
  34        while (de < end) {
  35                const char *de_name;
  36                int de_namelen;
  37                unsigned char d_type;
  38#ifdef CONFIG_EROFS_FS_DEBUG
  39                unsigned int dbg_namelen;
  40                unsigned char dbg_namebuf[EROFS_NAME_LEN];
  41#endif
  42
  43                if (unlikely(de->file_type < EROFS_FT_MAX))
  44                        d_type = erofs_filetype_table[de->file_type];
  45                else
  46                        d_type = DT_UNKNOWN;
  47
  48                nameoff = le16_to_cpu(de->nameoff);
  49                de_name = (char *)dentry_blk + nameoff;
  50
  51                de_namelen = unlikely(de + 1 >= end) ?
  52                        /* last directory entry */
  53                        strnlen(de_name, maxsize - nameoff) :
  54                        le16_to_cpu(de[1].nameoff) - nameoff;
  55
  56                /* a corrupted entry is found */
  57                if (unlikely(de_namelen < 0)) {
  58                        DBG_BUGON(1);
  59                        return -EIO;
  60                }
  61
  62#ifdef CONFIG_EROFS_FS_DEBUG
  63                dbg_namelen = min(EROFS_NAME_LEN - 1, de_namelen);
  64                memcpy(dbg_namebuf, de_name, dbg_namelen);
  65                dbg_namebuf[dbg_namelen] = '\0';
  66
  67                debugln("%s, found de_name %s de_len %d d_type %d", __func__,
  68                        dbg_namebuf, de_namelen, d_type);
  69#endif
  70
  71                if (!dir_emit(ctx, de_name, de_namelen,
  72                              le64_to_cpu(de->nid), d_type))
  73                        /* stopped by some reason */
  74                        return 1;
  75                ++de;
  76                *ofs += sizeof(struct erofs_dirent);
  77        }
  78        *ofs = maxsize;
  79        return 0;
  80}
  81
  82static int erofs_readdir(struct file *f, struct dir_context *ctx)
  83{
  84        struct inode *dir = file_inode(f);
  85        struct address_space *mapping = dir->i_mapping;
  86        const size_t dirsize = i_size_read(dir);
  87        unsigned int i = ctx->pos / EROFS_BLKSIZ;
  88        unsigned int ofs = ctx->pos % EROFS_BLKSIZ;
  89        int err = 0;
  90        bool initial = true;
  91
  92        while (ctx->pos < dirsize) {
  93                struct page *dentry_page;
  94                struct erofs_dirent *de;
  95                unsigned int nameoff, maxsize;
  96
  97                dentry_page = read_mapping_page(mapping, i, NULL);
  98                if (IS_ERR(dentry_page))
  99                        continue;
 100
 101                lock_page(dentry_page);
 102                de = (struct erofs_dirent *)kmap(dentry_page);
 103
 104                nameoff = le16_to_cpu(de->nameoff);
 105
 106                if (unlikely(nameoff < sizeof(struct erofs_dirent) ||
 107                        nameoff >= PAGE_SIZE)) {
 108                        errln("%s, invalid de[0].nameoff %u",
 109                                __func__, nameoff);
 110
 111                        err = -EIO;
 112                        goto skip_this;
 113                }
 114
 115                maxsize = min_t(unsigned int,
 116                                dirsize - ctx->pos + ofs, PAGE_SIZE);
 117
 118                /* search dirents at the arbitrary position */
 119                if (unlikely(initial)) {
 120                        initial = false;
 121
 122                        ofs = roundup(ofs, sizeof(struct erofs_dirent));
 123                        if (unlikely(ofs >= nameoff))
 124                                goto skip_this;
 125                }
 126
 127                err = erofs_fill_dentries(ctx, de, &ofs, nameoff, maxsize);
 128skip_this:
 129                kunmap(dentry_page);
 130
 131                unlock_page(dentry_page);
 132                put_page(dentry_page);
 133
 134                ctx->pos = blknr_to_addr(i) + ofs;
 135
 136                if (unlikely(err))
 137                        break;
 138                ++i;
 139                ofs = 0;
 140        }
 141        return err < 0 ? err : 0;
 142}
 143
 144const struct file_operations erofs_dir_fops = {
 145        .llseek         = generic_file_llseek,
 146        .read           = generic_read_dir,
 147        .iterate        = erofs_readdir,
 148};
 149
 150