xref: /openbmc/linux/fs/minix/namei.c (revision f7f43858)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *  linux/fs/minix/namei.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *  Copyright (C) 1991, 1992  Linus Torvalds
61da177e4SLinus Torvalds  */
71da177e4SLinus Torvalds 
81da177e4SLinus Torvalds #include "minix.h"
91da177e4SLinus Torvalds 
add_nondir(struct dentry * dentry,struct inode * inode)101da177e4SLinus Torvalds static int add_nondir(struct dentry *dentry, struct inode *inode)
111da177e4SLinus Torvalds {
121da177e4SLinus Torvalds 	int err = minix_add_link(dentry, inode);
131da177e4SLinus Torvalds 	if (!err) {
141da177e4SLinus Torvalds 		d_instantiate(dentry, inode);
151da177e4SLinus Torvalds 		return 0;
161da177e4SLinus Torvalds 	}
1778ec7b69SAlexey Dobriyan 	inode_dec_link_count(inode);
181da177e4SLinus Torvalds 	iput(inode);
191da177e4SLinus Torvalds 	return err;
201da177e4SLinus Torvalds }
211da177e4SLinus Torvalds 
minix_lookup(struct inode * dir,struct dentry * dentry,unsigned int flags)2200cd8dd3SAl Viro static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry, unsigned int flags)
231da177e4SLinus Torvalds {
241da177e4SLinus Torvalds 	struct inode * inode = NULL;
251da177e4SLinus Torvalds 	ino_t ino;
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds 	if (dentry->d_name.len > minix_sb(dir->i_sb)->s_namelen)
281da177e4SLinus Torvalds 		return ERR_PTR(-ENAMETOOLONG);
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds 	ino = minix_inode_by_name(dentry);
31b0149516SAl Viro 	if (ino)
32a90a0880SDavid Howells 		inode = minix_iget(dir->i_sb, ino);
33b0149516SAl Viro 	return d_splice_alias(inode, dentry);
341da177e4SLinus Torvalds }
351da177e4SLinus Torvalds 
minix_mknod(struct mnt_idmap * idmap,struct inode * dir,struct dentry * dentry,umode_t mode,dev_t rdev)365ebb29beSChristian Brauner static int minix_mknod(struct mnt_idmap *idmap, struct inode *dir,
37549c7297SChristian Brauner 		       struct dentry *dentry, umode_t mode, dev_t rdev)
381da177e4SLinus Torvalds {
391da177e4SLinus Torvalds 	struct inode *inode;
401da177e4SLinus Torvalds 
411da177e4SLinus Torvalds 	if (!old_valid_dev(rdev))
421da177e4SLinus Torvalds 		return -EINVAL;
431da177e4SLinus Torvalds 
444a29a126SAl Viro 	inode = minix_new_inode(dir, mode);
454a29a126SAl Viro 	if (IS_ERR(inode))
464a29a126SAl Viro 		return PTR_ERR(inode);
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds 	minix_set_inode(inode, rdev);
491da177e4SLinus Torvalds 	mark_inode_dirty(inode);
504a29a126SAl Viro 	return add_nondir(dentry, inode);
511da177e4SLinus Torvalds }
521da177e4SLinus Torvalds 
minix_tmpfile(struct mnt_idmap * idmap,struct inode * dir,struct file * file,umode_t mode)53011e2b71SChristian Brauner static int minix_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
54863f144fSMiklos Szeredi 			 struct file *file, umode_t mode)
5560545d0dSAl Viro {
564a29a126SAl Viro 	struct inode *inode = minix_new_inode(dir, mode);
574a29a126SAl Viro 
584a29a126SAl Viro 	if (IS_ERR(inode))
594a29a126SAl Viro 		return finish_open_simple(file, PTR_ERR(inode));
6060545d0dSAl Viro 	minix_set_inode(inode, 0);
6160545d0dSAl Viro 	mark_inode_dirty(inode);
62863f144fSMiklos Szeredi 	d_tmpfile(file, inode);
634a29a126SAl Viro 	return finish_open_simple(file, 0);
6460545d0dSAl Viro }
6560545d0dSAl Viro 
minix_create(struct mnt_idmap * idmap,struct inode * dir,struct dentry * dentry,umode_t mode,bool excl)666c960e68SChristian Brauner static int minix_create(struct mnt_idmap *idmap, struct inode *dir,
67549c7297SChristian Brauner 			struct dentry *dentry, umode_t mode, bool excl)
681da177e4SLinus Torvalds {
695ebb29beSChristian Brauner 	return minix_mknod(&nop_mnt_idmap, dir, dentry, mode, 0);
701da177e4SLinus Torvalds }
711da177e4SLinus Torvalds 
minix_symlink(struct mnt_idmap * idmap,struct inode * dir,struct dentry * dentry,const char * symname)727a77db95SChristian Brauner static int minix_symlink(struct mnt_idmap *idmap, struct inode *dir,
73549c7297SChristian Brauner 			 struct dentry *dentry, const char *symname)
741da177e4SLinus Torvalds {
751da177e4SLinus Torvalds 	int i = strlen(symname)+1;
761da177e4SLinus Torvalds 	struct inode * inode;
774a29a126SAl Viro 	int err;
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds 	if (i > dir->i_sb->s_blocksize)
804a29a126SAl Viro 		return -ENAMETOOLONG;
811da177e4SLinus Torvalds 
824a29a126SAl Viro 	inode = minix_new_inode(dir, S_IFLNK | 0777);
834a29a126SAl Viro 	if (IS_ERR(inode))
844a29a126SAl Viro 		return PTR_ERR(inode);
851da177e4SLinus Torvalds 
861da177e4SLinus Torvalds 	minix_set_inode(inode, 0);
871da177e4SLinus Torvalds 	err = page_symlink(inode, symname, i);
884a29a126SAl Viro 	if (unlikely(err)) {
8978ec7b69SAlexey Dobriyan 		inode_dec_link_count(inode);
901da177e4SLinus Torvalds 		iput(inode);
914a29a126SAl Viro 		return err;
924a29a126SAl Viro 	}
934a29a126SAl Viro 	return add_nondir(dentry, inode);
941da177e4SLinus Torvalds }
951da177e4SLinus Torvalds 
minix_link(struct dentry * old_dentry,struct inode * dir,struct dentry * dentry)961da177e4SLinus Torvalds static int minix_link(struct dentry * old_dentry, struct inode * dir,
971da177e4SLinus Torvalds 	struct dentry *dentry)
981da177e4SLinus Torvalds {
992b0143b5SDavid Howells 	struct inode *inode = d_inode(old_dentry);
1001da177e4SLinus Torvalds 
101*f7f43858SJeff Layton 	inode_set_ctime_current(inode);
10278ec7b69SAlexey Dobriyan 	inode_inc_link_count(inode);
1037de9c6eeSAl Viro 	ihold(inode);
1041da177e4SLinus Torvalds 	return add_nondir(dentry, inode);
1051da177e4SLinus Torvalds }
1061da177e4SLinus Torvalds 
minix_mkdir(struct mnt_idmap * idmap,struct inode * dir,struct dentry * dentry,umode_t mode)107c54bd91eSChristian Brauner static int minix_mkdir(struct mnt_idmap *idmap, struct inode *dir,
108549c7297SChristian Brauner 		       struct dentry *dentry, umode_t mode)
1091da177e4SLinus Torvalds {
1101da177e4SLinus Torvalds 	struct inode * inode;
1118de52778SAl Viro 	int err;
1121da177e4SLinus Torvalds 
1134a29a126SAl Viro 	inode = minix_new_inode(dir, S_IFDIR | mode);
1144a29a126SAl Viro 	if (IS_ERR(inode))
1154a29a126SAl Viro 		return PTR_ERR(inode);
1164a29a126SAl Viro 
11778ec7b69SAlexey Dobriyan 	inode_inc_link_count(dir);
1181da177e4SLinus Torvalds 	minix_set_inode(inode, 0);
11978ec7b69SAlexey Dobriyan 	inode_inc_link_count(inode);
1201da177e4SLinus Torvalds 
1211da177e4SLinus Torvalds 	err = minix_make_empty(inode, dir);
1221da177e4SLinus Torvalds 	if (err)
1231da177e4SLinus Torvalds 		goto out_fail;
1241da177e4SLinus Torvalds 
1251da177e4SLinus Torvalds 	err = minix_add_link(dentry, inode);
1261da177e4SLinus Torvalds 	if (err)
1271da177e4SLinus Torvalds 		goto out_fail;
1281da177e4SLinus Torvalds 
1291da177e4SLinus Torvalds 	d_instantiate(dentry, inode);
1301da177e4SLinus Torvalds out:
1311da177e4SLinus Torvalds 	return err;
1321da177e4SLinus Torvalds 
1331da177e4SLinus Torvalds out_fail:
13478ec7b69SAlexey Dobriyan 	inode_dec_link_count(inode);
13578ec7b69SAlexey Dobriyan 	inode_dec_link_count(inode);
1361da177e4SLinus Torvalds 	iput(inode);
13778ec7b69SAlexey Dobriyan 	inode_dec_link_count(dir);
1381da177e4SLinus Torvalds 	goto out;
1391da177e4SLinus Torvalds }
1401da177e4SLinus Torvalds 
minix_unlink(struct inode * dir,struct dentry * dentry)1411da177e4SLinus Torvalds static int minix_unlink(struct inode * dir, struct dentry *dentry)
1421da177e4SLinus Torvalds {
1432b0143b5SDavid Howells 	struct inode * inode = d_inode(dentry);
1441da177e4SLinus Torvalds 	struct page * page;
1451da177e4SLinus Torvalds 	struct minix_dir_entry * de;
14635bb6a09SChristoph Hellwig 	int err;
1471da177e4SLinus Torvalds 
1481da177e4SLinus Torvalds 	de = minix_find_entry(dentry, &page);
1491da177e4SLinus Torvalds 	if (!de)
15035bb6a09SChristoph Hellwig 		return -ENOENT;
1511da177e4SLinus Torvalds 	err = minix_delete_entry(de, page);
15235bb6a09SChristoph Hellwig 	kunmap(page);
15335bb6a09SChristoph Hellwig 	put_page(page);
1541da177e4SLinus Torvalds 
15535bb6a09SChristoph Hellwig 	if (err)
15635bb6a09SChristoph Hellwig 		return err;
157*f7f43858SJeff Layton 	inode_set_ctime_to_ts(inode, inode_get_ctime(dir));
15878ec7b69SAlexey Dobriyan 	inode_dec_link_count(inode);
15935bb6a09SChristoph Hellwig 	return 0;
1601da177e4SLinus Torvalds }
1611da177e4SLinus Torvalds 
minix_rmdir(struct inode * dir,struct dentry * dentry)1621da177e4SLinus Torvalds static int minix_rmdir(struct inode * dir, struct dentry *dentry)
1631da177e4SLinus Torvalds {
1642b0143b5SDavid Howells 	struct inode * inode = d_inode(dentry);
1651da177e4SLinus Torvalds 	int err = -ENOTEMPTY;
1661da177e4SLinus Torvalds 
1671da177e4SLinus Torvalds 	if (minix_empty_dir(inode)) {
1681da177e4SLinus Torvalds 		err = minix_unlink(dir, dentry);
1691da177e4SLinus Torvalds 		if (!err) {
17078ec7b69SAlexey Dobriyan 			inode_dec_link_count(dir);
17178ec7b69SAlexey Dobriyan 			inode_dec_link_count(inode);
1721da177e4SLinus Torvalds 		}
1731da177e4SLinus Torvalds 	}
1741da177e4SLinus Torvalds 	return err;
1751da177e4SLinus Torvalds }
1761da177e4SLinus Torvalds 
minix_rename(struct mnt_idmap * idmap,struct inode * old_dir,struct dentry * old_dentry,struct inode * new_dir,struct dentry * new_dentry,unsigned int flags)177e18275aeSChristian Brauner static int minix_rename(struct mnt_idmap *idmap,
178549c7297SChristian Brauner 			struct inode *old_dir, struct dentry *old_dentry,
179f03b8ad8SMiklos Szeredi 			struct inode *new_dir, struct dentry *new_dentry,
180f03b8ad8SMiklos Szeredi 			unsigned int flags)
1811da177e4SLinus Torvalds {
1822b0143b5SDavid Howells 	struct inode * old_inode = d_inode(old_dentry);
1832b0143b5SDavid Howells 	struct inode * new_inode = d_inode(new_dentry);
1841da177e4SLinus Torvalds 	struct page * dir_page = NULL;
1851da177e4SLinus Torvalds 	struct minix_dir_entry * dir_de = NULL;
1861da177e4SLinus Torvalds 	struct page * old_page;
1871da177e4SLinus Torvalds 	struct minix_dir_entry * old_de;
1881da177e4SLinus Torvalds 	int err = -ENOENT;
1891da177e4SLinus Torvalds 
190f03b8ad8SMiklos Szeredi 	if (flags & ~RENAME_NOREPLACE)
191f03b8ad8SMiklos Szeredi 		return -EINVAL;
192f03b8ad8SMiklos Szeredi 
1931da177e4SLinus Torvalds 	old_de = minix_find_entry(old_dentry, &old_page);
1941da177e4SLinus Torvalds 	if (!old_de)
1951da177e4SLinus Torvalds 		goto out;
1961da177e4SLinus Torvalds 
1971da177e4SLinus Torvalds 	if (S_ISDIR(old_inode->i_mode)) {
1981da177e4SLinus Torvalds 		err = -EIO;
1991da177e4SLinus Torvalds 		dir_de = minix_dotdot(old_inode, &dir_page);
2001da177e4SLinus Torvalds 		if (!dir_de)
2011da177e4SLinus Torvalds 			goto out_old;
2021da177e4SLinus Torvalds 	}
2031da177e4SLinus Torvalds 
2041da177e4SLinus Torvalds 	if (new_inode) {
2051da177e4SLinus Torvalds 		struct page * new_page;
2061da177e4SLinus Torvalds 		struct minix_dir_entry * new_de;
2071da177e4SLinus Torvalds 
2081da177e4SLinus Torvalds 		err = -ENOTEMPTY;
2091da177e4SLinus Torvalds 		if (dir_de && !minix_empty_dir(new_inode))
2101da177e4SLinus Torvalds 			goto out_dir;
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds 		err = -ENOENT;
2131da177e4SLinus Torvalds 		new_de = minix_find_entry(new_dentry, &new_page);
2141da177e4SLinus Torvalds 		if (!new_de)
2151da177e4SLinus Torvalds 			goto out_dir;
2162d1a9d59SChristoph Hellwig 		err = minix_set_link(new_de, new_page, old_inode);
21735bb6a09SChristoph Hellwig 		kunmap(new_page);
21835bb6a09SChristoph Hellwig 		put_page(new_page);
2192d1a9d59SChristoph Hellwig 		if (err)
2202d1a9d59SChristoph Hellwig 			goto out_dir;
221*f7f43858SJeff Layton 		inode_set_ctime_current(new_inode);
2221da177e4SLinus Torvalds 		if (dir_de)
2239a53c3a7SDave Hansen 			drop_nlink(new_inode);
22478ec7b69SAlexey Dobriyan 		inode_dec_link_count(new_inode);
2251da177e4SLinus Torvalds 	} else {
2261da177e4SLinus Torvalds 		err = minix_add_link(new_dentry, old_inode);
2276f88049cSAl Viro 		if (err)
2281da177e4SLinus Torvalds 			goto out_dir;
2291da177e4SLinus Torvalds 		if (dir_de)
23078ec7b69SAlexey Dobriyan 			inode_inc_link_count(new_dir);
2311da177e4SLinus Torvalds 	}
2321da177e4SLinus Torvalds 
2332cb6a442SAl Viro 	err = minix_delete_entry(old_de, old_page);
2342cb6a442SAl Viro 	if (err)
2352cb6a442SAl Viro 		goto out_dir;
2362cb6a442SAl Viro 
2376f88049cSAl Viro 	mark_inode_dirty(old_inode);
2381da177e4SLinus Torvalds 
2391da177e4SLinus Torvalds 	if (dir_de) {
2402d1a9d59SChristoph Hellwig 		err = minix_set_link(dir_de, dir_page, new_dir);
2412d1a9d59SChristoph Hellwig 		if (!err)
24278ec7b69SAlexey Dobriyan 			inode_dec_link_count(old_dir);
2431da177e4SLinus Torvalds 	}
2441da177e4SLinus Torvalds out_dir:
2451da177e4SLinus Torvalds 	if (dir_de) {
2461da177e4SLinus Torvalds 		kunmap(dir_page);
24709cbfeafSKirill A. Shutemov 		put_page(dir_page);
2481da177e4SLinus Torvalds 	}
2491da177e4SLinus Torvalds out_old:
2501da177e4SLinus Torvalds 	kunmap(old_page);
25109cbfeafSKirill A. Shutemov 	put_page(old_page);
2521da177e4SLinus Torvalds out:
2531da177e4SLinus Torvalds 	return err;
2541da177e4SLinus Torvalds }
2551da177e4SLinus Torvalds 
2561da177e4SLinus Torvalds /*
2571da177e4SLinus Torvalds  * directories can handle most operations...
2581da177e4SLinus Torvalds  */
25992e1d5beSArjan van de Ven const struct inode_operations minix_dir_inode_operations = {
2601da177e4SLinus Torvalds 	.create		= minix_create,
2611da177e4SLinus Torvalds 	.lookup		= minix_lookup,
2621da177e4SLinus Torvalds 	.link		= minix_link,
2631da177e4SLinus Torvalds 	.unlink		= minix_unlink,
2641da177e4SLinus Torvalds 	.symlink	= minix_symlink,
2651da177e4SLinus Torvalds 	.mkdir		= minix_mkdir,
2661da177e4SLinus Torvalds 	.rmdir		= minix_rmdir,
2671da177e4SLinus Torvalds 	.mknod		= minix_mknod,
2681da177e4SLinus Torvalds 	.rename		= minix_rename,
2691da177e4SLinus Torvalds 	.getattr	= minix_getattr,
27060545d0dSAl Viro 	.tmpfile	= minix_tmpfile,
2711da177e4SLinus Torvalds };
272