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                /* the corrupted directory found */
  57                BUG_ON(de_namelen < 0);
  58
  59#ifdef CONFIG_EROFS_FS_DEBUG
  60                dbg_namelen = min(EROFS_NAME_LEN - 1, de_namelen);
  61                memcpy(dbg_namebuf, de_name, dbg_namelen);
  62                dbg_namebuf[dbg_namelen] = '\0';
  63
  64                debugln("%s, found de_name %s de_len %d d_type %d", __func__,
  65                        dbg_namebuf, de_namelen, d_type);
  66#endif
  67
  68                if (!dir_emit(ctx, de_name, de_namelen,
  69                                        le64_to_cpu(de->nid), d_type))
  70                        /* stoped by some reason */
  71                        return 1;
  72                ++de;
  73                *ofs += sizeof(struct erofs_dirent);
  74        }
  75        *ofs = maxsize;
  76        return 0;
  77}
  78
  79static int erofs_readdir(struct file *f, struct dir_context *ctx)
  80{
  81        struct inode *dir = file_inode(f);
  82        struct address_space *mapping = dir->i_mapping;
  83        const size_t dirsize = i_size_read(dir);
  84        unsigned int i = ctx->pos / EROFS_BLKSIZ;
  85        unsigned int ofs = ctx->pos % EROFS_BLKSIZ;
  86        int err = 0;
  87        bool initial = true;
  88
  89        while (ctx->pos < dirsize) {
  90                struct page *dentry_page;
  91                struct erofs_dirent *de;
  92                unsigned int nameoff, maxsize;
  93
  94                dentry_page = read_mapping_page(mapping, i, NULL);
  95                if (IS_ERR(dentry_page))
  96                        continue;
  97
  98                lock_page(dentry_page);
  99                de = (struct erofs_dirent *)kmap(dentry_page);
 100
 101                nameoff = le16_to_cpu(de->nameoff);
 102
 103                if (unlikely(nameoff < sizeof(struct erofs_dirent) ||
 104                        nameoff >= PAGE_SIZE)) {
 105                        errln("%s, invalid de[0].nameoff %u",
 106                                __func__, nameoff);
 107
 108                        err = -EIO;
 109                        goto skip_this;
 110                }
 111
 112                maxsize = min_t(unsigned int,
 113                                dirsize - ctx->pos + ofs, PAGE_SIZE);
 114
 115                /* search dirents at the arbitrary position */
 116                if (unlikely(initial)) {
 117                        initial = false;
 118
 119                        ofs = roundup(ofs, sizeof(struct erofs_dirent));
 120                        if (unlikely(ofs >= nameoff))
 121                                goto skip_this;
 122                }
 123
 124                err = erofs_fill_dentries(ctx, de, &ofs, nameoff, maxsize);
 125skip_this:
 126                kunmap(dentry_page);
 127
 128                unlock_page(dentry_page);
 129                put_page(dentry_page);
 130
 131                ctx->pos = blknr_to_addr(i) + ofs;
 132
 133                if (unlikely(err))
 134                        break;
 135                ++i;
 136                ofs = 0;
 137        }
 138        return err < 0 ? err : 0;
 139}
 140
 141const struct file_operations erofs_dir_fops = {
 142        .llseek         = generic_file_llseek,
 143        .read           = generic_read_dir,
 144        .iterate        = erofs_readdir,
 145};
 146
 147