Linux 2.2.0
[davej-history.git] / fs / umsdos / namei.c
blob8e7780395a8942643905a278170c6e1e08379e94
1 /*
2 * linux/fs/umsdos/namei.c
4 * Written 1993 by Jacques Gelinas
5 * Inspired from linux/fs/msdos/... by Werner Almesberger
7 * Maintain and access the --linux alternate directory file.
8 */
10 #include <linux/errno.h>
11 #include <linux/kernel.h>
12 #include <linux/sched.h>
13 #include <linux/types.h>
14 #include <linux/fcntl.h>
15 #include <linux/stat.h>
16 #include <linux/string.h>
17 #include <linux/msdos_fs.h>
18 #include <linux/umsdos_fs.h>
19 #include <linux/malloc.h>
21 #if 1
23 * Wait for creation exclusivity.
24 * Return 0 if the dir was already available.
25 * Return 1 if a wait was necessary.
26 * When 1 is return, it means a wait was done. It does not
27 * mean the directory is available.
29 static int umsdos_waitcreate (struct inode *dir)
31 int ret = 0;
33 if (dir->u.umsdos_i.u.dir_info.creating
34 && dir->u.umsdos_i.u.dir_info.pid != current->pid) {
35 sleep_on (&dir->u.umsdos_i.u.dir_info.p);
36 ret = 1;
38 return ret;
42 * Wait for any lookup process to finish
44 static void umsdos_waitlookup (struct inode *dir)
46 while (dir->u.umsdos_i.u.dir_info.looking) {
47 sleep_on (&dir->u.umsdos_i.u.dir_info.p);
52 * Lock all other process out of this directory.
54 /* #Specification: file creation / not atomic
55 * File creation is a two step process. First we create (allocate)
56 * an entry in the EMD file and then (using the entry offset) we
57 * build a unique name for MSDOS. We create this name in the msdos
58 * space.
60 * We have to use semaphore (sleep_on/wake_up) to prevent lookup
61 * into a directory when we create a file or directory and to
62 * prevent creation while a lookup is going on. Since many lookup
63 * may happen at the same time, the semaphore is a counter.
65 * Only one creation is allowed at the same time. This protection
66 * may not be necessary. The problem arise mainly when a lookup
67 * or a readdir is done while a file is partially created. The
68 * lookup process see that as a "normal" problem and silently
69 * erase the file from the EMD file. Normal because a file
70 * may be erased during a MSDOS session, but not removed from
71 * the EMD file.
73 * The locking is done on a directory per directory basis. Each
74 * directory inode has its wait_queue.
76 * For some operation like hard link, things even get worse. Many
77 * creation must occur at once (atomic). To simplify the design
78 * a process is allowed to recursively lock the directory for
79 * creation. The pid of the locking process is kept along with
80 * a counter so a second level of locking is granted or not.
82 void umsdos_lockcreate (struct inode *dir)
85 * Wait for any creation process to finish except
86 * if we (the process) own the lock
88 while (umsdos_waitcreate (dir) != 0);
89 dir->u.umsdos_i.u.dir_info.creating++;
90 dir->u.umsdos_i.u.dir_info.pid = current->pid;
91 umsdos_waitlookup (dir);
95 * Lock all other process out of those two directories.
97 static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
100 * We must check that both directory are available before
101 * locking anyone of them. This is to avoid some deadlock.
102 * Thanks to dglaude@is1.vub.ac.be (GLAUDE DAVID) for pointing
103 * this to me.
105 while (1) {
106 if (umsdos_waitcreate (dir1) == 0
107 && umsdos_waitcreate (dir2) == 0) {
108 /* We own both now */
109 dir1->u.umsdos_i.u.dir_info.creating++;
110 dir1->u.umsdos_i.u.dir_info.pid = current->pid;
111 dir2->u.umsdos_i.u.dir_info.creating++;
112 dir2->u.umsdos_i.u.dir_info.pid = current->pid;
113 break;
116 umsdos_waitlookup (dir1);
117 umsdos_waitlookup (dir2);
121 * Wait until creation is finish in this directory.
123 void umsdos_startlookup (struct inode *dir)
125 while (umsdos_waitcreate (dir) != 0);
126 dir->u.umsdos_i.u.dir_info.looking++;
130 * Unlock the directory.
132 void umsdos_unlockcreate (struct inode *dir)
134 dir->u.umsdos_i.u.dir_info.creating--;
135 if (dir->u.umsdos_i.u.dir_info.creating < 0) {
136 printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.creating < 0: %d"
137 ,dir->u.umsdos_i.u.dir_info.creating);
139 wake_up (&dir->u.umsdos_i.u.dir_info.p);
143 * Tell directory lookup is over.
145 void umsdos_endlookup (struct inode *dir)
147 dir->u.umsdos_i.u.dir_info.looking--;
148 if (dir->u.umsdos_i.u.dir_info.looking < 0) {
149 printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.looking < 0: %d"
150 ,dir->u.umsdos_i.u.dir_info.looking);
152 wake_up (&dir->u.umsdos_i.u.dir_info.p);
155 #else
156 static void umsdos_lockcreate (struct inode *dir)
159 static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
162 void umsdos_startlookup (struct inode *dir)
165 static void umsdos_unlockcreate (struct inode *dir)
168 void umsdos_endlookup (struct inode *dir)
172 #endif
175 * Check whether we can delete from the directory.
177 static int is_sticky(struct inode *dir, int uid)
179 return !((dir->i_mode & S_ISVTX) == 0 ||
180 current->fsuid == uid ||
181 current->fsuid == dir->i_uid ||
182 capable (CAP_FOWNER));
186 static int umsdos_nevercreat (struct inode *dir, struct dentry *dentry,
187 int errcod)
189 int ret = 0;
191 if (umsdos_is_pseudodos (dir, dentry)) {
192 /* #Specification: pseudo root / any file creation /DOS
193 * The pseudo sub-directory /DOS can't be created!
194 * EEXIST is returned.
196 * The pseudo sub-directory /DOS can't be removed!
197 * EPERM is returned.
199 ret = errcod;
201 return ret;
205 * Add a new file (ordinary or special) into the alternate directory.
206 * The file is added to the real MSDOS directory. If successful, it
207 * is then added to the EMD file.
209 * Return the status of the operation. 0 mean success.
211 * #Specification: create / file exists in DOS
212 * Here is a situation: we are trying to create a file with
213 * UMSDOS. The file is unknown to UMSDOS but already
214 * exists in the DOS directory.
216 * Here is what we are NOT doing:
218 * We could silently assume that everything is fine
219 * and allows the creation to succeed.
221 * It is possible not all files in the partition
222 * are meant to be visible from linux. By trying to create
223 * those file in some directory, one user may get access
224 * to those file without proper permissions. Looks like
225 * a security hole to me. Off course sharing a file system
226 * with DOS is some kind of security hole :-)
228 * So ?
230 * We return EEXIST in this case.
231 * The same is true for directory creation.
233 static int umsdos_create_any (struct inode *dir, struct dentry *dentry,
234 int mode, int rdev, char flags)
236 struct dentry *fake;
237 struct inode *inode;
238 int ret;
239 struct umsdos_info info;
241 ret = umsdos_nevercreat (dir, dentry, -EEXIST);
242 if (ret)
243 goto out;
245 ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
246 if (ret)
247 goto out;
249 info.entry.mode = mode;
250 info.entry.rdev = rdev;
251 info.entry.flags = flags;
252 info.entry.uid = current->fsuid;
253 info.entry.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
254 info.entry.ctime = info.entry.atime = info.entry.mtime = CURRENT_TIME;
255 info.entry.nlink = 1;
256 ret = umsdos_newentry (dentry->d_parent, &info);
257 if (ret)
258 goto out;
260 /* do a real lookup to get the short name dentry */
261 fake = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname,
262 info.fake.len, 1);
263 ret = PTR_ERR(fake);
264 if (IS_ERR(fake))
265 goto out_remove;
267 /* keep the short name anonymous ... */
268 if (dentry != fake)
269 d_drop(fake);
271 /* should not exist yet ... */
272 ret = -EEXIST;
273 if (fake->d_inode)
274 goto out_remove_dput;
276 ret = msdos_create (dir, fake, S_IFREG | 0777);
277 if (ret)
278 goto out_remove_dput;
280 inode = fake->d_inode;
282 * Note! The long and short name might be the same,
283 * so check first before doing the instantiate ...
285 if (dentry != fake) {
286 inode->i_count++;
287 d_instantiate (dentry, inode);
289 dput(fake);
290 if (inode->i_count > 1) {
291 printk(KERN_WARNING
292 "umsdos_create_any: %s/%s, ino=%ld, icount=%d??\n",
293 dentry->d_parent->d_name.name, dentry->d_name.name,
294 inode->i_ino, inode->i_count);
296 umsdos_lookup_patch_new(dentry, &info);
298 out:
299 return ret;
301 /* Creation failed ... remove the EMD entry */
302 out_remove_dput:
303 dput(fake);
304 out_remove:
305 if (ret == -EEXIST)
306 printk(KERN_WARNING "UMSDOS: out of sync, deleting %s/%s\n",
307 dentry->d_parent->d_name.name, info.fake.fname);
308 umsdos_delentry (dentry->d_parent, &info, S_ISDIR (info.entry.mode));
309 goto out;
313 * Add a new file into the alternate directory.
314 * The file is added to the real MSDOS directory. If successful, it
315 * is then added to the EMD file.
317 * Return the status of the operation. 0 mean success.
319 int UMSDOS_create (struct inode *dir, struct dentry *dentry, int mode)
321 return umsdos_create_any (dir, dentry, mode, 0, 0);
326 * Initialise the new_entry from the old for a rename operation.
327 * (Only useful for umsdos_rename_f() below).
329 static void umsdos_ren_init (struct umsdos_info *new_info,
330 struct umsdos_info *old_info)
332 new_info->entry.mode = old_info->entry.mode;
333 new_info->entry.rdev = old_info->entry.rdev;
334 new_info->entry.uid = old_info->entry.uid;
335 new_info->entry.gid = old_info->entry.gid;
336 new_info->entry.ctime = old_info->entry.ctime;
337 new_info->entry.atime = old_info->entry.atime;
338 new_info->entry.mtime = old_info->entry.mtime;
339 new_info->entry.flags = old_info->entry.flags;
340 new_info->entry.nlink = old_info->entry.nlink;
343 #ifdef OBSOLETE
344 #define chkstk() \
345 if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page){\
346 printk(KERN_ALERT "UMSDOS: %s magic %x != %lx ligne %d\n" \
347 , current->comm,STACK_MAGIC \
348 ,*(unsigned long *)current->kernel_stack_page \
349 ,__LINE__); \
352 #undef chkstk
353 #define chkstk() do { } while (0);
354 #endif
357 * Rename a file (move) in the file system.
360 static int umsdos_rename_f (struct inode *old_dir, struct dentry *old_dentry,
361 struct inode *new_dir, struct dentry *new_dentry,
362 int flags)
364 struct inode *old_inode = old_dentry->d_inode;
365 struct dentry *old, *new, *old_emd;
366 int err, ret, rehash = 0;
367 struct umsdos_info old_info;
368 struct umsdos_info new_info;
370 ret = -EPERM;
371 err = umsdos_parse (old_dentry->d_name.name,
372 old_dentry->d_name.len, &old_info);
373 if (err)
374 goto out;
375 err = umsdos_parse (new_dentry->d_name.name,
376 new_dentry->d_name.len, &new_info);
377 if (err)
378 goto out;
380 /* Get the EMD dentry for the old parent */
381 old_emd = umsdos_get_emd_dentry(old_dentry->d_parent);
382 ret = PTR_ERR(old_emd);
383 if (IS_ERR(old_emd))
384 goto out;
386 umsdos_lockcreate2 (old_dir, new_dir);
388 ret = umsdos_findentry(old_emd->d_parent, &old_info, 0);
389 if (ret) {
390 printk(KERN_ERR
391 "umsdos_rename_f: old entry %s/%s not in EMD, ret=%d\n",
392 old_dentry->d_parent->d_name.name, old_info.entry.name,
393 ret);
394 goto out_unlock;
397 /* check sticky bit on old_dir */
398 ret = -EPERM;
399 if (is_sticky(old_dir, old_info.entry.uid)) {
400 printk("umsdos_rename_f: %s/%s old sticky bit, fsuid=%d, uid=%d, dir=%d\n",
401 old_dentry->d_parent->d_name.name, old_info.entry.name,
402 current->fsuid, old_info.entry.uid, old_dir->i_uid);
403 goto out_unlock;
407 * Check whether the new_name already exists, and
408 * if so whether we're allowed to replace it.
410 err = umsdos_findentry(new_dentry->d_parent, &new_info, 0);
411 if (err == 0) {
412 /* Are we allowed to replace it? */
413 if (is_sticky(new_dir, new_info.entry.uid)) {
414 Printk (("sticky set on new "));
415 goto out_unlock;
417 /* check whether it _really_ exists ... */
418 ret = -EEXIST;
419 if (new_dentry->d_inode)
420 goto out_unlock;
422 /* bogus lookup? complain and fix up the EMD ... */
423 printk(KERN_WARNING
424 "umsdos_rename_f: entry %s/%s exists, inode NULL??\n",
425 new_dentry->d_parent->d_name.name, new_info.entry.name);
426 err = umsdos_delentry(new_dentry->d_parent, &new_info,
427 S_ISDIR(new_info.entry.mode));
430 Printk (("new newentry "));
431 /* create the new entry ... */
432 umsdos_ren_init (&new_info, &old_info);
433 if (flags)
434 new_info.entry.flags = flags;
435 ret = umsdos_newentry (new_dentry->d_parent, &new_info);
436 if (ret) {
437 printk(KERN_WARNING
438 "umsdos_rename_f: newentry %s/%s failed, ret=%d\n",
439 new_dentry->d_parent->d_name.name, new_info.entry.name,
440 ret);
441 goto out_unlock;
444 /* If we're moving a hardlink, drop it first */
445 if (old_info.entry.flags & UMSDOS_HLINK) {
446 rehash = !list_empty(&old_dentry->d_hash);
447 d_drop(old_dentry);
448 printk("umsdos_rename_f: moving hardlink %s/%s, rehash=%d\n",
449 old_dentry->d_parent->d_name.name, old_info.entry.name, rehash);
452 /* Do a real lookup to get the old short name dentry */
453 old = umsdos_lookup_dentry(old_dentry->d_parent, old_info.fake.fname,
454 old_info.fake.len, 1);
455 ret = PTR_ERR(old);
456 if (IS_ERR(old)) {
457 printk(KERN_WARNING
458 "umsdos_rename_f: lookup old dentry %s/%s, ret=%d\n",
459 old_dentry->d_parent->d_name.name, old_info.fake.fname,
460 ret);
461 goto out_unlock;
463 /* short and long name dentries match? */
464 if (old == old_dentry)
465 dput(old);
466 else {
467 /* make sure it's the same inode! */
468 ret = -ENOENT;
469 if (old->d_inode != old_inode)
470 goto out_dput;
472 * A cross-directory move with different short and long
473 * names has nasty complications: msdos-fs will need to
474 * change inodes, so we must check whether the original
475 * dentry is busy, and if the rename succeeds the short
476 * dentry will come back with a different inode.
478 * To handle this, we drop the dentry and free the inode,
479 * and then pick up the new inode after the rename.
481 if (old_dir != new_dir) {
482 ret = -EBUSY;
483 if (old_dentry->d_count > 1) {
484 printk("umsdos_rename_f: old dentry %s/%s busy, d_count=%d\n",
485 old_dentry->d_parent->d_name.name, old_dentry->d_name.name,old_dentry->d_count);
486 goto out_dput;
488 d_drop(old_dentry);
489 d_delete(old_dentry);
490 printk("umsdos_rename_f: cross-dir move, %s/%s dropped\n",
491 old_dentry->d_parent->d_name.name, old_dentry->d_name.name);
495 new = umsdos_lookup_dentry(new_dentry->d_parent, new_info.fake.fname,
496 new_info.fake.len, 1);
497 ret = PTR_ERR(new);
498 if (IS_ERR(new)) {
499 printk(KERN_WARNING
500 "umsdos_rename_f: lookup new dentry %s/%s, ret=%d\n",
501 new_dentry->d_parent->d_name.name, new_info.fake.fname,
502 ret);
503 goto out_dput;
505 #ifdef UMSDOS_PARANOIA
506 if (new->d_inode != new_dentry->d_inode)
507 printk("umsdos_rename_f: new %s/%s, inode %p!=%p??\n",
508 new->d_parent->d_name.name, new->d_name.name, new->d_inode,new_dentry->d_inode);
509 #endif
510 /* short and long name dentries match? */
511 if (new == new_dentry)
512 dput(new);
514 #ifdef UMSDOS_DEBUG_VERBOSE
515 printk("umsdos_rename_f: msdos_rename %s/%s(%ld) to %s/%s(%ld)\n",
516 old->d_parent->d_name.name, old->d_name.name, old->d_inode->i_ino,
517 new->d_parent->d_name.name, new->d_name.name,
518 new->d_inode ? new->d_inode->i_ino : 0);
519 #endif
520 /* Do the msdos-level rename */
521 ret = msdos_rename (old_dir, old, new_dir, new);
522 Printk(("umsdos_rename_f: now %s/%s, ret=%d\n",
523 old->d_parent->d_name.name, old->d_name.name, ret));
525 if (new != new_dentry)
526 dput(new);
528 /* If the rename failed, remove the new EMD entry */
529 if (ret != 0) {
530 Printk(("umsdos_rename_f: rename failed, ret=%d, removing %s/%s\n",
531 ret, new_dentry->d_parent->d_name.name, new_info.entry.name));
532 umsdos_delentry (new_dentry->d_parent, &new_info,
533 S_ISDIR (new_info.entry.mode));
534 goto out_dput;
538 * Rename successful ... remove the old name from the EMD.
539 * Note that we use the EMD parent here, as the old dentry
540 * may have moved to a new parent ...
542 err = umsdos_delentry (old_emd->d_parent, &old_info,
543 S_ISDIR (old_info.entry.mode));
544 if (err) {
545 /* Failed? Complain a bit, but don't fail the operation */
546 printk(KERN_WARNING
547 "umsdos_rename_f: delentry %s/%s failed, error=%d\n",
548 old_emd->d_parent->d_name.name, old_info.entry.name,
549 err);
553 * Check whether to update the dcache ... if both
554 * old and new dentries match, it's already correct.
555 * If the targets were aliases, the old short-name
556 * dentry has the original target name.
558 if (old_dentry != old) {
559 if (!old_dentry->d_inode) {
560 struct inode *inode = old->d_inode;
561 inode->i_count++;
562 d_instantiate(old_dentry, inode);
563 printk("umsdos_rename_f: %s/%s gets new ino=%ld\n",
564 old_dentry->d_parent->d_name.name, old_dentry->d_name.name, inode->i_ino);
566 if (new_dentry == new)
567 new_dentry = old;
568 goto move_it;
569 } else if (new_dentry != new) {
570 move_it:
571 /* this will rehash the dentry ... */
572 d_move(old_dentry, new_dentry);
574 /* Check whether the old inode changed ... */
575 if (old_dentry->d_inode != old_inode) {
576 umsdos_lookup_patch_new(old_dentry, &new_info);
580 * Update f_pos so notify_change will succeed
581 * if the file was already in use.
583 umsdos_set_dirinfo_new(old_dentry, new_info.f_pos);
585 /* dput() the dentry if we haven't already */
586 out_dput:
587 if (old_dentry != old)
588 dput(old);
590 out_unlock:
591 dput(old_emd);
592 umsdos_unlockcreate (old_dir);
593 umsdos_unlockcreate (new_dir);
595 out:
596 Printk ((" _ret=%d\n", ret));
597 return ret;
601 * Setup a Symbolic link or a (pseudo) hard link
602 * Return a negative error code or 0 if OK.
604 /* #Specification: symbolic links / strategy
605 * A symbolic link is simply a file which holds a path. It is
606 * implemented as a normal MSDOS file (not very space efficient :-()
608 * I see two different ways to do this: One is to place the link data
609 * in unused entries of the EMD file; the other is to have a separate
610 * file dedicated to hold all symbolic links data.
612 * Let's go for simplicity...
615 extern struct inode_operations umsdos_symlink_inode_operations;
617 static int umsdos_symlink_x (struct inode *dir, struct dentry *dentry,
618 const char *symname, int mode, char flags)
620 int ret, len;
621 struct file filp;
623 Printk(("umsdos_symlink: %s/%s to %s\n",
624 dentry->d_parent->d_name.name, dentry->d_name.name, symname));
626 ret = umsdos_create_any (dir, dentry, mode, 0, flags);
627 if (ret) {
628 printk(KERN_WARNING
629 "umsdos_symlink: create failed, ret=%d\n", ret);
630 goto out;
633 fill_new_filp (&filp, dentry);
634 len = strlen (symname);
635 ret = umsdos_file_write_kmem_real (&filp, symname, len);
636 if (ret < 0)
637 goto out_unlink;
638 if (ret != len)
639 goto out_error;
640 ret = 0;
641 out:
642 return ret;
644 out_error:
645 ret = -EIO;
646 out_unlink:
647 printk(KERN_WARNING "umsdos_symlink: write failed, unlinking\n");
648 UMSDOS_unlink (dir, dentry);
649 goto out;
653 * Setup a Symbolic link.
654 * Return a negative error code or 0 if OK.
656 int UMSDOS_symlink ( struct inode *dir, struct dentry *dentry,
657 const char *symname)
659 return umsdos_symlink_x (dir, dentry, symname, S_IFLNK | 0777, 0);
663 * Add a link to an inode in a directory
665 int UMSDOS_link (struct dentry *olddentry, struct inode *dir,
666 struct dentry *dentry)
668 struct inode *oldinode = olddentry->d_inode;
669 struct inode *olddir = olddentry->d_parent->d_inode;
670 struct dentry *temp;
671 char *path;
672 unsigned long buffer;
673 int ret;
674 struct umsdos_info old_info;
675 struct umsdos_info hid_info;
677 #ifdef UMSDOS_DEBUG_VERBOSE
678 printk("umsdos_link: new %s%s -> %s/%s\n",
679 dentry->d_parent->d_name.name, dentry->d_name.name,
680 olddentry->d_parent->d_name.name, olddentry->d_name.name);
681 #endif
683 ret = -EPERM;
684 if (S_ISDIR (oldinode->i_mode))
685 goto out;
687 ret = umsdos_nevercreat (dir, dentry, -EPERM);
688 if (ret)
689 goto out;
691 ret = -ENOMEM;
692 buffer = get_free_page(GFP_KERNEL);
693 if (!buffer)
694 goto out;
697 * Lock the link parent if it's not the same directory.
699 ret = -EDEADLOCK;
700 if (olddir != dir) {
701 if (atomic_read(&olddir->i_sem.count) < 1)
702 goto out_free;
703 down(&olddir->i_sem);
707 * Parse the name and get the visible directory entry.
709 ret = umsdos_parse (olddentry->d_name.name, olddentry->d_name.len,
710 &old_info);
711 if (ret)
712 goto out_unlock;
713 ret = umsdos_findentry (olddentry->d_parent, &old_info, 1);
714 if (ret) {
715 printk("UMSDOS_link: %s/%s not in EMD, ret=%d\n",
716 olddentry->d_parent->d_name.name, olddentry->d_name.name, ret);
717 goto out_unlock;
721 * If the visible dentry is a pseudo-hardlink, the original
722 * file must be already hidden.
724 if (!(old_info.entry.flags & UMSDOS_HLINK)) {
725 int err;
727 /* create a hidden link name */
728 ret = umsdos_newhidden (olddentry->d_parent, &hid_info);
729 if (ret) {
730 printk("umsdos_link: can't make hidden %s/%s, ret=%d\n",
731 olddentry->d_parent->d_name.name, hid_info.entry.name, ret);
732 goto out_unlock;
736 * Make a dentry and rename the original file ...
738 temp = umsdos_lookup_dentry(olddentry->d_parent,
739 hid_info.entry.name,
740 hid_info.entry.name_len, 0);
741 ret = PTR_ERR(temp);
742 if (IS_ERR(temp)) {
743 printk("umsdos_link: lookup %s/%s failed, ret=%d\n",
744 dentry->d_parent->d_name.name, hid_info.entry.name, ret);
745 goto cleanup;
747 /* rename the link to the hidden location ... */
748 ret = umsdos_rename_f (olddir, olddentry, olddir, temp,
749 UMSDOS_HIDDEN);
750 dput(temp);
751 if (ret) {
752 printk("umsdos_link: rename to %s/%s failed, ret=%d\n",
753 temp->d_parent->d_name.name, temp->d_name.name, ret);
754 goto cleanup;
756 /* mark the inode as a hardlink */
757 oldinode->u.umsdos_i.i_is_hlink = 1;
760 * Capture the path to the hidden link.
762 path = umsdos_d_path(olddentry, (char *) buffer, PAGE_SIZE);
763 Printk(("umsdos_link: hidden link path=%s\n", path));
766 * Recreate a dentry for the original name and symlink it,
767 * then symlink the new dentry. Don't give up if one fails,
768 * or we'll lose the file completely!
770 * Note: this counts as the "original" reference, so we
771 * don't increment i_nlink for this one.
773 temp = umsdos_lookup_dentry(olddentry->d_parent,
774 old_info.entry.name,
775 old_info.entry.name_len, 0);
776 ret = PTR_ERR(temp);
777 if (!IS_ERR(temp)) {
778 ret = umsdos_symlink_x (olddir, temp, path,
779 S_IFREG | 0777, UMSDOS_HLINK);
780 dput(temp);
783 /* This symlink increments i_nlink (see below.) */
784 err = umsdos_symlink_x (dir, dentry, path,
785 S_IFREG | 0777, UMSDOS_HLINK);
786 /* fold the two errors */
787 if (!ret)
788 ret = err;
789 goto out_unlock;
791 /* creation failed ... remove the link entry */
792 cleanup:
793 printk("umsdos_link: link failed, ret=%d, removing %s/%s\n",
794 ret, olddentry->d_parent->d_name.name, hid_info.entry.name);
795 err = umsdos_delentry(olddentry->d_parent, &hid_info, 0);
796 goto out_unlock;
799 Printk(("UMSDOS_link: %s/%s already hidden\n",
800 olddentry->d_parent->d_name.name, olddentry->d_name.name));
802 * The original file is already hidden, and we need to get
803 * the dentry for its real name, not the visible name.
804 * N.B. make sure it's the hidden inode ...
806 if (!oldinode->u.umsdos_i.i_is_hlink)
807 printk("UMSDOS_link: %s/%s hidden, ino=%ld not hlink??\n",
808 olddentry->d_parent->d_name.name,
809 olddentry->d_name.name, oldinode->i_ino);
812 * In order to get the correct (real) inode, we just drop
813 * the original dentry.
815 d_drop(olddentry);
816 Printk(("UMSDOS_link: hard link %s/%s, fake=%s\n",
817 olddentry->d_parent->d_name.name, olddentry->d_name.name, old_info.fake.fname));
819 /* Do a real lookup to get the short name dentry */
820 temp = umsdos_lookup_dentry(olddentry->d_parent,
821 old_info.fake.fname,
822 old_info.fake.len, 1);
823 ret = PTR_ERR(temp);
824 if (IS_ERR(temp))
825 goto out_unlock;
827 /* now resolve the link ... */
828 temp = umsdos_solve_hlink(temp);
829 ret = PTR_ERR(temp);
830 if (IS_ERR(temp))
831 goto out_unlock;
832 path = umsdos_d_path(temp, (char *) buffer, PAGE_SIZE);
833 dput(temp);
834 Printk(("umsdos_link: %s/%s already hidden, path=%s\n",
835 olddentry->d_parent->d_name.name, olddentry->d_name.name, path));
837 /* finally we can symlink it ... */
838 ret = umsdos_symlink_x (dir, dentry, path, S_IFREG | 0777,UMSDOS_HLINK);
840 out_unlock:
841 /* remain locked for the call to notify_change ... */
842 if (ret == 0) {
843 struct iattr newattrs;
845 #ifdef UMSDOS_PARANOIA
846 if (!oldinode->u.umsdos_i.i_is_hlink)
847 printk("UMSDOS_link: %s/%s, ino=%ld, not marked as hlink!\n",
848 olddentry->d_parent->d_name.name, olddentry->d_name.name, oldinode->i_ino);
849 #endif
850 oldinode->i_nlink++;
851 Printk(("UMSDOS_link: linked %s/%s, ino=%ld, nlink=%d\n",
852 olddentry->d_parent->d_name.name, olddentry->d_name.name,
853 oldinode->i_ino, oldinode->i_nlink));
854 newattrs.ia_valid = 0;
855 ret = umsdos_notify_change_locked(olddentry, &newattrs);
857 if (olddir != dir)
858 up(&olddir->i_sem);
860 out_free:
861 free_page(buffer);
862 out:
863 Printk (("umsdos_link %d\n", ret));
864 return ret;
869 * Add a sub-directory in a directory
871 /* #Specification: mkdir / Directory already exist in DOS
872 * We do the same thing as for file creation.
873 * For all user it is an error.
875 /* #Specification: mkdir / umsdos directory / create EMD
876 * When we created a new sub-directory in a UMSDOS
877 * directory (one with full UMSDOS semantics), we
878 * create immediately an EMD file in the new
879 * sub-directory so it inherits UMSDOS semantics.
881 int UMSDOS_mkdir (struct inode *dir, struct dentry *dentry, int mode)
883 struct dentry *temp;
884 struct inode *inode;
885 int ret, err;
886 struct umsdos_info info;
888 ret = umsdos_nevercreat (dir, dentry, -EEXIST);
889 if (ret)
890 goto out;
892 ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
893 if (ret)
894 goto out;
896 info.entry.mode = mode | S_IFDIR;
897 info.entry.rdev = 0;
898 info.entry.uid = current->fsuid;
899 info.entry.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
900 info.entry.ctime = info.entry.atime = info.entry.mtime = CURRENT_TIME;
901 info.entry.flags = 0;
902 info.entry.nlink = 1;
903 ret = umsdos_newentry (dentry->d_parent, &info);
904 if (ret)
905 goto out;
907 /* lookup the short name dentry */
908 temp = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname,
909 info.fake.len, 1);
910 ret = PTR_ERR(temp);
911 if (IS_ERR(temp))
912 goto out_remove;
914 /* Keep the short name dentry anonymous */
915 if (temp != dentry)
916 d_drop(temp);
918 /* Make sure the short name doesn't exist */
919 ret = -EEXIST;
920 if (temp->d_inode) {
921 printk("umsdos_mkdir: short name %s/%s exists\n",
922 dentry->d_parent->d_name.name, info.fake.fname);
923 goto out_remove_dput;
926 ret = msdos_mkdir (dir, temp, mode);
927 if (ret)
928 goto out_remove_dput;
931 * Lock the inode to protect the EMD creation ...
933 inode = temp->d_inode;
934 down(&inode->i_sem);
937 * Note! The long and short name might be the same,
938 * so check first before doing the instantiate ...
940 if (dentry != temp) {
941 if (dentry->d_inode)
942 printk("umsdos_mkdir: dentry not negative!\n");
943 inode->i_count++;
944 d_instantiate(dentry, inode);
946 /* N.B. this should have an option to create the EMD ... */
947 umsdos_lookup_patch_new(dentry, &info);
950 * Create the EMD file, and set up the dir so it is
951 * promoted to EMD with the EMD file invisible.
953 * N.B. error return if EMD fails?
955 err = umsdos_make_emd(dentry);
956 umsdos_setup_dir(dentry);
958 up(&inode->i_sem);
959 dput(temp);
961 out:
962 Printk(("umsdos_mkdir: %s/%s, ret=%d\n",
963 dentry->d_parent->d_name.name, dentry->d_name.name, ret));
964 return ret;
966 /* an error occurred ... remove EMD entry. */
967 out_remove_dput:
968 dput(temp);
969 out_remove:
970 umsdos_delentry (dentry->d_parent, &info, 1);
971 goto out;
975 * Add a new device special file into a directory.
977 * #Specification: Special files / strategy
978 * Device special file, pipes, etc ... are created like normal
979 * file in the msdos file system. Of course they remain empty.
981 * One strategy was to create those files only in the EMD file
982 * since they were not important for MSDOS. The problem with
983 * that, is that there were not getting inode number allocated.
984 * The MSDOS filesystems is playing a nice game to fake inode
985 * number, so why not use it.
987 * The absence of inode number compatible with those allocated
988 * for ordinary files was causing major trouble with hard link
989 * in particular and other parts of the kernel I guess.
991 int UMSDOS_mknod (struct inode *dir, struct dentry *dentry,
992 int mode, int rdev)
994 return umsdos_create_any (dir, dentry, mode, rdev, 0);
998 * Remove a sub-directory.
1000 int UMSDOS_rmdir (struct inode *dir, struct dentry *dentry)
1002 struct dentry *temp;
1003 int ret, err, empty;
1004 struct umsdos_info info;
1006 ret = umsdos_nevercreat (dir, dentry, -EPERM);
1007 if (ret)
1008 goto out;
1010 ret = -EBUSY;
1011 if (!list_empty(&dentry->d_hash))
1012 goto out;
1014 /* check whether the EMD is empty */
1015 ret = -ENOTEMPTY;
1016 empty = umsdos_isempty (dentry);
1018 /* Have to remove the EMD file? */
1019 if (empty == 1) {
1020 struct dentry *demd;
1022 demd = umsdos_get_emd_dentry(dentry);
1023 if (!IS_ERR(demd)) {
1024 err = -ENOENT;
1025 if (demd->d_inode)
1026 err = msdos_unlink (dentry->d_inode, demd);
1027 Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err));
1028 #ifdef UMSDOS_PARANOIA
1029 if (err)
1030 printk("umsdos_rmdir: EMD %s/%s unlink failed, err=%d\n",
1031 demd->d_parent->d_name.name, demd->d_name.name, err);
1032 #endif
1033 dput(demd);
1034 if (!err)
1035 ret = 0;
1037 } else if (empty == 2)
1038 ret = 0;
1039 if (ret)
1040 goto out;
1042 umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
1043 /* Call findentry to complete the mangling */
1044 umsdos_findentry (dentry->d_parent, &info, 2);
1045 temp = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname,
1046 info.fake.len, 1);
1047 ret = PTR_ERR(temp);
1048 if (IS_ERR(temp))
1049 goto out;
1051 * If the short name is an alias, dput() it now;
1052 * otherwise d_drop() it to keep it anonymous.
1054 if (temp == dentry)
1055 dput(temp);
1056 else
1057 d_drop(temp);
1060 * Attempt to remove the msdos name.
1062 ret = msdos_rmdir (dir, temp);
1063 if (ret && ret != -ENOENT)
1064 goto out_dput;
1066 /* OK so far ... remove the name from the EMD */
1067 ret = umsdos_delentry (dentry->d_parent, &info, 1);
1068 #ifdef UMSDOS_PARANOIA
1069 if (ret)
1070 printk("umsdos_rmdir: delentry %s failed, ret=%d\n", info.entry.name, ret);
1071 #endif
1073 /* dput() temp if we didn't do it above */
1074 out_dput:
1075 if (temp != dentry)
1076 dput(temp);
1078 out:
1079 Printk (("umsdos_rmdir %d\n", ret));
1080 return ret;
1085 * Remove a file from the directory.
1087 * #Specification: hard link / deleting a link
1088 * When we delete a file and this file is a link,
1089 * we must subtract 1 from the nlink field of the
1090 * hidden link.
1092 * If the count goes to 0, we delete this hidden
1093 * link too.
1095 int UMSDOS_unlink (struct inode *dir, struct dentry *dentry)
1097 struct dentry *temp, *link = NULL;
1098 struct inode *inode;
1099 int ret, rehash = 0;
1100 struct umsdos_info info;
1102 Printk(("UMSDOS_unlink: entering %s/%s\n",
1103 dentry->d_parent->d_name.name, dentry->d_name.name));
1105 ret = umsdos_nevercreat (dir, dentry, -EPERM);
1106 if (ret)
1107 goto out;
1109 ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
1110 if (ret)
1111 goto out;
1113 umsdos_lockcreate (dir);
1114 ret = umsdos_findentry (dentry->d_parent, &info, 1);
1115 if (ret) {
1116 printk("UMSDOS_unlink: %s/%s not in EMD, ret=%d\n",
1117 dentry->d_parent->d_name.name, dentry->d_name.name, ret);
1118 goto out_unlock;
1121 Printk (("UMSDOS_unlink %.*s ", info.fake.len, info.fake.fname));
1123 ret = -EPERM;
1124 /* check sticky bit */
1125 if (is_sticky(dir, info.entry.uid)) {
1126 printk("umsdos_unlink: %s/%s is sticky\n",
1127 dentry->d_parent->d_name.name, dentry->d_name.name);
1128 goto out_unlock;
1132 * Note! If this is a hardlink and the names are aliased,
1133 * the short-name lookup will return the hardlink dentry.
1134 * In order to get the correct (real) inode, we just drop
1135 * the original dentry.
1137 if (info.entry.flags & UMSDOS_HLINK) {
1138 rehash = !list_empty(&dentry->d_hash);
1139 d_drop(dentry);
1140 Printk(("UMSDOS_unlink: hard link %s/%s, fake=%s, rehash=%d\n",
1141 dentry->d_parent->d_name.name, dentry->d_name.name, info.fake.fname, rehash));
1144 /* Do a real lookup to get the short name dentry */
1145 temp = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname,
1146 info.fake.len, 1);
1147 ret = PTR_ERR(temp);
1148 if (IS_ERR(temp))
1149 goto out_unlock;
1152 * Resolve hardlinks now, but defer processing until later.
1154 if (info.entry.flags & UMSDOS_HLINK) {
1155 link = umsdos_solve_hlink(dget(temp));
1159 * If the short and long names are aliased,
1160 * dput() it now so the dentry isn't busy.
1162 if (temp == dentry)
1163 dput(temp);
1165 /* Delete the EMD entry */
1166 ret = umsdos_delentry (dentry->d_parent, &info, 0);
1167 if (ret && ret != -ENOENT) {
1168 printk(KERN_WARNING "UMSDOS_unlink: delentry %s, error=%d\n",
1169 info.entry.name, ret);
1170 goto out_dput;
1173 ret = msdos_unlink_umsdos (dir, temp);
1174 #ifdef UMSDOS_PARANOIA
1175 if (ret)
1176 printk("umsdos_unlink: %s/%s unlink failed, ret=%d\n",
1177 temp->d_parent->d_name.name, temp->d_name.name, ret);
1178 #endif
1180 /* dput() temp if we didn't do it above */
1181 out_dput:
1182 if (temp != dentry) {
1183 d_drop(temp);
1184 dput(temp);
1185 if (!ret)
1186 d_delete (dentry);
1189 out_unlock:
1190 umsdos_unlockcreate (dir);
1193 * Now check for deferred handling of a hardlink.
1195 if (!link)
1196 goto out;
1198 if (IS_ERR(link)) {
1199 printk("umsdos_unlink: failed to resolve %s/%s\n",
1200 dentry->d_parent->d_name.name, dentry->d_name.name);
1201 if (!ret)
1202 ret = PTR_ERR(link);
1203 goto out;
1206 Printk(("umsdos_unlink: link %s/%s deferred, pending ret=%d\n",
1207 link->d_parent->d_name.name, link->d_name.name, ret));
1209 /* already have an error? */
1210 if (ret)
1211 goto out_cleanup;
1213 /* make sure the link exists ... */
1214 inode = link->d_inode;
1215 if (!inode) {
1216 printk(KERN_WARNING "umsdos_unlink: hard link not found\n");
1217 goto out_cleanup;
1221 * If this was the last linked reference, delete it now.
1223 * N.B. Deadlock problem? We should be holding the lock
1224 * for the hardlink's parent, but another process might
1225 * be holding that lock waiting for us to finish ...
1227 if (inode->i_nlink <= 1) {
1228 ret = UMSDOS_unlink (link->d_parent->d_inode, link);
1229 if (ret) {
1230 printk(KERN_WARNING
1231 "umsdos_unlink: link removal failed, ret=%d\n",
1232 ret);
1234 } else {
1235 struct iattr newattrs;
1236 inode->i_nlink--;
1237 newattrs.ia_valid = 0;
1238 ret = umsdos_notify_change_locked(link, &newattrs);
1241 out_cleanup:
1242 d_drop(link);
1243 dput(link);
1245 out:
1246 Printk (("umsdos_unlink %d\n", ret));
1247 return ret;
1252 * Rename (move) a file.
1254 int UMSDOS_rename (struct inode *old_dir, struct dentry *old_dentry,
1255 struct inode *new_dir, struct dentry *new_dentry)
1257 struct dentry *new_target;
1258 int ret;
1260 #ifdef UMSDOS_DEBUG_VERBOSE
1261 printk("umsdos_rename: enter, %s/%s(%ld) to %s/%s(%ld)\n",
1262 old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
1263 old_dentry->d_inode->i_ino,
1264 new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
1265 new_dentry->d_inode ? new_dentry->d_inode->i_ino : 0);
1266 #endif
1267 ret = umsdos_nevercreat (new_dir, new_dentry, -EEXIST);
1268 if (ret)
1269 goto out;
1272 * If the target already exists, delete it first.
1274 if (new_dentry->d_inode) {
1275 if (S_ISDIR(new_dentry->d_inode->i_mode))
1276 ret = UMSDOS_rmdir (new_dir, new_dentry);
1277 else
1278 ret = UMSDOS_unlink (new_dir, new_dentry);
1279 if (ret)
1280 goto out;
1284 * If we didn't get a negative dentry, make a copy and hash it.
1286 new_target = new_dentry;
1287 if (new_dentry->d_inode) {
1288 printk("umsdos_rename: %s/%s not negative, hash=%d\n",
1289 new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
1290 !list_empty(&new_dentry->d_hash));
1291 ret = -ENOMEM;
1292 new_target = d_alloc(new_dentry->d_parent, &new_dentry->d_name);
1293 if (!new_target)
1294 goto out;
1295 d_add(new_target, NULL);
1297 ret = umsdos_rename_f(old_dir, old_dentry, new_dir, new_target, 0);
1298 if (new_target != new_dentry)
1299 dput(new_target);
1301 out:
1302 return ret;