| 1 | // SPDX-License-Identifier: GPL-2.0 | 
|---|
| 2 | /* | 
|---|
| 3 | *  linux/fs/ext4/dir.c | 
|---|
| 4 | * | 
|---|
| 5 | * Copyright (C) 1992, 1993, 1994, 1995 | 
|---|
| 6 | * Remy Card (card@masi.ibp.fr) | 
|---|
| 7 | * Laboratoire MASI - Institut Blaise Pascal | 
|---|
| 8 | * Universite Pierre et Marie Curie (Paris VI) | 
|---|
| 9 | * | 
|---|
| 10 | *  from | 
|---|
| 11 | * | 
|---|
| 12 | *  linux/fs/minix/dir.c | 
|---|
| 13 | * | 
|---|
| 14 | *  Copyright (C) 1991, 1992  Linus Torvalds | 
|---|
| 15 | * | 
|---|
| 16 | *  ext4 directory handling functions | 
|---|
| 17 | * | 
|---|
| 18 | *  Big-endian to little-endian byte-swapping/bitmaps by | 
|---|
| 19 | *        David S. Miller (davem@caip.rutgers.edu), 1995 | 
|---|
| 20 | * | 
|---|
| 21 | * Hash Tree Directory indexing (c) 2001  Daniel Phillips | 
|---|
| 22 | * | 
|---|
| 23 | */ | 
|---|
| 24 |  | 
|---|
| 25 | #include <linux/fs.h> | 
|---|
| 26 | #include <linux/buffer_head.h> | 
|---|
| 27 | #include <linux/slab.h> | 
|---|
| 28 | #include <linux/iversion.h> | 
|---|
| 29 | #include <linux/unicode.h> | 
|---|
| 30 | #include "ext4.h" | 
|---|
| 31 | #include "xattr.h" | 
|---|
| 32 |  | 
|---|
| 33 | static int ext4_dx_readdir(struct file *, struct dir_context *); | 
|---|
| 34 |  | 
|---|
| 35 | /** | 
|---|
| 36 | * is_dx_dir() - check if a directory is using htree indexing | 
|---|
| 37 | * @inode: directory inode | 
|---|
| 38 | * | 
|---|
| 39 | * Check if the given dir-inode refers to an htree-indexed directory | 
|---|
| 40 | * (or a directory which could potentially get converted to use htree | 
|---|
| 41 | * indexing). | 
|---|
| 42 | * | 
|---|
| 43 | * Return 1 if it is a dx dir, 0 if not | 
|---|
| 44 | */ | 
|---|
| 45 | static int is_dx_dir(struct inode *inode) | 
|---|
| 46 | { | 
|---|
| 47 | struct super_block *sb = inode->i_sb; | 
|---|
| 48 |  | 
|---|
| 49 | if (ext4_has_feature_dir_index(sb: inode->i_sb) && | 
|---|
| 50 | ((ext4_test_inode_flag(inode, bit: EXT4_INODE_INDEX)) || | 
|---|
| 51 | ((inode->i_size >> sb->s_blocksize_bits) == 1) || | 
|---|
| 52 | ext4_has_inline_data(inode))) | 
|---|
| 53 | return 1; | 
|---|
| 54 |  | 
|---|
| 55 | return 0; | 
|---|
| 56 | } | 
|---|
| 57 |  | 
|---|
| 58 | static bool is_fake_dir_entry(struct ext4_dir_entry_2 *de) | 
|---|
| 59 | { | 
|---|
| 60 | /* Check if . or .. , or skip if namelen is 0 */ | 
|---|
| 61 | if ((de->name_len > 0) && (de->name_len <= 2) && (de->name[0] == '.') && | 
|---|
| 62 | (de->name[1] == '.' || de->name[1] == '\0')) | 
|---|
| 63 | return true; | 
|---|
| 64 | /* Check if this is a csum entry */ | 
|---|
| 65 | if (de->file_type == EXT4_FT_DIR_CSUM) | 
|---|
| 66 | return true; | 
|---|
| 67 | return false; | 
|---|
| 68 | } | 
|---|
| 69 |  | 
|---|
| 70 | /* | 
|---|
| 71 | * Return 0 if the directory entry is OK, and 1 if there is a problem | 
|---|
| 72 | * | 
|---|
| 73 | * Note: this is the opposite of what ext2 and ext3 historically returned... | 
|---|
| 74 | * | 
|---|
| 75 | * bh passed here can be an inode block or a dir data block, depending | 
|---|
| 76 | * on the inode inline data flag. | 
|---|
| 77 | */ | 
|---|
| 78 | int __ext4_check_dir_entry(const char *function, unsigned int line, | 
|---|
| 79 | struct inode *dir, struct file *filp, | 
|---|
| 80 | struct ext4_dir_entry_2 *de, | 
|---|
| 81 | struct buffer_head *bh, char *buf, int size, | 
|---|
| 82 | unsigned int offset) | 
|---|
| 83 | { | 
|---|
| 84 | const char *error_msg = NULL; | 
|---|
| 85 | const int rlen = ext4_rec_len_from_disk(dlen: de->rec_len, | 
|---|
| 86 | blocksize: dir->i_sb->s_blocksize); | 
|---|
| 87 | const int next_offset = ((char *) de - buf) + rlen; | 
|---|
| 88 | bool fake = is_fake_dir_entry(de); | 
|---|
| 89 | bool has_csum = ext4_has_feature_metadata_csum(sb: dir->i_sb); | 
|---|
| 90 |  | 
|---|
| 91 | if (unlikely(rlen < ext4_dir_rec_len(1, fake ? NULL : dir))) | 
|---|
| 92 | error_msg = "rec_len is smaller than minimal"; | 
|---|
| 93 | else if (unlikely(rlen % 4 != 0)) | 
|---|
| 94 | error_msg = "rec_len % 4 != 0"; | 
|---|
| 95 | else if (unlikely(rlen < ext4_dir_rec_len(de->name_len, | 
|---|
| 96 | fake ? NULL : dir))) | 
|---|
| 97 | error_msg = "rec_len is too small for name_len"; | 
|---|
| 98 | else if (unlikely(next_offset > size)) | 
|---|
| 99 | error_msg = "directory entry overrun"; | 
|---|
| 100 | else if (unlikely(next_offset > size - ext4_dir_rec_len(1, | 
|---|
| 101 | has_csum ? NULL : dir) && | 
|---|
| 102 | next_offset != size)) | 
|---|
| 103 | error_msg = "directory entry too close to block end"; | 
|---|
| 104 | else if (unlikely(le32_to_cpu(de->inode) > | 
|---|
| 105 | le32_to_cpu(EXT4_SB(dir->i_sb)->s_es->s_inodes_count))) | 
|---|
| 106 | error_msg = "inode out of bounds"; | 
|---|
| 107 | else if (unlikely(next_offset == size && de->name_len == 1 && | 
|---|
| 108 | de->name[0] == '.')) | 
|---|
| 109 | error_msg = "'.' directory cannot be the last in data block"; | 
|---|
| 110 | else | 
|---|
| 111 | return 0; | 
|---|
| 112 |  | 
|---|
| 113 | if (filp) | 
|---|
| 114 | ext4_error_file(filp, function, line, bh->b_blocknr, | 
|---|
| 115 | "bad entry in directory: %s - offset=%u, " | 
|---|
| 116 | "inode=%u, rec_len=%d, size=%d fake=%d", | 
|---|
| 117 | error_msg, offset, le32_to_cpu(de->inode), | 
|---|
| 118 | rlen, size, fake); | 
|---|
| 119 | else | 
|---|
| 120 | ext4_error_inode(dir, function, line, bh->b_blocknr, | 
|---|
| 121 | "bad entry in directory: %s - offset=%u, " | 
|---|
| 122 | "inode=%u, rec_len=%d, size=%d fake=%d", | 
|---|
| 123 | error_msg, offset, le32_to_cpu(de->inode), | 
|---|
| 124 | rlen, size, fake); | 
|---|
| 125 |  | 
|---|
| 126 | return 1; | 
|---|
| 127 | } | 
|---|
| 128 |  | 
|---|
| 129 | static int ext4_readdir(struct file *file, struct dir_context *ctx) | 
|---|
| 130 | { | 
|---|
| 131 | unsigned int offset; | 
|---|
| 132 | int i; | 
|---|
| 133 | struct ext4_dir_entry_2 *de; | 
|---|
| 134 | int err; | 
|---|
| 135 | struct inode *inode = file_inode(f: file); | 
|---|
| 136 | struct super_block *sb = inode->i_sb; | 
|---|
| 137 | struct buffer_head *bh = NULL; | 
|---|
| 138 | struct fscrypt_str fstr = FSTR_INIT(NULL, 0); | 
|---|
| 139 | struct dir_private_info *info = file->private_data; | 
|---|
| 140 |  | 
|---|
| 141 | err = fscrypt_prepare_readdir(dir: inode); | 
|---|
| 142 | if (err) | 
|---|
| 143 | return err; | 
|---|
| 144 |  | 
|---|
| 145 | if (is_dx_dir(inode)) { | 
|---|
| 146 | err = ext4_dx_readdir(file, ctx); | 
|---|
| 147 | if (err != ERR_BAD_DX_DIR) | 
|---|
| 148 | return err; | 
|---|
| 149 |  | 
|---|
| 150 | /* Can we just clear INDEX flag to ignore htree information? */ | 
|---|
| 151 | if (!ext4_has_feature_metadata_csum(sb)) { | 
|---|
| 152 | /* | 
|---|
| 153 | * We don't set the inode dirty flag since it's not | 
|---|
| 154 | * critical that it gets flushed back to the disk. | 
|---|
| 155 | */ | 
|---|
| 156 | ext4_clear_inode_flag(inode, bit: EXT4_INODE_INDEX); | 
|---|
| 157 | } | 
|---|
| 158 | } | 
|---|
| 159 |  | 
|---|
| 160 | if (ext4_has_inline_data(inode)) { | 
|---|
| 161 | int has_inline_data = 1; | 
|---|
| 162 | err = ext4_read_inline_dir(filp: file, ctx, | 
|---|
| 163 | has_inline_data: &has_inline_data); | 
|---|
| 164 | if (has_inline_data) | 
|---|
| 165 | return err; | 
|---|
| 166 | } | 
|---|
| 167 |  | 
|---|
| 168 | if (IS_ENCRYPTED(inode)) { | 
|---|
| 169 | err = fscrypt_fname_alloc_buffer(EXT4_NAME_LEN, crypto_str: &fstr); | 
|---|
| 170 | if (err < 0) | 
|---|
| 171 | return err; | 
|---|
| 172 | } | 
|---|
| 173 |  | 
|---|
| 174 | while (ctx->pos < inode->i_size) { | 
|---|
| 175 | struct ext4_map_blocks map; | 
|---|
| 176 |  | 
|---|
| 177 | if (fatal_signal_pending(current)) { | 
|---|
| 178 | err = -ERESTARTSYS; | 
|---|
| 179 | goto errout; | 
|---|
| 180 | } | 
|---|
| 181 | cond_resched(); | 
|---|
| 182 | offset = ctx->pos & (sb->s_blocksize - 1); | 
|---|
| 183 | map.m_lblk = ctx->pos >> EXT4_BLOCK_SIZE_BITS(sb); | 
|---|
| 184 | map.m_len = 1; | 
|---|
| 185 | err = ext4_map_blocks(NULL, inode, map: &map, flags: 0); | 
|---|
| 186 | if (err == 0) { | 
|---|
| 187 | /* m_len should never be zero but let's avoid | 
|---|
| 188 | * an infinite loop if it somehow is */ | 
|---|
| 189 | if (map.m_len == 0) | 
|---|
| 190 | map.m_len = 1; | 
|---|
| 191 | ctx->pos += map.m_len * sb->s_blocksize; | 
|---|
| 192 | continue; | 
|---|
| 193 | } | 
|---|
| 194 | if (err > 0) { | 
|---|
| 195 | pgoff_t index = map.m_pblk >> | 
|---|
| 196 | (PAGE_SHIFT - inode->i_blkbits); | 
|---|
| 197 | if (!ra_has_index(ra: &file->f_ra, index)) | 
|---|
| 198 | page_cache_sync_readahead( | 
|---|
| 199 | mapping: sb->s_bdev->bd_mapping, | 
|---|
| 200 | ra: &file->f_ra, file, | 
|---|
| 201 | index, req_count: 1); | 
|---|
| 202 | file->f_ra.prev_pos = (loff_t)index << PAGE_SHIFT; | 
|---|
| 203 | bh = ext4_bread(NULL, inode, map.m_lblk, 0); | 
|---|
| 204 | if (IS_ERR(ptr: bh)) { | 
|---|
| 205 | err = PTR_ERR(ptr: bh); | 
|---|
| 206 | bh = NULL; | 
|---|
| 207 | goto errout; | 
|---|
| 208 | } | 
|---|
| 209 | } | 
|---|
| 210 |  | 
|---|
| 211 | if (!bh) { | 
|---|
| 212 | /* corrupt size?  Maybe no more blocks to read */ | 
|---|
| 213 | if (ctx->pos > inode->i_blocks << 9) | 
|---|
| 214 | break; | 
|---|
| 215 | ctx->pos += sb->s_blocksize - offset; | 
|---|
| 216 | continue; | 
|---|
| 217 | } | 
|---|
| 218 |  | 
|---|
| 219 | /* Check the checksum */ | 
|---|
| 220 | if (!buffer_verified(bh) && | 
|---|
| 221 | !ext4_dirblock_csum_verify(inode, bh)) { | 
|---|
| 222 | EXT4_ERROR_FILE(file, 0, "directory fails checksum " | 
|---|
| 223 | "at offset %llu", | 
|---|
| 224 | (unsigned long long)ctx->pos); | 
|---|
| 225 | ctx->pos += sb->s_blocksize - offset; | 
|---|
| 226 | brelse(bh); | 
|---|
| 227 | bh = NULL; | 
|---|
| 228 | continue; | 
|---|
| 229 | } | 
|---|
| 230 | set_buffer_verified(bh); | 
|---|
| 231 |  | 
|---|
| 232 | /* If the dir block has changed since the last call to | 
|---|
| 233 | * readdir(2), then we might be pointing to an invalid | 
|---|
| 234 | * dirent right now.  Scan from the start of the block | 
|---|
| 235 | * to make sure. */ | 
|---|
| 236 | if (!inode_eq_iversion(inode, old: info->cookie)) { | 
|---|
| 237 | for (i = 0; i < sb->s_blocksize && i < offset; ) { | 
|---|
| 238 | de = (struct ext4_dir_entry_2 *) | 
|---|
| 239 | (bh->b_data + i); | 
|---|
| 240 | /* It's too expensive to do a full | 
|---|
| 241 | * dirent test each time round this | 
|---|
| 242 | * loop, but we do have to test at | 
|---|
| 243 | * least that it is non-zero.  A | 
|---|
| 244 | * failure will be detected in the | 
|---|
| 245 | * dirent test below. */ | 
|---|
| 246 | if (ext4_rec_len_from_disk(dlen: de->rec_len, | 
|---|
| 247 | blocksize: sb->s_blocksize) < ext4_dir_rec_len(name_len: 1, | 
|---|
| 248 | dir: inode)) | 
|---|
| 249 | break; | 
|---|
| 250 | i += ext4_rec_len_from_disk(dlen: de->rec_len, | 
|---|
| 251 | blocksize: sb->s_blocksize); | 
|---|
| 252 | } | 
|---|
| 253 | offset = i; | 
|---|
| 254 | ctx->pos = (ctx->pos & ~(sb->s_blocksize - 1)) | 
|---|
| 255 | | offset; | 
|---|
| 256 | info->cookie = inode_query_iversion(inode); | 
|---|
| 257 | } | 
|---|
| 258 |  | 
|---|
| 259 | while (ctx->pos < inode->i_size | 
|---|
| 260 | && offset < sb->s_blocksize) { | 
|---|
| 261 | de = (struct ext4_dir_entry_2 *) (bh->b_data + offset); | 
|---|
| 262 | if (ext4_check_dir_entry(inode, file, de, bh, | 
|---|
| 263 | bh->b_data, bh->b_size, | 
|---|
| 264 | offset)) { | 
|---|
| 265 | /* | 
|---|
| 266 | * On error, skip to the next block | 
|---|
| 267 | */ | 
|---|
| 268 | ctx->pos = (ctx->pos | | 
|---|
| 269 | (sb->s_blocksize - 1)) + 1; | 
|---|
| 270 | break; | 
|---|
| 271 | } | 
|---|
| 272 | offset += ext4_rec_len_from_disk(dlen: de->rec_len, | 
|---|
| 273 | blocksize: sb->s_blocksize); | 
|---|
| 274 | if (le32_to_cpu(de->inode)) { | 
|---|
| 275 | if (!IS_ENCRYPTED(inode)) { | 
|---|
| 276 | if (!dir_emit(ctx, name: de->name, | 
|---|
| 277 | namelen: de->name_len, | 
|---|
| 278 | le32_to_cpu(de->inode), | 
|---|
| 279 | type: get_dtype(sb, filetype: de->file_type))) | 
|---|
| 280 | goto done; | 
|---|
| 281 | } else { | 
|---|
| 282 | int save_len = fstr.len; | 
|---|
| 283 | struct fscrypt_str de_name = | 
|---|
| 284 | FSTR_INIT(de->name, | 
|---|
| 285 | de->name_len); | 
|---|
| 286 | u32 hash; | 
|---|
| 287 | u32 minor_hash; | 
|---|
| 288 |  | 
|---|
| 289 | if (IS_CASEFOLDED(inode)) { | 
|---|
| 290 | hash = EXT4_DIRENT_HASH(de); | 
|---|
| 291 | minor_hash = EXT4_DIRENT_MINOR_HASH(de); | 
|---|
| 292 | } else { | 
|---|
| 293 | hash = 0; | 
|---|
| 294 | minor_hash = 0; | 
|---|
| 295 | } | 
|---|
| 296 |  | 
|---|
| 297 | /* Directory is encrypted */ | 
|---|
| 298 | err = fscrypt_fname_disk_to_usr(inode, | 
|---|
| 299 | hash, minor_hash, iname: &de_name, oname: &fstr); | 
|---|
| 300 | de_name = fstr; | 
|---|
| 301 | fstr.len = save_len; | 
|---|
| 302 | if (err) | 
|---|
| 303 | goto errout; | 
|---|
| 304 | if (!dir_emit(ctx, | 
|---|
| 305 | name: de_name.name, namelen: de_name.len, | 
|---|
| 306 | le32_to_cpu(de->inode), | 
|---|
| 307 | type: get_dtype(sb, filetype: de->file_type))) | 
|---|
| 308 | goto done; | 
|---|
| 309 | } | 
|---|
| 310 | } | 
|---|
| 311 | ctx->pos += ext4_rec_len_from_disk(dlen: de->rec_len, | 
|---|
| 312 | blocksize: sb->s_blocksize); | 
|---|
| 313 | } | 
|---|
| 314 | if ((ctx->pos < inode->i_size) && !dir_relax_shared(inode)) | 
|---|
| 315 | goto done; | 
|---|
| 316 | brelse(bh); | 
|---|
| 317 | bh = NULL; | 
|---|
| 318 | } | 
|---|
| 319 | done: | 
|---|
| 320 | err = 0; | 
|---|
| 321 | errout: | 
|---|
| 322 | fscrypt_fname_free_buffer(crypto_str: &fstr); | 
|---|
| 323 | brelse(bh); | 
|---|
| 324 | return err; | 
|---|
| 325 | } | 
|---|
| 326 |  | 
|---|
| 327 | static inline int is_32bit_api(void) | 
|---|
| 328 | { | 
|---|
| 329 | #ifdef CONFIG_COMPAT | 
|---|
| 330 | return in_compat_syscall(); | 
|---|
| 331 | #else | 
|---|
| 332 | return (BITS_PER_LONG == 32); | 
|---|
| 333 | #endif | 
|---|
| 334 | } | 
|---|
| 335 |  | 
|---|
| 336 | /* | 
|---|
| 337 | * These functions convert from the major/minor hash to an f_pos | 
|---|
| 338 | * value for dx directories | 
|---|
| 339 | * | 
|---|
| 340 | * Upper layer (for example NFS) should specify FMODE_32BITHASH or | 
|---|
| 341 | * FMODE_64BITHASH explicitly. On the other hand, we allow ext4 to be mounted | 
|---|
| 342 | * directly on both 32-bit and 64-bit nodes, under such case, neither | 
|---|
| 343 | * FMODE_32BITHASH nor FMODE_64BITHASH is specified. | 
|---|
| 344 | */ | 
|---|
| 345 | static inline loff_t hash2pos(struct file *filp, __u32 major, __u32 minor) | 
|---|
| 346 | { | 
|---|
| 347 | if ((filp->f_mode & FMODE_32BITHASH) || | 
|---|
| 348 | (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api())) | 
|---|
| 349 | return major >> 1; | 
|---|
| 350 | else | 
|---|
| 351 | return ((__u64)(major >> 1) << 32) | (__u64)minor; | 
|---|
| 352 | } | 
|---|
| 353 |  | 
|---|
| 354 | static inline __u32 pos2maj_hash(struct file *filp, loff_t pos) | 
|---|
| 355 | { | 
|---|
| 356 | if ((filp->f_mode & FMODE_32BITHASH) || | 
|---|
| 357 | (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api())) | 
|---|
| 358 | return (pos << 1) & 0xffffffff; | 
|---|
| 359 | else | 
|---|
| 360 | return ((pos >> 32) << 1) & 0xffffffff; | 
|---|
| 361 | } | 
|---|
| 362 |  | 
|---|
| 363 | static inline __u32 pos2min_hash(struct file *filp, loff_t pos) | 
|---|
| 364 | { | 
|---|
| 365 | if ((filp->f_mode & FMODE_32BITHASH) || | 
|---|
| 366 | (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api())) | 
|---|
| 367 | return 0; | 
|---|
| 368 | else | 
|---|
| 369 | return pos & 0xffffffff; | 
|---|
| 370 | } | 
|---|
| 371 |  | 
|---|
| 372 | /* | 
|---|
| 373 | * Return 32- or 64-bit end-of-file for dx directories | 
|---|
| 374 | */ | 
|---|
| 375 | static inline loff_t ext4_get_htree_eof(struct file *filp) | 
|---|
| 376 | { | 
|---|
| 377 | if ((filp->f_mode & FMODE_32BITHASH) || | 
|---|
| 378 | (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api())) | 
|---|
| 379 | return EXT4_HTREE_EOF_32BIT; | 
|---|
| 380 | else | 
|---|
| 381 | return EXT4_HTREE_EOF_64BIT; | 
|---|
| 382 | } | 
|---|
| 383 |  | 
|---|
| 384 |  | 
|---|
| 385 | /* | 
|---|
| 386 | * ext4_dir_llseek() calls generic_file_llseek_size to handle htree | 
|---|
| 387 | * directories, where the "offset" is in terms of the filename hash | 
|---|
| 388 | * value instead of the byte offset. | 
|---|
| 389 | * | 
|---|
| 390 | * Because we may return a 64-bit hash that is well beyond offset limits, | 
|---|
| 391 | * we need to pass the max hash as the maximum allowable offset in | 
|---|
| 392 | * the htree directory case. | 
|---|
| 393 | * | 
|---|
| 394 | * For non-htree, ext4_llseek already chooses the proper max offset. | 
|---|
| 395 | */ | 
|---|
| 396 | static loff_t ext4_dir_llseek(struct file *file, loff_t offset, int whence) | 
|---|
| 397 | { | 
|---|
| 398 | struct inode *inode = file->f_mapping->host; | 
|---|
| 399 | struct dir_private_info *info = file->private_data; | 
|---|
| 400 | int dx_dir = is_dx_dir(inode); | 
|---|
| 401 | loff_t ret, htree_max = ext4_get_htree_eof(filp: file); | 
|---|
| 402 |  | 
|---|
| 403 | if (likely(dx_dir)) | 
|---|
| 404 | ret = generic_file_llseek_size(file, offset, whence, | 
|---|
| 405 | maxsize: htree_max, eof: htree_max); | 
|---|
| 406 | else | 
|---|
| 407 | ret = ext4_llseek(file, offset, origin: whence); | 
|---|
| 408 | info->cookie = inode_peek_iversion(inode) - 1; | 
|---|
| 409 | return ret; | 
|---|
| 410 | } | 
|---|
| 411 |  | 
|---|
| 412 | /* | 
|---|
| 413 | * This structure holds the nodes of the red-black tree used to store | 
|---|
| 414 | * the directory entry in hash order. | 
|---|
| 415 | */ | 
|---|
| 416 | struct fname { | 
|---|
| 417 | __u32		hash; | 
|---|
| 418 | __u32		minor_hash; | 
|---|
| 419 | struct rb_node	rb_hash; | 
|---|
| 420 | struct fname	*next; | 
|---|
| 421 | __u32		inode; | 
|---|
| 422 | __u8		name_len; | 
|---|
| 423 | __u8		file_type; | 
|---|
| 424 | char		name[] __counted_by(name_len); | 
|---|
| 425 | }; | 
|---|
| 426 |  | 
|---|
| 427 | /* | 
|---|
| 428 | * This function implements a non-recursive way of freeing all of the | 
|---|
| 429 | * nodes in the red-black tree. | 
|---|
| 430 | */ | 
|---|
| 431 | static void free_rb_tree_fname(struct rb_root *root) | 
|---|
| 432 | { | 
|---|
| 433 | struct fname *fname, *next; | 
|---|
| 434 |  | 
|---|
| 435 | rbtree_postorder_for_each_entry_safe(fname, next, root, rb_hash) | 
|---|
| 436 | while (fname) { | 
|---|
| 437 | struct fname *old = fname; | 
|---|
| 438 | fname = fname->next; | 
|---|
| 439 | kfree(objp: old); | 
|---|
| 440 | } | 
|---|
| 441 |  | 
|---|
| 442 | *root = RB_ROOT; | 
|---|
| 443 | } | 
|---|
| 444 |  | 
|---|
| 445 | static void ext4_htree_init_dir_info(struct file *filp, loff_t pos) | 
|---|
| 446 | { | 
|---|
| 447 | struct dir_private_info *p = filp->private_data; | 
|---|
| 448 |  | 
|---|
| 449 | if (is_dx_dir(inode: file_inode(f: filp)) && !p->initialized) { | 
|---|
| 450 | p->curr_hash = pos2maj_hash(filp, pos); | 
|---|
| 451 | p->curr_minor_hash = pos2min_hash(filp, pos); | 
|---|
| 452 | p->initialized = true; | 
|---|
| 453 | } | 
|---|
| 454 | } | 
|---|
| 455 |  | 
|---|
| 456 | void ext4_htree_free_dir_info(struct dir_private_info *p) | 
|---|
| 457 | { | 
|---|
| 458 | free_rb_tree_fname(root: &p->root); | 
|---|
| 459 | kfree(objp: p); | 
|---|
| 460 | } | 
|---|
| 461 |  | 
|---|
| 462 | /* | 
|---|
| 463 | * Given a directory entry, enter it into the fname rb tree. | 
|---|
| 464 | * | 
|---|
| 465 | * When filename encryption is enabled, the dirent will hold the | 
|---|
| 466 | * encrypted filename, while the htree will hold decrypted filename. | 
|---|
| 467 | * The decrypted filename is passed in via ent_name.  parameter. | 
|---|
| 468 | */ | 
|---|
| 469 | int ext4_htree_store_dirent(struct file *dir_file, __u32 hash, | 
|---|
| 470 | __u32 minor_hash, | 
|---|
| 471 | struct ext4_dir_entry_2 *dirent, | 
|---|
| 472 | struct fscrypt_str *ent_name) | 
|---|
| 473 | { | 
|---|
| 474 | struct rb_node **p, *parent = NULL; | 
|---|
| 475 | struct fname *fname, *new_fn; | 
|---|
| 476 | struct dir_private_info *info; | 
|---|
| 477 |  | 
|---|
| 478 | info = dir_file->private_data; | 
|---|
| 479 | p = &info->root.rb_node; | 
|---|
| 480 |  | 
|---|
| 481 | /* Create and allocate the fname structure */ | 
|---|
| 482 | new_fn = kzalloc(struct_size(new_fn, name, ent_name->len + 1), | 
|---|
| 483 | GFP_KERNEL); | 
|---|
| 484 | if (!new_fn) | 
|---|
| 485 | return -ENOMEM; | 
|---|
| 486 | new_fn->hash = hash; | 
|---|
| 487 | new_fn->minor_hash = minor_hash; | 
|---|
| 488 | new_fn->inode = le32_to_cpu(dirent->inode); | 
|---|
| 489 | new_fn->name_len = ent_name->len; | 
|---|
| 490 | new_fn->file_type = dirent->file_type; | 
|---|
| 491 | memcpy(to: new_fn->name, from: ent_name->name, len: ent_name->len); | 
|---|
| 492 |  | 
|---|
| 493 | while (*p) { | 
|---|
| 494 | parent = *p; | 
|---|
| 495 | fname = rb_entry(parent, struct fname, rb_hash); | 
|---|
| 496 |  | 
|---|
| 497 | /* | 
|---|
| 498 | * If the hash and minor hash match up, then we put | 
|---|
| 499 | * them on a linked list.  This rarely happens... | 
|---|
| 500 | */ | 
|---|
| 501 | if ((new_fn->hash == fname->hash) && | 
|---|
| 502 | (new_fn->minor_hash == fname->minor_hash)) { | 
|---|
| 503 | new_fn->next = fname->next; | 
|---|
| 504 | fname->next = new_fn; | 
|---|
| 505 | return 0; | 
|---|
| 506 | } | 
|---|
| 507 |  | 
|---|
| 508 | if (new_fn->hash < fname->hash) | 
|---|
| 509 | p = &(*p)->rb_left; | 
|---|
| 510 | else if (new_fn->hash > fname->hash) | 
|---|
| 511 | p = &(*p)->rb_right; | 
|---|
| 512 | else if (new_fn->minor_hash < fname->minor_hash) | 
|---|
| 513 | p = &(*p)->rb_left; | 
|---|
| 514 | else /* if (new_fn->minor_hash > fname->minor_hash) */ | 
|---|
| 515 | p = &(*p)->rb_right; | 
|---|
| 516 | } | 
|---|
| 517 |  | 
|---|
| 518 | rb_link_node(node: &new_fn->rb_hash, parent, rb_link: p); | 
|---|
| 519 | rb_insert_color(&new_fn->rb_hash, &info->root); | 
|---|
| 520 | return 0; | 
|---|
| 521 | } | 
|---|
| 522 |  | 
|---|
| 523 |  | 
|---|
| 524 |  | 
|---|
| 525 | /* | 
|---|
| 526 | * This is a helper function for ext4_dx_readdir.  It calls filldir | 
|---|
| 527 | * for all entries on the fname linked list.  (Normally there is only | 
|---|
| 528 | * one entry on the linked list, unless there are 62 bit hash collisions.) | 
|---|
| 529 | */ | 
|---|
| 530 | static int call_filldir(struct file *file, struct dir_context *ctx, | 
|---|
| 531 | struct fname *fname) | 
|---|
| 532 | { | 
|---|
| 533 | struct dir_private_info *info = file->private_data; | 
|---|
| 534 | struct inode *inode = file_inode(f: file); | 
|---|
| 535 | struct super_block *sb = inode->i_sb; | 
|---|
| 536 |  | 
|---|
| 537 | if (!fname) { | 
|---|
| 538 | ext4_msg(sb, KERN_ERR, "%s:%d: inode #%lu: comm %s: " | 
|---|
| 539 | "called with null fname?!?", __func__, __LINE__, | 
|---|
| 540 | inode->i_ino, current->comm); | 
|---|
| 541 | return 0; | 
|---|
| 542 | } | 
|---|
| 543 | ctx->pos = hash2pos(filp: file, major: fname->hash, minor: fname->minor_hash); | 
|---|
| 544 | while (fname) { | 
|---|
| 545 | if (!dir_emit(ctx, name: fname->name, | 
|---|
| 546 | namelen: fname->name_len, | 
|---|
| 547 | ino: fname->inode, | 
|---|
| 548 | type: get_dtype(sb, filetype: fname->file_type))) { | 
|---|
| 549 | info->extra_fname = fname; | 
|---|
| 550 | return 1; | 
|---|
| 551 | } | 
|---|
| 552 | fname = fname->next; | 
|---|
| 553 | } | 
|---|
| 554 | return 0; | 
|---|
| 555 | } | 
|---|
| 556 |  | 
|---|
| 557 | static int ext4_dx_readdir(struct file *file, struct dir_context *ctx) | 
|---|
| 558 | { | 
|---|
| 559 | struct dir_private_info *info = file->private_data; | 
|---|
| 560 | struct inode *inode = file_inode(f: file); | 
|---|
| 561 | struct fname *fname; | 
|---|
| 562 | int ret = 0; | 
|---|
| 563 |  | 
|---|
| 564 | ext4_htree_init_dir_info(filp: file, pos: ctx->pos); | 
|---|
| 565 |  | 
|---|
| 566 | if (ctx->pos == ext4_get_htree_eof(filp: file)) | 
|---|
| 567 | return 0;	/* EOF */ | 
|---|
| 568 |  | 
|---|
| 569 | /* Some one has messed with f_pos; reset the world */ | 
|---|
| 570 | if (info->last_pos != ctx->pos) { | 
|---|
| 571 | free_rb_tree_fname(root: &info->root); | 
|---|
| 572 | info->curr_node = NULL; | 
|---|
| 573 | info->extra_fname = NULL; | 
|---|
| 574 | info->curr_hash = pos2maj_hash(filp: file, pos: ctx->pos); | 
|---|
| 575 | info->curr_minor_hash = pos2min_hash(filp: file, pos: ctx->pos); | 
|---|
| 576 | } | 
|---|
| 577 |  | 
|---|
| 578 | /* | 
|---|
| 579 | * If there are any leftover names on the hash collision | 
|---|
| 580 | * chain, return them first. | 
|---|
| 581 | */ | 
|---|
| 582 | if (info->extra_fname) { | 
|---|
| 583 | if (call_filldir(file, ctx, fname: info->extra_fname)) | 
|---|
| 584 | goto finished; | 
|---|
| 585 | info->extra_fname = NULL; | 
|---|
| 586 | goto next_node; | 
|---|
| 587 | } else if (!info->curr_node) | 
|---|
| 588 | info->curr_node = rb_first(&info->root); | 
|---|
| 589 |  | 
|---|
| 590 | while (1) { | 
|---|
| 591 | /* | 
|---|
| 592 | * Fill the rbtree if we have no more entries, | 
|---|
| 593 | * or the inode has changed since we last read in the | 
|---|
| 594 | * cached entries. | 
|---|
| 595 | */ | 
|---|
| 596 | if ((!info->curr_node) || | 
|---|
| 597 | !inode_eq_iversion(inode, old: info->cookie)) { | 
|---|
| 598 | info->curr_node = NULL; | 
|---|
| 599 | free_rb_tree_fname(root: &info->root); | 
|---|
| 600 | info->cookie = inode_query_iversion(inode); | 
|---|
| 601 | ret = ext4_htree_fill_tree(dir_file: file, start_hash: info->curr_hash, | 
|---|
| 602 | start_minor_hash: info->curr_minor_hash, | 
|---|
| 603 | next_hash: &info->next_hash); | 
|---|
| 604 | if (ret < 0) | 
|---|
| 605 | goto finished; | 
|---|
| 606 | if (ret == 0) { | 
|---|
| 607 | ctx->pos = ext4_get_htree_eof(filp: file); | 
|---|
| 608 | break; | 
|---|
| 609 | } | 
|---|
| 610 | info->curr_node = rb_first(&info->root); | 
|---|
| 611 | } | 
|---|
| 612 |  | 
|---|
| 613 | fname = rb_entry(info->curr_node, struct fname, rb_hash); | 
|---|
| 614 | info->curr_hash = fname->hash; | 
|---|
| 615 | info->curr_minor_hash = fname->minor_hash; | 
|---|
| 616 | if (call_filldir(file, ctx, fname)) | 
|---|
| 617 | break; | 
|---|
| 618 | next_node: | 
|---|
| 619 | info->curr_node = rb_next(info->curr_node); | 
|---|
| 620 | if (info->curr_node) { | 
|---|
| 621 | fname = rb_entry(info->curr_node, struct fname, | 
|---|
| 622 | rb_hash); | 
|---|
| 623 | info->curr_hash = fname->hash; | 
|---|
| 624 | info->curr_minor_hash = fname->minor_hash; | 
|---|
| 625 | } else { | 
|---|
| 626 | if (info->next_hash == ~0) { | 
|---|
| 627 | ctx->pos = ext4_get_htree_eof(filp: file); | 
|---|
| 628 | break; | 
|---|
| 629 | } | 
|---|
| 630 | info->curr_hash = info->next_hash; | 
|---|
| 631 | info->curr_minor_hash = 0; | 
|---|
| 632 | } | 
|---|
| 633 | } | 
|---|
| 634 | finished: | 
|---|
| 635 | info->last_pos = ctx->pos; | 
|---|
| 636 | return ret < 0 ? ret : 0; | 
|---|
| 637 | } | 
|---|
| 638 |  | 
|---|
| 639 | static int ext4_release_dir(struct inode *inode, struct file *filp) | 
|---|
| 640 | { | 
|---|
| 641 | if (filp->private_data) | 
|---|
| 642 | ext4_htree_free_dir_info(p: filp->private_data); | 
|---|
| 643 |  | 
|---|
| 644 | return 0; | 
|---|
| 645 | } | 
|---|
| 646 |  | 
|---|
| 647 | int ext4_check_all_de(struct inode *dir, struct buffer_head *bh, void *buf, | 
|---|
| 648 | int buf_size) | 
|---|
| 649 | { | 
|---|
| 650 | struct ext4_dir_entry_2 *de; | 
|---|
| 651 | int rlen; | 
|---|
| 652 | unsigned int offset = 0; | 
|---|
| 653 | char *top; | 
|---|
| 654 |  | 
|---|
| 655 | de = buf; | 
|---|
| 656 | top = buf + buf_size; | 
|---|
| 657 | while ((char *) de < top) { | 
|---|
| 658 | if (ext4_check_dir_entry(dir, NULL, de, bh, | 
|---|
| 659 | buf, buf_size, offset)) | 
|---|
| 660 | return -EFSCORRUPTED; | 
|---|
| 661 | rlen = ext4_rec_len_from_disk(dlen: de->rec_len, blocksize: buf_size); | 
|---|
| 662 | de = (struct ext4_dir_entry_2 *)((char *)de + rlen); | 
|---|
| 663 | offset += rlen; | 
|---|
| 664 | } | 
|---|
| 665 | if ((char *) de > top) | 
|---|
| 666 | return -EFSCORRUPTED; | 
|---|
| 667 |  | 
|---|
| 668 | return 0; | 
|---|
| 669 | } | 
|---|
| 670 |  | 
|---|
| 671 | static int ext4_dir_open(struct inode *inode, struct file *file) | 
|---|
| 672 | { | 
|---|
| 673 | struct dir_private_info *info; | 
|---|
| 674 |  | 
|---|
| 675 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 
|---|
| 676 | if (!info) | 
|---|
| 677 | return -ENOMEM; | 
|---|
| 678 | file->private_data = info; | 
|---|
| 679 | return 0; | 
|---|
| 680 | } | 
|---|
| 681 |  | 
|---|
| 682 | const struct file_operations ext4_dir_operations = { | 
|---|
| 683 | .open		= ext4_dir_open, | 
|---|
| 684 | .llseek		= ext4_dir_llseek, | 
|---|
| 685 | .read		= generic_read_dir, | 
|---|
| 686 | .iterate_shared	= ext4_readdir, | 
|---|
| 687 | .unlocked_ioctl = ext4_ioctl, | 
|---|
| 688 | #ifdef CONFIG_COMPAT | 
|---|
| 689 | .compat_ioctl	= ext4_compat_ioctl, | 
|---|
| 690 | #endif | 
|---|
| 691 | .fsync		= ext4_sync_file, | 
|---|
| 692 | .release	= ext4_release_dir, | 
|---|
| 693 | }; | 
|---|
| 694 |  | 
|---|