xref: /openbmc/linux/fs/sysv/namei.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *  linux/fs/sysv/namei.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *  minix/namei.c
61da177e4SLinus Torvalds  *  Copyright (C) 1991, 1992  Linus Torvalds
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  *  coh/namei.c
91da177e4SLinus Torvalds  *  Copyright (C) 1993  Pascal Haible, Bruno Haible
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  *  sysv/namei.c
121da177e4SLinus Torvalds  *  Copyright (C) 1993  Bruno Haible
131da177e4SLinus Torvalds  *  Copyright (C) 1997, 1998  Krzysztof G. Baranowski
141da177e4SLinus Torvalds  */
151da177e4SLinus Torvalds 
161da177e4SLinus Torvalds #include <linux/pagemap.h>
171da177e4SLinus Torvalds #include "sysv.h"
181da177e4SLinus Torvalds 
add_nondir(struct dentry * dentry,struct inode * inode)191da177e4SLinus Torvalds static int add_nondir(struct dentry *dentry, struct inode *inode)
201da177e4SLinus Torvalds {
211da177e4SLinus Torvalds 	int err = sysv_add_link(dentry, inode);
221da177e4SLinus Torvalds 	if (!err) {
231da177e4SLinus Torvalds 		d_instantiate(dentry, inode);
241da177e4SLinus Torvalds 		return 0;
251da177e4SLinus Torvalds 	}
264e907c3dSAlexey Dobriyan 	inode_dec_link_count(inode);
271da177e4SLinus Torvalds 	iput(inode);
281da177e4SLinus Torvalds 	return err;
291da177e4SLinus Torvalds }
301da177e4SLinus Torvalds 
sysv_lookup(struct inode * dir,struct dentry * dentry,unsigned int flags)3100cd8dd3SAl Viro static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry, unsigned int flags)
321da177e4SLinus Torvalds {
331da177e4SLinus Torvalds 	struct inode * inode = NULL;
341da177e4SLinus Torvalds 	ino_t ino;
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds 	if (dentry->d_name.len > SYSV_NAMELEN)
371da177e4SLinus Torvalds 		return ERR_PTR(-ENAMETOOLONG);
381da177e4SLinus Torvalds 	ino = sysv_inode_by_name(dentry);
395bf35449SAl Viro 	if (ino)
40b8e1343fSDavid Howells 		inode = sysv_iget(dir->i_sb, ino);
415bf35449SAl Viro 	return d_splice_alias(inode, dentry);
421da177e4SLinus Torvalds }
431da177e4SLinus Torvalds 
sysv_mknod(struct mnt_idmap * idmap,struct inode * dir,struct dentry * dentry,umode_t mode,dev_t rdev)445ebb29beSChristian Brauner static int sysv_mknod(struct mnt_idmap *idmap, struct inode *dir,
45549c7297SChristian Brauner 		      struct dentry *dentry, umode_t mode, dev_t rdev)
461da177e4SLinus Torvalds {
471da177e4SLinus Torvalds 	struct inode * inode;
481da177e4SLinus Torvalds 	int err;
491da177e4SLinus Torvalds 
501da177e4SLinus Torvalds 	if (!old_valid_dev(rdev))
511da177e4SLinus Torvalds 		return -EINVAL;
521da177e4SLinus Torvalds 
531da177e4SLinus Torvalds 	inode = sysv_new_inode(dir, mode);
541da177e4SLinus Torvalds 	err = PTR_ERR(inode);
551da177e4SLinus Torvalds 
561da177e4SLinus Torvalds 	if (!IS_ERR(inode)) {
571da177e4SLinus Torvalds 		sysv_set_inode(inode, rdev);
581da177e4SLinus Torvalds 		mark_inode_dirty(inode);
591da177e4SLinus Torvalds 		err = add_nondir(dentry, inode);
601da177e4SLinus Torvalds 	}
611da177e4SLinus Torvalds 	return err;
621da177e4SLinus Torvalds }
631da177e4SLinus Torvalds 
sysv_create(struct mnt_idmap * idmap,struct inode * dir,struct dentry * dentry,umode_t mode,bool excl)646c960e68SChristian Brauner static int sysv_create(struct mnt_idmap *idmap, struct inode *dir,
65549c7297SChristian Brauner 		       struct dentry *dentry, umode_t mode, bool excl)
661da177e4SLinus Torvalds {
675ebb29beSChristian Brauner 	return sysv_mknod(&nop_mnt_idmap, dir, dentry, mode, 0);
681da177e4SLinus Torvalds }
691da177e4SLinus Torvalds 
sysv_symlink(struct mnt_idmap * idmap,struct inode * dir,struct dentry * dentry,const char * symname)707a77db95SChristian Brauner static int sysv_symlink(struct mnt_idmap *idmap, struct inode *dir,
71549c7297SChristian Brauner 			struct dentry *dentry, const char *symname)
721da177e4SLinus Torvalds {
731da177e4SLinus Torvalds 	int err = -ENAMETOOLONG;
741da177e4SLinus Torvalds 	int l = strlen(symname)+1;
751da177e4SLinus Torvalds 	struct inode * inode;
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds 	if (l > dir->i_sb->s_blocksize)
781da177e4SLinus Torvalds 		goto out;
791da177e4SLinus Torvalds 
801da177e4SLinus Torvalds 	inode = sysv_new_inode(dir, S_IFLNK|0777);
811da177e4SLinus Torvalds 	err = PTR_ERR(inode);
821da177e4SLinus Torvalds 	if (IS_ERR(inode))
831da177e4SLinus Torvalds 		goto out;
841da177e4SLinus Torvalds 
851da177e4SLinus Torvalds 	sysv_set_inode(inode, 0);
861da177e4SLinus Torvalds 	err = page_symlink(inode, symname, l);
871da177e4SLinus Torvalds 	if (err)
881da177e4SLinus Torvalds 		goto out_fail;
891da177e4SLinus Torvalds 
901da177e4SLinus Torvalds 	mark_inode_dirty(inode);
911da177e4SLinus Torvalds 	err = add_nondir(dentry, inode);
921da177e4SLinus Torvalds out:
931da177e4SLinus Torvalds 	return err;
941da177e4SLinus Torvalds 
951da177e4SLinus Torvalds out_fail:
964e907c3dSAlexey Dobriyan 	inode_dec_link_count(inode);
971da177e4SLinus Torvalds 	iput(inode);
981da177e4SLinus Torvalds 	goto out;
991da177e4SLinus Torvalds }
1001da177e4SLinus Torvalds 
sysv_link(struct dentry * old_dentry,struct inode * dir,struct dentry * dentry)1011da177e4SLinus Torvalds static int sysv_link(struct dentry * old_dentry, struct inode * dir,
1021da177e4SLinus Torvalds 	struct dentry * dentry)
1031da177e4SLinus Torvalds {
1042b0143b5SDavid Howells 	struct inode *inode = d_inode(old_dentry);
1051da177e4SLinus Torvalds 
106*c801b095SJeff Layton 	inode_set_ctime_current(inode);
1074e907c3dSAlexey Dobriyan 	inode_inc_link_count(inode);
1087de9c6eeSAl Viro 	ihold(inode);
1091da177e4SLinus Torvalds 
1101da177e4SLinus Torvalds 	return add_nondir(dentry, inode);
1111da177e4SLinus Torvalds }
1121da177e4SLinus Torvalds 
sysv_mkdir(struct mnt_idmap * idmap,struct inode * dir,struct dentry * dentry,umode_t mode)113c54bd91eSChristian Brauner static int sysv_mkdir(struct mnt_idmap *idmap, struct inode *dir,
114549c7297SChristian Brauner 		      struct dentry *dentry, umode_t mode)
1151da177e4SLinus Torvalds {
1161da177e4SLinus Torvalds 	struct inode * inode;
1178de52778SAl Viro 	int err;
1181da177e4SLinus Torvalds 
1194e907c3dSAlexey Dobriyan 	inode_inc_link_count(dir);
1201da177e4SLinus Torvalds 
1211da177e4SLinus Torvalds 	inode = sysv_new_inode(dir, S_IFDIR|mode);
1221da177e4SLinus Torvalds 	err = PTR_ERR(inode);
1231da177e4SLinus Torvalds 	if (IS_ERR(inode))
1241da177e4SLinus Torvalds 		goto out_dir;
1251da177e4SLinus Torvalds 
1261da177e4SLinus Torvalds 	sysv_set_inode(inode, 0);
1271da177e4SLinus Torvalds 
1284e907c3dSAlexey Dobriyan 	inode_inc_link_count(inode);
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds 	err = sysv_make_empty(inode, dir);
1311da177e4SLinus Torvalds 	if (err)
1321da177e4SLinus Torvalds 		goto out_fail;
1331da177e4SLinus Torvalds 
1341da177e4SLinus Torvalds 	err = sysv_add_link(dentry, inode);
1351da177e4SLinus Torvalds 	if (err)
1361da177e4SLinus Torvalds 		goto out_fail;
1371da177e4SLinus Torvalds 
1381da177e4SLinus Torvalds         d_instantiate(dentry, inode);
1391da177e4SLinus Torvalds out:
1401da177e4SLinus Torvalds 	return err;
1411da177e4SLinus Torvalds 
1421da177e4SLinus Torvalds out_fail:
1434e907c3dSAlexey Dobriyan 	inode_dec_link_count(inode);
1444e907c3dSAlexey Dobriyan 	inode_dec_link_count(inode);
1451da177e4SLinus Torvalds 	iput(inode);
1461da177e4SLinus Torvalds out_dir:
1474e907c3dSAlexey Dobriyan 	inode_dec_link_count(dir);
1481da177e4SLinus Torvalds 	goto out;
1491da177e4SLinus Torvalds }
1501da177e4SLinus Torvalds 
sysv_unlink(struct inode * dir,struct dentry * dentry)1511da177e4SLinus Torvalds static int sysv_unlink(struct inode * dir, struct dentry * dentry)
1521da177e4SLinus Torvalds {
1532b0143b5SDavid Howells 	struct inode * inode = d_inode(dentry);
1541da177e4SLinus Torvalds 	struct page * page;
1551da177e4SLinus Torvalds 	struct sysv_dir_entry * de;
156abb7c742SAl Viro 	int err;
1571da177e4SLinus Torvalds 
1581da177e4SLinus Torvalds 	de = sysv_find_entry(dentry, &page);
1591da177e4SLinus Torvalds 	if (!de)
160abb7c742SAl Viro 		return -ENOENT;
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds 	err = sysv_delete_entry(de, page);
163abb7c742SAl Viro 	if (!err) {
164*c801b095SJeff Layton 		inode_set_ctime_to_ts(inode, inode_get_ctime(dir));
1654e907c3dSAlexey Dobriyan 		inode_dec_link_count(inode);
166abb7c742SAl Viro 	}
167d0e13540SFabio M. De Francesco 	unmap_and_put_page(page, de);
1681da177e4SLinus Torvalds 	return err;
1691da177e4SLinus Torvalds }
1701da177e4SLinus Torvalds 
sysv_rmdir(struct inode * dir,struct dentry * dentry)1711da177e4SLinus Torvalds static int sysv_rmdir(struct inode * dir, struct dentry * dentry)
1721da177e4SLinus Torvalds {
1732b0143b5SDavid Howells 	struct inode *inode = d_inode(dentry);
1741da177e4SLinus Torvalds 	int err = -ENOTEMPTY;
1751da177e4SLinus Torvalds 
1761da177e4SLinus Torvalds 	if (sysv_empty_dir(inode)) {
1771da177e4SLinus Torvalds 		err = sysv_unlink(dir, dentry);
1781da177e4SLinus Torvalds 		if (!err) {
1791da177e4SLinus Torvalds 			inode->i_size = 0;
1804e907c3dSAlexey Dobriyan 			inode_dec_link_count(inode);
1814e907c3dSAlexey Dobriyan 			inode_dec_link_count(dir);
1821da177e4SLinus Torvalds 		}
1831da177e4SLinus Torvalds 	}
1841da177e4SLinus Torvalds 	return err;
1851da177e4SLinus Torvalds }
1861da177e4SLinus Torvalds 
1871da177e4SLinus Torvalds /*
1881da177e4SLinus Torvalds  * Anybody can rename anything with this: the permission checks are left to the
1891da177e4SLinus Torvalds  * higher-level routines.
1901da177e4SLinus Torvalds  */
sysv_rename(struct mnt_idmap * idmap,struct inode * old_dir,struct dentry * old_dentry,struct inode * new_dir,struct dentry * new_dentry,unsigned int flags)191e18275aeSChristian Brauner static int sysv_rename(struct mnt_idmap *idmap, struct inode *old_dir,
192549c7297SChristian Brauner 		       struct dentry *old_dentry, struct inode *new_dir,
193549c7297SChristian Brauner 		       struct dentry *new_dentry, unsigned int flags)
1941da177e4SLinus Torvalds {
1952b0143b5SDavid Howells 	struct inode * old_inode = d_inode(old_dentry);
1962b0143b5SDavid Howells 	struct inode * new_inode = d_inode(new_dentry);
1971da177e4SLinus Torvalds 	struct page * dir_page = NULL;
1981da177e4SLinus Torvalds 	struct sysv_dir_entry * dir_de = NULL;
1991da177e4SLinus Torvalds 	struct page * old_page;
2001da177e4SLinus Torvalds 	struct sysv_dir_entry * old_de;
2011da177e4SLinus Torvalds 	int err = -ENOENT;
2021da177e4SLinus Torvalds 
203f03b8ad8SMiklos Szeredi 	if (flags & ~RENAME_NOREPLACE)
204f03b8ad8SMiklos Szeredi 		return -EINVAL;
205f03b8ad8SMiklos Szeredi 
2061da177e4SLinus Torvalds 	old_de = sysv_find_entry(old_dentry, &old_page);
2071da177e4SLinus Torvalds 	if (!old_de)
2081da177e4SLinus Torvalds 		goto out;
2091da177e4SLinus Torvalds 
2101da177e4SLinus Torvalds 	if (S_ISDIR(old_inode->i_mode)) {
2111da177e4SLinus Torvalds 		err = -EIO;
2121da177e4SLinus Torvalds 		dir_de = sysv_dotdot(old_inode, &dir_page);
2131da177e4SLinus Torvalds 		if (!dir_de)
2141da177e4SLinus Torvalds 			goto out_old;
2151da177e4SLinus Torvalds 	}
2161da177e4SLinus Torvalds 
2171da177e4SLinus Torvalds 	if (new_inode) {
2181da177e4SLinus Torvalds 		struct page * new_page;
2191da177e4SLinus Torvalds 		struct sysv_dir_entry * new_de;
2201da177e4SLinus Torvalds 
2211da177e4SLinus Torvalds 		err = -ENOTEMPTY;
2221da177e4SLinus Torvalds 		if (dir_de && !sysv_empty_dir(new_inode))
2231da177e4SLinus Torvalds 			goto out_dir;
2241da177e4SLinus Torvalds 
2251da177e4SLinus Torvalds 		err = -ENOENT;
2261da177e4SLinus Torvalds 		new_de = sysv_find_entry(new_dentry, &new_page);
2271da177e4SLinus Torvalds 		if (!new_de)
2281da177e4SLinus Torvalds 			goto out_dir;
229abb7c742SAl Viro 		err = sysv_set_link(new_de, new_page, old_inode);
230d0e13540SFabio M. De Francesco 		unmap_and_put_page(new_page, new_de);
231abb7c742SAl Viro 		if (err)
232abb7c742SAl Viro 			goto out_dir;
233*c801b095SJeff Layton 		inode_set_ctime_current(new_inode);
2341da177e4SLinus Torvalds 		if (dir_de)
2359a53c3a7SDave Hansen 			drop_nlink(new_inode);
2364e907c3dSAlexey Dobriyan 		inode_dec_link_count(new_inode);
2371da177e4SLinus Torvalds 	} else {
2381da177e4SLinus Torvalds 		err = sysv_add_link(new_dentry, old_inode);
2394787d45fSAl Viro 		if (err)
2401da177e4SLinus Torvalds 			goto out_dir;
2411da177e4SLinus Torvalds 		if (dir_de)
2424e907c3dSAlexey Dobriyan 			inode_inc_link_count(new_dir);
2431da177e4SLinus Torvalds 	}
2441da177e4SLinus Torvalds 
245abb7c742SAl Viro 	err = sysv_delete_entry(old_de, old_page);
246abb7c742SAl Viro 	if (err)
247abb7c742SAl Viro 		goto out_dir;
248abb7c742SAl Viro 
2494787d45fSAl Viro 	mark_inode_dirty(old_inode);
2501da177e4SLinus Torvalds 
2511da177e4SLinus Torvalds 	if (dir_de) {
252abb7c742SAl Viro 		err = sysv_set_link(dir_de, dir_page, new_dir);
253abb7c742SAl Viro 		if (!err)
2544e907c3dSAlexey Dobriyan 			inode_dec_link_count(old_dir);
2551da177e4SLinus Torvalds 	}
2561da177e4SLinus Torvalds 
2571da177e4SLinus Torvalds out_dir:
258c26ddc49SFabio M. De Francesco 	if (dir_de)
259d0e13540SFabio M. De Francesco 		unmap_and_put_page(dir_page, dir_de);
2601da177e4SLinus Torvalds out_old:
261d0e13540SFabio M. De Francesco 	unmap_and_put_page(old_page, old_de);
2621da177e4SLinus Torvalds out:
2631da177e4SLinus Torvalds 	return err;
2641da177e4SLinus Torvalds }
2651da177e4SLinus Torvalds 
2661da177e4SLinus Torvalds /*
2671da177e4SLinus Torvalds  * directories can handle most operations...
2681da177e4SLinus Torvalds  */
269c5ef1c42SArjan van de Ven const struct inode_operations sysv_dir_inode_operations = {
2701da177e4SLinus Torvalds 	.create		= sysv_create,
2711da177e4SLinus Torvalds 	.lookup		= sysv_lookup,
2721da177e4SLinus Torvalds 	.link		= sysv_link,
2731da177e4SLinus Torvalds 	.unlink		= sysv_unlink,
2741da177e4SLinus Torvalds 	.symlink	= sysv_symlink,
2751da177e4SLinus Torvalds 	.mkdir		= sysv_mkdir,
2761da177e4SLinus Torvalds 	.rmdir		= sysv_rmdir,
2771da177e4SLinus Torvalds 	.mknod		= sysv_mknod,
2781da177e4SLinus Torvalds 	.rename		= sysv_rename,
2791da177e4SLinus Torvalds 	.getattr	= sysv_getattr,
2801da177e4SLinus Torvalds };
281