ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / fs / umsdos / namei.c
1 /*
2  *  linux/fs/umsdos/namei.c
3  *
4  *      Written 1993 by Jacques Gelinas 
5  *      Inspired from linux/fs/msdos/... by Werner Almesberger
6  *
7  * Maintain and access the --linux alternate directory file.
8  */
9  /*
10   * You are in the maze of twisted functions - half of them shouldn't
11   * be here...
12   */
13
14 #include <linux/errno.h>
15 #include <linux/kernel.h>
16 #include <linux/time.h>
17 #include <linux/types.h>
18 #include <linux/fcntl.h>
19 #include <linux/stat.h>
20 #include <linux/string.h>
21 #include <linux/msdos_fs.h>
22 #include <linux/umsdos_fs.h>
23 #include <linux/slab.h>
24
25 #define UMSDOS_DIR_LOCK
26
27 #ifdef UMSDOS_DIR_LOCK
28
29 static inline void u_sleep_on (struct inode *dir)
30 {
31         sleep_on (&UMSDOS_I(dir)->dir_info.p);
32 }
33
34 static inline void u_wake_up (struct inode *dir)
35 {
36         wake_up (&UMSDOS_I(dir)->dir_info.p);
37 }
38
39 /*
40  * Wait for creation exclusivity.
41  * Return 0 if the dir was already available.
42  * Return 1 if a wait was necessary.
43  * When 1 is return, it means a wait was done. It does not
44  * mean the directory is available.
45  */
46 static int umsdos_waitcreate (struct inode *dir)
47 {
48         int ret = 0;
49
50         if (UMSDOS_I(dir)->dir_info.creating
51             && UMSDOS_I(dir)->dir_info.pid != current->pid) {
52                 PRINTK (("creating && dir_info.pid=%lu, current->pid=%u\n", UMSDOS_I(dir)->dir_info.pid, current->pid));
53                 u_sleep_on (dir);
54                 ret = 1;
55         }
56         return ret;
57 }
58
59 /*
60  * Wait for any lookup process to finish
61  */
62 static void umsdos_waitlookup (struct inode *dir)
63 {
64         while (UMSDOS_I(dir)->dir_info.looking) {
65                 u_sleep_on (dir);
66         }
67 }
68
69 /*
70  * Lock all other process out of this directory.
71  */
72 /* #Specification: file creation / not atomic
73  * File creation is a two step process. First we create (allocate)
74  * an entry in the EMD file and then (using the entry offset) we
75  * build a unique name for MSDOS. We create this name in the msdos
76  * space.
77  * 
78  * We have to use semaphore (sleep_on/wake_up) to prevent lookup
79  * into a directory when we create a file or directory and to
80  * prevent creation while a lookup is going on. Since many lookup
81  * may happen at the same time, the semaphore is a counter.
82  * 
83  * Only one creation is allowed at the same time. This protection
84  * may not be necessary. The problem arise mainly when a lookup
85  * or a readdir is done while a file is partially created. The
86  * lookup process see that as a "normal" problem and silently
87  * erase the file from the EMD file. Normal because a file
88  * may be erased during a MSDOS session, but not removed from
89  * the EMD file.
90  * 
91  * The locking is done on a directory per directory basis. Each
92  * directory inode has its wait_queue.
93  * 
94  * For some operation like hard link, things even get worse. Many
95  * creation must occur at once (atomic). To simplify the design
96  * a process is allowed to recursively lock the directory for
97  * creation. The pid of the locking process is kept along with
98  * a counter so a second level of locking is granted or not.
99  */
100 void umsdos_lockcreate (struct inode *dir)
101 {
102         /*
103          * Wait for any creation process to finish except
104          * if we (the process) own the lock
105          */
106         while (umsdos_waitcreate (dir) != 0);
107         UMSDOS_I(dir)->dir_info.creating++;
108         UMSDOS_I(dir)->dir_info.pid = current->pid;
109         umsdos_waitlookup (dir);
110 }
111
112 /*
113  * Lock all other process out of those two directories.
114  */
115 static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
116 {
117         /*
118          * We must check that both directory are available before
119          * locking anyone of them. This is to avoid some deadlock.
120          * Thanks to dglaude@is1.vub.ac.be (GLAUDE DAVID) for pointing
121          * this to me.
122          */
123         while (1) {
124                 if (umsdos_waitcreate (dir1) == 0
125                     && umsdos_waitcreate (dir2) == 0) {
126                         /* We own both now */
127                         UMSDOS_I(dir1)->dir_info.creating++;
128                         UMSDOS_I(dir1)->dir_info.pid = current->pid;
129                         UMSDOS_I(dir2)->dir_info.creating++;
130                         UMSDOS_I(dir2)->dir_info.pid = current->pid;
131                         break;
132                 }
133         }
134         umsdos_waitlookup (dir1);
135         umsdos_waitlookup (dir2);
136 }
137
138 /*
139  * Wait until creation is finish in this directory.
140  */
141 void umsdos_startlookup (struct inode *dir)
142 {
143         while (umsdos_waitcreate (dir) != 0);
144         UMSDOS_I(dir)->dir_info.looking++;
145 }
146
147 /*
148  * Unlock the directory.
149  */
150 void umsdos_unlockcreate (struct inode *dir)
151 {
152         UMSDOS_I(dir)->dir_info.creating--;
153         if (UMSDOS_I(dir)->dir_info.creating < 0) {
154                 printk ("UMSDOS: UMSDOS_I(dir)->dir_info.creating < 0: %d"
155                         ,UMSDOS_I(dir)->dir_info.creating);
156         }
157         u_wake_up (dir);
158 }
159
160 /*
161  * Tell directory lookup is over.
162  */
163 void umsdos_endlookup (struct inode *dir)
164 {
165         UMSDOS_I(dir)->dir_info.looking--;
166         if (UMSDOS_I(dir)->dir_info.looking < 0) {
167                 printk ("UMSDOS: UMSDOS_I(dir)->dir_info.looking < 0: %d"
168                         ,UMSDOS_I(dir)->dir_info.looking);
169         }
170         u_wake_up (dir);
171 }
172
173 #else
174 static void umsdos_lockcreate (struct inode *dir)
175 {
176 }
177 static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
178 {
179 }
180 void umsdos_startlookup (struct inode *dir)
181 {
182 }
183 static void umsdos_unlockcreate (struct inode *dir)
184 {
185 }
186 void umsdos_endlookup (struct inode *dir)
187 {
188 }
189
190 #endif
191
192 static int umsdos_nevercreat (struct inode *dir, struct dentry *dentry,
193                                 int errcod)
194 {
195         int ret = 0;
196
197         if (umsdos_is_pseudodos (dir, dentry)) {
198                 /* #Specification: pseudo root / any file creation /DOS
199                  * The pseudo sub-directory /DOS can't be created!
200                  * EEXIST is returned.
201                  * 
202                  * The pseudo sub-directory /DOS can't be removed!
203                  * EPERM is returned.
204                  */
205                 ret = errcod;
206         }
207         return ret;
208 }
209
210 /*
211  * Add a new file (ordinary or special) into the alternate directory.
212  * The file is added to the real MSDOS directory. If successful, it
213  * is then added to the EMD file.
214  * 
215  * Return the status of the operation. 0 mean success.
216  *
217  * #Specification: create / file exists in DOS
218  * Here is a situation: we are trying to create a file with
219  * UMSDOS. The file is unknown to UMSDOS but already
220  * exists in the DOS directory.
221  * 
222  * Here is what we are NOT doing:
223  * 
224  * We could silently assume that everything is fine
225  * and allows the creation to succeed.
226  * 
227  * It is possible not all files in the partition
228  * are meant to be visible from linux. By trying to create
229  * those file in some directory, one user may get access
230  * to those file without proper permissions. Looks like
231  * a security hole to me. Off course sharing a file system
232  * with DOS is some kind of security hole :-)
233  * 
234  * So ?
235  * 
236  * We return EEXIST in this case.
237  * The same is true for directory creation.
238  */
239 static int umsdos_create_any (struct inode *dir, struct dentry *dentry,
240                                 int mode, dev_t rdev, char flags)
241 {
242         struct dentry *fake;
243         struct inode *inode;
244         int ret;
245         struct umsdos_info info;
246
247         ret = umsdos_nevercreat (dir, dentry, -EEXIST);
248         if (ret)
249                 goto out;
250
251         ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
252         if (ret)
253                 goto out;
254
255         info.entry.mode = mode;
256         info.entry.rdev = rdev;
257         info.entry.flags = flags;
258         info.entry.uid = current->fsuid;
259         info.entry.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
260         info.entry.ctime = info.entry.atime = info.entry.mtime = get_seconds();
261         info.entry.nlink = 1;
262         ret = umsdos_newentry (dentry->d_parent, &info);
263         if (ret)
264                 goto out;
265
266         /* do a real lookup to get the short name dentry */
267         fake = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
268         ret = PTR_ERR(fake);
269         if (IS_ERR(fake))
270                 goto out_remove;
271
272         /* should not exist yet ... */
273         ret = -EEXIST;
274         if (fake->d_inode)
275                 goto out_remove_dput;
276
277         ret = msdos_create (dir, fake, S_IFREG | 0777, NULL);
278         if (ret)
279                 goto out_remove_dput;
280
281         inode = fake->d_inode;
282         atomic_inc(&inode->i_count);
283         d_instantiate (dentry, inode);
284         dput(fake);
285         if (atomic_read(&inode->i_count) > 1) {
286                 printk(KERN_WARNING
287                         "umsdos_create_any: %s/%s, ino=%ld, icount=%d??\n",
288                         dentry->d_parent->d_name.name, dentry->d_name.name,
289                         inode->i_ino, atomic_read(&inode->i_count));
290         }
291         umsdos_lookup_patch_new(dentry, &info);
292
293 out:
294         return ret;
295
296         /* Creation failed ... remove the EMD entry */
297 out_remove_dput:
298         dput(fake);
299 out_remove:
300         if (ret == -EEXIST)
301                 printk(KERN_WARNING "UMSDOS: out of sync, deleting %s/%s\n",
302                         dentry->d_parent->d_name.name, info.fake.fname);
303         umsdos_delentry (dentry->d_parent, &info, S_ISDIR (info.entry.mode));
304         goto out;
305 }
306
307 /*
308  * Add a new file into the alternate directory.
309  * The file is added to the real MSDOS directory. If successful, it
310  * is then added to the EMD file.
311  * 
312  * Return the status of the operation. 0 mean success.
313  */
314 int UMSDOS_create (struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd)
315 {
316         return umsdos_create_any (dir, dentry, mode, 0, 0);
317 }
318
319
320 /*
321  * Initialise the new_entry from the old for a rename operation.
322  * (Only useful for umsdos_rename_f() below).
323  */
324 static void umsdos_ren_init (struct umsdos_info *new_info,
325                              struct umsdos_info *old_info)
326 {
327         new_info->entry.mode = old_info->entry.mode;
328         new_info->entry.rdev = old_info->entry.rdev;
329         new_info->entry.uid = old_info->entry.uid;
330         new_info->entry.gid = old_info->entry.gid;
331         new_info->entry.ctime = old_info->entry.ctime;
332         new_info->entry.atime = old_info->entry.atime;
333         new_info->entry.mtime = old_info->entry.mtime;
334         new_info->entry.flags = old_info->entry.flags;
335         new_info->entry.nlink = old_info->entry.nlink;
336 }
337
338 /*
339  * Rename a file (move) in the file system.
340  */
341  
342 static int umsdos_rename_f (struct inode *old_dir, struct dentry *old_dentry,
343                             struct inode *new_dir, struct dentry *new_dentry,
344                             int flags)
345 {
346         struct inode *old_inode = old_dentry->d_inode;
347         struct dentry *old, *new, *old_emd;
348         int err, ret;
349         struct umsdos_info old_info;
350         struct umsdos_info new_info;
351
352         ret = -EPERM;
353         err = umsdos_parse (old_dentry->d_name.name,
354                                 old_dentry->d_name.len, &old_info);
355         if (err)
356                 goto out;
357         err = umsdos_parse (new_dentry->d_name.name,
358                                 new_dentry->d_name.len, &new_info);
359         if (err)
360                 goto out;
361
362         /* Get the EMD dentry for the old parent */
363         old_emd = umsdos_get_emd_dentry(old_dentry->d_parent);
364         ret = PTR_ERR(old_emd);
365         if (IS_ERR(old_emd))
366                 goto out;
367
368         umsdos_lockcreate2 (old_dir, new_dir);
369
370         ret = umsdos_findentry(old_emd->d_parent, &old_info, 0);
371         if (ret)
372                 goto out_unlock;
373
374         err = umsdos_findentry(new_dentry->d_parent, &new_info, 0);
375         if (err == 0) {
376                 /* check whether it _really_ exists ... */
377                 ret = -EEXIST;
378                 if (new_dentry->d_inode)
379                         goto out_unlock;
380
381                 /* bogus lookup? complain and fix up the EMD ... */
382                 printk(KERN_WARNING
383                         "umsdos_rename_f: entry %s/%s exists, inode NULL??\n",
384                         new_dentry->d_parent->d_name.name, new_info.entry.name);
385                 err = umsdos_delentry(new_dentry->d_parent, &new_info,
386                                         S_ISDIR(new_info.entry.mode));
387         }
388
389         umsdos_ren_init (&new_info, &old_info);
390         if (flags)
391                 new_info.entry.flags = flags;
392         ret = umsdos_newentry (new_dentry->d_parent, &new_info);
393         if (ret)
394                 goto out_unlock;
395
396         /* If we're moving a hardlink, drop it first */
397         if (old_info.entry.flags & UMSDOS_HLINK) {
398                 d_drop(old_dentry);
399         }
400
401         old = umsdos_covered(old_dentry->d_parent, old_info.fake.fname, 
402                                         old_info.fake.len);
403         ret = PTR_ERR(old);
404         if (IS_ERR(old))
405                 goto out_unlock;
406         /* make sure it's the same inode! */
407         ret = -ENOENT;
408         /*
409          * note: for hardlinks they will be different!
410          *  old_inode will contain inode of .LINKxxx file containing data, and
411          *  old->d_inode will contain inode of file containing path to .LINKxxx file
412          */
413         if (!(old_info.entry.flags & UMSDOS_HLINK)) {
414                 if (old->d_inode != old_inode)
415                         goto out_dput;
416         }
417
418         new = umsdos_covered(new_dentry->d_parent, new_info.fake.fname, 
419                                         new_info.fake.len);
420         ret = PTR_ERR(new);
421         if (IS_ERR(new))
422                 goto out_dput;
423
424         /* Do the msdos-level rename */
425         ret = msdos_rename (old_dir, old, new_dir, new);
426
427         dput(new);
428
429         /* If the rename failed, remove the new EMD entry */
430         if (ret != 0) {
431                 umsdos_delentry (new_dentry->d_parent, &new_info,
432                                  S_ISDIR (new_info.entry.mode));
433                 goto out_dput;
434         }
435
436         /*
437          * Rename successful ... remove the old name from the EMD.
438          * Note that we use the EMD parent here, as the old dentry
439          * may have moved to a new parent ...
440          */
441         err = umsdos_delentry (old_emd->d_parent, &old_info,
442                                 S_ISDIR (old_info.entry.mode));
443         if (err) {
444                 /* Failed? Complain a bit, but don't fail the operation */
445                 printk(KERN_WARNING 
446                         "umsdos_rename_f: delentry %s/%s failed, error=%d\n",
447                         old_emd->d_parent->d_name.name, old_info.entry.name,
448                         err);
449         }
450
451         /*
452          * Update f_pos so notify_change will succeed
453          * if the file was already in use.
454          */
455         umsdos_set_dirinfo_new(old_dentry, new_info.f_pos);
456
457         /* dput() the dentry if we haven't already */
458 out_dput:
459         dput(old);
460
461 out_unlock:
462         dput(old_emd);
463         umsdos_unlockcreate (old_dir);
464         umsdos_unlockcreate (new_dir);
465
466 out:
467         Printk ((" _ret=%d\n", ret));
468         return ret;
469 }
470
471 /*
472  * Setup a Symbolic link or a (pseudo) hard link
473  * Return a negative error code or 0 if OK.
474  */
475 /* #Specification: symbolic links / strategy
476  * A symbolic link is simply a file which holds a path. It is
477  * implemented as a normal MSDOS file (not very space efficient :-()
478  * 
479  * I see two different ways to do this: One is to place the link data
480  * in unused entries of the EMD file; the other is to have a separate
481  * file dedicated to hold all symbolic links data.
482  * 
483  * Let's go for simplicity...
484  */
485
486 /*
487  * AV. Should be called with dir->i_sem down.
488  */
489 static int umsdos_symlink_x (struct inode *dir, struct dentry *dentry,
490                         const char *symname, int mode, char flags)
491 {
492         int ret, len;
493
494         ret = umsdos_create_any (dir, dentry, mode, 0, flags);
495         if (ret) {
496                 printk(KERN_WARNING
497                         "umsdos_symlink: create failed, ret=%d\n", ret);
498                 goto out;
499         }
500
501         len = strlen (symname) + 1;
502         ret = page_symlink(dentry->d_inode, symname, len);
503         if (ret < 0)
504                 goto out_unlink;
505 out:
506         return ret;
507
508 out_unlink:
509         printk(KERN_WARNING "umsdos_symlink: write failed, unlinking\n");
510         UMSDOS_unlink (dir, dentry);
511         d_drop(dentry);
512         goto out;
513 }
514
515 /*
516  * Setup a Symbolic link.
517  * Return a negative error code or 0 if OK.
518  */
519 int UMSDOS_symlink ( struct inode *dir, struct dentry *dentry,
520                  const char *symname)
521 {
522         return umsdos_symlink_x (dir, dentry, symname, S_IFLNK | 0777, 0);
523 }
524
525 /*
526  * Add a link to an inode in a directory
527  */
528 int UMSDOS_link (struct dentry *olddentry, struct inode *dir,
529                  struct dentry *dentry)
530 {
531         struct inode *oldinode = olddentry->d_inode;
532         struct inode *olddir = olddentry->d_parent->d_inode;
533         struct dentry *temp;
534         char *path;
535         unsigned long buffer;
536         int ret;
537         struct umsdos_info old_info;
538         struct umsdos_info hid_info;
539
540 #ifdef UMSDOS_DEBUG_VERBOSE
541 printk("umsdos_link: new %s/%s -> %s/%s\n",
542 dentry->d_parent->d_name.name, dentry->d_name.name, 
543 olddentry->d_parent->d_name.name, olddentry->d_name.name);
544 #endif
545  
546         ret = -EPERM;
547         if (S_ISDIR (oldinode->i_mode))
548                 goto out;
549
550         ret = umsdos_nevercreat (dir, dentry, -EPERM);
551         if (ret)
552                 goto out;
553
554         ret = -ENOMEM;
555         buffer = get_zeroed_page(GFP_KERNEL);
556         if (!buffer)
557                 goto out;
558
559         /*
560          * Lock the link parent if it's not the same directory.
561          */
562         ret = -EDEADLOCK;
563         if (olddir != dir) {
564                 if (atomic_read(&olddir->i_sem.count) < 1)
565                         goto out_free;
566                 down(&olddir->i_sem);
567         }
568
569         /*
570          * Parse the name and get the visible directory entry.
571          */
572         ret = umsdos_parse (olddentry->d_name.name, olddentry->d_name.len,
573                                 &old_info);
574         if (ret)
575                 goto out_unlock;
576         ret = umsdos_findentry (olddentry->d_parent, &old_info, 1);
577         if (ret) {
578 printk("UMSDOS_link: %s/%s not in EMD, ret=%d\n",
579 olddentry->d_parent->d_name.name, olddentry->d_name.name, ret);
580                 goto out_unlock;
581         }
582
583         /*
584          * If the visible dentry is a pseudo-hardlink, the original
585          * file must be already hidden.
586          */
587         if (!(old_info.entry.flags & UMSDOS_HLINK)) {
588                 int err;
589
590                 /* create a hidden link name */
591                 ret = umsdos_newhidden (olddentry->d_parent, &hid_info);
592                 if (ret) {
593 printk("umsdos_link: can't make hidden %s/%s, ret=%d\n",
594 olddentry->d_parent->d_name.name, hid_info.entry.name, ret);
595                         goto out_unlock;
596                 }
597
598                 /*
599                  * Make a dentry and rename the original file ...
600                  */
601                 temp = umsdos_lookup_dentry(olddentry->d_parent,
602                                                 hid_info.entry.name,
603                                                 hid_info.entry.name_len, 0); 
604                 ret = PTR_ERR(temp);
605                 if (IS_ERR(temp)) {
606 printk("umsdos_link: lookup %s/%s failed, ret=%d\n",
607 dentry->d_parent->d_name.name, hid_info.entry.name, ret);
608                         goto cleanup;
609                 }
610                 /* rename the link to the hidden location ... */
611                 ret = umsdos_rename_f(olddir, olddentry, olddir, temp,
612                                         UMSDOS_HIDDEN);
613                 d_move(olddentry, temp);
614                 dput(temp);
615                 if (ret) {
616 printk("umsdos_link: rename to %s/%s failed, ret=%d\n",
617 temp->d_parent->d_name.name, temp->d_name.name, ret);
618                         goto cleanup;
619                 }
620                 /* mark the inode as a hardlink */
621                 UMSDOS_I(oldinode)->i_is_hlink = 1;
622
623                 /*
624                  * Capture the path to the hidden link.
625                  */
626                 path = umsdos_d_path(olddentry, (char *) buffer, PAGE_SIZE);
627 Printk(("umsdos_link: hidden link path=%s\n", path));
628
629                 /*
630                  * Recreate a dentry for the original name and symlink it,
631                  * then symlink the new dentry. Don't give up if one fails,
632                  * or we'll lose the file completely!
633                  *
634                  * Note: this counts as the "original" reference, so we 
635                  * don't increment i_nlink for this one.
636                  */ 
637                 temp = umsdos_lookup_dentry(olddentry->d_parent,
638                                                 old_info.entry.name,
639                                                 old_info.entry.name_len, 0); 
640                 ret = PTR_ERR(temp);
641                 if (!IS_ERR(temp)) {
642                         ret = umsdos_symlink_x (olddir, temp, path, 
643                                                 S_IFREG | 0777, UMSDOS_HLINK);
644                         dput(temp);
645                 }
646
647                 /* This symlink increments i_nlink (see below.) */
648                 err = umsdos_symlink_x (dir, dentry, path,
649                                         S_IFREG | 0777, UMSDOS_HLINK);
650                 /* fold the two errors */
651                 if (!ret)
652                         ret = err;
653                 goto out_unlock;
654
655                 /* creation failed ... remove the link entry */
656         cleanup:
657 printk("umsdos_link: link failed, ret=%d, removing %s/%s\n",
658 ret, olddentry->d_parent->d_name.name, hid_info.entry.name);
659                 err = umsdos_delentry(olddentry->d_parent, &hid_info, 0);
660                 goto out_unlock;
661         }
662
663 Printk(("UMSDOS_link: %s/%s already hidden\n",
664 olddentry->d_parent->d_name.name, olddentry->d_name.name));
665         /*
666          * The original file is already hidden, and we need to get 
667          * the dentry for its real name, not the visible name.
668          * N.B. make sure it's the hidden inode ...
669          */
670         if (!UMSDOS_I(oldinode)->i_is_hlink)
671                 printk("UMSDOS_link: %s/%s hidden, ino=%ld not hlink??\n",
672                         olddentry->d_parent->d_name.name,
673                         olddentry->d_name.name, oldinode->i_ino);
674
675         /*
676          * In order to get the correct (real) inode, we just drop
677          * the original dentry.
678          */ 
679         d_drop(olddentry);
680 Printk(("UMSDOS_link: hard link %s/%s, fake=%s\n",
681 olddentry->d_parent->d_name.name, olddentry->d_name.name, old_info.fake.fname));
682
683         /* Do a real lookup to get the short name dentry */
684         temp = umsdos_covered(olddentry->d_parent, old_info.fake.fname, 
685                                         old_info.fake.len);
686         ret = PTR_ERR(temp);
687         if (IS_ERR(temp))
688                 goto out_unlock;
689
690         /* now resolve the link ... */
691         temp = umsdos_solve_hlink(temp);
692         ret = PTR_ERR(temp);
693         if (IS_ERR(temp))
694                 goto out_unlock;
695         path = umsdos_d_path(temp, (char *) buffer, PAGE_SIZE);
696         dput(temp);
697 Printk(("umsdos_link: %s/%s already hidden, path=%s\n",
698 olddentry->d_parent->d_name.name, olddentry->d_name.name, path));
699
700         /* finally we can symlink it ... */
701         ret = umsdos_symlink_x (dir, dentry, path, S_IFREG | 0777,UMSDOS_HLINK);
702
703 out_unlock:
704         /* remain locked for the call to notify_change ... */
705         if (ret == 0) {
706                 struct iattr newattrs;
707
708                 /* Do a real lookup to get the short name dentry */
709                 temp = umsdos_covered(olddentry->d_parent,
710                                         old_info.fake.fname,
711                                         old_info.fake.len);
712                 ret = PTR_ERR(temp);
713                 if (IS_ERR(temp))
714                         goto out_unlock2;
715
716                 /* now resolve the link ... */
717                 temp = umsdos_solve_hlink(temp);
718                 ret = PTR_ERR(temp);
719                 if (IS_ERR(temp))
720                         goto out_unlock2;
721
722
723 #ifdef UMSDOS_PARANOIA
724 if (!UMSDOS_I(oldinode)->i_is_hlink)
725 printk("UMSDOS_link: %s/%s, ino=%ld, not marked as hlink!\n",
726 olddentry->d_parent->d_name.name, olddentry->d_name.name, oldinode->i_ino);
727 #endif
728                 temp->d_inode->i_nlink++;
729 Printk(("UMSDOS_link: linked %s/%s, ino=%ld, nlink=%d\n",
730 olddentry->d_parent->d_name.name, olddentry->d_name.name,
731 oldinode->i_ino, oldinode->i_nlink));
732                 newattrs.ia_valid = 0;
733                 ret = umsdos_notify_change_locked(temp, &newattrs);
734                 if (ret == 0)
735                         mark_inode_dirty(temp->d_inode);
736                 dput(temp);
737 out_unlock2:    
738                 if (ret == 0)
739                         mark_inode_dirty(olddentry->d_inode);
740         }
741         if (olddir != dir)
742                 up(&olddir->i_sem);
743
744 out_free:
745         free_page(buffer);
746 out:
747         Printk (("umsdos_link %d\n", ret));
748         return ret;
749 }
750
751
752 /*
753  * Add a sub-directory in a directory
754  */
755 /* #Specification: mkdir / Directory already exist in DOS
756  * We do the same thing as for file creation.
757  * For all user it is an error.
758  */
759 /* #Specification: mkdir / umsdos directory / create EMD
760  * When we created a new sub-directory in a UMSDOS
761  * directory (one with full UMSDOS semantics), we
762  * create immediately an EMD file in the new
763  * sub-directory so it inherits UMSDOS semantics.
764  */
765 int UMSDOS_mkdir (struct inode *dir, struct dentry *dentry, int mode)
766 {
767         struct dentry *temp;
768         struct inode *inode;
769         int ret, err;
770         struct umsdos_info info;
771
772         ret = umsdos_nevercreat (dir, dentry, -EEXIST);
773         if (ret)
774                 goto out;
775
776         ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
777         if (ret)
778                 goto out;
779
780         info.entry.mode = mode | S_IFDIR;
781         info.entry.rdev = 0;
782         info.entry.uid = current->fsuid;
783         info.entry.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
784         info.entry.ctime = info.entry.atime = info.entry.mtime = get_seconds();
785         info.entry.flags = 0;
786         info.entry.nlink = 1;
787         ret = umsdos_newentry (dentry->d_parent, &info);
788         if (ret)
789                 goto out;
790
791         /* lookup the short name dentry */
792         temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
793         ret = PTR_ERR(temp);
794         if (IS_ERR(temp))
795                 goto out_remove;
796
797         /* Make sure the short name doesn't exist */
798         ret = -EEXIST;
799         if (temp->d_inode) {
800 printk("umsdos_mkdir: short name %s/%s exists\n",
801 dentry->d_parent->d_name.name, info.fake.fname);
802                 goto out_remove_dput;
803         }
804
805         ret = msdos_mkdir (dir, temp, mode);
806         if (ret)
807                 goto out_remove_dput;
808
809         /*
810          * Lock the inode to protect the EMD creation ...
811          */
812         inode = temp->d_inode;
813         down(&inode->i_sem);
814
815         atomic_inc(&inode->i_count);
816         d_instantiate(dentry, inode);
817
818         /* N.B. this should have an option to create the EMD ... */
819         umsdos_lookup_patch_new(dentry, &info);
820
821         /* 
822          * Create the EMD file, and set up the dir so it is
823          * promoted to EMD with the EMD file invisible.
824          *
825          * N.B. error return if EMD fails?
826          */
827         err = umsdos_make_emd(dentry);
828         umsdos_setup_dir(dentry);
829
830         up(&inode->i_sem);
831         dput(temp);
832
833 out:
834         Printk(("umsdos_mkdir: %s/%s, ret=%d\n",
835                 dentry->d_parent->d_name.name, dentry->d_name.name, ret));
836         return ret;
837
838         /* an error occurred ... remove EMD entry. */
839 out_remove_dput:
840         dput(temp);
841 out_remove:
842         umsdos_delentry (dentry->d_parent, &info, 1);
843         goto out;
844 }
845
846 /*
847  * Add a new device special file into a directory.
848  *
849  * #Specification: Special files / strategy
850  * Device special file, pipes, etc ... are created like normal
851  * file in the msdos file system. Of course they remain empty.
852  * 
853  * One strategy was to create those files only in the EMD file
854  * since they were not important for MSDOS. The problem with
855  * that, is that there were not getting inode number allocated.
856  * The MSDOS filesystems is playing a nice game to fake inode
857  * number, so why not use it.
858  * 
859  * The absence of inode number compatible with those allocated
860  * for ordinary files was causing major trouble with hard link
861  * in particular and other parts of the kernel I guess.
862  */
863 int UMSDOS_mknod (struct inode *dir, struct dentry *dentry,
864                  int mode, dev_t rdev)
865 {
866         return umsdos_create_any (dir, dentry, mode, rdev, 0);
867 }
868
869 /*
870  * Remove a sub-directory.
871  */
872 int UMSDOS_rmdir (struct inode *dir, struct dentry *dentry)
873 {
874         struct dentry *temp;
875         int ret, err, empty;
876         struct umsdos_info info;
877
878         ret = umsdos_nevercreat (dir, dentry, -EPERM);
879         if (ret)
880                 goto out;
881
882         ret = -EBUSY;
883         if (!d_unhashed(dentry))
884                 goto out;
885
886         /* check whether the EMD is empty */
887         ret = -ENOTEMPTY;
888         empty = umsdos_isempty (dentry);
889
890         /* Have to remove the EMD file? */
891         if (empty == 1) {
892                 struct dentry *demd;
893
894                 demd = umsdos_get_emd_dentry(dentry);
895                 if (!IS_ERR(demd)) {
896                         err = -ENOENT;
897                         if (demd->d_inode)
898                                 err = msdos_unlink (dentry->d_inode, demd);
899 Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err));
900 #ifdef UMSDOS_PARANOIA
901 if (err)
902 printk("umsdos_rmdir: EMD %s/%s unlink failed, err=%d\n",
903 demd->d_parent->d_name.name, demd->d_name.name, err);
904 #endif
905                         if (!err) {
906                                 d_delete(demd);
907                                 ret = 0;
908                         }
909                         dput(demd);
910                 }
911         } else if (empty == 2)
912                 ret = 0;
913         if (ret)
914                 goto out;
915
916         umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
917         /* Call findentry to complete the mangling */
918         umsdos_findentry (dentry->d_parent, &info, 2);
919         temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
920         ret = PTR_ERR(temp);
921         if (IS_ERR(temp))
922                 goto out;
923         /*
924          * Attempt to remove the msdos name.
925          */
926         ret = msdos_rmdir (dir, temp);
927         if (ret && ret != -ENOENT)
928                 goto out_dput;
929
930         d_delete(temp);
931         /* OK so far ... remove the name from the EMD */
932         ret = umsdos_delentry (dentry->d_parent, &info, 1);
933 #ifdef UMSDOS_PARANOIA
934 if (ret)
935 printk("umsdos_rmdir: delentry %s failed, ret=%d\n", info.entry.name, ret);
936 #endif
937
938         /* dput() temp if we didn't do it above */
939 out_dput:
940         dput(temp);
941
942 out:
943         Printk (("umsdos_rmdir %d\n", ret));
944         return ret;
945 }
946
947
948 /*
949  * Remove a file from the directory.
950  *
951  * #Specification: hard link / deleting a link
952  * When we delete a file and this file is a link,
953  * we must subtract 1 from the nlink field of the
954  * hidden link.
955  * 
956  * If the count goes to 0, we delete this hidden
957  * link too.
958  */
959 int UMSDOS_unlink (struct inode *dir, struct dentry *dentry)
960 {
961         struct dentry *temp, *link = NULL;
962         struct inode *inode;
963         int ret;
964         struct umsdos_info info;
965
966 Printk(("UMSDOS_unlink: entering %s/%s\n",
967 dentry->d_parent->d_name.name, dentry->d_name.name));
968
969         ret = umsdos_nevercreat (dir, dentry, -EPERM);
970         if (ret)
971                 goto out;
972
973         ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
974         if (ret)
975                 goto out;
976
977         umsdos_lockcreate (dir);
978         ret = umsdos_findentry (dentry->d_parent, &info, 1);
979         if (ret) {
980 printk("UMSDOS_unlink: %s/%s not in EMD, ret=%d\n",
981 dentry->d_parent->d_name.name, dentry->d_name.name, ret);
982                 goto out_unlock;
983         }
984
985 Printk (("UMSDOS_unlink %.*s ", info.fake.len, info.fake.fname));
986
987         /*
988          * Note! If this is a hardlink and the names are aliased,
989          * the short-name lookup will return the hardlink dentry.
990          * In order to get the correct (real) inode, we just drop
991          * the original dentry.
992          */ 
993         if (info.entry.flags & UMSDOS_HLINK) {
994                 d_drop(dentry);
995         }
996
997         /* Do a real lookup to get the short name dentry */
998         temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
999         ret = PTR_ERR(temp);
1000         if (IS_ERR(temp))
1001                 goto out_unlock;
1002
1003         /*
1004          * Resolve hardlinks now, but defer processing until later.
1005          */
1006         if (info.entry.flags & UMSDOS_HLINK) {
1007                 link = umsdos_solve_hlink(dget(temp));
1008         }
1009
1010         /* Delete the EMD entry */
1011         ret = umsdos_delentry (dentry->d_parent, &info, 0);
1012         if (ret && ret != -ENOENT) {
1013                 printk(KERN_WARNING "UMSDOS_unlink: delentry %s, error=%d\n",
1014                         info.entry.name, ret);
1015                 goto out_dput;
1016         }
1017
1018         ret = msdos_unlink(dir, temp);
1019         if (!ret)
1020                 d_delete(temp);
1021 #ifdef UMSDOS_PARANOIA
1022 if (ret)
1023 printk("umsdos_unlink: %s/%s unlink failed, ret=%d\n",
1024 temp->d_parent->d_name.name, temp->d_name.name, ret);
1025 #endif
1026
1027         /* dput() temp if we didn't do it above */
1028 out_dput:
1029         dput(temp);
1030
1031 out_unlock:
1032         umsdos_unlockcreate (dir);
1033
1034         /*
1035          * Now check for deferred handling of a hardlink.
1036          */
1037         if (!link)
1038                 goto out;
1039
1040         if (IS_ERR(link)) {
1041 printk("umsdos_unlink: failed to resolve %s/%s\n",
1042 dentry->d_parent->d_name.name, dentry->d_name.name);
1043                 if (!ret)
1044                         ret = PTR_ERR(link);
1045                 goto out;
1046         }
1047
1048 Printk(("umsdos_unlink: link %s/%s deferred, pending ret=%d\n",
1049 link->d_parent->d_name.name, link->d_name.name, ret));
1050
1051         /* already have an error? */
1052         if (ret)
1053                 goto out_cleanup;
1054
1055         /* make sure the link exists ... */
1056         inode = link->d_inode;
1057         if (!inode) {
1058                 printk(KERN_WARNING "umsdos_unlink: hard link not found\n");
1059                 goto out_cleanup;
1060         }
1061
1062         /*
1063          * If this was the last linked reference, delete it now.
1064          *
1065          * N.B. Deadlock problem? We should be holding the lock
1066          * for the hardlink's parent, but another process might
1067          * be holding that lock waiting for us to finish ...
1068          */
1069         if (inode->i_nlink <= 1) {
1070                 ret = UMSDOS_unlink (link->d_parent->d_inode, link);
1071                 if (ret) {
1072                         printk(KERN_WARNING
1073                                 "umsdos_unlink: link removal failed, ret=%d\n",
1074                                  ret);
1075                 } else
1076                         d_delete(link);
1077         } else {
1078                 struct iattr newattrs;
1079                 inode->i_nlink--;
1080                 newattrs.ia_valid = 0;
1081                 ret = umsdos_notify_change_locked(link, &newattrs);
1082                 if (!ret)
1083                         mark_inode_dirty(link->d_inode);
1084         }
1085
1086 out_cleanup:
1087         d_drop(link);
1088         dput(link);
1089
1090 out:
1091         Printk (("umsdos_unlink %d\n", ret));
1092         return ret;
1093 }
1094
1095 /*
1096  * Rename (move) a file.
1097  */
1098 int UMSDOS_rename (struct inode *old_dir, struct dentry *old_dentry,
1099                    struct inode *new_dir, struct dentry *new_dentry)
1100 {
1101         int ret;
1102
1103         ret = umsdos_nevercreat (new_dir, new_dentry, -EEXIST);
1104         if (ret)
1105                 return ret;
1106
1107                 /*
1108                  * If the target already exists, delete it first.
1109                  */
1110         if (new_dentry->d_inode) {
1111                 dget(new_dentry);
1112                 if (S_ISDIR(old_dentry->d_inode->i_mode))
1113                         ret = UMSDOS_rmdir (new_dir, new_dentry);
1114                 else
1115                         ret = UMSDOS_unlink (new_dir, new_dentry);
1116                 if (!ret)
1117                         d_drop(new_dentry);
1118                 dput(new_dentry);
1119                 if (ret)
1120                         return ret;
1121         }
1122         ret = umsdos_rename_f(old_dir, old_dentry, new_dir, new_dentry, 0);
1123         return ret;
1124 }