cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dir.c (3489B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 *  linux/fs/affs/dir.c
      4 *
      5 *  (c) 1996  Hans-Joachim Widmaier - Rewritten
      6 *
      7 *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
      8 *
      9 *  (C) 1992  Eric Youngdale Modified for ISO 9660 filesystem.
     10 *
     11 *  (C) 1991  Linus Torvalds - minix filesystem
     12 *
     13 *  affs directory handling functions
     14 *
     15 */
     16
     17#include <linux/iversion.h>
     18#include "affs.h"
     19
     20static int affs_readdir(struct file *, struct dir_context *);
     21
     22const struct file_operations affs_dir_operations = {
     23	.read		= generic_read_dir,
     24	.llseek		= generic_file_llseek,
     25	.iterate_shared	= affs_readdir,
     26	.fsync		= affs_file_fsync,
     27};
     28
     29/*
     30 * directories can handle most operations...
     31 */
     32const struct inode_operations affs_dir_inode_operations = {
     33	.create		= affs_create,
     34	.lookup		= affs_lookup,
     35	.link		= affs_link,
     36	.unlink		= affs_unlink,
     37	.symlink	= affs_symlink,
     38	.mkdir		= affs_mkdir,
     39	.rmdir		= affs_rmdir,
     40	.rename		= affs_rename2,
     41	.setattr	= affs_notify_change,
     42};
     43
     44static int
     45affs_readdir(struct file *file, struct dir_context *ctx)
     46{
     47	struct inode		*inode = file_inode(file);
     48	struct super_block	*sb = inode->i_sb;
     49	struct buffer_head	*dir_bh = NULL;
     50	struct buffer_head	*fh_bh = NULL;
     51	unsigned char		*name;
     52	int			 namelen;
     53	u32			 i;
     54	int			 hash_pos;
     55	int			 chain_pos;
     56	u32			 ino;
     57	int			 error = 0;
     58
     59	pr_debug("%s(ino=%lu,f_pos=%llx)\n", __func__, inode->i_ino, ctx->pos);
     60
     61	if (ctx->pos < 2) {
     62		file->private_data = (void *)0;
     63		if (!dir_emit_dots(file, ctx))
     64			return 0;
     65	}
     66
     67	affs_lock_dir(inode);
     68	chain_pos = (ctx->pos - 2) & 0xffff;
     69	hash_pos  = (ctx->pos - 2) >> 16;
     70	if (chain_pos == 0xffff) {
     71		affs_warning(sb, "readdir", "More than 65535 entries in chain");
     72		chain_pos = 0;
     73		hash_pos++;
     74		ctx->pos = ((hash_pos << 16) | chain_pos) + 2;
     75	}
     76	dir_bh = affs_bread(sb, inode->i_ino);
     77	if (!dir_bh)
     78		goto out_unlock_dir;
     79
     80	/* If the directory hasn't changed since the last call to readdir(),
     81	 * we can jump directly to where we left off.
     82	 */
     83	ino = (u32)(long)file->private_data;
     84	if (ino && inode_eq_iversion(inode, file->f_version)) {
     85		pr_debug("readdir() left off=%d\n", ino);
     86		goto inside;
     87	}
     88
     89	ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]);
     90	for (i = 0; ino && i < chain_pos; i++) {
     91		fh_bh = affs_bread(sb, ino);
     92		if (!fh_bh) {
     93			affs_error(sb, "readdir","Cannot read block %d", i);
     94			error = -EIO;
     95			goto out_brelse_dir;
     96		}
     97		ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
     98		affs_brelse(fh_bh);
     99		fh_bh = NULL;
    100	}
    101	if (ino)
    102		goto inside;
    103	hash_pos++;
    104
    105	for (; hash_pos < AFFS_SB(sb)->s_hashsize; hash_pos++) {
    106		ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]);
    107		if (!ino)
    108			continue;
    109		ctx->pos = (hash_pos << 16) + 2;
    110inside:
    111		do {
    112			fh_bh = affs_bread(sb, ino);
    113			if (!fh_bh) {
    114				affs_error(sb, "readdir",
    115					   "Cannot read block %d", ino);
    116				break;
    117			}
    118
    119			namelen = min(AFFS_TAIL(sb, fh_bh)->name[0],
    120				      (u8)AFFSNAMEMAX);
    121			name = AFFS_TAIL(sb, fh_bh)->name + 1;
    122			pr_debug("readdir(): dir_emit(\"%.*s\", ino=%u), hash=%d, f_pos=%llx\n",
    123				 namelen, name, ino, hash_pos, ctx->pos);
    124
    125			if (!dir_emit(ctx, name, namelen, ino, DT_UNKNOWN))
    126				goto done;
    127			ctx->pos++;
    128			ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
    129			affs_brelse(fh_bh);
    130			fh_bh = NULL;
    131		} while (ino);
    132	}
    133done:
    134	file->f_version = inode_query_iversion(inode);
    135	file->private_data = (void *)(long)ino;
    136	affs_brelse(fh_bh);
    137
    138out_brelse_dir:
    139	affs_brelse(dir_bh);
    140
    141out_unlock_dir:
    142	affs_unlock_dir(inode);
    143	return error;
    144}