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