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