]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * linux/fs/hpfs/namei.c | |
3 | * | |
4 | * Mikulas Patocka ([email protected]), 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 | }; |