Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.1-rc7 152 lines 3.8 kB view raw
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 void debug_one_dentry(unsigned char d_type, const char *de_name, 27 unsigned int de_namelen) 28{ 29#ifdef CONFIG_EROFS_FS_DEBUG 30 /* since the on-disk name could not have the trailing '\0' */ 31 unsigned char dbg_namebuf[EROFS_NAME_LEN + 1]; 32 33 memcpy(dbg_namebuf, de_name, de_namelen); 34 dbg_namebuf[de_namelen] = '\0'; 35 36 debugln("found dirent %s de_len %u d_type %d", dbg_namebuf, 37 de_namelen, d_type); 38#endif 39} 40 41static int erofs_fill_dentries(struct dir_context *ctx, 42 void *dentry_blk, unsigned int *ofs, 43 unsigned int nameoff, unsigned int maxsize) 44{ 45 struct erofs_dirent *de = dentry_blk; 46 const struct erofs_dirent *end = dentry_blk + nameoff; 47 48 de = dentry_blk + *ofs; 49 while (de < end) { 50 const char *de_name; 51 unsigned int de_namelen; 52 unsigned char d_type; 53 54 if (de->file_type < EROFS_FT_MAX) 55 d_type = erofs_filetype_table[de->file_type]; 56 else 57 d_type = DT_UNKNOWN; 58 59 nameoff = le16_to_cpu(de->nameoff); 60 de_name = (char *)dentry_blk + nameoff; 61 62 /* the last dirent in the block? */ 63 if (de + 1 >= end) 64 de_namelen = strnlen(de_name, maxsize - nameoff); 65 else 66 de_namelen = le16_to_cpu(de[1].nameoff) - nameoff; 67 68 /* a corrupted entry is found */ 69 if (unlikely(nameoff + de_namelen > maxsize || 70 de_namelen > EROFS_NAME_LEN)) { 71 DBG_BUGON(1); 72 return -EIO; 73 } 74 75 debug_one_dentry(d_type, de_name, de_namelen); 76 if (!dir_emit(ctx, de_name, de_namelen, 77 le64_to_cpu(de->nid), d_type)) 78 /* stopped by some reason */ 79 return 1; 80 ++de; 81 *ofs += sizeof(struct erofs_dirent); 82 } 83 *ofs = maxsize; 84 return 0; 85} 86 87static int erofs_readdir(struct file *f, struct dir_context *ctx) 88{ 89 struct inode *dir = file_inode(f); 90 struct address_space *mapping = dir->i_mapping; 91 const size_t dirsize = i_size_read(dir); 92 unsigned int i = ctx->pos / EROFS_BLKSIZ; 93 unsigned int ofs = ctx->pos % EROFS_BLKSIZ; 94 int err = 0; 95 bool initial = true; 96 97 while (ctx->pos < dirsize) { 98 struct page *dentry_page; 99 struct erofs_dirent *de; 100 unsigned int nameoff, maxsize; 101 102 dentry_page = read_mapping_page(mapping, i, NULL); 103 if (IS_ERR(dentry_page)) 104 continue; 105 106 de = (struct erofs_dirent *)kmap(dentry_page); 107 108 nameoff = le16_to_cpu(de->nameoff); 109 110 if (unlikely(nameoff < sizeof(struct erofs_dirent) || 111 nameoff >= PAGE_SIZE)) { 112 errln("%s, invalid de[0].nameoff %u", 113 __func__, nameoff); 114 115 err = -EIO; 116 goto skip_this; 117 } 118 119 maxsize = min_t(unsigned int, 120 dirsize - ctx->pos + ofs, PAGE_SIZE); 121 122 /* search dirents at the arbitrary position */ 123 if (unlikely(initial)) { 124 initial = false; 125 126 ofs = roundup(ofs, sizeof(struct erofs_dirent)); 127 if (unlikely(ofs >= nameoff)) 128 goto skip_this; 129 } 130 131 err = erofs_fill_dentries(ctx, de, &ofs, nameoff, maxsize); 132skip_this: 133 kunmap(dentry_page); 134 135 put_page(dentry_page); 136 137 ctx->pos = blknr_to_addr(i) + ofs; 138 139 if (unlikely(err)) 140 break; 141 ++i; 142 ofs = 0; 143 } 144 return err < 0 ? err : 0; 145} 146 147const struct file_operations erofs_dir_fops = { 148 .llseek = generic_file_llseek, 149 .read = generic_read_dir, 150 .iterate_shared = erofs_readdir, 151}; 152