1 /*
2  *  linux/fs/sysv/namei.c
3  *
4  *  minix/namei.c
5  *  Copyright (C) 1991, 1992  Linus Torvalds
6  *
7  *  coh/namei.c
8  *  Copyright (C) 1993  Pascal Haible, Bruno Haible
9  *
10  *  sysv/namei.c
11  *  Copyright (C) 1993  Bruno Haible
12  *  Copyright (C) 1997, 1998  Krzysztof G. Baranowski
13  */
14 
15 #include <linux/fs.h>
16 #include <linux/sysv_fs.h>
17 #include <linux/pagemap.h>
18 
inc_count(struct inode * inode)19 static inline void inc_count(struct inode *inode)
20 {
21 	inode->i_nlink++;
22 	mark_inode_dirty(inode);
23 }
24 
dec_count(struct inode * inode)25 static inline void dec_count(struct inode *inode)
26 {
27 	inode->i_nlink--;
28 	mark_inode_dirty(inode);
29 }
30 
add_nondir(struct dentry * dentry,struct inode * inode)31 static int add_nondir(struct dentry *dentry, struct inode *inode)
32 {
33 	int err = sysv_add_link(dentry, inode);
34 	if (!err) {
35 		d_instantiate(dentry, inode);
36 		return 0;
37 	}
38 	dec_count(inode);
39 	iput(inode);
40 	return err;
41 }
42 
sysv_hash(struct dentry * dentry,struct qstr * qstr)43 static int sysv_hash(struct dentry *dentry, struct qstr *qstr)
44 {
45 	unsigned long hash;
46 	int i;
47 	const unsigned char *name;
48 
49 	i = SYSV_NAMELEN;
50 	if (i >= qstr->len)
51 		return 0;
52 	/* Truncate the name in place, avoids having to define a compare
53 	   function. */
54 	qstr->len = i;
55 	name = qstr->name;
56 	hash = init_name_hash();
57 	while (i--)
58 		hash = partial_name_hash(*name++, hash);
59 	qstr->hash = end_name_hash(hash);
60 	return 0;
61 }
62 
63 struct dentry_operations sysv_dentry_operations = {
64 	d_hash:		sysv_hash,
65 };
66 
sysv_lookup(struct inode * dir,struct dentry * dentry)67 static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry)
68 {
69 	struct inode * inode = NULL;
70 	ino_t ino;
71 
72 	dentry->d_op = dir->i_sb->s_root->d_op;
73 	if (dentry->d_name.len > SYSV_NAMELEN)
74 		return ERR_PTR(-ENAMETOOLONG);
75 	ino = sysv_inode_by_name(dentry);
76 
77 	if (ino) {
78 		inode = iget(dir->i_sb, ino);
79 		if (!inode)
80 			return ERR_PTR(-EACCES);
81 	}
82 	d_add(dentry, inode);
83 	return NULL;
84 }
85 
sysv_mknod(struct inode * dir,struct dentry * dentry,int mode,int rdev)86 static int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev)
87 {
88 	struct inode * inode = sysv_new_inode(dir, mode);
89 	int err = PTR_ERR(inode);
90 
91 	if (!IS_ERR(inode)) {
92 		sysv_set_inode(inode, rdev);
93 		mark_inode_dirty(inode);
94 		err = add_nondir(dentry, inode);
95 	}
96 	return err;
97 }
98 
sysv_create(struct inode * dir,struct dentry * dentry,int mode)99 static int sysv_create(struct inode * dir, struct dentry * dentry, int mode)
100 {
101 	return sysv_mknod(dir, dentry, mode, 0);
102 }
103 
sysv_symlink(struct inode * dir,struct dentry * dentry,const char * symname)104 static int sysv_symlink(struct inode * dir, struct dentry * dentry,
105 	const char * symname)
106 {
107 	int err = -ENAMETOOLONG;
108 	int l = strlen(symname)+1;
109 	struct inode * inode;
110 
111 	if (l > dir->i_sb->s_blocksize)
112 		goto out;
113 
114 	inode = sysv_new_inode(dir, S_IFLNK|0777);
115 	err = PTR_ERR(inode);
116 	if (IS_ERR(inode))
117 		goto out;
118 
119 	sysv_set_inode(inode, 0);
120 	err = block_symlink(inode, symname, l);
121 	if (err)
122 		goto out_fail;
123 
124 	mark_inode_dirty(inode);
125 	err = add_nondir(dentry, inode);
126 out:
127 	return err;
128 
129 out_fail:
130 	dec_count(inode);
131 	iput(inode);
132 	goto out;
133 }
134 
sysv_link(struct dentry * old_dentry,struct inode * dir,struct dentry * dentry)135 static int sysv_link(struct dentry * old_dentry, struct inode * dir,
136 	struct dentry * dentry)
137 {
138 	struct inode *inode = old_dentry->d_inode;
139 
140 	if (S_ISDIR(inode->i_mode))
141 		return -EPERM;
142 
143 	if (inode->i_nlink >= inode->i_sb->sv_link_max)
144 		return -EMLINK;
145 
146 	inode->i_ctime = CURRENT_TIME;
147 	inc_count(inode);
148 	atomic_inc(&inode->i_count);
149 
150 	return add_nondir(dentry, inode);
151 }
152 
sysv_mkdir(struct inode * dir,struct dentry * dentry,int mode)153 static int sysv_mkdir(struct inode * dir, struct dentry *dentry, int mode)
154 {
155 	struct inode * inode;
156 	int err = -EMLINK;
157 
158 	if (dir->i_nlink >= dir->i_sb->sv_link_max)
159 		goto out;
160 	inc_count(dir);
161 
162 	inode = sysv_new_inode(dir, S_IFDIR|mode);
163 	err = PTR_ERR(inode);
164 	if (IS_ERR(inode))
165 		goto out_dir;
166 
167 	sysv_set_inode(inode, 0);
168 
169 	inc_count(inode);
170 
171 	err = sysv_make_empty(inode, dir);
172 	if (err)
173 		goto out_fail;
174 
175 	err = sysv_add_link(dentry, inode);
176 	if (err)
177 		goto out_fail;
178 
179         d_instantiate(dentry, inode);
180 out:
181 	return err;
182 
183 out_fail:
184 	dec_count(inode);
185 	dec_count(inode);
186 	iput(inode);
187 out_dir:
188 	dec_count(dir);
189 	goto out;
190 }
191 
sysv_unlink(struct inode * dir,struct dentry * dentry)192 static int sysv_unlink(struct inode * dir, struct dentry * dentry)
193 {
194 	struct inode * inode = dentry->d_inode;
195 	struct page * page;
196 	struct sysv_dir_entry * de;
197 	int err = -ENOENT;
198 
199 	de = sysv_find_entry(dentry, &page);
200 	if (!de)
201 		goto out;
202 
203 	err = sysv_delete_entry (de, page);
204 	if (err)
205 		goto out;
206 
207 	inode->i_ctime = dir->i_ctime;
208 	dec_count(inode);
209 out:
210 	return err;
211 }
212 
sysv_rmdir(struct inode * dir,struct dentry * dentry)213 static int sysv_rmdir(struct inode * dir, struct dentry * dentry)
214 {
215 	struct inode *inode = dentry->d_inode;
216 	int err = -ENOTEMPTY;
217 
218 	if (sysv_empty_dir(inode)) {
219 		err = sysv_unlink(dir, dentry);
220 		if (!err) {
221 			inode->i_size = 0;
222 			dec_count(inode);
223 			dec_count(dir);
224 		}
225 	}
226 	return err;
227 }
228 
229 /*
230  * Anybody can rename anything with this: the permission checks are left to the
231  * higher-level routines.
232  */
sysv_rename(struct inode * old_dir,struct dentry * old_dentry,struct inode * new_dir,struct dentry * new_dentry)233 static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
234 		  struct inode * new_dir, struct dentry * new_dentry)
235 {
236 	struct inode * old_inode = old_dentry->d_inode;
237 	struct inode * new_inode = new_dentry->d_inode;
238 	struct page * dir_page = NULL;
239 	struct sysv_dir_entry * dir_de = NULL;
240 	struct page * old_page;
241 	struct sysv_dir_entry * old_de;
242 	int err = -ENOENT;
243 
244 	old_de = sysv_find_entry(old_dentry, &old_page);
245 	if (!old_de)
246 		goto out;
247 
248 	if (S_ISDIR(old_inode->i_mode)) {
249 		err = -EIO;
250 		dir_de = sysv_dotdot(old_inode, &dir_page);
251 		if (!dir_de)
252 			goto out_old;
253 	}
254 
255 	if (new_inode) {
256 		struct page * new_page;
257 		struct sysv_dir_entry * new_de;
258 
259 		err = -ENOTEMPTY;
260 		if (dir_de && !sysv_empty_dir(new_inode))
261 			goto out_dir;
262 
263 		err = -ENOENT;
264 		new_de = sysv_find_entry(new_dentry, &new_page);
265 		if (!new_de)
266 			goto out_dir;
267 		inc_count(old_inode);
268 		sysv_set_link(new_de, new_page, old_inode);
269 		new_inode->i_ctime = CURRENT_TIME;
270 		if (dir_de)
271 			new_inode->i_nlink--;
272 		dec_count(new_inode);
273 	} else {
274 		if (dir_de) {
275 			err = -EMLINK;
276 			if (new_dir->i_nlink >= new_dir->i_sb->sv_link_max)
277 				goto out_dir;
278 		}
279 		inc_count(old_inode);
280 		err = sysv_add_link(new_dentry, old_inode);
281 		if (err) {
282 			dec_count(old_inode);
283 			goto out_dir;
284 		}
285 		if (dir_de)
286 			inc_count(new_dir);
287 	}
288 
289 	sysv_delete_entry(old_de, old_page);
290 	dec_count(old_inode);
291 
292 	if (dir_de) {
293 		sysv_set_link(dir_de, dir_page, new_dir);
294 		dec_count(old_dir);
295 	}
296 	return 0;
297 
298 out_dir:
299 	if (dir_de) {
300 		kunmap(dir_page);
301 		page_cache_release(dir_page);
302 	}
303 out_old:
304 	kunmap(old_page);
305 	page_cache_release(old_page);
306 out:
307 	return err;
308 }
309 
310 /*
311  * directories can handle most operations...
312  */
313 struct inode_operations sysv_dir_inode_operations = {
314 	create:		sysv_create,
315 	lookup:		sysv_lookup,
316 	link:		sysv_link,
317 	unlink:		sysv_unlink,
318 	symlink:	sysv_symlink,
319 	mkdir:		sysv_mkdir,
320 	rmdir:		sysv_rmdir,
321 	mknod:		sysv_mknod,
322 	rename:		sysv_rename,
323 };
324