more changes on original files
[linux-2.4.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/sched.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 (&dir->u.umsdos_i.dir_info.p);
32 }
33
34 static inline void u_wake_up (struct inode *dir)
35 {
36         wake_up (&dir->u.umsdos_i.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 (dir->u.umsdos_i.dir_info.creating
51             && dir->u.umsdos_i.dir_info.pid != current->pid) {
52                 PRINTK (("creating && dir_info.pid=%lu, current->pid=%u\n", dir->u.umsdos_i.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 (dir->u.umsdos_i.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         dir->u.umsdos_i.dir_info.creating++;
108         dir->u.umsdos_i.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                         dir1->u.umsdos_i.dir_info.creating++;
128                         dir1->u.umsdos_i.dir_info.pid = current->pid;
129                         dir2->u.umsdos_i.dir_info.creating++;
130                         dir2->u.umsdos_i.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         dir->u.umsdos_i.dir_info.looking++;
145 }
146
147 /*
148  * Unlock the directory.
149  */
150 void umsdos_unlockcreate (struct inode *dir)
151 {
152         dir->u.umsdos_i.dir_info.creating--;
153         if (dir->u.umsdos_i.dir_info.creating < 0) {
154                 printk ("UMSDOS: dir->u.umsdos_i.dir_info.creating < 0: %d"
155                         ,dir->u.umsdos_i.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         dir->u.umsdos_i.dir_info.looking--;
166         if (dir->u.umsdos_i.dir_info.looking < 0) {
167                 printk ("UMSDOS: dir->u.umsdos_i.dir_info.looking < 0: %d"
168                         ,dir->u.umsdos_i.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, int 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 = CURRENT_TIME;
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);
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)
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 = block_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_free_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                 /*
621                  * Capture the path to the hidden link.
622                  */
623                 path = umsdos_d_path(olddentry, (char *) buffer, PAGE_SIZE);
624                 if (IS_ERR(path)) {
625                         ret = PTR_ERR(path);
626                         goto cleanup;
627                 }
628 Printk(("umsdos_link: hidden link path=%s\n", path));
629
630                 /* mark the inode as a hardlink */
631                 oldinode->u.umsdos_i.i_is_hlink = 1;
632
633                 /*
634                  * Recreate a dentry for the original name and symlink it,
635                  * then symlink the new dentry. Don't give up if one fails,
636                  * or we'll lose the file completely!
637                  *
638                  * Note: this counts as the "original" reference, so we 
639                  * don't increment i_nlink for this one.
640                  */ 
641                 temp = umsdos_lookup_dentry(olddentry->d_parent,
642                                                 old_info.entry.name,
643                                                 old_info.entry.name_len, 0); 
644                 ret = PTR_ERR(temp);
645                 if (!IS_ERR(temp)) {
646                         ret = umsdos_symlink_x (olddir, temp, path, 
647                                                 S_IFREG | 0777, UMSDOS_HLINK);
648                         dput(temp);
649                 }
650
651                 /* This symlink increments i_nlink (see below.) */
652                 err = umsdos_symlink_x (dir, dentry, path,
653                                         S_IFREG | 0777, UMSDOS_HLINK);
654                 /* fold the two errors */
655                 if (!ret)
656                         ret = err;
657                 goto out_unlock;
658
659                 /* creation failed ... remove the link entry */
660         cleanup:
661 printk("umsdos_link: link failed, ret=%d, removing %s/%s\n",
662 ret, olddentry->d_parent->d_name.name, hid_info.entry.name);
663                 err = umsdos_delentry(olddentry->d_parent, &hid_info, 0);
664                 goto out_unlock;
665         }
666
667 Printk(("UMSDOS_link: %s/%s already hidden\n",
668 olddentry->d_parent->d_name.name, olddentry->d_name.name));
669         /*
670          * The original file is already hidden, and we need to get 
671          * the dentry for its real name, not the visible name.
672          * N.B. make sure it's the hidden inode ...
673          */
674         if (!oldinode->u.umsdos_i.i_is_hlink)
675                 printk("UMSDOS_link: %s/%s hidden, ino=%ld not hlink??\n",
676                         olddentry->d_parent->d_name.name,
677                         olddentry->d_name.name, oldinode->i_ino);
678
679         /*
680          * In order to get the correct (real) inode, we just drop
681          * the original dentry.
682          */ 
683         d_drop(olddentry);
684 Printk(("UMSDOS_link: hard link %s/%s, fake=%s\n",
685 olddentry->d_parent->d_name.name, olddentry->d_name.name, old_info.fake.fname));
686
687         /* Do a real lookup to get the short name dentry */
688         temp = umsdos_covered(olddentry->d_parent, old_info.fake.fname, 
689                                         old_info.fake.len);
690         ret = PTR_ERR(temp);
691         if (IS_ERR(temp))
692                 goto out_unlock;
693
694         /* now resolve the link ... */
695         temp = umsdos_solve_hlink(temp);
696         ret = PTR_ERR(temp);
697         if (IS_ERR(temp))
698                 goto out_unlock;
699         path = umsdos_d_path(temp, (char *) buffer, PAGE_SIZE);
700         dput(temp);
701         if (IS_ERR(path))
702                 goto out_unlock;
703 Printk(("umsdos_link: %s/%s already hidden, path=%s\n",
704 olddentry->d_parent->d_name.name, olddentry->d_name.name, path));
705
706         /* finally we can symlink it ... */
707         ret = umsdos_symlink_x (dir, dentry, path, S_IFREG | 0777,UMSDOS_HLINK);
708
709 out_unlock:
710         /* remain locked for the call to notify_change ... */
711         if (ret == 0) {
712                 struct iattr newattrs;
713
714                 /* Do a real lookup to get the short name dentry */
715                 temp = umsdos_covered(olddentry->d_parent,
716                                         old_info.fake.fname,
717                                         old_info.fake.len);
718                 ret = PTR_ERR(temp);
719                 if (IS_ERR(temp))
720                         goto out_unlock2;
721
722                 /* now resolve the link ... */
723                 temp = umsdos_solve_hlink(temp);
724                 ret = PTR_ERR(temp);
725                 if (IS_ERR(temp))
726                         goto out_unlock2;
727
728
729 #ifdef UMSDOS_PARANOIA
730 if (!oldinode->u.umsdos_i.i_is_hlink)
731 printk("UMSDOS_link: %s/%s, ino=%ld, not marked as hlink!\n",
732 olddentry->d_parent->d_name.name, olddentry->d_name.name, oldinode->i_ino);
733 #endif
734                 temp->d_inode->i_nlink++;
735 Printk(("UMSDOS_link: linked %s/%s, ino=%ld, nlink=%d\n",
736 olddentry->d_parent->d_name.name, olddentry->d_name.name,
737 oldinode->i_ino, oldinode->i_nlink));
738                 newattrs.ia_valid = 0;
739                 ret = umsdos_notify_change_locked(temp, &newattrs);
740                 if (ret == 0)
741                         mark_inode_dirty(temp->d_inode);
742                 dput(temp);
743 out_unlock2:    
744                 if (ret == 0)
745                         mark_inode_dirty(olddentry->d_inode);
746         }
747         if (olddir != dir)
748                 up(&olddir->i_sem);
749
750 out_free:
751         free_page(buffer);
752 out:
753         Printk (("umsdos_link %d\n", ret));
754         return ret;
755 }
756
757
758 /*
759  * Add a sub-directory in a directory
760  */
761 /* #Specification: mkdir / Directory already exist in DOS
762  * We do the same thing as for file creation.
763  * For all user it is an error.
764  */
765 /* #Specification: mkdir / umsdos directory / create EMD
766  * When we created a new sub-directory in a UMSDOS
767  * directory (one with full UMSDOS semantics), we
768  * create immediately an EMD file in the new
769  * sub-directory so it inherits UMSDOS semantics.
770  */
771 int UMSDOS_mkdir (struct inode *dir, struct dentry *dentry, int mode)
772 {
773         struct dentry *temp;
774         struct inode *inode;
775         int ret, err;
776         struct umsdos_info info;
777
778         ret = umsdos_nevercreat (dir, dentry, -EEXIST);
779         if (ret)
780                 goto out;
781
782         ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
783         if (ret)
784                 goto out;
785
786         info.entry.mode = mode | S_IFDIR;
787         info.entry.rdev = 0;
788         info.entry.uid = current->fsuid;
789         info.entry.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
790         info.entry.ctime = info.entry.atime = info.entry.mtime = CURRENT_TIME;
791         info.entry.flags = 0;
792         info.entry.nlink = 1;
793         ret = umsdos_newentry (dentry->d_parent, &info);
794         if (ret)
795                 goto out;
796
797         /* lookup the short name dentry */
798         temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
799         ret = PTR_ERR(temp);
800         if (IS_ERR(temp))
801                 goto out_remove;
802
803         /* Make sure the short name doesn't exist */
804         ret = -EEXIST;
805         if (temp->d_inode) {
806 printk("umsdos_mkdir: short name %s/%s exists\n",
807 dentry->d_parent->d_name.name, info.fake.fname);
808                 goto out_remove_dput;
809         }
810
811         ret = msdos_mkdir (dir, temp, mode);
812         if (ret)
813                 goto out_remove_dput;
814
815         /*
816          * Lock the inode to protect the EMD creation ...
817          */
818         inode = temp->d_inode;
819         down(&inode->i_sem);
820
821         atomic_inc(&inode->i_count);
822         d_instantiate(dentry, inode);
823
824         /* N.B. this should have an option to create the EMD ... */
825         umsdos_lookup_patch_new(dentry, &info);
826
827         /* 
828          * Create the EMD file, and set up the dir so it is
829          * promoted to EMD with the EMD file invisible.
830          *
831          * N.B. error return if EMD fails?
832          */
833         err = umsdos_make_emd(dentry);
834         umsdos_setup_dir(dentry);
835
836         up(&inode->i_sem);
837         dput(temp);
838
839 out:
840         Printk(("umsdos_mkdir: %s/%s, ret=%d\n",
841                 dentry->d_parent->d_name.name, dentry->d_name.name, ret));
842         return ret;
843
844         /* an error occurred ... remove EMD entry. */
845 out_remove_dput:
846         dput(temp);
847 out_remove:
848         umsdos_delentry (dentry->d_parent, &info, 1);
849         goto out;
850 }
851
852 /*
853  * Add a new device special file into a directory.
854  *
855  * #Specification: Special files / strategy
856  * Device special file, pipes, etc ... are created like normal
857  * file in the msdos file system. Of course they remain empty.
858  * 
859  * One strategy was to create those files only in the EMD file
860  * since they were not important for MSDOS. The problem with
861  * that, is that there were not getting inode number allocated.
862  * The MSDOS filesystems is playing a nice game to fake inode
863  * number, so why not use it.
864  * 
865  * The absence of inode number compatible with those allocated
866  * for ordinary files was causing major trouble with hard link
867  * in particular and other parts of the kernel I guess.
868  */
869 int UMSDOS_mknod (struct inode *dir, struct dentry *dentry,
870                  int mode, int rdev)
871 {
872         return umsdos_create_any (dir, dentry, mode, rdev, 0);
873 }
874
875 /*
876  * Remove a sub-directory.
877  */
878 int UMSDOS_rmdir (struct inode *dir, struct dentry *dentry)
879 {
880         struct dentry *temp;
881         int ret, err, empty;
882         struct umsdos_info info;
883
884         ret = umsdos_nevercreat (dir, dentry, -EPERM);
885         if (ret)
886                 goto out;
887
888         ret = -EBUSY;
889         if (!d_unhashed(dentry))
890                 goto out;
891
892         /* check whether the EMD is empty */
893         ret = -ENOTEMPTY;
894         empty = umsdos_isempty (dentry);
895
896         /* Have to remove the EMD file? */
897         if (empty == 1) {
898                 struct dentry *demd;
899
900                 demd = umsdos_get_emd_dentry(dentry);
901                 if (!IS_ERR(demd)) {
902                         err = -ENOENT;
903                         if (demd->d_inode)
904                                 err = msdos_unlink (dentry->d_inode, demd);
905 Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err));
906 #ifdef UMSDOS_PARANOIA
907 if (err)
908 printk("umsdos_rmdir: EMD %s/%s unlink failed, err=%d\n",
909 demd->d_parent->d_name.name, demd->d_name.name, err);
910 #endif
911                         if (!err) {
912                                 d_delete(demd);
913                                 ret = 0;
914                         }
915                         dput(demd);
916                 }
917         } else if (empty == 2)
918                 ret = 0;
919         if (ret)
920                 goto out;
921
922         umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
923         /* Call findentry to complete the mangling */
924         umsdos_findentry (dentry->d_parent, &info, 2);
925         temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
926         ret = PTR_ERR(temp);
927         if (IS_ERR(temp))
928                 goto out;
929         /*
930          * Attempt to remove the msdos name.
931          */
932         ret = msdos_rmdir (dir, temp);
933         if (ret && ret != -ENOENT)
934                 goto out_dput;
935
936         d_delete(temp);
937         /* OK so far ... remove the name from the EMD */
938         ret = umsdos_delentry (dentry->d_parent, &info, 1);
939 #ifdef UMSDOS_PARANOIA
940 if (ret)
941 printk("umsdos_rmdir: delentry %s failed, ret=%d\n", info.entry.name, ret);
942 #endif
943
944         /* dput() temp if we didn't do it above */
945 out_dput:
946         dput(temp);
947
948 out:
949         Printk (("umsdos_rmdir %d\n", ret));
950         return ret;
951 }
952
953
954 /*
955  * Remove a file from the directory.
956  *
957  * #Specification: hard link / deleting a link
958  * When we delete a file and this file is a link,
959  * we must subtract 1 from the nlink field of the
960  * hidden link.
961  * 
962  * If the count goes to 0, we delete this hidden
963  * link too.
964  */
965 int UMSDOS_unlink (struct inode *dir, struct dentry *dentry)
966 {
967         struct dentry *temp, *link = NULL;
968         struct inode *inode;
969         int ret;
970         struct umsdos_info info;
971
972 Printk(("UMSDOS_unlink: entering %s/%s\n",
973 dentry->d_parent->d_name.name, dentry->d_name.name));
974
975         ret = umsdos_nevercreat (dir, dentry, -EPERM);
976         if (ret)
977                 goto out;
978
979         ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
980         if (ret)
981                 goto out;
982
983         umsdos_lockcreate (dir);
984         ret = umsdos_findentry (dentry->d_parent, &info, 1);
985         if (ret) {
986 printk("UMSDOS_unlink: %s/%s not in EMD, ret=%d\n",
987 dentry->d_parent->d_name.name, dentry->d_name.name, ret);
988                 goto out_unlock;
989         }
990
991 Printk (("UMSDOS_unlink %.*s ", info.fake.len, info.fake.fname));
992
993         /*
994          * Note! If this is a hardlink and the names are aliased,
995          * the short-name lookup will return the hardlink dentry.
996          * In order to get the correct (real) inode, we just drop
997          * the original dentry.
998          */ 
999         if (info.entry.flags & UMSDOS_HLINK) {
1000                 d_drop(dentry);
1001         }
1002
1003         /* Do a real lookup to get the short name dentry */
1004         temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
1005         ret = PTR_ERR(temp);
1006         if (IS_ERR(temp))
1007                 goto out_unlock;
1008
1009         /*
1010          * Resolve hardlinks now, but defer processing until later.
1011          */
1012         if (info.entry.flags & UMSDOS_HLINK) {
1013                 link = umsdos_solve_hlink(dget(temp));
1014         }
1015
1016         /* Delete the EMD entry */
1017         ret = umsdos_delentry (dentry->d_parent, &info, 0);
1018         if (ret && ret != -ENOENT) {
1019                 printk(KERN_WARNING "UMSDOS_unlink: delentry %s, error=%d\n",
1020                         info.entry.name, ret);
1021                 goto out_dput;
1022         }
1023
1024         ret = msdos_unlink(dir, temp);
1025         if (!ret)
1026                 d_delete(temp);
1027 #ifdef UMSDOS_PARANOIA
1028 if (ret)
1029 printk("umsdos_unlink: %s/%s unlink failed, ret=%d\n",
1030 temp->d_parent->d_name.name, temp->d_name.name, ret);
1031 #endif
1032
1033         /* dput() temp if we didn't do it above */
1034 out_dput:
1035         dput(temp);
1036
1037 out_unlock:
1038         umsdos_unlockcreate (dir);
1039
1040         /*
1041          * Now check for deferred handling of a hardlink.
1042          */
1043         if (!link)
1044                 goto out;
1045
1046         if (IS_ERR(link)) {
1047 printk("umsdos_unlink: failed to resolve %s/%s\n",
1048 dentry->d_parent->d_name.name, dentry->d_name.name);
1049                 if (!ret)
1050                         ret = PTR_ERR(link);
1051                 goto out;
1052         }
1053
1054 Printk(("umsdos_unlink: link %s/%s deferred, pending ret=%d\n",
1055 link->d_parent->d_name.name, link->d_name.name, ret));
1056
1057         /* already have an error? */
1058         if (ret)
1059                 goto out_cleanup;
1060
1061         /* make sure the link exists ... */
1062         inode = link->d_inode;
1063         if (!inode) {
1064                 printk(KERN_WARNING "umsdos_unlink: hard link not found\n");
1065                 goto out_cleanup;
1066         }
1067
1068         /*
1069          * If this was the last linked reference, delete it now.
1070          *
1071          * N.B. Deadlock problem? We should be holding the lock
1072          * for the hardlink's parent, but another process might
1073          * be holding that lock waiting for us to finish ...
1074          */
1075         if (inode->i_nlink <= 1) {
1076                 ret = UMSDOS_unlink (link->d_parent->d_inode, link);
1077                 if (ret) {
1078                         printk(KERN_WARNING
1079                                 "umsdos_unlink: link removal failed, ret=%d\n",
1080                                  ret);
1081                 } else
1082                         d_delete(link);
1083         } else {
1084                 struct iattr newattrs;
1085                 inode->i_nlink--;
1086                 newattrs.ia_valid = 0;
1087                 ret = umsdos_notify_change_locked(link, &newattrs);
1088                 if (!ret)
1089                         mark_inode_dirty(link->d_inode);
1090         }
1091
1092 out_cleanup:
1093         d_drop(link);
1094         dput(link);
1095
1096 out:
1097         Printk (("umsdos_unlink %d\n", ret));
1098         return ret;
1099 }
1100
1101 /*
1102  * Rename (move) a file.
1103  */
1104 int UMSDOS_rename (struct inode *old_dir, struct dentry *old_dentry,
1105                    struct inode *new_dir, struct dentry *new_dentry)
1106 {
1107         int ret;
1108
1109         ret = umsdos_nevercreat (new_dir, new_dentry, -EEXIST);
1110         if (ret)
1111                 return ret;
1112
1113                 /*
1114                  * If the target already exists, delete it first.
1115                  */
1116         if (new_dentry->d_inode) {
1117                 dget(new_dentry);
1118                 if (S_ISDIR(old_dentry->d_inode->i_mode))
1119                         ret = UMSDOS_rmdir (new_dir, new_dentry);
1120                 else
1121                         ret = UMSDOS_unlink (new_dir, new_dentry);
1122                 if (!ret)
1123                         d_drop(new_dentry);
1124                 dput(new_dentry);
1125                 if (ret)
1126                         return ret;
1127         }
1128         ret = umsdos_rename_f(old_dir, old_dentry, new_dir, new_dentry, 0);
1129         return ret;
1130 }