diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /fs/hpfs/namei.c |
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'fs/hpfs/namei.c')
-rw-r--r-- | fs/hpfs/namei.c | 673 |
1 files changed, 673 insertions, 0 deletions
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c new file mode 100644 index 00000000000..8ff8fc433fc --- /dev/null +++ b/fs/hpfs/namei.c | |||
@@ -0,0 +1,673 @@ | |||
1 | /* | ||
2 | * linux/fs/hpfs/namei.c | ||
3 | * | ||
4 | * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999 | ||
5 | * | ||
6 | * adding & removing files & directories | ||
7 | */ | ||
8 | |||
9 | #include "hpfs_fn.h" | ||
10 | |||
11 | static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | ||
12 | { | ||
13 | const char *name = dentry->d_name.name; | ||
14 | unsigned len = dentry->d_name.len; | ||
15 | struct quad_buffer_head qbh0; | ||
16 | struct buffer_head *bh; | ||
17 | struct hpfs_dirent *de; | ||
18 | struct fnode *fnode; | ||
19 | struct dnode *dnode; | ||
20 | struct inode *result; | ||
21 | fnode_secno fno; | ||
22 | dnode_secno dno; | ||
23 | int r; | ||
24 | struct hpfs_dirent dee; | ||
25 | int err; | ||
26 | if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err; | ||
27 | lock_kernel(); | ||
28 | err = -ENOSPC; | ||
29 | fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh); | ||
30 | if (!fnode) | ||
31 | goto bail; | ||
32 | dnode = hpfs_alloc_dnode(dir->i_sb, fno, &dno, &qbh0, 1); | ||
33 | if (!dnode) | ||
34 | goto bail1; | ||
35 | memset(&dee, 0, sizeof dee); | ||
36 | dee.directory = 1; | ||
37 | if (!(mode & 0222)) dee.read_only = 1; | ||
38 | /*dee.archive = 0;*/ | ||
39 | dee.hidden = name[0] == '.'; | ||
40 | dee.fnode = fno; | ||
41 | dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds()); | ||
42 | result = new_inode(dir->i_sb); | ||
43 | if (!result) | ||
44 | goto bail2; | ||
45 | hpfs_init_inode(result); | ||
46 | result->i_ino = fno; | ||
47 | hpfs_i(result)->i_parent_dir = dir->i_ino; | ||
48 | hpfs_i(result)->i_dno = dno; | ||
49 | result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date); | ||
50 | result->i_ctime.tv_nsec = 0; | ||
51 | result->i_mtime.tv_nsec = 0; | ||
52 | result->i_atime.tv_nsec = 0; | ||
53 | hpfs_i(result)->i_ea_size = 0; | ||
54 | result->i_mode |= S_IFDIR; | ||
55 | result->i_op = &hpfs_dir_iops; | ||
56 | result->i_fop = &hpfs_dir_ops; | ||
57 | result->i_blocks = 4; | ||
58 | result->i_size = 2048; | ||
59 | result->i_nlink = 2; | ||
60 | if (dee.read_only) | ||
61 | result->i_mode &= ~0222; | ||
62 | |||
63 | down(&hpfs_i(dir)->i_sem); | ||
64 | r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0); | ||
65 | if (r == 1) | ||
66 | goto bail3; | ||
67 | if (r == -1) { | ||
68 | err = -EEXIST; | ||
69 | goto bail3; | ||
70 | } | ||
71 | fnode->len = len; | ||
72 | memcpy(fnode->name, name, len > 15 ? 15 : len); | ||
73 | fnode->up = dir->i_ino; | ||
74 | fnode->dirflag = 1; | ||
75 | fnode->btree.n_free_nodes = 7; | ||
76 | fnode->btree.n_used_nodes = 1; | ||
77 | fnode->btree.first_free = 0x14; | ||
78 | fnode->u.external[0].disk_secno = dno; | ||
79 | fnode->u.external[0].file_secno = -1; | ||
80 | dnode->root_dnode = 1; | ||
81 | dnode->up = fno; | ||
82 | de = hpfs_add_de(dir->i_sb, dnode, "\001\001", 2, 0); | ||
83 | de->creation_date = de->write_date = de->read_date = gmt_to_local(dir->i_sb, get_seconds()); | ||
84 | if (!(mode & 0222)) de->read_only = 1; | ||
85 | de->first = de->directory = 1; | ||
86 | /*de->hidden = de->system = 0;*/ | ||
87 | de->fnode = fno; | ||
88 | mark_buffer_dirty(bh); | ||
89 | brelse(bh); | ||
90 | hpfs_mark_4buffers_dirty(&qbh0); | ||
91 | hpfs_brelse4(&qbh0); | ||
92 | dir->i_nlink++; | ||
93 | insert_inode_hash(result); | ||
94 | |||
95 | if (result->i_uid != current->fsuid || | ||
96 | result->i_gid != current->fsgid || | ||
97 | result->i_mode != (mode | S_IFDIR)) { | ||
98 | result->i_uid = current->fsuid; | ||
99 | result->i_gid = current->fsgid; | ||
100 | result->i_mode = mode | S_IFDIR; | ||
101 | hpfs_write_inode_nolock(result); | ||
102 | } | ||
103 | d_instantiate(dentry, result); | ||
104 | up(&hpfs_i(dir)->i_sem); | ||
105 | unlock_kernel(); | ||
106 | return 0; | ||
107 | bail3: | ||
108 | up(&hpfs_i(dir)->i_sem); | ||
109 | iput(result); | ||
110 | bail2: | ||
111 | hpfs_brelse4(&qbh0); | ||
112 | hpfs_free_dnode(dir->i_sb, dno); | ||
113 | bail1: | ||
114 | brelse(bh); | ||
115 | hpfs_free_sectors(dir->i_sb, fno, 1); | ||
116 | bail: | ||
117 | unlock_kernel(); | ||
118 | return err; | ||
119 | } | ||
120 | |||
121 | static int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) | ||
122 | { | ||
123 | const char *name = dentry->d_name.name; | ||
124 | unsigned len = dentry->d_name.len; | ||
125 | struct inode *result = NULL; | ||
126 | struct buffer_head *bh; | ||
127 | struct fnode *fnode; | ||
128 | fnode_secno fno; | ||
129 | int r; | ||
130 | struct hpfs_dirent dee; | ||
131 | int err; | ||
132 | if ((err = hpfs_chk_name((char *)name, &len))) | ||
133 | return err==-ENOENT ? -EINVAL : err; | ||
134 | lock_kernel(); | ||
135 | err = -ENOSPC; | ||
136 | fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh); | ||
137 | if (!fnode) | ||
138 | goto bail; | ||
139 | memset(&dee, 0, sizeof dee); | ||
140 | if (!(mode & 0222)) dee.read_only = 1; | ||
141 | dee.archive = 1; | ||
142 | dee.hidden = name[0] == '.'; | ||
143 | dee.fnode = fno; | ||
144 | dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds()); | ||
145 | |||
146 | result = new_inode(dir->i_sb); | ||
147 | if (!result) | ||
148 | goto bail1; | ||
149 | |||
150 | hpfs_init_inode(result); | ||
151 | result->i_ino = fno; | ||
152 | result->i_mode |= S_IFREG; | ||
153 | result->i_mode &= ~0111; | ||
154 | result->i_op = &hpfs_file_iops; | ||
155 | result->i_fop = &hpfs_file_ops; | ||
156 | result->i_nlink = 1; | ||
157 | hpfs_decide_conv(result, (char *)name, len); | ||
158 | hpfs_i(result)->i_parent_dir = dir->i_ino; | ||
159 | result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date); | ||
160 | result->i_ctime.tv_nsec = 0; | ||
161 | result->i_mtime.tv_nsec = 0; | ||
162 | result->i_atime.tv_nsec = 0; | ||
163 | hpfs_i(result)->i_ea_size = 0; | ||
164 | if (dee.read_only) | ||
165 | result->i_mode &= ~0222; | ||
166 | result->i_blocks = 1; | ||
167 | result->i_size = 0; | ||
168 | result->i_data.a_ops = &hpfs_aops; | ||
169 | hpfs_i(result)->mmu_private = 0; | ||
170 | |||
171 | down(&hpfs_i(dir)->i_sem); | ||
172 | r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0); | ||
173 | if (r == 1) | ||
174 | goto bail2; | ||
175 | if (r == -1) { | ||
176 | err = -EEXIST; | ||
177 | goto bail2; | ||
178 | } | ||
179 | fnode->len = len; | ||
180 | memcpy(fnode->name, name, len > 15 ? 15 : len); | ||
181 | fnode->up = dir->i_ino; | ||
182 | mark_buffer_dirty(bh); | ||
183 | brelse(bh); | ||
184 | |||
185 | insert_inode_hash(result); | ||
186 | |||
187 | if (result->i_uid != current->fsuid || | ||
188 | result->i_gid != current->fsgid || | ||
189 | result->i_mode != (mode | S_IFREG)) { | ||
190 | result->i_uid = current->fsuid; | ||
191 | result->i_gid = current->fsgid; | ||
192 | result->i_mode = mode | S_IFREG; | ||
193 | hpfs_write_inode_nolock(result); | ||
194 | } | ||
195 | d_instantiate(dentry, result); | ||
196 | up(&hpfs_i(dir)->i_sem); | ||
197 | unlock_kernel(); | ||
198 | return 0; | ||
199 | |||
200 | bail2: | ||
201 | up(&hpfs_i(dir)->i_sem); | ||
202 | iput(result); | ||
203 | bail1: | ||
204 | brelse(bh); | ||
205 | hpfs_free_sectors(dir->i_sb, fno, 1); | ||
206 | bail: | ||
207 | unlock_kernel(); | ||
208 | return err; | ||
209 | } | ||
210 | |||
211 | static int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) | ||
212 | { | ||
213 | const char *name = dentry->d_name.name; | ||
214 | unsigned len = dentry->d_name.len; | ||
215 | struct buffer_head *bh; | ||
216 | struct fnode *fnode; | ||
217 | fnode_secno fno; | ||
218 | int r; | ||
219 | struct hpfs_dirent dee; | ||
220 | struct inode *result = NULL; | ||
221 | int err; | ||
222 | if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err; | ||
223 | if (hpfs_sb(dir->i_sb)->sb_eas < 2) return -EPERM; | ||
224 | if (!new_valid_dev(rdev)) | ||
225 | return -EINVAL; | ||
226 | lock_kernel(); | ||
227 | err = -ENOSPC; | ||
228 | fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh); | ||
229 | if (!fnode) | ||
230 | goto bail; | ||
231 | memset(&dee, 0, sizeof dee); | ||
232 | if (!(mode & 0222)) dee.read_only = 1; | ||
233 | dee.archive = 1; | ||
234 | dee.hidden = name[0] == '.'; | ||
235 | dee.fnode = fno; | ||
236 | dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds()); | ||
237 | |||
238 | result = new_inode(dir->i_sb); | ||
239 | if (!result) | ||
240 | goto bail1; | ||
241 | |||
242 | hpfs_init_inode(result); | ||
243 | result->i_ino = fno; | ||
244 | hpfs_i(result)->i_parent_dir = dir->i_ino; | ||
245 | result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date); | ||
246 | result->i_ctime.tv_nsec = 0; | ||
247 | result->i_mtime.tv_nsec = 0; | ||
248 | result->i_atime.tv_nsec = 0; | ||
249 | hpfs_i(result)->i_ea_size = 0; | ||
250 | result->i_uid = current->fsuid; | ||
251 | result->i_gid = current->fsgid; | ||
252 | result->i_nlink = 1; | ||
253 | result->i_size = 0; | ||
254 | result->i_blocks = 1; | ||
255 | init_special_inode(result, mode, rdev); | ||
256 | |||
257 | down(&hpfs_i(dir)->i_sem); | ||
258 | r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0); | ||
259 | if (r == 1) | ||
260 | goto bail2; | ||
261 | if (r == -1) { | ||
262 | err = -EEXIST; | ||
263 | goto bail2; | ||
264 | } | ||
265 | fnode->len = len; | ||
266 | memcpy(fnode->name, name, len > 15 ? 15 : len); | ||
267 | fnode->up = dir->i_ino; | ||
268 | mark_buffer_dirty(bh); | ||
269 | |||
270 | insert_inode_hash(result); | ||
271 | |||
272 | hpfs_write_inode_nolock(result); | ||
273 | d_instantiate(dentry, result); | ||
274 | up(&hpfs_i(dir)->i_sem); | ||
275 | brelse(bh); | ||
276 | unlock_kernel(); | ||
277 | return 0; | ||
278 | bail2: | ||
279 | up(&hpfs_i(dir)->i_sem); | ||
280 | iput(result); | ||
281 | bail1: | ||
282 | brelse(bh); | ||
283 | hpfs_free_sectors(dir->i_sb, fno, 1); | ||
284 | bail: | ||
285 | unlock_kernel(); | ||
286 | return err; | ||
287 | } | ||
288 | |||
289 | static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *symlink) | ||
290 | { | ||
291 | const char *name = dentry->d_name.name; | ||
292 | unsigned len = dentry->d_name.len; | ||
293 | struct buffer_head *bh; | ||
294 | struct fnode *fnode; | ||
295 | fnode_secno fno; | ||
296 | int r; | ||
297 | struct hpfs_dirent dee; | ||
298 | struct inode *result; | ||
299 | int err; | ||
300 | if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err; | ||
301 | lock_kernel(); | ||
302 | if (hpfs_sb(dir->i_sb)->sb_eas < 2) { | ||
303 | unlock_kernel(); | ||
304 | return -EPERM; | ||
305 | } | ||
306 | err = -ENOSPC; | ||
307 | fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh); | ||
308 | if (!fnode) | ||
309 | goto bail; | ||
310 | memset(&dee, 0, sizeof dee); | ||
311 | dee.archive = 1; | ||
312 | dee.hidden = name[0] == '.'; | ||
313 | dee.fnode = fno; | ||
314 | dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds()); | ||
315 | |||
316 | result = new_inode(dir->i_sb); | ||
317 | if (!result) | ||
318 | goto bail1; | ||
319 | result->i_ino = fno; | ||
320 | hpfs_init_inode(result); | ||
321 | hpfs_i(result)->i_parent_dir = dir->i_ino; | ||
322 | result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date); | ||
323 | result->i_ctime.tv_nsec = 0; | ||
324 | result->i_mtime.tv_nsec = 0; | ||
325 | result->i_atime.tv_nsec = 0; | ||
326 | hpfs_i(result)->i_ea_size = 0; | ||
327 | result->i_mode = S_IFLNK | 0777; | ||
328 | result->i_uid = current->fsuid; | ||
329 | result->i_gid = current->fsgid; | ||
330 | result->i_blocks = 1; | ||
331 | result->i_nlink = 1; | ||
332 | result->i_size = strlen(symlink); | ||
333 | result->i_op = &page_symlink_inode_operations; | ||
334 | result->i_data.a_ops = &hpfs_symlink_aops; | ||
335 | |||
336 | down(&hpfs_i(dir)->i_sem); | ||
337 | r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0); | ||
338 | if (r == 1) | ||
339 | goto bail2; | ||
340 | if (r == -1) { | ||
341 | err = -EEXIST; | ||
342 | goto bail2; | ||
343 | } | ||
344 | fnode->len = len; | ||
345 | memcpy(fnode->name, name, len > 15 ? 15 : len); | ||
346 | fnode->up = dir->i_ino; | ||
347 | hpfs_set_ea(result, fnode, "SYMLINK", (char *)symlink, strlen(symlink)); | ||
348 | mark_buffer_dirty(bh); | ||
349 | brelse(bh); | ||
350 | |||
351 | insert_inode_hash(result); | ||
352 | |||
353 | hpfs_write_inode_nolock(result); | ||
354 | d_instantiate(dentry, result); | ||
355 | up(&hpfs_i(dir)->i_sem); | ||
356 | unlock_kernel(); | ||
357 | return 0; | ||
358 | bail2: | ||
359 | up(&hpfs_i(dir)->i_sem); | ||
360 | iput(result); | ||
361 | bail1: | ||
362 | brelse(bh); | ||
363 | hpfs_free_sectors(dir->i_sb, fno, 1); | ||
364 | bail: | ||
365 | unlock_kernel(); | ||
366 | return err; | ||
367 | } | ||
368 | |||
369 | static int hpfs_unlink(struct inode *dir, struct dentry *dentry) | ||
370 | { | ||
371 | const char *name = dentry->d_name.name; | ||
372 | unsigned len = dentry->d_name.len; | ||
373 | struct quad_buffer_head qbh; | ||
374 | struct hpfs_dirent *de; | ||
375 | struct inode *inode = dentry->d_inode; | ||
376 | dnode_secno dno; | ||
377 | fnode_secno fno; | ||
378 | int r; | ||
379 | int rep = 0; | ||
380 | int err; | ||
381 | |||
382 | lock_kernel(); | ||
383 | hpfs_adjust_length((char *)name, &len); | ||
384 | again: | ||
385 | down(&hpfs_i(inode)->i_parent); | ||
386 | down(&hpfs_i(dir)->i_sem); | ||
387 | err = -ENOENT; | ||
388 | de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *)name, len, &dno, &qbh); | ||
389 | if (!de) | ||
390 | goto out; | ||
391 | |||
392 | err = -EPERM; | ||
393 | if (de->first) | ||
394 | goto out1; | ||
395 | |||
396 | err = -EISDIR; | ||
397 | if (de->directory) | ||
398 | goto out1; | ||
399 | |||
400 | fno = de->fnode; | ||
401 | r = hpfs_remove_dirent(dir, dno, de, &qbh, 1); | ||
402 | switch (r) { | ||
403 | case 1: | ||
404 | hpfs_error(dir->i_sb, "there was error when removing dirent"); | ||
405 | err = -EFSERROR; | ||
406 | break; | ||
407 | case 2: /* no space for deleting, try to truncate file */ | ||
408 | |||
409 | err = -ENOSPC; | ||
410 | if (rep++) | ||
411 | break; | ||
412 | |||
413 | up(&hpfs_i(dir)->i_sem); | ||
414 | up(&hpfs_i(inode)->i_parent); | ||
415 | d_drop(dentry); | ||
416 | spin_lock(&dentry->d_lock); | ||
417 | if (atomic_read(&dentry->d_count) > 1 || | ||
418 | permission(inode, MAY_WRITE, NULL) || | ||
419 | !S_ISREG(inode->i_mode) || | ||
420 | get_write_access(inode)) { | ||
421 | spin_unlock(&dentry->d_lock); | ||
422 | d_rehash(dentry); | ||
423 | } else { | ||
424 | struct iattr newattrs; | ||
425 | spin_unlock(&dentry->d_lock); | ||
426 | /*printk("HPFS: truncating file before delete.\n");*/ | ||
427 | newattrs.ia_size = 0; | ||
428 | newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; | ||
429 | err = notify_change(dentry, &newattrs); | ||
430 | put_write_access(inode); | ||
431 | if (!err) | ||
432 | goto again; | ||
433 | } | ||
434 | unlock_kernel(); | ||
435 | return -ENOSPC; | ||
436 | default: | ||
437 | inode->i_nlink--; | ||
438 | err = 0; | ||
439 | } | ||
440 | goto out; | ||
441 | |||
442 | out1: | ||
443 | hpfs_brelse4(&qbh); | ||
444 | out: | ||
445 | up(&hpfs_i(dir)->i_sem); | ||
446 | up(&hpfs_i(inode)->i_parent); | ||
447 | unlock_kernel(); | ||
448 | return err; | ||
449 | } | ||
450 | |||
451 | static int hpfs_rmdir(struct inode *dir, struct dentry *dentry) | ||
452 | { | ||
453 | const char *name = dentry->d_name.name; | ||
454 | unsigned len = dentry->d_name.len; | ||
455 | struct quad_buffer_head qbh; | ||
456 | struct hpfs_dirent *de; | ||
457 | struct inode *inode = dentry->d_inode; | ||
458 | dnode_secno dno; | ||
459 | fnode_secno fno; | ||
460 | int n_items = 0; | ||
461 | int err; | ||
462 | int r; | ||
463 | |||
464 | hpfs_adjust_length((char *)name, &len); | ||
465 | lock_kernel(); | ||
466 | down(&hpfs_i(inode)->i_parent); | ||
467 | down(&hpfs_i(dir)->i_sem); | ||
468 | err = -ENOENT; | ||
469 | de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *)name, len, &dno, &qbh); | ||
470 | if (!de) | ||
471 | goto out; | ||
472 | |||
473 | err = -EPERM; | ||
474 | if (de->first) | ||
475 | goto out1; | ||
476 | |||
477 | err = -ENOTDIR; | ||
478 | if (!de->directory) | ||
479 | goto out1; | ||
480 | |||
481 | hpfs_count_dnodes(dir->i_sb, hpfs_i(inode)->i_dno, NULL, NULL, &n_items); | ||
482 | err = -ENOTEMPTY; | ||
483 | if (n_items) | ||
484 | goto out1; | ||
485 | |||
486 | fno = de->fnode; | ||
487 | r = hpfs_remove_dirent(dir, dno, de, &qbh, 1); | ||
488 | switch (r) { | ||
489 | case 1: | ||
490 | hpfs_error(dir->i_sb, "there was error when removing dirent"); | ||
491 | err = -EFSERROR; | ||
492 | break; | ||
493 | case 2: | ||
494 | err = -ENOSPC; | ||
495 | break; | ||
496 | default: | ||
497 | dir->i_nlink--; | ||
498 | inode->i_nlink = 0; | ||
499 | err = 0; | ||
500 | } | ||
501 | goto out; | ||
502 | out1: | ||
503 | hpfs_brelse4(&qbh); | ||
504 | out: | ||
505 | up(&hpfs_i(dir)->i_sem); | ||
506 | up(&hpfs_i(inode)->i_parent); | ||
507 | unlock_kernel(); | ||
508 | return err; | ||
509 | } | ||
510 | |||
511 | static int hpfs_symlink_readpage(struct file *file, struct page *page) | ||
512 | { | ||
513 | char *link = kmap(page); | ||
514 | struct inode *i = page->mapping->host; | ||
515 | struct fnode *fnode; | ||
516 | struct buffer_head *bh; | ||
517 | int err; | ||
518 | |||
519 | err = -EIO; | ||
520 | lock_kernel(); | ||
521 | if (!(fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh))) | ||
522 | goto fail; | ||
523 | err = hpfs_read_ea(i->i_sb, fnode, "SYMLINK", link, PAGE_SIZE); | ||
524 | brelse(bh); | ||
525 | if (err) | ||
526 | goto fail; | ||
527 | unlock_kernel(); | ||
528 | SetPageUptodate(page); | ||
529 | kunmap(page); | ||
530 | unlock_page(page); | ||
531 | return 0; | ||
532 | |||
533 | fail: | ||
534 | unlock_kernel(); | ||
535 | SetPageError(page); | ||
536 | kunmap(page); | ||
537 | unlock_page(page); | ||
538 | return err; | ||
539 | } | ||
540 | |||
541 | struct address_space_operations hpfs_symlink_aops = { | ||
542 | .readpage = hpfs_symlink_readpage | ||
543 | }; | ||
544 | |||
545 | static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, | ||
546 | struct inode *new_dir, struct dentry *new_dentry) | ||
547 | { | ||
548 | char *old_name = (char *)old_dentry->d_name.name; | ||
549 | int old_len = old_dentry->d_name.len; | ||
550 | char *new_name = (char *)new_dentry->d_name.name; | ||
551 | int new_len = new_dentry->d_name.len; | ||
552 | struct inode *i = old_dentry->d_inode; | ||
553 | struct inode *new_inode = new_dentry->d_inode; | ||
554 | struct quad_buffer_head qbh, qbh1; | ||
555 | struct hpfs_dirent *dep, *nde; | ||
556 | struct hpfs_dirent de; | ||
557 | dnode_secno dno; | ||
558 | int r; | ||
559 | struct buffer_head *bh; | ||
560 | struct fnode *fnode; | ||
561 | int err; | ||
562 | if ((err = hpfs_chk_name((char *)new_name, &new_len))) return err; | ||
563 | err = 0; | ||
564 | hpfs_adjust_length((char *)old_name, &old_len); | ||
565 | |||
566 | lock_kernel(); | ||
567 | /* order doesn't matter, due to VFS exclusion */ | ||
568 | down(&hpfs_i(i)->i_parent); | ||
569 | if (new_inode) | ||
570 | down(&hpfs_i(new_inode)->i_parent); | ||
571 | down(&hpfs_i(old_dir)->i_sem); | ||
572 | if (new_dir != old_dir) | ||
573 | down(&hpfs_i(new_dir)->i_sem); | ||
574 | |||
575 | /* Erm? Moving over the empty non-busy directory is perfectly legal */ | ||
576 | if (new_inode && S_ISDIR(new_inode->i_mode)) { | ||
577 | err = -EINVAL; | ||
578 | goto end1; | ||
579 | } | ||
580 | |||
581 | if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, (char *)old_name, old_len, &dno, &qbh))) { | ||
582 | hpfs_error(i->i_sb, "lookup succeeded but map dirent failed"); | ||
583 | err = -ENOENT; | ||
584 | goto end1; | ||
585 | } | ||
586 | copy_de(&de, dep); | ||
587 | de.hidden = new_name[0] == '.'; | ||
588 | |||
589 | if (new_inode) { | ||
590 | int r; | ||
591 | if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 1)) != 2) { | ||
592 | if ((nde = map_dirent(new_dir, hpfs_i(new_dir)->i_dno, (char *)new_name, new_len, NULL, &qbh1))) { | ||
593 | new_inode->i_nlink = 0; | ||
594 | copy_de(nde, &de); | ||
595 | memcpy(nde->name, new_name, new_len); | ||
596 | hpfs_mark_4buffers_dirty(&qbh1); | ||
597 | hpfs_brelse4(&qbh1); | ||
598 | goto end; | ||
599 | } | ||
600 | hpfs_error(new_dir->i_sb, "hpfs_rename: could not find dirent"); | ||
601 | err = -EFSERROR; | ||
602 | goto end1; | ||
603 | } | ||
604 | err = r == 2 ? -ENOSPC : r == 1 ? -EFSERROR : 0; | ||
605 | goto end1; | ||
606 | } | ||
607 | |||
608 | if (new_dir == old_dir) hpfs_brelse4(&qbh); | ||
609 | |||
610 | hpfs_lock_creation(i->i_sb); | ||
611 | if ((r = hpfs_add_dirent(new_dir, new_name, new_len, &de, 1))) { | ||
612 | hpfs_unlock_creation(i->i_sb); | ||
613 | if (r == -1) hpfs_error(new_dir->i_sb, "hpfs_rename: dirent already exists!"); | ||
614 | err = r == 1 ? -ENOSPC : -EFSERROR; | ||
615 | if (new_dir != old_dir) hpfs_brelse4(&qbh); | ||
616 | goto end1; | ||
617 | } | ||
618 | |||
619 | if (new_dir == old_dir) | ||
620 | if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, (char *)old_name, old_len, &dno, &qbh))) { | ||
621 | hpfs_unlock_creation(i->i_sb); | ||
622 | hpfs_error(i->i_sb, "lookup succeeded but map dirent failed at #2"); | ||
623 | err = -ENOENT; | ||
624 | goto end1; | ||
625 | } | ||
626 | |||
627 | if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 0))) { | ||
628 | hpfs_unlock_creation(i->i_sb); | ||
629 | hpfs_error(i->i_sb, "hpfs_rename: could not remove dirent"); | ||
630 | err = r == 2 ? -ENOSPC : -EFSERROR; | ||
631 | goto end1; | ||
632 | } | ||
633 | hpfs_unlock_creation(i->i_sb); | ||
634 | |||
635 | end: | ||
636 | hpfs_i(i)->i_parent_dir = new_dir->i_ino; | ||
637 | if (S_ISDIR(i->i_mode)) { | ||
638 | new_dir->i_nlink++; | ||
639 | old_dir->i_nlink--; | ||
640 | } | ||
641 | if ((fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh))) { | ||
642 | fnode->up = new_dir->i_ino; | ||
643 | fnode->len = new_len; | ||
644 | memcpy(fnode->name, new_name, new_len>15?15:new_len); | ||
645 | if (new_len < 15) memset(&fnode->name[new_len], 0, 15 - new_len); | ||
646 | mark_buffer_dirty(bh); | ||
647 | brelse(bh); | ||
648 | } | ||
649 | hpfs_i(i)->i_conv = hpfs_sb(i->i_sb)->sb_conv; | ||
650 | hpfs_decide_conv(i, (char *)new_name, new_len); | ||
651 | end1: | ||
652 | if (old_dir != new_dir) | ||
653 | up(&hpfs_i(new_dir)->i_sem); | ||
654 | up(&hpfs_i(old_dir)->i_sem); | ||
655 | up(&hpfs_i(i)->i_parent); | ||
656 | if (new_inode) | ||
657 | up(&hpfs_i(new_inode)->i_parent); | ||
658 | unlock_kernel(); | ||
659 | return err; | ||
660 | } | ||
661 | |||
662 | struct inode_operations hpfs_dir_iops = | ||
663 | { | ||
664 | .create = hpfs_create, | ||
665 | .lookup = hpfs_lookup, | ||
666 | .unlink = hpfs_unlink, | ||
667 | .symlink = hpfs_symlink, | ||
668 | .mkdir = hpfs_mkdir, | ||
669 | .rmdir = hpfs_rmdir, | ||
670 | .mknod = hpfs_mknod, | ||
671 | .rename = hpfs_rename, | ||
672 | .setattr = hpfs_notify_change, | ||
673 | }; | ||