* added 0.99 linux version
[mascara-docs.git] / i386 / linux / linux-2.3.21 / fs / umsdos / namei.c
blob444e9ffae2cde57f30ab5320dea5f427934d5720
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 */
9 /*
10 * You are in the maze of twisted functions - half of them shouldn't
11 * be here...
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/malloc.h>
25 #if 1
27 * Wait for creation exclusivity.
28 * Return 0 if the dir was already available.
29 * Return 1 if a wait was necessary.
30 * When 1 is return, it means a wait was done. It does not
31 * mean the directory is available.
33 static int umsdos_waitcreate (struct inode *dir)
35 int ret = 0;
37 if (dir->u.umsdos_i.u.dir_info.creating
38 && dir->u.umsdos_i.u.dir_info.pid != current->pid) {
39 sleep_on (&dir->u.umsdos_i.u.dir_info.p);
40 ret = 1;
42 return ret;
46 * Wait for any lookup process to finish
48 static void umsdos_waitlookup (struct inode *dir)
50 while (dir->u.umsdos_i.u.dir_info.looking) {
51 sleep_on (&dir->u.umsdos_i.u.dir_info.p);
56 * Lock all other process out of this directory.
58 /* #Specification: file creation / not atomic
59 * File creation is a two step process. First we create (allocate)
60 * an entry in the EMD file and then (using the entry offset) we
61 * build a unique name for MSDOS. We create this name in the msdos
62 * space.
64 * We have to use semaphore (sleep_on/wake_up) to prevent lookup
65 * into a directory when we create a file or directory and to
66 * prevent creation while a lookup is going on. Since many lookup
67 * may happen at the same time, the semaphore is a counter.
69 * Only one creation is allowed at the same time. This protection
70 * may not be necessary. The problem arise mainly when a lookup
71 * or a readdir is done while a file is partially created. The
72 * lookup process see that as a "normal" problem and silently
73 * erase the file from the EMD file. Normal because a file
74 * may be erased during a MSDOS session, but not removed from
75 * the EMD file.
77 * The locking is done on a directory per directory basis. Each
78 * directory inode has its wait_queue.
80 * For some operation like hard link, things even get worse. Many
81 * creation must occur at once (atomic). To simplify the design
82 * a process is allowed to recursively lock the directory for
83 * creation. The pid of the locking process is kept along with
84 * a counter so a second level of locking is granted or not.
86 void umsdos_lockcreate (struct inode *dir)
89 * Wait for any creation process to finish except
90 * if we (the process) own the lock
92 while (umsdos_waitcreate (dir) != 0);
93 dir->u.umsdos_i.u.dir_info.creating++;
94 dir->u.umsdos_i.u.dir_info.pid = current->pid;
95 umsdos_waitlookup (dir);
99 * Lock all other process out of those two directories.
101 static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
104 * We must check that both directory are available before
105 * locking anyone of them. This is to avoid some deadlock.
106 * Thanks to dglaude@is1.vub.ac.be (GLAUDE DAVID) for pointing
107 * this to me.
109 while (1) {
110 if (umsdos_waitcreate (dir1) == 0
111 && umsdos_waitcreate (dir2) == 0) {
112 /* We own both now */
113 dir1->u.umsdos_i.u.dir_info.creating++;
114 dir1->u.umsdos_i.u.dir_info.pid = current->pid;
115 dir2->u.umsdos_i.u.dir_info.creating++;
116 dir2->u.umsdos_i.u.dir_info.pid = current->pid;
117 break;
120 umsdos_waitlookup (dir1);
121 umsdos_waitlookup (dir2);
125 * Wait until creation is finish in this directory.
127 void umsdos_startlookup (struct inode *dir)
129 while (umsdos_waitcreate (dir) != 0);
130 dir->u.umsdos_i.u.dir_info.looking++;
134 * Unlock the directory.
136 void umsdos_unlockcreate (struct inode *dir)
138 dir->u.umsdos_i.u.dir_info.creating--;
139 if (dir->u.umsdos_i.u.dir_info.creating < 0) {
140 printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.creating < 0: %d"
141 ,dir->u.umsdos_i.u.dir_info.creating);
143 wake_up (&dir->u.umsdos_i.u.dir_info.p);
147 * Tell directory lookup is over.
149 void umsdos_endlookup (struct inode *dir)
151 dir->u.umsdos_i.u.dir_info.looking--;
152 if (dir->u.umsdos_i.u.dir_info.looking < 0) {
153 printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.looking < 0: %d"
154 ,dir->u.umsdos_i.u.dir_info.looking);
156 wake_up (&dir->u.umsdos_i.u.dir_info.p);
159 #else
160 static void umsdos_lockcreate (struct inode *dir)
163 static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
166 void umsdos_startlookup (struct inode *dir)
169 static void umsdos_unlockcreate (struct inode *dir)
172 void umsdos_endlookup (struct inode *dir)
176 #endif
178 static int umsdos_nevercreat (struct inode *dir, struct dentry *dentry,
179 int errcod)
181 int ret = 0;
183 if (umsdos_is_pseudodos (dir, dentry)) {
184 /* #Specification: pseudo root / any file creation /DOS
185 * The pseudo sub-directory /DOS can't be created!
186 * EEXIST is returned.
188 * The pseudo sub-directory /DOS can't be removed!
189 * EPERM is returned.
191 ret = errcod;
193 return ret;
197 * Add a new file (ordinary or special) into the alternate directory.
198 * The file is added to the real MSDOS directory. If successful, it
199 * is then added to the EMD file.
201 * Return the status of the operation. 0 mean success.
203 * #Specification: create / file exists in DOS
204 * Here is a situation: we are trying to create a file with
205 * UMSDOS. The file is unknown to UMSDOS but already
206 * exists in the DOS directory.
208 * Here is what we are NOT doing:
210 * We could silently assume that everything is fine
211 * and allows the creation to succeed.
213 * It is possible not all files in the partition
214 * are meant to be visible from linux. By trying to create
215 * those file in some directory, one user may get access
216 * to those file without proper permissions. Looks like
217 * a security hole to me. Off course sharing a file system
218 * with DOS is some kind of security hole :-)
220 * So ?
222 * We return EEXIST in this case.
223 * The same is true for directory creation.
225 static int umsdos_create_any (struct inode *dir, struct dentry *dentry,
226 int mode, int rdev, char flags)
228 struct dentry *fake;
229 struct inode *inode;
230 int ret;
231 struct umsdos_info info;
233 ret = umsdos_nevercreat (dir, dentry, -EEXIST);
234 if (ret)
235 goto out;
237 ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
238 if (ret)
239 goto out;
241 info.entry.mode = mode;
242 info.entry.rdev = rdev;
243 info.entry.flags = flags;
244 info.entry.uid = current->fsuid;
245 info.entry.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
246 info.entry.ctime = info.entry.atime = info.entry.mtime = CURRENT_TIME;
247 info.entry.nlink = 1;
248 ret = umsdos_newentry (dentry->d_parent, &info);
249 if (ret)
250 goto out;
252 /* do a real lookup to get the short name dentry */
253 fake = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
254 ret = PTR_ERR(fake);
255 if (IS_ERR(fake))
256 goto out_remove;
258 /* should not exist yet ... */
259 ret = -EEXIST;
260 if (fake->d_inode)
261 goto out_remove_dput;
263 ret = msdos_create (dir, fake, S_IFREG | 0777);
264 if (ret)
265 goto out_remove_dput;
267 inode = fake->d_inode;
268 inode->i_count++;
269 d_instantiate (dentry, inode);
270 dput(fake);
271 if (inode->i_count > 1) {
272 printk(KERN_WARNING
273 "umsdos_create_any: %s/%s, ino=%ld, icount=%d??\n",
274 dentry->d_parent->d_name.name, dentry->d_name.name,
275 inode->i_ino, inode->i_count);
277 umsdos_lookup_patch_new(dentry, &info);
279 out:
280 return ret;
282 /* Creation failed ... remove the EMD entry */
283 out_remove_dput:
284 dput(fake);
285 out_remove:
286 if (ret == -EEXIST)
287 printk(KERN_WARNING "UMSDOS: out of sync, deleting %s/%s\n",
288 dentry->d_parent->d_name.name, info.fake.fname);
289 umsdos_delentry (dentry->d_parent, &info, S_ISDIR (info.entry.mode));
290 goto out;
294 * Add a new file into the alternate directory.
295 * The file is added to the real MSDOS directory. If successful, it
296 * is then added to the EMD file.
298 * Return the status of the operation. 0 mean success.
300 int UMSDOS_create (struct inode *dir, struct dentry *dentry, int mode)
302 return umsdos_create_any (dir, dentry, mode, 0, 0);
307 * Initialise the new_entry from the old for a rename operation.
308 * (Only useful for umsdos_rename_f() below).
310 static void umsdos_ren_init (struct umsdos_info *new_info,
311 struct umsdos_info *old_info)
313 new_info->entry.mode = old_info->entry.mode;
314 new_info->entry.rdev = old_info->entry.rdev;
315 new_info->entry.uid = old_info->entry.uid;
316 new_info->entry.gid = old_info->entry.gid;
317 new_info->entry.ctime = old_info->entry.ctime;
318 new_info->entry.atime = old_info->entry.atime;
319 new_info->entry.mtime = old_info->entry.mtime;
320 new_info->entry.flags = old_info->entry.flags;
321 new_info->entry.nlink = old_info->entry.nlink;
324 #ifdef OBSOLETE
325 #define chkstk() \
326 if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page){\
327 printk(KERN_ALERT "UMSDOS: %s magic %x != %lx ligne %d\n" \
328 , current->comm,STACK_MAGIC \
329 ,*(unsigned long *)current->kernel_stack_page \
330 ,__LINE__); \
333 #undef chkstk
334 #define chkstk() do { } while (0);
335 #endif
338 * Rename a file (move) in the file system.
341 static int umsdos_rename_f (struct inode *old_dir, struct dentry *old_dentry,
342 struct inode *new_dir, struct dentry *new_dentry,
343 int flags)
345 struct inode *old_inode = old_dentry->d_inode;
346 struct dentry *old, *new, *old_emd;
347 int err, ret;
348 struct umsdos_info old_info;
349 struct umsdos_info new_info;
351 ret = -EPERM;
352 err = umsdos_parse (old_dentry->d_name.name,
353 old_dentry->d_name.len, &old_info);
354 if (err)
355 goto out;
356 err = umsdos_parse (new_dentry->d_name.name,
357 new_dentry->d_name.len, &new_info);
358 if (err)
359 goto out;
361 /* Get the EMD dentry for the old parent */
362 old_emd = umsdos_get_emd_dentry(old_dentry->d_parent);
363 ret = PTR_ERR(old_emd);
364 if (IS_ERR(old_emd))
365 goto out;
367 umsdos_lockcreate2 (old_dir, new_dir);
369 ret = umsdos_findentry(old_emd->d_parent, &old_info, 0);
370 if (ret)
371 goto out_unlock;
373 err = umsdos_findentry(new_dentry->d_parent, &new_info, 0);
374 if (err == 0) {
375 /* check whether it _really_ exists ... */
376 ret = -EEXIST;
377 if (new_dentry->d_inode)
378 goto out_unlock;
380 /* bogus lookup? complain and fix up the EMD ... */
381 printk(KERN_WARNING
382 "umsdos_rename_f: entry %s/%s exists, inode NULL??\n",
383 new_dentry->d_parent->d_name.name, new_info.entry.name);
384 err = umsdos_delentry(new_dentry->d_parent, &new_info,
385 S_ISDIR(new_info.entry.mode));
388 umsdos_ren_init (&new_info, &old_info);
389 if (flags)
390 new_info.entry.flags = flags;
391 ret = umsdos_newentry (new_dentry->d_parent, &new_info);
392 if (ret)
393 goto out_unlock;
395 /* If we're moving a hardlink, drop it first */
396 if (old_info.entry.flags & UMSDOS_HLINK) {
397 d_drop(old_dentry);
400 old = umsdos_covered(old_dentry->d_parent, old_info.fake.fname,
401 old_info.fake.len);
402 ret = PTR_ERR(old);
403 if (IS_ERR(old))
404 goto out_unlock;
405 /* make sure it's the same inode! */
406 ret = -ENOENT;
407 if (old->d_inode != old_inode)
408 goto out_dput;
410 new = umsdos_covered(new_dentry->d_parent, new_info.fake.fname,
411 new_info.fake.len);
412 ret = PTR_ERR(new);
413 if (IS_ERR(new))
414 goto out_dput;
416 /* Do the msdos-level rename */
417 ret = msdos_rename (old_dir, old, new_dir, new);
419 dput(new);
421 /* If the rename failed, remove the new EMD entry */
422 if (ret != 0) {
423 umsdos_delentry (new_dentry->d_parent, &new_info,
424 S_ISDIR (new_info.entry.mode));
425 goto out_dput;
429 * Rename successful ... remove the old name from the EMD.
430 * Note that we use the EMD parent here, as the old dentry
431 * may have moved to a new parent ...
433 err = umsdos_delentry (old_emd->d_parent, &old_info,
434 S_ISDIR (old_info.entry.mode));
435 if (err) {
436 /* Failed? Complain a bit, but don't fail the operation */
437 printk(KERN_WARNING
438 "umsdos_rename_f: delentry %s/%s failed, error=%d\n",
439 old_emd->d_parent->d_name.name, old_info.entry.name,
440 err);
444 * Update f_pos so notify_change will succeed
445 * if the file was already in use.
447 umsdos_set_dirinfo_new(old_dentry, new_info.f_pos);
449 /* dput() the dentry if we haven't already */
450 out_dput:
451 dput(old);
453 out_unlock:
454 dput(old_emd);
455 umsdos_unlockcreate (old_dir);
456 umsdos_unlockcreate (new_dir);
458 out:
459 Printk ((" _ret=%d\n", ret));
460 return ret;
464 * Setup a Symbolic link or a (pseudo) hard link
465 * Return a negative error code or 0 if OK.
467 /* #Specification: symbolic links / strategy
468 * A symbolic link is simply a file which holds a path. It is
469 * implemented as a normal MSDOS file (not very space efficient :-()
471 * I see two different ways to do this: One is to place the link data
472 * in unused entries of the EMD file; the other is to have a separate
473 * file dedicated to hold all symbolic links data.
475 * Let's go for simplicity...
478 extern struct inode_operations umsdos_symlink_inode_operations;
481 * AV. Should be called with dir->i_sem down.
483 static int umsdos_symlink_x (struct inode *dir, struct dentry *dentry,
484 const char *symname, int mode, char flags)
486 int ret, len;
487 struct file filp;
489 Printk(("umsdos_symlink: %s/%s to %s\n",
490 dentry->d_parent->d_name.name, dentry->d_name.name, symname));
492 ret = umsdos_create_any (dir, dentry, mode, 0, flags);
493 if (ret) {
494 printk(KERN_WARNING
495 "umsdos_symlink: create failed, ret=%d\n", ret);
496 goto out;
499 fill_new_filp (&filp, dentry);
500 len = strlen (symname);
501 ret = umsdos_file_write_kmem_real (&filp, symname, len);
502 if (ret < 0)
503 goto out_unlink;
504 if (ret != len)
505 goto out_error;
506 ret = 0;
507 out:
508 return ret;
510 out_error:
511 ret = -EIO;
512 out_unlink:
513 printk(KERN_WARNING "umsdos_symlink: write failed, unlinking\n");
514 UMSDOS_unlink (dir, dentry);
515 goto out;
519 * Setup a Symbolic link.
520 * Return a negative error code or 0 if OK.
522 int UMSDOS_symlink ( struct inode *dir, struct dentry *dentry,
523 const char *symname)
525 return umsdos_symlink_x (dir, dentry, symname, S_IFLNK | 0777, 0);
529 * Add a link to an inode in a directory
531 int UMSDOS_link (struct dentry *olddentry, struct inode *dir,
532 struct dentry *dentry)
534 struct inode *oldinode = olddentry->d_inode;
535 struct inode *olddir = olddentry->d_parent->d_inode;
536 struct dentry *temp;
537 char *path;
538 unsigned long buffer;
539 int ret;
540 struct umsdos_info old_info;
541 struct umsdos_info hid_info;
543 #ifdef UMSDOS_DEBUG_VERBOSE
544 printk("umsdos_link: new %s%s -> %s/%s\n",
545 dentry->d_parent->d_name.name, dentry->d_name.name,
546 olddentry->d_parent->d_name.name, olddentry->d_name.name);
547 #endif
549 ret = -EPERM;
550 if (S_ISDIR (oldinode->i_mode))
551 goto out;
553 ret = umsdos_nevercreat (dir, dentry, -EPERM);
554 if (ret)
555 goto out;
557 ret = -ENOMEM;
558 buffer = get_free_page(GFP_KERNEL);
559 if (!buffer)
560 goto out;
563 * Lock the link parent if it's not the same directory.
565 ret = -EDEADLOCK;
566 if (olddir != dir) {
567 if (atomic_read(&olddir->i_sem.count) < 1)
568 goto out_free;
569 down(&olddir->i_sem);
573 * Parse the name and get the visible directory entry.
575 ret = umsdos_parse (olddentry->d_name.name, olddentry->d_name.len,
576 &old_info);
577 if (ret)
578 goto out_unlock;
579 ret = umsdos_findentry (olddentry->d_parent, &old_info, 1);
580 if (ret) {
581 printk("UMSDOS_link: %s/%s not in EMD, ret=%d\n",
582 olddentry->d_parent->d_name.name, olddentry->d_name.name, ret);
583 goto out_unlock;
587 * If the visible dentry is a pseudo-hardlink, the original
588 * file must be already hidden.
590 if (!(old_info.entry.flags & UMSDOS_HLINK)) {
591 int err;
593 /* create a hidden link name */
594 ret = umsdos_newhidden (olddentry->d_parent, &hid_info);
595 if (ret) {
596 printk("umsdos_link: can't make hidden %s/%s, ret=%d\n",
597 olddentry->d_parent->d_name.name, hid_info.entry.name, ret);
598 goto out_unlock;
602 * Make a dentry and rename the original file ...
604 temp = umsdos_lookup_dentry(olddentry->d_parent,
605 hid_info.entry.name,
606 hid_info.entry.name_len, 0);
607 ret = PTR_ERR(temp);
608 if (IS_ERR(temp)) {
609 printk("umsdos_link: lookup %s/%s failed, ret=%d\n",
610 dentry->d_parent->d_name.name, hid_info.entry.name, ret);
611 goto cleanup;
613 /* rename the link to the hidden location ... */
614 ret = umsdos_rename_f(olddir, olddentry, olddir, temp,
615 UMSDOS_HIDDEN);
616 d_move(olddentry, temp);
617 dput(temp);
618 if (ret) {
619 printk("umsdos_link: rename to %s/%s failed, ret=%d\n",
620 temp->d_parent->d_name.name, temp->d_name.name, ret);
621 goto cleanup;
623 /* mark the inode as a hardlink */
624 oldinode->u.umsdos_i.i_is_hlink = 1;
627 * Capture the path to the hidden link.
629 path = umsdos_d_path(olddentry, (char *) buffer, PAGE_SIZE);
630 Printk(("umsdos_link: hidden link path=%s\n", path));
633 * Recreate a dentry for the original name and symlink it,
634 * then symlink the new dentry. Don't give up if one fails,
635 * or we'll lose the file completely!
637 * Note: this counts as the "original" reference, so we
638 * don't increment i_nlink for this one.
640 temp = umsdos_lookup_dentry(olddentry->d_parent,
641 old_info.entry.name,
642 old_info.entry.name_len, 0);
643 ret = PTR_ERR(temp);
644 if (!IS_ERR(temp)) {
645 ret = umsdos_symlink_x (olddir, temp, path,
646 S_IFREG | 0777, UMSDOS_HLINK);
647 dput(temp);
650 /* This symlink increments i_nlink (see below.) */
651 err = umsdos_symlink_x (dir, dentry, path,
652 S_IFREG | 0777, UMSDOS_HLINK);
653 /* fold the two errors */
654 if (!ret)
655 ret = err;
656 goto out_unlock;
658 /* creation failed ... remove the link entry */
659 cleanup:
660 printk("umsdos_link: link failed, ret=%d, removing %s/%s\n",
661 ret, olddentry->d_parent->d_name.name, hid_info.entry.name);
662 err = umsdos_delentry(olddentry->d_parent, &hid_info, 0);
663 goto out_unlock;
666 Printk(("UMSDOS_link: %s/%s already hidden\n",
667 olddentry->d_parent->d_name.name, olddentry->d_name.name));
669 * The original file is already hidden, and we need to get
670 * the dentry for its real name, not the visible name.
671 * N.B. make sure it's the hidden inode ...
673 if (!oldinode->u.umsdos_i.i_is_hlink)
674 printk("UMSDOS_link: %s/%s hidden, ino=%ld not hlink??\n",
675 olddentry->d_parent->d_name.name,
676 olddentry->d_name.name, oldinode->i_ino);
679 * In order to get the correct (real) inode, we just drop
680 * the original dentry.
682 d_drop(olddentry);
683 Printk(("UMSDOS_link: hard link %s/%s, fake=%s\n",
684 olddentry->d_parent->d_name.name, olddentry->d_name.name, old_info.fake.fname));
686 /* Do a real lookup to get the short name dentry */
687 temp = umsdos_covered(olddentry->d_parent, old_info.fake.fname,
688 old_info.fake.len);
689 ret = PTR_ERR(temp);
690 if (IS_ERR(temp))
691 goto out_unlock;
693 /* now resolve the link ... */
694 temp = umsdos_solve_hlink(temp);
695 ret = PTR_ERR(temp);
696 if (IS_ERR(temp))
697 goto out_unlock;
698 path = umsdos_d_path(temp, (char *) buffer, PAGE_SIZE);
699 dput(temp);
700 Printk(("umsdos_link: %s/%s already hidden, path=%s\n",
701 olddentry->d_parent->d_name.name, olddentry->d_name.name, path));
703 /* finally we can symlink it ... */
704 ret = umsdos_symlink_x (dir, dentry, path, S_IFREG | 0777,UMSDOS_HLINK);
706 out_unlock:
707 /* remain locked for the call to notify_change ... */
708 if (ret == 0) {
709 struct iattr newattrs;
711 #ifdef UMSDOS_PARANOIA
712 if (!oldinode->u.umsdos_i.i_is_hlink)
713 printk("UMSDOS_link: %s/%s, ino=%ld, not marked as hlink!\n",
714 olddentry->d_parent->d_name.name, olddentry->d_name.name, oldinode->i_ino);
715 #endif
716 oldinode->i_nlink++;
717 Printk(("UMSDOS_link: linked %s/%s, ino=%ld, nlink=%d\n",
718 olddentry->d_parent->d_name.name, olddentry->d_name.name,
719 oldinode->i_ino, oldinode->i_nlink));
720 newattrs.ia_valid = 0;
721 ret = umsdos_notify_change_locked(olddentry, &newattrs);
723 if (olddir != dir)
724 up(&olddir->i_sem);
726 out_free:
727 free_page(buffer);
728 out:
729 Printk (("umsdos_link %d\n", ret));
730 return ret;
735 * Add a sub-directory in a directory
737 /* #Specification: mkdir / Directory already exist in DOS
738 * We do the same thing as for file creation.
739 * For all user it is an error.
741 /* #Specification: mkdir / umsdos directory / create EMD
742 * When we created a new sub-directory in a UMSDOS
743 * directory (one with full UMSDOS semantics), we
744 * create immediately an EMD file in the new
745 * sub-directory so it inherits UMSDOS semantics.
747 int UMSDOS_mkdir (struct inode *dir, struct dentry *dentry, int mode)
749 struct dentry *temp;
750 struct inode *inode;
751 int ret, err;
752 struct umsdos_info info;
754 ret = umsdos_nevercreat (dir, dentry, -EEXIST);
755 if (ret)
756 goto out;
758 ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
759 if (ret)
760 goto out;
762 info.entry.mode = mode | S_IFDIR;
763 info.entry.rdev = 0;
764 info.entry.uid = current->fsuid;
765 info.entry.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
766 info.entry.ctime = info.entry.atime = info.entry.mtime = CURRENT_TIME;
767 info.entry.flags = 0;
768 info.entry.nlink = 1;
769 ret = umsdos_newentry (dentry->d_parent, &info);
770 if (ret)
771 goto out;
773 /* lookup the short name dentry */
774 temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
775 ret = PTR_ERR(temp);
776 if (IS_ERR(temp))
777 goto out_remove;
779 /* Make sure the short name doesn't exist */
780 ret = -EEXIST;
781 if (temp->d_inode) {
782 printk("umsdos_mkdir: short name %s/%s exists\n",
783 dentry->d_parent->d_name.name, info.fake.fname);
784 goto out_remove_dput;
787 ret = msdos_mkdir (dir, temp, mode);
788 if (ret)
789 goto out_remove_dput;
792 * Lock the inode to protect the EMD creation ...
794 inode = temp->d_inode;
795 down(&inode->i_sem);
797 inode->i_count++;
798 d_instantiate(dentry, inode);
800 /* N.B. this should have an option to create the EMD ... */
801 umsdos_lookup_patch_new(dentry, &info);
804 * Create the EMD file, and set up the dir so it is
805 * promoted to EMD with the EMD file invisible.
807 * N.B. error return if EMD fails?
809 err = umsdos_make_emd(dentry);
810 umsdos_setup_dir(dentry);
812 up(&inode->i_sem);
813 dput(temp);
815 out:
816 Printk(("umsdos_mkdir: %s/%s, ret=%d\n",
817 dentry->d_parent->d_name.name, dentry->d_name.name, ret));
818 return ret;
820 /* an error occurred ... remove EMD entry. */
821 out_remove_dput:
822 dput(temp);
823 out_remove:
824 umsdos_delentry (dentry->d_parent, &info, 1);
825 goto out;
829 * Add a new device special file into a directory.
831 * #Specification: Special files / strategy
832 * Device special file, pipes, etc ... are created like normal
833 * file in the msdos file system. Of course they remain empty.
835 * One strategy was to create those files only in the EMD file
836 * since they were not important for MSDOS. The problem with
837 * that, is that there were not getting inode number allocated.
838 * The MSDOS filesystems is playing a nice game to fake inode
839 * number, so why not use it.
841 * The absence of inode number compatible with those allocated
842 * for ordinary files was causing major trouble with hard link
843 * in particular and other parts of the kernel I guess.
845 int UMSDOS_mknod (struct inode *dir, struct dentry *dentry,
846 int mode, int rdev)
848 return umsdos_create_any (dir, dentry, mode, rdev, 0);
852 * Remove a sub-directory.
854 int UMSDOS_rmdir (struct inode *dir, struct dentry *dentry)
856 struct dentry *temp;
857 int ret, err, empty;
858 struct umsdos_info info;
860 ret = umsdos_nevercreat (dir, dentry, -EPERM);
861 if (ret)
862 goto out;
864 ret = -EBUSY;
865 if (!list_empty(&dentry->d_hash))
866 goto out;
868 /* check whether the EMD is empty */
869 ret = -ENOTEMPTY;
870 empty = umsdos_isempty (dentry);
872 /* Have to remove the EMD file? */
873 if (empty == 1) {
874 struct dentry *demd;
876 demd = umsdos_get_emd_dentry(dentry);
877 if (!IS_ERR(demd)) {
878 err = -ENOENT;
879 if (demd->d_inode)
880 err = msdos_unlink (dentry->d_inode, demd);
881 Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err));
882 #ifdef UMSDOS_PARANOIA
883 if (err)
884 printk("umsdos_rmdir: EMD %s/%s unlink failed, err=%d\n",
885 demd->d_parent->d_name.name, demd->d_name.name, err);
886 #endif
887 dput(demd);
888 if (!err)
889 ret = 0;
891 } else if (empty == 2)
892 ret = 0;
893 if (ret)
894 goto out;
896 umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
897 /* Call findentry to complete the mangling */
898 umsdos_findentry (dentry->d_parent, &info, 2);
899 temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
900 ret = PTR_ERR(temp);
901 if (IS_ERR(temp))
902 goto out;
904 * Attempt to remove the msdos name.
906 ret = msdos_rmdir (dir, temp);
907 if (ret && ret != -ENOENT)
908 goto out_dput;
910 /* OK so far ... remove the name from the EMD */
911 ret = umsdos_delentry (dentry->d_parent, &info, 1);
912 #ifdef UMSDOS_PARANOIA
913 if (ret)
914 printk("umsdos_rmdir: delentry %s failed, ret=%d\n", info.entry.name, ret);
915 #endif
917 /* dput() temp if we didn't do it above */
918 out_dput:
919 dput(temp);
921 out:
922 Printk (("umsdos_rmdir %d\n", ret));
923 return ret;
928 * Remove a file from the directory.
930 * #Specification: hard link / deleting a link
931 * When we delete a file and this file is a link,
932 * we must subtract 1 from the nlink field of the
933 * hidden link.
935 * If the count goes to 0, we delete this hidden
936 * link too.
938 int UMSDOS_unlink (struct inode *dir, struct dentry *dentry)
940 struct dentry *temp, *link = NULL;
941 struct inode *inode;
942 int ret;
943 struct umsdos_info info;
945 Printk(("UMSDOS_unlink: entering %s/%s\n",
946 dentry->d_parent->d_name.name, dentry->d_name.name));
948 ret = umsdos_nevercreat (dir, dentry, -EPERM);
949 if (ret)
950 goto out;
952 ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
953 if (ret)
954 goto out;
956 umsdos_lockcreate (dir);
957 ret = umsdos_findentry (dentry->d_parent, &info, 1);
958 if (ret) {
959 printk("UMSDOS_unlink: %s/%s not in EMD, ret=%d\n",
960 dentry->d_parent->d_name.name, dentry->d_name.name, ret);
961 goto out_unlock;
964 Printk (("UMSDOS_unlink %.*s ", info.fake.len, info.fake.fname));
967 * Note! If this is a hardlink and the names are aliased,
968 * the short-name lookup will return the hardlink dentry.
969 * In order to get the correct (real) inode, we just drop
970 * the original dentry.
972 if (info.entry.flags & UMSDOS_HLINK) {
973 d_drop(dentry);
976 /* Do a real lookup to get the short name dentry */
977 temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
978 ret = PTR_ERR(temp);
979 if (IS_ERR(temp))
980 goto out_unlock;
983 * Resolve hardlinks now, but defer processing until later.
985 if (info.entry.flags & UMSDOS_HLINK) {
986 link = umsdos_solve_hlink(dget(temp));
989 /* Delete the EMD entry */
990 ret = umsdos_delentry (dentry->d_parent, &info, 0);
991 if (ret && ret != -ENOENT) {
992 printk(KERN_WARNING "UMSDOS_unlink: delentry %s, error=%d\n",
993 info.entry.name, ret);
994 goto out_dput;
997 ret = msdos_unlink(dir, temp);
998 #ifdef UMSDOS_PARANOIA
999 if (ret)
1000 printk("umsdos_unlink: %s/%s unlink failed, ret=%d\n",
1001 temp->d_parent->d_name.name, temp->d_name.name, ret);
1002 #endif
1004 /* dput() temp if we didn't do it above */
1005 out_dput:
1006 dput(temp);
1007 if (!ret)
1008 d_delete (dentry);
1010 out_unlock:
1011 umsdos_unlockcreate (dir);
1014 * Now check for deferred handling of a hardlink.
1016 if (!link)
1017 goto out;
1019 if (IS_ERR(link)) {
1020 printk("umsdos_unlink: failed to resolve %s/%s\n",
1021 dentry->d_parent->d_name.name, dentry->d_name.name);
1022 if (!ret)
1023 ret = PTR_ERR(link);
1024 goto out;
1027 Printk(("umsdos_unlink: link %s/%s deferred, pending ret=%d\n",
1028 link->d_parent->d_name.name, link->d_name.name, ret));
1030 /* already have an error? */
1031 if (ret)
1032 goto out_cleanup;
1034 /* make sure the link exists ... */
1035 inode = link->d_inode;
1036 if (!inode) {
1037 printk(KERN_WARNING "umsdos_unlink: hard link not found\n");
1038 goto out_cleanup;
1042 * If this was the last linked reference, delete it now.
1044 * N.B. Deadlock problem? We should be holding the lock
1045 * for the hardlink's parent, but another process might
1046 * be holding that lock waiting for us to finish ...
1048 if (inode->i_nlink <= 1) {
1049 ret = UMSDOS_unlink (link->d_parent->d_inode, link);
1050 if (ret) {
1051 printk(KERN_WARNING
1052 "umsdos_unlink: link removal failed, ret=%d\n",
1053 ret);
1055 } else {
1056 struct iattr newattrs;
1057 inode->i_nlink--;
1058 newattrs.ia_valid = 0;
1059 ret = umsdos_notify_change_locked(link, &newattrs);
1062 out_cleanup:
1063 d_drop(link);
1064 dput(link);
1066 out:
1067 Printk (("umsdos_unlink %d\n", ret));
1068 return ret;
1072 * Rename (move) a file.
1074 int UMSDOS_rename (struct inode *old_dir, struct dentry *old_dentry,
1075 struct inode *new_dir, struct dentry *new_dentry)
1077 int ret;
1079 ret = umsdos_nevercreat (new_dir, new_dentry, -EEXIST);
1080 if (ret)
1081 return ret;
1084 * If the target already exists, delete it first.
1086 if (new_dentry->d_inode) {
1087 new_dentry->d_count++;
1088 if (S_ISDIR(old_dentry->d_inode->i_mode))
1089 ret = UMSDOS_rmdir (new_dir, new_dentry);
1090 else
1091 ret = UMSDOS_unlink (new_dir, new_dentry);
1092 dput(new_dentry);
1093 if (ret)
1094 return ret;
1096 ret = umsdos_rename_f(old_dir, old_dentry, new_dir, new_dentry, 0);
1097 return ret;