Linux-2.4.0-test2
[davej-history.git] / fs / umsdos / namei.c
blobc4cb0cb9f8ef29ede4a16d2ca6e431ff4302bb01
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 #define UMSDOS_DIR_LOCK
27 #ifdef UMSDOS_DIR_LOCK
29 static inline void u_sleep_on (struct inode *dir)
31 sleep_on (&dir->u.umsdos_i.dir_info.p);
34 static inline void u_wake_up (struct inode *dir)
36 wake_up (&dir->u.umsdos_i.dir_info.p);
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.
46 static int umsdos_waitcreate (struct inode *dir)
48 int ret = 0;
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;
56 return ret;
60 * Wait for any lookup process to finish
62 static void umsdos_waitlookup (struct inode *dir)
64 while (dir->u.umsdos_i.dir_info.looking) {
65 u_sleep_on (dir);
70 * Lock all other process out of this directory.
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.
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.
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.
91 * The locking is done on a directory per directory basis. Each
92 * directory inode has its wait_queue.
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.
100 void umsdos_lockcreate (struct inode *dir)
103 * Wait for any creation process to finish except
104 * if we (the process) own the lock
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);
113 * Lock all other process out of those two directories.
115 static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
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.
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;
134 umsdos_waitlookup (dir1);
135 umsdos_waitlookup (dir2);
139 * Wait until creation is finish in this directory.
141 void umsdos_startlookup (struct inode *dir)
143 while (umsdos_waitcreate (dir) != 0);
144 dir->u.umsdos_i.dir_info.looking++;
148 * Unlock the directory.
150 void umsdos_unlockcreate (struct inode *dir)
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);
157 u_wake_up (dir);
161 * Tell directory lookup is over.
163 void umsdos_endlookup (struct inode *dir)
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);
170 u_wake_up (dir);
173 #else
174 static void umsdos_lockcreate (struct inode *dir)
177 static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
180 void umsdos_startlookup (struct inode *dir)
183 static void umsdos_unlockcreate (struct inode *dir)
186 void umsdos_endlookup (struct inode *dir)
190 #endif
192 static int umsdos_nevercreat (struct inode *dir, struct dentry *dentry,
193 int errcod)
195 int ret = 0;
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.
202 * The pseudo sub-directory /DOS can't be removed!
203 * EPERM is returned.
205 ret = errcod;
207 return ret;
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.
215 * Return the status of the operation. 0 mean success.
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.
222 * Here is what we are NOT doing:
224 * We could silently assume that everything is fine
225 * and allows the creation to succeed.
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 :-)
234 * So ?
236 * We return EEXIST in this case.
237 * The same is true for directory creation.
239 static int umsdos_create_any (struct inode *dir, struct dentry *dentry,
240 int mode, int rdev, char flags)
242 struct dentry *fake;
243 struct inode *inode;
244 int ret;
245 struct umsdos_info info;
247 ret = umsdos_nevercreat (dir, dentry, -EEXIST);
248 if (ret)
249 goto out;
251 ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
252 if (ret)
253 goto out;
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;
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;
272 /* should not exist yet ... */
273 ret = -EEXIST;
274 if (fake->d_inode)
275 goto out_remove_dput;
277 ret = msdos_create (dir, fake, S_IFREG | 0777);
278 if (ret)
279 goto out_remove_dput;
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));
291 umsdos_lookup_patch_new(dentry, &info);
293 out:
294 return ret;
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;
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.
312 * Return the status of the operation. 0 mean success.
314 int UMSDOS_create (struct inode *dir, struct dentry *dentry, int mode)
316 return umsdos_create_any (dir, dentry, mode, 0, 0);
321 * Initialise the new_entry from the old for a rename operation.
322 * (Only useful for umsdos_rename_f() below).
324 static void umsdos_ren_init (struct umsdos_info *new_info,
325 struct umsdos_info *old_info)
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;
338 #ifdef OBSOLETE
339 #define chkstk() \
340 if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page){\
341 printk(KERN_ALERT "UMSDOS: %s magic %x != %lx ligne %d\n" \
342 , current->comm,STACK_MAGIC \
343 ,*(unsigned long *)current->kernel_stack_page \
344 ,__LINE__); \
347 #undef chkstk
348 #define chkstk() do { } while (0);
349 #endif
352 * Rename a file (move) in the file system.
355 static int umsdos_rename_f (struct inode *old_dir, struct dentry *old_dentry,
356 struct inode *new_dir, struct dentry *new_dentry,
357 int flags)
359 struct inode *old_inode = old_dentry->d_inode;
360 struct dentry *old, *new, *old_emd;
361 int err, ret;
362 struct umsdos_info old_info;
363 struct umsdos_info new_info;
365 ret = -EPERM;
366 err = umsdos_parse (old_dentry->d_name.name,
367 old_dentry->d_name.len, &old_info);
368 if (err)
369 goto out;
370 err = umsdos_parse (new_dentry->d_name.name,
371 new_dentry->d_name.len, &new_info);
372 if (err)
373 goto out;
375 /* Get the EMD dentry for the old parent */
376 old_emd = umsdos_get_emd_dentry(old_dentry->d_parent);
377 ret = PTR_ERR(old_emd);
378 if (IS_ERR(old_emd))
379 goto out;
381 umsdos_lockcreate2 (old_dir, new_dir);
383 ret = umsdos_findentry(old_emd->d_parent, &old_info, 0);
384 if (ret)
385 goto out_unlock;
387 err = umsdos_findentry(new_dentry->d_parent, &new_info, 0);
388 if (err == 0) {
389 /* check whether it _really_ exists ... */
390 ret = -EEXIST;
391 if (new_dentry->d_inode)
392 goto out_unlock;
394 /* bogus lookup? complain and fix up the EMD ... */
395 printk(KERN_WARNING
396 "umsdos_rename_f: entry %s/%s exists, inode NULL??\n",
397 new_dentry->d_parent->d_name.name, new_info.entry.name);
398 err = umsdos_delentry(new_dentry->d_parent, &new_info,
399 S_ISDIR(new_info.entry.mode));
402 umsdos_ren_init (&new_info, &old_info);
403 if (flags)
404 new_info.entry.flags = flags;
405 ret = umsdos_newentry (new_dentry->d_parent, &new_info);
406 if (ret)
407 goto out_unlock;
409 /* If we're moving a hardlink, drop it first */
410 if (old_info.entry.flags & UMSDOS_HLINK) {
411 d_drop(old_dentry);
414 old = umsdos_covered(old_dentry->d_parent, old_info.fake.fname,
415 old_info.fake.len);
416 ret = PTR_ERR(old);
417 if (IS_ERR(old))
418 goto out_unlock;
419 /* make sure it's the same inode! */
420 ret = -ENOENT;
421 if (old->d_inode != old_inode)
422 goto out_dput;
424 new = umsdos_covered(new_dentry->d_parent, new_info.fake.fname,
425 new_info.fake.len);
426 ret = PTR_ERR(new);
427 if (IS_ERR(new))
428 goto out_dput;
430 /* Do the msdos-level rename */
431 ret = msdos_rename (old_dir, old, new_dir, new);
433 dput(new);
435 /* If the rename failed, remove the new EMD entry */
436 if (ret != 0) {
437 umsdos_delentry (new_dentry->d_parent, &new_info,
438 S_ISDIR (new_info.entry.mode));
439 goto out_dput;
443 * Rename successful ... remove the old name from the EMD.
444 * Note that we use the EMD parent here, as the old dentry
445 * may have moved to a new parent ...
447 err = umsdos_delentry (old_emd->d_parent, &old_info,
448 S_ISDIR (old_info.entry.mode));
449 if (err) {
450 /* Failed? Complain a bit, but don't fail the operation */
451 printk(KERN_WARNING
452 "umsdos_rename_f: delentry %s/%s failed, error=%d\n",
453 old_emd->d_parent->d_name.name, old_info.entry.name,
454 err);
458 * Update f_pos so notify_change will succeed
459 * if the file was already in use.
461 umsdos_set_dirinfo_new(old_dentry, new_info.f_pos);
463 /* dput() the dentry if we haven't already */
464 out_dput:
465 dput(old);
467 out_unlock:
468 dput(old_emd);
469 umsdos_unlockcreate (old_dir);
470 umsdos_unlockcreate (new_dir);
472 out:
473 Printk ((" _ret=%d\n", ret));
474 return ret;
478 * Setup a Symbolic link or a (pseudo) hard link
479 * Return a negative error code or 0 if OK.
481 /* #Specification: symbolic links / strategy
482 * A symbolic link is simply a file which holds a path. It is
483 * implemented as a normal MSDOS file (not very space efficient :-()
485 * I see two different ways to do this: One is to place the link data
486 * in unused entries of the EMD file; the other is to have a separate
487 * file dedicated to hold all symbolic links data.
489 * Let's go for simplicity...
493 * AV. Should be called with dir->i_sem down.
495 static int umsdos_symlink_x (struct inode *dir, struct dentry *dentry,
496 const char *symname, int mode, char flags)
498 int ret, len;
499 struct file filp;
501 Printk(("umsdos_symlink: %s/%s to %s\n",
502 dentry->d_parent->d_name.name, dentry->d_name.name, symname));
504 ret = umsdos_create_any (dir, dentry, mode, 0, flags);
505 if (ret) {
506 printk(KERN_WARNING
507 "umsdos_symlink: create failed, ret=%d\n", ret);
508 goto out;
511 fill_new_filp (&filp, dentry);
512 len = strlen (symname);
513 ret = umsdos_file_write_kmem_real (&filp, symname, len);
514 if (ret < 0)
515 goto out_unlink;
516 if (ret != len)
517 goto out_error;
518 ret = 0;
519 out:
520 return ret;
522 out_error:
523 ret = -EIO;
524 out_unlink:
525 printk(KERN_WARNING "umsdos_symlink: write failed, unlinking\n");
526 UMSDOS_unlink (dir, dentry);
527 d_drop(dentry);
528 goto out;
532 * Setup a Symbolic link.
533 * Return a negative error code or 0 if OK.
535 int UMSDOS_symlink ( struct inode *dir, struct dentry *dentry,
536 const char *symname)
538 return umsdos_symlink_x (dir, dentry, symname, S_IFLNK | 0777, 0);
542 * Add a link to an inode in a directory
544 int UMSDOS_link (struct dentry *olddentry, struct inode *dir,
545 struct dentry *dentry)
547 struct inode *oldinode = olddentry->d_inode;
548 struct inode *olddir = olddentry->d_parent->d_inode;
549 struct dentry *temp;
550 char *path;
551 unsigned long buffer;
552 int ret;
553 struct umsdos_info old_info;
554 struct umsdos_info hid_info;
556 #ifdef UMSDOS_DEBUG_VERBOSE
557 printk("umsdos_link: new %s%s -> %s/%s\n",
558 dentry->d_parent->d_name.name, dentry->d_name.name,
559 olddentry->d_parent->d_name.name, olddentry->d_name.name);
560 #endif
562 ret = -EPERM;
563 if (S_ISDIR (oldinode->i_mode))
564 goto out;
566 ret = umsdos_nevercreat (dir, dentry, -EPERM);
567 if (ret)
568 goto out;
570 ret = -ENOMEM;
571 buffer = get_free_page(GFP_KERNEL);
572 if (!buffer)
573 goto out;
576 * Lock the link parent if it's not the same directory.
578 ret = -EDEADLOCK;
579 if (olddir != dir) {
580 if (atomic_read(&olddir->i_sem.count) < 1)
581 goto out_free;
582 down(&olddir->i_sem);
586 * Parse the name and get the visible directory entry.
588 ret = umsdos_parse (olddentry->d_name.name, olddentry->d_name.len,
589 &old_info);
590 if (ret)
591 goto out_unlock;
592 ret = umsdos_findentry (olddentry->d_parent, &old_info, 1);
593 if (ret) {
594 printk("UMSDOS_link: %s/%s not in EMD, ret=%d\n",
595 olddentry->d_parent->d_name.name, olddentry->d_name.name, ret);
596 goto out_unlock;
600 * If the visible dentry is a pseudo-hardlink, the original
601 * file must be already hidden.
603 if (!(old_info.entry.flags & UMSDOS_HLINK)) {
604 int err;
606 /* create a hidden link name */
607 ret = umsdos_newhidden (olddentry->d_parent, &hid_info);
608 if (ret) {
609 printk("umsdos_link: can't make hidden %s/%s, ret=%d\n",
610 olddentry->d_parent->d_name.name, hid_info.entry.name, ret);
611 goto out_unlock;
615 * Make a dentry and rename the original file ...
617 temp = umsdos_lookup_dentry(olddentry->d_parent,
618 hid_info.entry.name,
619 hid_info.entry.name_len, 0);
620 ret = PTR_ERR(temp);
621 if (IS_ERR(temp)) {
622 printk("umsdos_link: lookup %s/%s failed, ret=%d\n",
623 dentry->d_parent->d_name.name, hid_info.entry.name, ret);
624 goto cleanup;
626 /* rename the link to the hidden location ... */
627 ret = umsdos_rename_f(olddir, olddentry, olddir, temp,
628 UMSDOS_HIDDEN);
629 d_move(olddentry, temp);
630 dput(temp);
631 if (ret) {
632 printk("umsdos_link: rename to %s/%s failed, ret=%d\n",
633 temp->d_parent->d_name.name, temp->d_name.name, ret);
634 goto cleanup;
636 /* mark the inode as a hardlink */
637 oldinode->u.umsdos_i.i_is_hlink = 1;
640 * Capture the path to the hidden link.
642 path = umsdos_d_path(olddentry, (char *) buffer, PAGE_SIZE);
643 Printk(("umsdos_link: hidden link path=%s\n", path));
646 * Recreate a dentry for the original name and symlink it,
647 * then symlink the new dentry. Don't give up if one fails,
648 * or we'll lose the file completely!
650 * Note: this counts as the "original" reference, so we
651 * don't increment i_nlink for this one.
653 temp = umsdos_lookup_dentry(olddentry->d_parent,
654 old_info.entry.name,
655 old_info.entry.name_len, 0);
656 ret = PTR_ERR(temp);
657 if (!IS_ERR(temp)) {
658 ret = umsdos_symlink_x (olddir, temp, path,
659 S_IFREG | 0777, UMSDOS_HLINK);
660 dput(temp);
663 /* This symlink increments i_nlink (see below.) */
664 err = umsdos_symlink_x (dir, dentry, path,
665 S_IFREG | 0777, UMSDOS_HLINK);
666 /* fold the two errors */
667 if (!ret)
668 ret = err;
669 goto out_unlock;
671 /* creation failed ... remove the link entry */
672 cleanup:
673 printk("umsdos_link: link failed, ret=%d, removing %s/%s\n",
674 ret, olddentry->d_parent->d_name.name, hid_info.entry.name);
675 err = umsdos_delentry(olddentry->d_parent, &hid_info, 0);
676 goto out_unlock;
679 Printk(("UMSDOS_link: %s/%s already hidden\n",
680 olddentry->d_parent->d_name.name, olddentry->d_name.name));
682 * The original file is already hidden, and we need to get
683 * the dentry for its real name, not the visible name.
684 * N.B. make sure it's the hidden inode ...
686 if (!oldinode->u.umsdos_i.i_is_hlink)
687 printk("UMSDOS_link: %s/%s hidden, ino=%ld not hlink??\n",
688 olddentry->d_parent->d_name.name,
689 olddentry->d_name.name, oldinode->i_ino);
692 * In order to get the correct (real) inode, we just drop
693 * the original dentry.
695 d_drop(olddentry);
696 Printk(("UMSDOS_link: hard link %s/%s, fake=%s\n",
697 olddentry->d_parent->d_name.name, olddentry->d_name.name, old_info.fake.fname));
699 /* Do a real lookup to get the short name dentry */
700 temp = umsdos_covered(olddentry->d_parent, old_info.fake.fname,
701 old_info.fake.len);
702 ret = PTR_ERR(temp);
703 if (IS_ERR(temp))
704 goto out_unlock;
706 /* now resolve the link ... */
707 temp = umsdos_solve_hlink(temp);
708 ret = PTR_ERR(temp);
709 if (IS_ERR(temp))
710 goto out_unlock;
711 path = umsdos_d_path(temp, (char *) buffer, PAGE_SIZE);
712 dput(temp);
713 Printk(("umsdos_link: %s/%s already hidden, path=%s\n",
714 olddentry->d_parent->d_name.name, olddentry->d_name.name, path));
716 /* finally we can symlink it ... */
717 ret = umsdos_symlink_x (dir, dentry, path, S_IFREG | 0777,UMSDOS_HLINK);
719 out_unlock:
720 /* remain locked for the call to notify_change ... */
721 if (ret == 0) {
722 struct iattr newattrs;
724 #ifdef UMSDOS_PARANOIA
725 if (!oldinode->u.umsdos_i.i_is_hlink)
726 printk("UMSDOS_link: %s/%s, ino=%ld, not marked as hlink!\n",
727 olddentry->d_parent->d_name.name, olddentry->d_name.name, oldinode->i_ino);
728 #endif
729 oldinode->i_nlink++;
730 Printk(("UMSDOS_link: linked %s/%s, ino=%ld, nlink=%d\n",
731 olddentry->d_parent->d_name.name, olddentry->d_name.name,
732 oldinode->i_ino, oldinode->i_nlink));
733 newattrs.ia_valid = 0;
734 ret = umsdos_notify_change_locked(olddentry, &newattrs);
735 if (ret == 0)
736 mark_inode_dirty(olddentry->d_inode);
738 if (olddir != dir)
739 up(&olddir->i_sem);
741 out_free:
742 free_page(buffer);
743 out:
744 Printk (("umsdos_link %d\n", ret));
745 return ret;
750 * Add a sub-directory in a directory
752 /* #Specification: mkdir / Directory already exist in DOS
753 * We do the same thing as for file creation.
754 * For all user it is an error.
756 /* #Specification: mkdir / umsdos directory / create EMD
757 * When we created a new sub-directory in a UMSDOS
758 * directory (one with full UMSDOS semantics), we
759 * create immediately an EMD file in the new
760 * sub-directory so it inherits UMSDOS semantics.
762 int UMSDOS_mkdir (struct inode *dir, struct dentry *dentry, int mode)
764 struct dentry *temp;
765 struct inode *inode;
766 int ret, err;
767 struct umsdos_info info;
769 ret = umsdos_nevercreat (dir, dentry, -EEXIST);
770 if (ret)
771 goto out;
773 ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
774 if (ret)
775 goto out;
777 info.entry.mode = mode | S_IFDIR;
778 info.entry.rdev = 0;
779 info.entry.uid = current->fsuid;
780 info.entry.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
781 info.entry.ctime = info.entry.atime = info.entry.mtime = CURRENT_TIME;
782 info.entry.flags = 0;
783 info.entry.nlink = 1;
784 ret = umsdos_newentry (dentry->d_parent, &info);
785 if (ret)
786 goto out;
788 /* lookup the short name dentry */
789 temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
790 ret = PTR_ERR(temp);
791 if (IS_ERR(temp))
792 goto out_remove;
794 /* Make sure the short name doesn't exist */
795 ret = -EEXIST;
796 if (temp->d_inode) {
797 printk("umsdos_mkdir: short name %s/%s exists\n",
798 dentry->d_parent->d_name.name, info.fake.fname);
799 goto out_remove_dput;
802 ret = msdos_mkdir (dir, temp, mode);
803 if (ret)
804 goto out_remove_dput;
807 * Lock the inode to protect the EMD creation ...
809 inode = temp->d_inode;
810 down(&inode->i_sem);
812 atomic_inc(&inode->i_count);
813 d_instantiate(dentry, inode);
815 /* N.B. this should have an option to create the EMD ... */
816 umsdos_lookup_patch_new(dentry, &info);
819 * Create the EMD file, and set up the dir so it is
820 * promoted to EMD with the EMD file invisible.
822 * N.B. error return if EMD fails?
824 err = umsdos_make_emd(dentry);
825 umsdos_setup_dir(dentry);
827 up(&inode->i_sem);
828 dput(temp);
830 out:
831 Printk(("umsdos_mkdir: %s/%s, ret=%d\n",
832 dentry->d_parent->d_name.name, dentry->d_name.name, ret));
833 return ret;
835 /* an error occurred ... remove EMD entry. */
836 out_remove_dput:
837 dput(temp);
838 out_remove:
839 umsdos_delentry (dentry->d_parent, &info, 1);
840 goto out;
844 * Add a new device special file into a directory.
846 * #Specification: Special files / strategy
847 * Device special file, pipes, etc ... are created like normal
848 * file in the msdos file system. Of course they remain empty.
850 * One strategy was to create those files only in the EMD file
851 * since they were not important for MSDOS. The problem with
852 * that, is that there were not getting inode number allocated.
853 * The MSDOS filesystems is playing a nice game to fake inode
854 * number, so why not use it.
856 * The absence of inode number compatible with those allocated
857 * for ordinary files was causing major trouble with hard link
858 * in particular and other parts of the kernel I guess.
860 int UMSDOS_mknod (struct inode *dir, struct dentry *dentry,
861 int mode, int rdev)
863 return umsdos_create_any (dir, dentry, mode, rdev, 0);
867 * Remove a sub-directory.
869 int UMSDOS_rmdir (struct inode *dir, struct dentry *dentry)
871 struct dentry *temp;
872 int ret, err, empty;
873 struct umsdos_info info;
875 ret = umsdos_nevercreat (dir, dentry, -EPERM);
876 if (ret)
877 goto out;
879 ret = -EBUSY;
880 if (!d_unhashed(dentry))
881 goto out;
883 /* check whether the EMD is empty */
884 ret = -ENOTEMPTY;
885 empty = umsdos_isempty (dentry);
887 /* Have to remove the EMD file? */
888 if (empty == 1) {
889 struct dentry *demd;
891 demd = umsdos_get_emd_dentry(dentry);
892 if (!IS_ERR(demd)) {
893 err = -ENOENT;
894 if (demd->d_inode)
895 err = msdos_unlink (dentry->d_inode, demd);
896 Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err));
897 #ifdef UMSDOS_PARANOIA
898 if (err)
899 printk("umsdos_rmdir: EMD %s/%s unlink failed, err=%d\n",
900 demd->d_parent->d_name.name, demd->d_name.name, err);
901 #endif
902 if (!err) {
903 d_delete(demd);
904 ret = 0;
906 dput(demd);
908 } else if (empty == 2)
909 ret = 0;
910 if (ret)
911 goto out;
913 umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
914 /* Call findentry to complete the mangling */
915 umsdos_findentry (dentry->d_parent, &info, 2);
916 temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
917 ret = PTR_ERR(temp);
918 if (IS_ERR(temp))
919 goto out;
921 * Attempt to remove the msdos name.
923 ret = msdos_rmdir (dir, temp);
924 if (ret && ret != -ENOENT)
925 goto out_dput;
927 d_delete(temp);
928 /* OK so far ... remove the name from the EMD */
929 ret = umsdos_delentry (dentry->d_parent, &info, 1);
930 #ifdef UMSDOS_PARANOIA
931 if (ret)
932 printk("umsdos_rmdir: delentry %s failed, ret=%d\n", info.entry.name, ret);
933 #endif
935 /* dput() temp if we didn't do it above */
936 out_dput:
937 dput(temp);
939 out:
940 Printk (("umsdos_rmdir %d\n", ret));
941 return ret;
946 * Remove a file from the directory.
948 * #Specification: hard link / deleting a link
949 * When we delete a file and this file is a link,
950 * we must subtract 1 from the nlink field of the
951 * hidden link.
953 * If the count goes to 0, we delete this hidden
954 * link too.
956 int UMSDOS_unlink (struct inode *dir, struct dentry *dentry)
958 struct dentry *temp, *link = NULL;
959 struct inode *inode;
960 int ret;
961 struct umsdos_info info;
963 Printk(("UMSDOS_unlink: entering %s/%s\n",
964 dentry->d_parent->d_name.name, dentry->d_name.name));
966 ret = umsdos_nevercreat (dir, dentry, -EPERM);
967 if (ret)
968 goto out;
970 ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
971 if (ret)
972 goto out;
974 umsdos_lockcreate (dir);
975 ret = umsdos_findentry (dentry->d_parent, &info, 1);
976 if (ret) {
977 printk("UMSDOS_unlink: %s/%s not in EMD, ret=%d\n",
978 dentry->d_parent->d_name.name, dentry->d_name.name, ret);
979 goto out_unlock;
982 Printk (("UMSDOS_unlink %.*s ", info.fake.len, info.fake.fname));
985 * Note! If this is a hardlink and the names are aliased,
986 * the short-name lookup will return the hardlink dentry.
987 * In order to get the correct (real) inode, we just drop
988 * the original dentry.
990 if (info.entry.flags & UMSDOS_HLINK) {
991 d_drop(dentry);
994 /* Do a real lookup to get the short name dentry */
995 temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
996 ret = PTR_ERR(temp);
997 if (IS_ERR(temp))
998 goto out_unlock;
1001 * Resolve hardlinks now, but defer processing until later.
1003 if (info.entry.flags & UMSDOS_HLINK) {
1004 link = umsdos_solve_hlink(dget(temp));
1007 /* Delete the EMD entry */
1008 ret = umsdos_delentry (dentry->d_parent, &info, 0);
1009 if (ret && ret != -ENOENT) {
1010 printk(KERN_WARNING "UMSDOS_unlink: delentry %s, error=%d\n",
1011 info.entry.name, ret);
1012 goto out_dput;
1015 ret = msdos_unlink(dir, temp);
1016 if (!ret)
1017 d_delete(temp);
1018 #ifdef UMSDOS_PARANOIA
1019 if (ret)
1020 printk("umsdos_unlink: %s/%s unlink failed, ret=%d\n",
1021 temp->d_parent->d_name.name, temp->d_name.name, ret);
1022 #endif
1024 /* dput() temp if we didn't do it above */
1025 out_dput:
1026 dput(temp);
1028 out_unlock:
1029 umsdos_unlockcreate (dir);
1032 * Now check for deferred handling of a hardlink.
1034 if (!link)
1035 goto out;
1037 if (IS_ERR(link)) {
1038 printk("umsdos_unlink: failed to resolve %s/%s\n",
1039 dentry->d_parent->d_name.name, dentry->d_name.name);
1040 if (!ret)
1041 ret = PTR_ERR(link);
1042 goto out;
1045 Printk(("umsdos_unlink: link %s/%s deferred, pending ret=%d\n",
1046 link->d_parent->d_name.name, link->d_name.name, ret));
1048 /* already have an error? */
1049 if (ret)
1050 goto out_cleanup;
1052 /* make sure the link exists ... */
1053 inode = link->d_inode;
1054 if (!inode) {
1055 printk(KERN_WARNING "umsdos_unlink: hard link not found\n");
1056 goto out_cleanup;
1060 * If this was the last linked reference, delete it now.
1062 * N.B. Deadlock problem? We should be holding the lock
1063 * for the hardlink's parent, but another process might
1064 * be holding that lock waiting for us to finish ...
1066 if (inode->i_nlink <= 1) {
1067 ret = UMSDOS_unlink (link->d_parent->d_inode, link);
1068 if (ret) {
1069 printk(KERN_WARNING
1070 "umsdos_unlink: link removal failed, ret=%d\n",
1071 ret);
1072 } else
1073 d_delete(link);
1074 } else {
1075 struct iattr newattrs;
1076 inode->i_nlink--;
1077 newattrs.ia_valid = 0;
1078 ret = umsdos_notify_change_locked(link, &newattrs);
1079 if (!ret)
1080 mark_inode_dirty(link->d_inode);
1083 out_cleanup:
1084 d_drop(link);
1085 dput(link);
1087 out:
1088 Printk (("umsdos_unlink %d\n", ret));
1089 return ret;
1093 * Rename (move) a file.
1095 int UMSDOS_rename (struct inode *old_dir, struct dentry *old_dentry,
1096 struct inode *new_dir, struct dentry *new_dentry)
1098 int ret;
1100 ret = umsdos_nevercreat (new_dir, new_dentry, -EEXIST);
1101 if (ret)
1102 return ret;
1105 * If the target already exists, delete it first.
1107 if (new_dentry->d_inode) {
1108 dget(new_dentry);
1109 if (S_ISDIR(old_dentry->d_inode->i_mode))
1110 ret = UMSDOS_rmdir (new_dir, new_dentry);
1111 else
1112 ret = UMSDOS_unlink (new_dir, new_dentry);
1113 if (!ret)
1114 d_drop(new_dentry);
1115 dput(new_dentry);
1116 if (ret)
1117 return ret;
1119 ret = umsdos_rename_f(old_dir, old_dentry, new_dir, new_dentry, 0);
1120 return ret;