]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * linux/fs/ufs/namei.c | |
3 | * | |
4 | * Copyright (C) 1998 | |
5 | * Daniel Pirkl <daniel.pirkl@email.cz> | |
6 | * Charles University, Faculty of Mathematics and Physics | |
7 | * | |
8 | * from | |
9 | * | |
10 | * linux/fs/ext2/namei.c | |
11 | * | |
12 | * Copyright (C) 1992, 1993, 1994, 1995 | |
13 | * Remy Card (card@masi.ibp.fr) | |
14 | * Laboratoire MASI - Institut Blaise Pascal | |
15 | * Universite Pierre et Marie Curie (Paris VI) | |
16 | * | |
17 | * from | |
18 | * | |
19 | * linux/fs/minix/namei.c | |
20 | * | |
21 | * Copyright (C) 1991, 1992 Linus Torvalds | |
22 | * | |
23 | * Big-endian to little-endian byte-swapping/bitmaps by | |
24 | * David S. Miller (davem@caip.rutgers.edu), 1995 | |
25 | */ | |
26 | ||
27 | #include <linux/time.h> | |
28 | #include <linux/fs.h> | |
29 | #include <linux/ufs_fs.h> | |
30 | #include <linux/smp_lock.h> | |
31 | #include <linux/buffer_head.h> | |
32 | #include "swab.h" /* will go away - see comment in mknod() */ | |
33 | #include "util.h" | |
34 | ||
35 | /* | |
36 | #undef UFS_NAMEI_DEBUG | |
37 | */ | |
38 | #define UFS_NAMEI_DEBUG | |
39 | ||
40 | #ifdef UFS_NAMEI_DEBUG | |
41 | #define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x; | |
42 | #else | |
43 | #define UFSD(x) | |
44 | #endif | |
45 | ||
1da177e4 LT |
46 | static inline int ufs_add_nondir(struct dentry *dentry, struct inode *inode) |
47 | { | |
48 | int err = ufs_add_link(dentry, inode); | |
49 | if (!err) { | |
50 | d_instantiate(dentry, inode); | |
51 | return 0; | |
52 | } | |
3257545e | 53 | inode_dec_link_count(inode); |
1da177e4 LT |
54 | iput(inode); |
55 | return err; | |
56 | } | |
57 | ||
58 | static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) | |
59 | { | |
60 | struct inode * inode = NULL; | |
61 | ino_t ino; | |
62 | ||
63 | if (dentry->d_name.len > UFS_MAXNAMLEN) | |
64 | return ERR_PTR(-ENAMETOOLONG); | |
65 | ||
66 | lock_kernel(); | |
67 | ino = ufs_inode_by_name(dir, dentry); | |
68 | if (ino) { | |
69 | inode = iget(dir->i_sb, ino); | |
70 | if (!inode) { | |
71 | unlock_kernel(); | |
72 | return ERR_PTR(-EACCES); | |
73 | } | |
74 | } | |
75 | unlock_kernel(); | |
76 | d_add(dentry, inode); | |
77 | return NULL; | |
78 | } | |
79 | ||
80 | /* | |
81 | * By the time this is called, we already have created | |
82 | * the directory cache entry for the new file, but it | |
83 | * is so far negative - it has no inode. | |
84 | * | |
85 | * If the create succeeds, we fill in the inode information | |
86 | * with d_instantiate(). | |
87 | */ | |
88 | static int ufs_create (struct inode * dir, struct dentry * dentry, int mode, | |
89 | struct nameidata *nd) | |
90 | { | |
91 | struct inode * inode = ufs_new_inode(dir, mode); | |
92 | int err = PTR_ERR(inode); | |
93 | if (!IS_ERR(inode)) { | |
94 | inode->i_op = &ufs_file_inode_operations; | |
95 | inode->i_fop = &ufs_file_operations; | |
96 | inode->i_mapping->a_ops = &ufs_aops; | |
97 | mark_inode_dirty(inode); | |
98 | lock_kernel(); | |
99 | err = ufs_add_nondir(dentry, inode); | |
100 | unlock_kernel(); | |
101 | } | |
102 | return err; | |
103 | } | |
104 | ||
105 | static int ufs_mknod (struct inode * dir, struct dentry *dentry, int mode, dev_t rdev) | |
106 | { | |
107 | struct inode *inode; | |
108 | int err; | |
109 | ||
110 | if (!old_valid_dev(rdev)) | |
111 | return -EINVAL; | |
112 | inode = ufs_new_inode(dir, mode); | |
113 | err = PTR_ERR(inode); | |
114 | if (!IS_ERR(inode)) { | |
115 | init_special_inode(inode, mode, rdev); | |
116 | /* NOTE: that'll go when we get wide dev_t */ | |
117 | ufs_set_inode_dev(inode->i_sb, UFS_I(inode), rdev); | |
118 | mark_inode_dirty(inode); | |
119 | lock_kernel(); | |
120 | err = ufs_add_nondir(dentry, inode); | |
121 | unlock_kernel(); | |
122 | } | |
123 | return err; | |
124 | } | |
125 | ||
126 | static int ufs_symlink (struct inode * dir, struct dentry * dentry, | |
127 | const char * symname) | |
128 | { | |
129 | struct super_block * sb = dir->i_sb; | |
130 | int err = -ENAMETOOLONG; | |
131 | unsigned l = strlen(symname)+1; | |
132 | struct inode * inode; | |
133 | ||
134 | if (l > sb->s_blocksize) | |
135 | goto out; | |
136 | ||
137 | lock_kernel(); | |
138 | inode = ufs_new_inode(dir, S_IFLNK | S_IRWXUGO); | |
139 | err = PTR_ERR(inode); | |
140 | if (IS_ERR(inode)) | |
141 | goto out; | |
142 | ||
143 | if (l > UFS_SB(sb)->s_uspi->s_maxsymlinklen) { | |
144 | /* slow symlink */ | |
145 | inode->i_op = &page_symlink_inode_operations; | |
146 | inode->i_mapping->a_ops = &ufs_aops; | |
147 | err = page_symlink(inode, symname, l); | |
148 | if (err) | |
149 | goto out_fail; | |
150 | } else { | |
151 | /* fast symlink */ | |
152 | inode->i_op = &ufs_fast_symlink_inode_operations; | |
153 | memcpy((char*)&UFS_I(inode)->i_u1.i_data,symname,l); | |
154 | inode->i_size = l-1; | |
155 | } | |
156 | mark_inode_dirty(inode); | |
157 | ||
158 | err = ufs_add_nondir(dentry, inode); | |
159 | out: | |
160 | unlock_kernel(); | |
161 | return err; | |
162 | ||
163 | out_fail: | |
3257545e | 164 | inode_dec_link_count(inode); |
1da177e4 LT |
165 | iput(inode); |
166 | goto out; | |
167 | } | |
168 | ||
169 | static int ufs_link (struct dentry * old_dentry, struct inode * dir, | |
170 | struct dentry *dentry) | |
171 | { | |
172 | struct inode *inode = old_dentry->d_inode; | |
173 | int error; | |
174 | ||
175 | lock_kernel(); | |
176 | if (inode->i_nlink >= UFS_LINK_MAX) { | |
177 | unlock_kernel(); | |
178 | return -EMLINK; | |
179 | } | |
180 | ||
181 | inode->i_ctime = CURRENT_TIME_SEC; | |
3257545e | 182 | inode_inc_link_count(inode); |
1da177e4 LT |
183 | atomic_inc(&inode->i_count); |
184 | ||
185 | error = ufs_add_nondir(dentry, inode); | |
186 | unlock_kernel(); | |
187 | return error; | |
188 | } | |
189 | ||
190 | static int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode) | |
191 | { | |
192 | struct inode * inode; | |
193 | int err = -EMLINK; | |
194 | ||
195 | if (dir->i_nlink >= UFS_LINK_MAX) | |
196 | goto out; | |
197 | ||
198 | lock_kernel(); | |
3257545e | 199 | inode_inc_link_count(dir); |
1da177e4 LT |
200 | |
201 | inode = ufs_new_inode(dir, S_IFDIR|mode); | |
202 | err = PTR_ERR(inode); | |
203 | if (IS_ERR(inode)) | |
204 | goto out_dir; | |
205 | ||
206 | inode->i_op = &ufs_dir_inode_operations; | |
207 | inode->i_fop = &ufs_dir_operations; | |
208 | ||
3257545e | 209 | inode_inc_link_count(inode); |
1da177e4 LT |
210 | |
211 | err = ufs_make_empty(inode, dir); | |
212 | if (err) | |
213 | goto out_fail; | |
214 | ||
215 | err = ufs_add_link(dentry, inode); | |
216 | if (err) | |
217 | goto out_fail; | |
218 | unlock_kernel(); | |
219 | ||
220 | d_instantiate(dentry, inode); | |
221 | out: | |
222 | return err; | |
223 | ||
224 | out_fail: | |
3257545e AD |
225 | inode_dec_link_count(inode); |
226 | inode_dec_link_count(inode); | |
1da177e4 LT |
227 | iput (inode); |
228 | out_dir: | |
3257545e | 229 | inode_dec_link_count(dir); |
1da177e4 LT |
230 | unlock_kernel(); |
231 | goto out; | |
232 | } | |
233 | ||
234 | static int ufs_unlink(struct inode * dir, struct dentry *dentry) | |
235 | { | |
236 | struct inode * inode = dentry->d_inode; | |
237 | struct buffer_head * bh; | |
238 | struct ufs_dir_entry * de; | |
239 | int err = -ENOENT; | |
240 | ||
241 | lock_kernel(); | |
242 | de = ufs_find_entry (dentry, &bh); | |
243 | if (!de) | |
244 | goto out; | |
245 | ||
246 | err = ufs_delete_entry (dir, de, bh); | |
247 | if (err) | |
248 | goto out; | |
249 | ||
250 | inode->i_ctime = dir->i_ctime; | |
3257545e | 251 | inode_dec_link_count(inode); |
1da177e4 LT |
252 | err = 0; |
253 | out: | |
254 | unlock_kernel(); | |
255 | return err; | |
256 | } | |
257 | ||
258 | static int ufs_rmdir (struct inode * dir, struct dentry *dentry) | |
259 | { | |
260 | struct inode * inode = dentry->d_inode; | |
261 | int err= -ENOTEMPTY; | |
262 | ||
263 | lock_kernel(); | |
264 | if (ufs_empty_dir (inode)) { | |
265 | err = ufs_unlink(dir, dentry); | |
266 | if (!err) { | |
267 | inode->i_size = 0; | |
3257545e AD |
268 | inode_dec_link_count(inode); |
269 | inode_dec_link_count(dir); | |
1da177e4 LT |
270 | } |
271 | } | |
272 | unlock_kernel(); | |
273 | return err; | |
274 | } | |
275 | ||
276 | static int ufs_rename (struct inode * old_dir, struct dentry * old_dentry, | |
277 | struct inode * new_dir, struct dentry * new_dentry ) | |
278 | { | |
279 | struct inode *old_inode = old_dentry->d_inode; | |
280 | struct inode *new_inode = new_dentry->d_inode; | |
281 | struct buffer_head *dir_bh = NULL; | |
282 | struct ufs_dir_entry *dir_de = NULL; | |
283 | struct buffer_head *old_bh; | |
284 | struct ufs_dir_entry *old_de; | |
285 | int err = -ENOENT; | |
286 | ||
287 | lock_kernel(); | |
288 | old_de = ufs_find_entry (old_dentry, &old_bh); | |
289 | if (!old_de) | |
290 | goto out; | |
291 | ||
292 | if (S_ISDIR(old_inode->i_mode)) { | |
293 | err = -EIO; | |
294 | dir_de = ufs_dotdot(old_inode, &dir_bh); | |
295 | if (!dir_de) | |
296 | goto out_old; | |
297 | } | |
298 | ||
299 | if (new_inode) { | |
300 | struct buffer_head *new_bh; | |
301 | struct ufs_dir_entry *new_de; | |
302 | ||
303 | err = -ENOTEMPTY; | |
304 | if (dir_de && !ufs_empty_dir (new_inode)) | |
305 | goto out_dir; | |
306 | err = -ENOENT; | |
307 | new_de = ufs_find_entry (new_dentry, &new_bh); | |
308 | if (!new_de) | |
309 | goto out_dir; | |
3257545e | 310 | inode_inc_link_count(old_inode); |
1da177e4 LT |
311 | ufs_set_link(new_dir, new_de, new_bh, old_inode); |
312 | new_inode->i_ctime = CURRENT_TIME_SEC; | |
313 | if (dir_de) | |
314 | new_inode->i_nlink--; | |
3257545e | 315 | inode_dec_link_count(new_inode); |
1da177e4 LT |
316 | } else { |
317 | if (dir_de) { | |
318 | err = -EMLINK; | |
319 | if (new_dir->i_nlink >= UFS_LINK_MAX) | |
320 | goto out_dir; | |
321 | } | |
3257545e | 322 | inode_inc_link_count(old_inode); |
1da177e4 LT |
323 | err = ufs_add_link(new_dentry, old_inode); |
324 | if (err) { | |
3257545e | 325 | inode_dec_link_count(old_inode); |
1da177e4 LT |
326 | goto out_dir; |
327 | } | |
328 | if (dir_de) | |
3257545e | 329 | inode_inc_link_count(new_dir); |
1da177e4 LT |
330 | } |
331 | ||
332 | ufs_delete_entry (old_dir, old_de, old_bh); | |
333 | ||
3257545e | 334 | inode_dec_link_count(old_inode); |
1da177e4 LT |
335 | |
336 | if (dir_de) { | |
337 | ufs_set_link(old_inode, dir_de, dir_bh, new_dir); | |
3257545e | 338 | inode_dec_link_count(old_dir); |
1da177e4 LT |
339 | } |
340 | unlock_kernel(); | |
341 | return 0; | |
342 | ||
343 | out_dir: | |
344 | if (dir_de) | |
345 | brelse(dir_bh); | |
346 | out_old: | |
347 | brelse (old_bh); | |
348 | out: | |
349 | unlock_kernel(); | |
350 | return err; | |
351 | } | |
352 | ||
353 | struct inode_operations ufs_dir_inode_operations = { | |
354 | .create = ufs_create, | |
355 | .lookup = ufs_lookup, | |
356 | .link = ufs_link, | |
357 | .unlink = ufs_unlink, | |
358 | .symlink = ufs_symlink, | |
359 | .mkdir = ufs_mkdir, | |
360 | .rmdir = ufs_rmdir, | |
361 | .mknod = ufs_mknod, | |
362 | .rename = ufs_rename, | |
363 | }; |