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

namei.c (4251B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 *  linux/fs/isofs/namei.c
      4 *
      5 *  (C) 1992  Eric Youngdale Modified for ISO 9660 filesystem.
      6 *
      7 *  (C) 1991  Linus Torvalds - minix filesystem
      8 */
      9
     10#include <linux/gfp.h>
     11#include "isofs.h"
     12
     13/*
     14 * ok, we cannot use strncmp, as the name is not in our data space.
     15 * Thus we'll have to use isofs_match. No big problem. Match also makes
     16 * some sanity tests.
     17 */
     18static int
     19isofs_cmp(struct dentry *dentry, const char *compare, int dlen)
     20{
     21	struct qstr qstr;
     22	qstr.name = compare;
     23	qstr.len = dlen;
     24	if (likely(!dentry->d_op))
     25		return dentry->d_name.len != dlen || memcmp(dentry->d_name.name, compare, dlen);
     26	return dentry->d_op->d_compare(NULL, dentry->d_name.len, dentry->d_name.name, &qstr);
     27}
     28
     29/*
     30 *	isofs_find_entry()
     31 *
     32 * finds an entry in the specified directory with the wanted name. It
     33 * returns the inode number of the found entry, or 0 on error.
     34 */
     35static unsigned long
     36isofs_find_entry(struct inode *dir, struct dentry *dentry,
     37	unsigned long *block_rv, unsigned long *offset_rv,
     38	char *tmpname, struct iso_directory_record *tmpde)
     39{
     40	unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
     41	unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
     42	unsigned long block, f_pos, offset, block_saved, offset_saved;
     43	struct buffer_head *bh = NULL;
     44	struct isofs_sb_info *sbi = ISOFS_SB(dir->i_sb);
     45
     46	if (!ISOFS_I(dir)->i_first_extent)
     47		return 0;
     48
     49	f_pos = 0;
     50	offset = 0;
     51	block = 0;
     52
     53	while (f_pos < dir->i_size) {
     54		struct iso_directory_record *de;
     55		int de_len, match, i, dlen;
     56		char *dpnt;
     57
     58		if (!bh) {
     59			bh = isofs_bread(dir, block);
     60			if (!bh)
     61				return 0;
     62		}
     63
     64		de = (struct iso_directory_record *) (bh->b_data + offset);
     65
     66		de_len = *(unsigned char *) de;
     67		if (!de_len) {
     68			brelse(bh);
     69			bh = NULL;
     70			f_pos = (f_pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1);
     71			block = f_pos >> bufbits;
     72			offset = 0;
     73			continue;
     74		}
     75
     76		block_saved = bh->b_blocknr;
     77		offset_saved = offset;
     78		offset += de_len;
     79		f_pos += de_len;
     80
     81		/* Make sure we have a full directory entry */
     82		if (offset >= bufsize) {
     83			int slop = bufsize - offset + de_len;
     84			memcpy(tmpde, de, slop);
     85			offset &= bufsize - 1;
     86			block++;
     87			brelse(bh);
     88			bh = NULL;
     89			if (offset) {
     90				bh = isofs_bread(dir, block);
     91				if (!bh)
     92					return 0;
     93				memcpy((void *) tmpde + slop, bh->b_data, offset);
     94			}
     95			de = tmpde;
     96		}
     97
     98		dlen = de->name_len[0];
     99		dpnt = de->name;
    100		/* Basic sanity check, whether name doesn't exceed dir entry */
    101		if (de_len < dlen + sizeof(struct iso_directory_record)) {
    102			printk(KERN_NOTICE "iso9660: Corrupted directory entry"
    103			       " in block %lu of inode %lu\n", block,
    104			       dir->i_ino);
    105			brelse(bh);
    106			return 0;
    107		}
    108
    109		if (sbi->s_rock &&
    110		    ((i = get_rock_ridge_filename(de, tmpname, dir)))) {
    111			dlen = i;	/* possibly -1 */
    112			dpnt = tmpname;
    113#ifdef CONFIG_JOLIET
    114		} else if (sbi->s_joliet_level) {
    115			dlen = get_joliet_filename(de, tmpname, dir);
    116			dpnt = tmpname;
    117#endif
    118		} else if (sbi->s_mapping == 'a') {
    119			dlen = get_acorn_filename(de, tmpname, dir);
    120			dpnt = tmpname;
    121		} else if (sbi->s_mapping == 'n') {
    122			dlen = isofs_name_translate(de, tmpname, dir);
    123			dpnt = tmpname;
    124		}
    125
    126		/*
    127		 * Skip hidden or associated files unless hide or showassoc,
    128		 * respectively, is set
    129		 */
    130		match = 0;
    131		if (dlen > 0 &&
    132			(!sbi->s_hide ||
    133				(!(de->flags[-sbi->s_high_sierra] & 1))) &&
    134			(sbi->s_showassoc ||
    135				(!(de->flags[-sbi->s_high_sierra] & 4)))) {
    136			if (dpnt && (dlen > 1 || dpnt[0] > 1))
    137				match = (isofs_cmp(dentry, dpnt, dlen) == 0);
    138		}
    139		if (match) {
    140			isofs_normalize_block_and_offset(de,
    141							 &block_saved,
    142							 &offset_saved);
    143			*block_rv = block_saved;
    144			*offset_rv = offset_saved;
    145			brelse(bh);
    146			return 1;
    147		}
    148	}
    149	brelse(bh);
    150	return 0;
    151}
    152
    153struct dentry *isofs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
    154{
    155	int found;
    156	unsigned long block;
    157	unsigned long offset;
    158	struct inode *inode;
    159	struct page *page;
    160
    161	page = alloc_page(GFP_USER);
    162	if (!page)
    163		return ERR_PTR(-ENOMEM);
    164
    165	found = isofs_find_entry(dir, dentry,
    166				&block, &offset,
    167				page_address(page),
    168				1024 + page_address(page));
    169	__free_page(page);
    170
    171	inode = found ? isofs_iget(dir->i_sb, block, offset) : NULL;
    172
    173	return d_splice_alias(inode, dentry);
    174}