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


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 *  linux/fs/sysv/namei.c
      4 *
      5 *  minix/namei.c
      6 *  Copyright (C) 1991, 1992  Linus Torvalds
      7 *
      8 *  coh/namei.c
      9 *  Copyright (C) 1993  Pascal Haible, Bruno Haible
     10 *
     11 *  sysv/namei.c
     12 *  Copyright (C) 1993  Bruno Haible
     13 *  Copyright (C) 1997, 1998  Krzysztof G. Baranowski
     14 */
     15
     16#include <linux/pagemap.h>
     17#include "sysv.h"
     18
     19static int add_nondir(struct dentry *dentry, struct inode *inode)
     20{
     21	int err = sysv_add_link(dentry, inode);
     22	if (!err) {
     23		d_instantiate(dentry, inode);
     24		return 0;
     25	}
     26	inode_dec_link_count(inode);
     27	iput(inode);
     28	return err;
     29}
     30
     31static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry, unsigned int flags)
     32{
     33	struct inode * inode = NULL;
     34	ino_t ino;
     35
     36	if (dentry->d_name.len > SYSV_NAMELEN)
     37		return ERR_PTR(-ENAMETOOLONG);
     38	ino = sysv_inode_by_name(dentry);
     39	if (ino)
     40		inode = sysv_iget(dir->i_sb, ino);
     41	return d_splice_alias(inode, dentry);
     42}
     43
     44static int sysv_mknod(struct user_namespace *mnt_userns, struct inode *dir,
     45		      struct dentry *dentry, umode_t mode, dev_t rdev)
     46{
     47	struct inode * inode;
     48	int err;
     49
     50	if (!old_valid_dev(rdev))
     51		return -EINVAL;
     52
     53	inode = sysv_new_inode(dir, mode);
     54	err = PTR_ERR(inode);
     55
     56	if (!IS_ERR(inode)) {
     57		sysv_set_inode(inode, rdev);
     58		mark_inode_dirty(inode);
     59		err = add_nondir(dentry, inode);
     60	}
     61	return err;
     62}
     63
     64static int sysv_create(struct user_namespace *mnt_userns, struct inode *dir,
     65		       struct dentry *dentry, umode_t mode, bool excl)
     66{
     67	return sysv_mknod(&init_user_ns, dir, dentry, mode, 0);
     68}
     69
     70static int sysv_symlink(struct user_namespace *mnt_userns, struct inode *dir,
     71			struct dentry *dentry, const char *symname)
     72{
     73	int err = -ENAMETOOLONG;
     74	int l = strlen(symname)+1;
     75	struct inode * inode;
     76
     77	if (l > dir->i_sb->s_blocksize)
     78		goto out;
     79
     80	inode = sysv_new_inode(dir, S_IFLNK|0777);
     81	err = PTR_ERR(inode);
     82	if (IS_ERR(inode))
     83		goto out;
     84	
     85	sysv_set_inode(inode, 0);
     86	err = page_symlink(inode, symname, l);
     87	if (err)
     88		goto out_fail;
     89
     90	mark_inode_dirty(inode);
     91	err = add_nondir(dentry, inode);
     92out:
     93	return err;
     94
     95out_fail:
     96	inode_dec_link_count(inode);
     97	iput(inode);
     98	goto out;
     99}
    100
    101static int sysv_link(struct dentry * old_dentry, struct inode * dir, 
    102	struct dentry * dentry)
    103{
    104	struct inode *inode = d_inode(old_dentry);
    105
    106	inode->i_ctime = current_time(inode);
    107	inode_inc_link_count(inode);
    108	ihold(inode);
    109
    110	return add_nondir(dentry, inode);
    111}
    112
    113static int sysv_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
    114		      struct dentry *dentry, umode_t mode)
    115{
    116	struct inode * inode;
    117	int err;
    118
    119	inode_inc_link_count(dir);
    120
    121	inode = sysv_new_inode(dir, S_IFDIR|mode);
    122	err = PTR_ERR(inode);
    123	if (IS_ERR(inode))
    124		goto out_dir;
    125
    126	sysv_set_inode(inode, 0);
    127
    128	inode_inc_link_count(inode);
    129
    130	err = sysv_make_empty(inode, dir);
    131	if (err)
    132		goto out_fail;
    133
    134	err = sysv_add_link(dentry, inode);
    135	if (err)
    136		goto out_fail;
    137
    138        d_instantiate(dentry, inode);
    139out:
    140	return err;
    141
    142out_fail:
    143	inode_dec_link_count(inode);
    144	inode_dec_link_count(inode);
    145	iput(inode);
    146out_dir:
    147	inode_dec_link_count(dir);
    148	goto out;
    149}
    150
    151static int sysv_unlink(struct inode * dir, struct dentry * dentry)
    152{
    153	struct inode * inode = d_inode(dentry);
    154	struct page * page;
    155	struct sysv_dir_entry * de;
    156	int err = -ENOENT;
    157
    158	de = sysv_find_entry(dentry, &page);
    159	if (!de)
    160		goto out;
    161
    162	err = sysv_delete_entry (de, page);
    163	if (err)
    164		goto out;
    165
    166	inode->i_ctime = dir->i_ctime;
    167	inode_dec_link_count(inode);
    168out:
    169	return err;
    170}
    171
    172static int sysv_rmdir(struct inode * dir, struct dentry * dentry)
    173{
    174	struct inode *inode = d_inode(dentry);
    175	int err = -ENOTEMPTY;
    176
    177	if (sysv_empty_dir(inode)) {
    178		err = sysv_unlink(dir, dentry);
    179		if (!err) {
    180			inode->i_size = 0;
    181			inode_dec_link_count(inode);
    182			inode_dec_link_count(dir);
    183		}
    184	}
    185	return err;
    186}
    187
    188/*
    189 * Anybody can rename anything with this: the permission checks are left to the
    190 * higher-level routines.
    191 */
    192static int sysv_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
    193		       struct dentry *old_dentry, struct inode *new_dir,
    194		       struct dentry *new_dentry, unsigned int flags)
    195{
    196	struct inode * old_inode = d_inode(old_dentry);
    197	struct inode * new_inode = d_inode(new_dentry);
    198	struct page * dir_page = NULL;
    199	struct sysv_dir_entry * dir_de = NULL;
    200	struct page * old_page;
    201	struct sysv_dir_entry * old_de;
    202	int err = -ENOENT;
    203
    204	if (flags & ~RENAME_NOREPLACE)
    205		return -EINVAL;
    206
    207	old_de = sysv_find_entry(old_dentry, &old_page);
    208	if (!old_de)
    209		goto out;
    210
    211	if (S_ISDIR(old_inode->i_mode)) {
    212		err = -EIO;
    213		dir_de = sysv_dotdot(old_inode, &dir_page);
    214		if (!dir_de)
    215			goto out_old;
    216	}
    217
    218	if (new_inode) {
    219		struct page * new_page;
    220		struct sysv_dir_entry * new_de;
    221
    222		err = -ENOTEMPTY;
    223		if (dir_de && !sysv_empty_dir(new_inode))
    224			goto out_dir;
    225
    226		err = -ENOENT;
    227		new_de = sysv_find_entry(new_dentry, &new_page);
    228		if (!new_de)
    229			goto out_dir;
    230		sysv_set_link(new_de, new_page, old_inode);
    231		new_inode->i_ctime = current_time(new_inode);
    232		if (dir_de)
    233			drop_nlink(new_inode);
    234		inode_dec_link_count(new_inode);
    235	} else {
    236		err = sysv_add_link(new_dentry, old_inode);
    237		if (err)
    238			goto out_dir;
    239		if (dir_de)
    240			inode_inc_link_count(new_dir);
    241	}
    242
    243	sysv_delete_entry(old_de, old_page);
    244	mark_inode_dirty(old_inode);
    245
    246	if (dir_de) {
    247		sysv_set_link(dir_de, dir_page, new_dir);
    248		inode_dec_link_count(old_dir);
    249	}
    250	return 0;
    251
    252out_dir:
    253	if (dir_de) {
    254		kunmap(dir_page);
    255		put_page(dir_page);
    256	}
    257out_old:
    258	kunmap(old_page);
    259	put_page(old_page);
    260out:
    261	return err;
    262}
    263
    264/*
    265 * directories can handle most operations...
    266 */
    267const struct inode_operations sysv_dir_inode_operations = {
    268	.create		= sysv_create,
    269	.lookup		= sysv_lookup,
    270	.link		= sysv_link,
    271	.unlink		= sysv_unlink,
    272	.symlink	= sysv_symlink,
    273	.mkdir		= sysv_mkdir,
    274	.rmdir		= sysv_rmdir,
    275	.mknod		= sysv_mknod,
    276	.rename		= sysv_rename,
    277	.getattr	= sysv_getattr,
    278};