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 (13630B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 *  linux/fs/affs/namei.c
      4 *
      5 *  (c) 1996  Hans-Joachim Widmaier - Rewritten
      6 *
      7 *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
      8 *
      9 *  (C) 1991  Linus Torvalds - minix filesystem
     10 */
     11
     12#include "affs.h"
     13#include <linux/exportfs.h>
     14
     15typedef int (*toupper_t)(int);
     16
     17/* Simple toupper() for DOS\1 */
     18
     19static int
     20affs_toupper(int ch)
     21{
     22	return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch;
     23}
     24
     25/* International toupper() for DOS\3 ("international") */
     26
     27static int
     28affs_intl_toupper(int ch)
     29{
     30	return (ch >= 'a' && ch <= 'z') || (ch >= 0xE0
     31		&& ch <= 0xFE && ch != 0xF7) ?
     32		ch - ('a' - 'A') : ch;
     33}
     34
     35static inline toupper_t
     36affs_get_toupper(struct super_block *sb)
     37{
     38	return affs_test_opt(AFFS_SB(sb)->s_flags, SF_INTL) ?
     39	       affs_intl_toupper : affs_toupper;
     40}
     41
     42/*
     43 * Note: the dentry argument is the parent dentry.
     44 */
     45static inline int
     46__affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr, toupper_t toupper, bool notruncate)
     47{
     48	const u8 *name = qstr->name;
     49	unsigned long hash;
     50	int retval;
     51	u32 len;
     52
     53	retval = affs_check_name(qstr->name, qstr->len, notruncate);
     54	if (retval)
     55		return retval;
     56
     57	hash = init_name_hash(dentry);
     58	len = min(qstr->len, AFFSNAMEMAX);
     59	for (; len > 0; name++, len--)
     60		hash = partial_name_hash(toupper(*name), hash);
     61	qstr->hash = end_name_hash(hash);
     62
     63	return 0;
     64}
     65
     66static int
     67affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
     68{
     69	return __affs_hash_dentry(dentry, qstr, affs_toupper,
     70				  affs_nofilenametruncate(dentry));
     71
     72}
     73
     74static int
     75affs_intl_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
     76{
     77	return __affs_hash_dentry(dentry, qstr, affs_intl_toupper,
     78				  affs_nofilenametruncate(dentry));
     79
     80}
     81
     82static inline int __affs_compare_dentry(unsigned int len,
     83		const char *str, const struct qstr *name, toupper_t toupper,
     84		bool notruncate)
     85{
     86	const u8 *aname = str;
     87	const u8 *bname = name->name;
     88
     89	/*
     90	 * 'str' is the name of an already existing dentry, so the name
     91	 * must be valid. 'name' must be validated first.
     92	 */
     93
     94	if (affs_check_name(name->name, name->len, notruncate))
     95		return 1;
     96
     97	/*
     98	 * If the names are longer than the allowed 30 chars,
     99	 * the excess is ignored, so their length may differ.
    100	 */
    101	if (len >= AFFSNAMEMAX) {
    102		if (name->len < AFFSNAMEMAX)
    103			return 1;
    104		len = AFFSNAMEMAX;
    105	} else if (len != name->len)
    106		return 1;
    107
    108	for (; len > 0; len--)
    109		if (toupper(*aname++) != toupper(*bname++))
    110			return 1;
    111
    112	return 0;
    113}
    114
    115static int
    116affs_compare_dentry(const struct dentry *dentry,
    117		unsigned int len, const char *str, const struct qstr *name)
    118{
    119
    120	return __affs_compare_dentry(len, str, name, affs_toupper,
    121				     affs_nofilenametruncate(dentry));
    122}
    123
    124static int
    125affs_intl_compare_dentry(const struct dentry *dentry,
    126		unsigned int len, const char *str, const struct qstr *name)
    127{
    128	return __affs_compare_dentry(len, str, name, affs_intl_toupper,
    129				     affs_nofilenametruncate(dentry));
    130
    131}
    132
    133/*
    134 * NOTE! unlike strncmp, affs_match returns 1 for success, 0 for failure.
    135 */
    136
    137static inline int
    138affs_match(struct dentry *dentry, const u8 *name2, toupper_t toupper)
    139{
    140	const u8 *name = dentry->d_name.name;
    141	int len = dentry->d_name.len;
    142
    143	if (len >= AFFSNAMEMAX) {
    144		if (*name2 < AFFSNAMEMAX)
    145			return 0;
    146		len = AFFSNAMEMAX;
    147	} else if (len != *name2)
    148		return 0;
    149
    150	for (name2++; len > 0; len--)
    151		if (toupper(*name++) != toupper(*name2++))
    152			return 0;
    153	return 1;
    154}
    155
    156int
    157affs_hash_name(struct super_block *sb, const u8 *name, unsigned int len)
    158{
    159	toupper_t toupper = affs_get_toupper(sb);
    160	u32 hash;
    161
    162	hash = len = min(len, AFFSNAMEMAX);
    163	for (; len > 0; len--)
    164		hash = (hash * 13 + toupper(*name++)) & 0x7ff;
    165
    166	return hash % AFFS_SB(sb)->s_hashsize;
    167}
    168
    169static struct buffer_head *
    170affs_find_entry(struct inode *dir, struct dentry *dentry)
    171{
    172	struct super_block *sb = dir->i_sb;
    173	struct buffer_head *bh;
    174	toupper_t toupper = affs_get_toupper(sb);
    175	u32 key;
    176
    177	pr_debug("%s(\"%pd\")\n", __func__, dentry);
    178
    179	bh = affs_bread(sb, dir->i_ino);
    180	if (!bh)
    181		return ERR_PTR(-EIO);
    182
    183	key = be32_to_cpu(AFFS_HEAD(bh)->table[affs_hash_name(sb, dentry->d_name.name, dentry->d_name.len)]);
    184
    185	for (;;) {
    186		affs_brelse(bh);
    187		if (key == 0)
    188			return NULL;
    189		bh = affs_bread(sb, key);
    190		if (!bh)
    191			return ERR_PTR(-EIO);
    192		if (affs_match(dentry, AFFS_TAIL(sb, bh)->name, toupper))
    193			return bh;
    194		key = be32_to_cpu(AFFS_TAIL(sb, bh)->hash_chain);
    195	}
    196}
    197
    198struct dentry *
    199affs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
    200{
    201	struct super_block *sb = dir->i_sb;
    202	struct buffer_head *bh;
    203	struct inode *inode = NULL;
    204	struct dentry *res;
    205
    206	pr_debug("%s(\"%pd\")\n", __func__, dentry);
    207
    208	affs_lock_dir(dir);
    209	bh = affs_find_entry(dir, dentry);
    210	if (IS_ERR(bh)) {
    211		affs_unlock_dir(dir);
    212		return ERR_CAST(bh);
    213	}
    214	if (bh) {
    215		u32 ino = bh->b_blocknr;
    216
    217		/* store the real header ino in d_fsdata for faster lookups */
    218		dentry->d_fsdata = (void *)(long)ino;
    219		switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
    220		//link to dirs disabled
    221		//case ST_LINKDIR:
    222		case ST_LINKFILE:
    223			ino = be32_to_cpu(AFFS_TAIL(sb, bh)->original);
    224		}
    225		affs_brelse(bh);
    226		inode = affs_iget(sb, ino);
    227	}
    228	res = d_splice_alias(inode, dentry);
    229	if (!IS_ERR_OR_NULL(res))
    230		res->d_fsdata = dentry->d_fsdata;
    231	affs_unlock_dir(dir);
    232	return res;
    233}
    234
    235int
    236affs_unlink(struct inode *dir, struct dentry *dentry)
    237{
    238	pr_debug("%s(dir=%lu, %lu \"%pd\")\n", __func__, dir->i_ino,
    239		 d_inode(dentry)->i_ino, dentry);
    240
    241	return affs_remove_header(dentry);
    242}
    243
    244int
    245affs_create(struct user_namespace *mnt_userns, struct inode *dir,
    246	    struct dentry *dentry, umode_t mode, bool excl)
    247{
    248	struct super_block *sb = dir->i_sb;
    249	struct inode	*inode;
    250	int		 error;
    251
    252	pr_debug("%s(%lu,\"%pd\",0%ho)\n",
    253		 __func__, dir->i_ino, dentry, mode);
    254
    255	inode = affs_new_inode(dir);
    256	if (!inode)
    257		return -ENOSPC;
    258
    259	inode->i_mode = mode;
    260	affs_mode_to_prot(inode);
    261	mark_inode_dirty(inode);
    262
    263	inode->i_op = &affs_file_inode_operations;
    264	inode->i_fop = &affs_file_operations;
    265	inode->i_mapping->a_ops = affs_test_opt(AFFS_SB(sb)->s_flags, SF_OFS) ?
    266				  &affs_aops_ofs : &affs_aops;
    267	error = affs_add_entry(dir, inode, dentry, ST_FILE);
    268	if (error) {
    269		clear_nlink(inode);
    270		iput(inode);
    271		return error;
    272	}
    273	return 0;
    274}
    275
    276int
    277affs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
    278	   struct dentry *dentry, umode_t mode)
    279{
    280	struct inode		*inode;
    281	int			 error;
    282
    283	pr_debug("%s(%lu,\"%pd\",0%ho)\n",
    284		 __func__, dir->i_ino, dentry, mode);
    285
    286	inode = affs_new_inode(dir);
    287	if (!inode)
    288		return -ENOSPC;
    289
    290	inode->i_mode = S_IFDIR | mode;
    291	affs_mode_to_prot(inode);
    292
    293	inode->i_op = &affs_dir_inode_operations;
    294	inode->i_fop = &affs_dir_operations;
    295
    296	error = affs_add_entry(dir, inode, dentry, ST_USERDIR);
    297	if (error) {
    298		clear_nlink(inode);
    299		mark_inode_dirty(inode);
    300		iput(inode);
    301		return error;
    302	}
    303	return 0;
    304}
    305
    306int
    307affs_rmdir(struct inode *dir, struct dentry *dentry)
    308{
    309	pr_debug("%s(dir=%lu, %lu \"%pd\")\n", __func__, dir->i_ino,
    310		 d_inode(dentry)->i_ino, dentry);
    311
    312	return affs_remove_header(dentry);
    313}
    314
    315int
    316affs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
    317	     struct dentry *dentry, const char *symname)
    318{
    319	struct super_block	*sb = dir->i_sb;
    320	struct buffer_head	*bh;
    321	struct inode		*inode;
    322	char			*p;
    323	int			 i, maxlen, error;
    324	char			 c, lc;
    325
    326	pr_debug("%s(%lu,\"%pd\" -> \"%s\")\n",
    327		 __func__, dir->i_ino, dentry, symname);
    328
    329	maxlen = AFFS_SB(sb)->s_hashsize * sizeof(u32) - 1;
    330	inode  = affs_new_inode(dir);
    331	if (!inode)
    332		return -ENOSPC;
    333
    334	inode->i_op = &affs_symlink_inode_operations;
    335	inode_nohighmem(inode);
    336	inode->i_data.a_ops = &affs_symlink_aops;
    337	inode->i_mode = S_IFLNK | 0777;
    338	affs_mode_to_prot(inode);
    339
    340	error = -EIO;
    341	bh = affs_bread(sb, inode->i_ino);
    342	if (!bh)
    343		goto err;
    344	i  = 0;
    345	p  = (char *)AFFS_HEAD(bh)->table;
    346	lc = '/';
    347	if (*symname == '/') {
    348		struct affs_sb_info *sbi = AFFS_SB(sb);
    349		while (*symname == '/')
    350			symname++;
    351		spin_lock(&sbi->symlink_lock);
    352		while (sbi->s_volume[i])	/* Cannot overflow */
    353			*p++ = sbi->s_volume[i++];
    354		spin_unlock(&sbi->symlink_lock);
    355	}
    356	while (i < maxlen && (c = *symname++)) {
    357		if (c == '.' && lc == '/' && *symname == '.' && symname[1] == '/') {
    358			*p++ = '/';
    359			i++;
    360			symname += 2;
    361			lc = '/';
    362		} else if (c == '.' && lc == '/' && *symname == '/') {
    363			symname++;
    364			lc = '/';
    365		} else {
    366			*p++ = c;
    367			lc   = c;
    368			i++;
    369		}
    370		if (lc == '/')
    371			while (*symname == '/')
    372				symname++;
    373	}
    374	*p = 0;
    375	inode->i_size = i + 1;
    376	mark_buffer_dirty_inode(bh, inode);
    377	affs_brelse(bh);
    378	mark_inode_dirty(inode);
    379
    380	error = affs_add_entry(dir, inode, dentry, ST_SOFTLINK);
    381	if (error)
    382		goto err;
    383
    384	return 0;
    385
    386err:
    387	clear_nlink(inode);
    388	mark_inode_dirty(inode);
    389	iput(inode);
    390	return error;
    391}
    392
    393int
    394affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
    395{
    396	struct inode *inode = d_inode(old_dentry);
    397
    398	pr_debug("%s(%lu, %lu, \"%pd\")\n", __func__, inode->i_ino, dir->i_ino,
    399		 dentry);
    400
    401	return affs_add_entry(dir, inode, dentry, ST_LINKFILE);
    402}
    403
    404static int
    405affs_rename(struct inode *old_dir, struct dentry *old_dentry,
    406	    struct inode *new_dir, struct dentry *new_dentry)
    407{
    408	struct super_block *sb = old_dir->i_sb;
    409	struct buffer_head *bh = NULL;
    410	int retval;
    411
    412	retval = affs_check_name(new_dentry->d_name.name,
    413				 new_dentry->d_name.len,
    414				 affs_nofilenametruncate(old_dentry));
    415
    416	if (retval)
    417		return retval;
    418
    419	/* Unlink destination if it already exists */
    420	if (d_really_is_positive(new_dentry)) {
    421		retval = affs_remove_header(new_dentry);
    422		if (retval)
    423			return retval;
    424	}
    425
    426	bh = affs_bread(sb, d_inode(old_dentry)->i_ino);
    427	if (!bh)
    428		return -EIO;
    429
    430	/* Remove header from its parent directory. */
    431	affs_lock_dir(old_dir);
    432	retval = affs_remove_hash(old_dir, bh);
    433	affs_unlock_dir(old_dir);
    434	if (retval)
    435		goto done;
    436
    437	/* And insert it into the new directory with the new name. */
    438	affs_copy_name(AFFS_TAIL(sb, bh)->name, new_dentry);
    439	affs_fix_checksum(sb, bh);
    440	affs_lock_dir(new_dir);
    441	retval = affs_insert_hash(new_dir, bh);
    442	affs_unlock_dir(new_dir);
    443	/* TODO: move it back to old_dir, if error? */
    444
    445done:
    446	mark_buffer_dirty_inode(bh, retval ? old_dir : new_dir);
    447	affs_brelse(bh);
    448	return retval;
    449}
    450
    451static int
    452affs_xrename(struct inode *old_dir, struct dentry *old_dentry,
    453	     struct inode *new_dir, struct dentry *new_dentry)
    454{
    455
    456	struct super_block *sb = old_dir->i_sb;
    457	struct buffer_head *bh_old = NULL;
    458	struct buffer_head *bh_new = NULL;
    459	int retval;
    460
    461	bh_old = affs_bread(sb, d_inode(old_dentry)->i_ino);
    462	if (!bh_old)
    463		return -EIO;
    464
    465	bh_new = affs_bread(sb, d_inode(new_dentry)->i_ino);
    466	if (!bh_new) {
    467		affs_brelse(bh_old);
    468		return -EIO;
    469	}
    470
    471	/* Remove old header from its parent directory. */
    472	affs_lock_dir(old_dir);
    473	retval = affs_remove_hash(old_dir, bh_old);
    474	affs_unlock_dir(old_dir);
    475	if (retval)
    476		goto done;
    477
    478	/* Remove new header from its parent directory. */
    479	affs_lock_dir(new_dir);
    480	retval = affs_remove_hash(new_dir, bh_new);
    481	affs_unlock_dir(new_dir);
    482	if (retval)
    483		goto done;
    484
    485	/* Insert old into the new directory with the new name. */
    486	affs_copy_name(AFFS_TAIL(sb, bh_old)->name, new_dentry);
    487	affs_fix_checksum(sb, bh_old);
    488	affs_lock_dir(new_dir);
    489	retval = affs_insert_hash(new_dir, bh_old);
    490	affs_unlock_dir(new_dir);
    491
    492	/* Insert new into the old directory with the old name. */
    493	affs_copy_name(AFFS_TAIL(sb, bh_new)->name, old_dentry);
    494	affs_fix_checksum(sb, bh_new);
    495	affs_lock_dir(old_dir);
    496	retval = affs_insert_hash(old_dir, bh_new);
    497	affs_unlock_dir(old_dir);
    498done:
    499	mark_buffer_dirty_inode(bh_old, new_dir);
    500	mark_buffer_dirty_inode(bh_new, old_dir);
    501	affs_brelse(bh_old);
    502	affs_brelse(bh_new);
    503	return retval;
    504}
    505
    506int affs_rename2(struct user_namespace *mnt_userns, struct inode *old_dir,
    507		 struct dentry *old_dentry, struct inode *new_dir,
    508		 struct dentry *new_dentry, unsigned int flags)
    509{
    510
    511	if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
    512		return -EINVAL;
    513
    514	pr_debug("%s(old=%lu,\"%pd\" to new=%lu,\"%pd\")\n", __func__,
    515		 old_dir->i_ino, old_dentry, new_dir->i_ino, new_dentry);
    516
    517	if (flags & RENAME_EXCHANGE)
    518		return affs_xrename(old_dir, old_dentry, new_dir, new_dentry);
    519
    520	return affs_rename(old_dir, old_dentry, new_dir, new_dentry);
    521}
    522
    523static struct dentry *affs_get_parent(struct dentry *child)
    524{
    525	struct inode *parent;
    526	struct buffer_head *bh;
    527
    528	bh = affs_bread(child->d_sb, d_inode(child)->i_ino);
    529	if (!bh)
    530		return ERR_PTR(-EIO);
    531
    532	parent = affs_iget(child->d_sb,
    533			   be32_to_cpu(AFFS_TAIL(child->d_sb, bh)->parent));
    534	brelse(bh);
    535	if (IS_ERR(parent))
    536		return ERR_CAST(parent);
    537
    538	return d_obtain_alias(parent);
    539}
    540
    541static struct inode *affs_nfs_get_inode(struct super_block *sb, u64 ino,
    542					u32 generation)
    543{
    544	struct inode *inode;
    545
    546	if (!affs_validblock(sb, ino))
    547		return ERR_PTR(-ESTALE);
    548
    549	inode = affs_iget(sb, ino);
    550	if (IS_ERR(inode))
    551		return ERR_CAST(inode);
    552
    553	return inode;
    554}
    555
    556static struct dentry *affs_fh_to_dentry(struct super_block *sb, struct fid *fid,
    557					int fh_len, int fh_type)
    558{
    559	return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
    560				    affs_nfs_get_inode);
    561}
    562
    563static struct dentry *affs_fh_to_parent(struct super_block *sb, struct fid *fid,
    564					int fh_len, int fh_type)
    565{
    566	return generic_fh_to_parent(sb, fid, fh_len, fh_type,
    567				    affs_nfs_get_inode);
    568}
    569
    570const struct export_operations affs_export_ops = {
    571	.fh_to_dentry = affs_fh_to_dentry,
    572	.fh_to_parent = affs_fh_to_parent,
    573	.get_parent = affs_get_parent,
    574};
    575
    576const struct dentry_operations affs_dentry_operations = {
    577	.d_hash		= affs_hash_dentry,
    578	.d_compare	= affs_compare_dentry,
    579};
    580
    581const struct dentry_operations affs_intl_dentry_operations = {
    582	.d_hash		= affs_intl_hash_dentry,
    583	.d_compare	= affs_intl_compare_dentry,
    584};