2 * linux/fs/umsdos/dir.c
4 * Written 1993 by Jacques Gelinas
5 * Inspired from linux/fs/msdos/... : Werner Almesberger
7 * Extended MS-DOS directory handling functions
10 #include <linux/sched.h>
11 #include <linux/string.h>
13 #include <linux/msdos_fs.h>
14 #include <linux/errno.h>
15 #include <linux/stat.h>
16 #include <linux/limits.h>
17 #include <linux/umsdos_fs.h>
18 #include <linux/malloc.h>
20 #include <asm/uaccess.h>
22 #define UMSDOS_SPECIAL_DIRFPOS 3
23 extern struct dentry
*saved_root
;
24 extern struct inode
*pseudo_root
;
26 /* #define UMSDOS_DEBUG_VERBOSE 1 */
29 * Dentry operations routines
32 /* nothing for now ... */
33 static int umsdos_dentry_validate(struct dentry
*dentry
, int flags
)
38 /* for now, drop everything to force lookups ... */
39 static void umsdos_dentry_dput(struct dentry
*dentry
)
41 struct inode
*inode
= dentry
->d_inode
;
47 struct dentry_operations umsdos_dentry_operations
=
49 umsdos_dentry_validate
, /* d_revalidate(struct dentry *, int) */
52 umsdos_dentry_dput
, /* d_delete(struct dentry *) */
59 * So grep * doesn't complain in the presence of directories.
62 int dummy_dir_read (struct file
*filp
, char *buff
, size_t size
, loff_t
*count
)
68 struct UMSDOS_DIR_ONCE
{
76 * Record a single entry the first call.
77 * Return -EINVAL the next one.
78 * NOTE: filldir DOES NOT use a dentry
81 static int umsdos_dir_once ( void *buf
,
88 struct UMSDOS_DIR_ONCE
*d
= (struct UMSDOS_DIR_ONCE
*) buf
;
91 PRINTK ((KERN_DEBUG
"dir_once :%.*s: offset %Ld\n",
93 ret
= d
->filldir (d
->dirbuf
, name
, len
, offset
, ino
);
102 * Read count directory entries from directory filp
103 * Return a negative value from linux/errno.h.
104 * Return > 0 if success (the number of bytes written by filldir).
106 * This function is used by the normal readdir VFS entry point,
107 * and in order to get the directory entry from a file's dentry.
108 * See umsdos_dentry_to_entry() below.
111 static int umsdos_readdir_x (struct inode
*dir
, struct file
*filp
,
112 void *dirbuf
, int internal_read
,
113 struct umsdos_dirent
*u_entry
,
114 int follow_hlink
, filldir_t filldir
)
119 struct file new_filp
;
121 umsdos_startlookup (dir
);
123 if (filp
->f_pos
== UMSDOS_SPECIAL_DIRFPOS
&&
124 dir
== pseudo_root
&& !internal_read
) {
127 * We don't need to simulate this pseudo directory
128 * when umsdos_readdir_x is called for internal operation
129 * of umsdos. This is why dirent_in_fs is tested
131 /* #Specification: pseudo root / directory /DOS
132 * When umsdos operates in pseudo root mode (C:\linux is the
133 * linux root), it simulate a directory /DOS which points to
134 * the real root of the file system.
137 Printk ((KERN_WARNING
"umsdos_readdir_x: pseudo_root thing UMSDOS_SPECIAL_DIRFPOS\n"));
138 if (filldir (dirbuf
, "DOS", 3,
139 UMSDOS_SPECIAL_DIRFPOS
, UMSDOS_ROOT_INO
) == 0) {
145 if (filp
->f_pos
< 2 ||
146 (dir
->i_ino
!= UMSDOS_ROOT_INO
&& filp
->f_pos
== 32)) {
148 int last_f_pos
= filp
->f_pos
;
149 struct UMSDOS_DIR_ONCE bufk
;
151 Printk (("umsdos_readdir_x: . or .. /mn/?\n"));
153 bufk
.dirbuf
= dirbuf
;
154 bufk
.filldir
= filldir
;
157 ret
= fat_readdir (filp
, &bufk
, umsdos_dir_once
);
158 if (last_f_pos
> 0 && filp
->f_pos
> last_f_pos
)
159 filp
->f_pos
= UMSDOS_SPECIAL_DIRFPOS
;
165 Printk (("umsdos_readdir_x: normal file /mn/?\n"));
167 /* get the EMD dentry */
168 demd
= umsdos_get_emd_dentry(filp
->f_dentry
);
173 if (!demd
->d_inode
) {
175 "umsdos_readir_x: EMD file %s/%s not found\n",
176 demd
->d_parent
->d_name
.name
, demd
->d_name
.name
);
180 /* set up our private filp ... */
181 fill_new_filp(&new_filp
, demd
);
182 new_filp
.f_pos
= filp
->f_pos
;
183 start_fpos
= filp
->f_pos
;
185 if (new_filp
.f_pos
<= UMSDOS_SPECIAL_DIRFPOS
+ 1)
187 Printk (("f_pos %Ld i_size %ld\n", new_filp
.f_pos
, demd
->d_inode
->i_size
));
189 while (new_filp
.f_pos
< demd
->d_inode
->i_size
) {
190 off_t cur_f_pos
= new_filp
.f_pos
;
193 struct umsdos_dirent entry
;
194 struct umsdos_info info
;
197 if (umsdos_emd_dir_readentry (&new_filp
, &entry
) != 0)
199 if (entry
.name_len
== 0)
201 #ifdef UMSDOS_DEBUG_VERBOSE
202 if (entry
.flags
& UMSDOS_HLINK
)
203 printk("umsdos_readdir_x: %s/%s is hardlink\n",
204 filp
->f_dentry
->d_name
.name
, entry
.name
);
207 umsdos_parse (entry
.name
, entry
.name_len
, &info
);
208 info
.f_pos
= cur_f_pos
;
209 umsdos_manglename (&info
);
211 * Do a real lookup on the short name.
213 dret
= umsdos_covered(filp
->f_dentry
, info
.fake
.fname
,
219 * If the file wasn't found, remove it from the EMD.
221 inode
= dret
->d_inode
;
224 #ifdef UMSDOS_DEBUG_VERBOSE
225 if (inode
->u
.umsdos_i
.i_is_hlink
)
226 printk("umsdos_readdir_x: %s/%s already resolved, ino=%ld\n",
227 dret
->d_parent
->d_name
.name
, dret
->d_name
.name
, inode
->i_ino
);
230 Printk (("Found %s/%s, ino=%ld, flags=%x\n",
231 dret
->d_parent
->d_name
.name
, info
.fake
.fname
, dret
->d_inode
->i_ino
,
233 /* check whether to resolve a hard-link */
234 if ((entry
.flags
& UMSDOS_HLINK
) && follow_hlink
&&
235 !inode
->u
.umsdos_i
.i_is_hlink
) {
236 dret
= umsdos_solve_hlink (dret
);
240 inode
= dret
->d_inode
;
242 printk("umsdos_readdir_x: %s/%s negative after link\n",
243 dret
->d_parent
->d_name
.name
, dret
->d_name
.name
);
248 /* #Specification: pseudo root / reading real root
249 * The pseudo root (/linux) is logically
250 * erased from the real root. This means that
251 * ls /DOS, won't show "linux". This avoids
252 * infinite recursion (/DOS/linux/DOS/linux/...) while
253 * walking the file system.
255 if (inode
!= pseudo_root
&&
256 (internal_read
|| !(entry
.flags
& UMSDOS_HIDDEN
))) {
257 if (filldir (dirbuf
, entry
.name
, entry
.name_len
,
258 cur_f_pos
, inode
->i_ino
) < 0) {
259 new_filp
.f_pos
= cur_f_pos
;
261 Printk(("umsdos_readdir_x: got %s/%s, ino=%ld\n",
262 dret
->d_parent
->d_name
.name
, dret
->d_name
.name
, inode
->i_ino
));
274 /* #Specification: umsdos / readdir / not in MSDOS
275 * During a readdir operation, if the file is not
276 * in the MS-DOS directory any more, the entry is
277 * removed from the EMD file silently.
279 #ifdef UMSDOS_PARANOIA
280 printk("umsdos_readdir_x: %s/%s out of sync, erasing\n",
281 filp
->f_dentry
->d_name
.name
, info
.entry
.name
);
283 ret
= umsdos_delentry(filp
->f_dentry
, &info
,
284 S_ISDIR(info
.entry
.mode
));
287 "umsdos_readdir_x: delentry %s, err=%d\n",
288 info
.entry
.name
, ret
);
292 * If the fillbuf has failed, f_pos is back to 0.
293 * To avoid getting back into the . and .. state
294 * (see comments at the beginning), we put back
295 * the special offset.
297 filp
->f_pos
= new_filp
.f_pos
;
298 if (filp
->f_pos
== 0)
299 filp
->f_pos
= start_fpos
;
304 umsdos_endlookup (dir
);
306 Printk ((KERN_DEBUG
"read dir %p pos %Ld ret %d\n",
307 dir
, filp
->f_pos
, ret
));
313 * Read count directory entries from directory filp.
314 * Return a negative value from linux/errno.h.
315 * Return 0 or positive if successful.
318 static int UMSDOS_readdir (struct file
*filp
, void *dirbuf
, filldir_t filldir
)
320 struct inode
*dir
= filp
->f_dentry
->d_inode
;
321 int ret
= 0, count
= 0;
322 struct UMSDOS_DIR_ONCE bufk
;
324 bufk
.dirbuf
= dirbuf
;
325 bufk
.filldir
= filldir
;
328 Printk (("UMSDOS_readdir in\n"));
329 while (ret
== 0 && bufk
.stop
== 0) {
330 struct umsdos_dirent entry
;
333 ret
= umsdos_readdir_x (dir
, filp
, &bufk
, 0, &entry
, 1,
339 Printk (("UMSDOS_readdir out %d count %d pos %Ld\n",
340 ret
, count
, filp
->f_pos
));
341 return count
? : ret
;
346 * Complete the inode content with info from the EMD file.
348 * This function modifies the state of a dir inode. It decides
349 * whether the dir is a UMSDOS or DOS directory. This is done
350 * deeper in umsdos_patch_inode() called at the end of this function.
352 * Because it is does disk access, umsdos_patch_inode() may block.
353 * At the same time, another process may get here to initialise
354 * the same directory inode. There are three cases.
356 * 1) The inode is already initialised. We do nothing.
357 * 2) The inode is not initialised. We lock access and do it.
358 * 3) Like 2 but another process has locked the inode, so we try
359 * to lock it and check right afterward check whether
360 * initialisation is still needed.
363 * Thanks to the "mem" option of the kernel command line, it was
364 * possible to consistently reproduce this problem by limiting
365 * my memory to 4 MB and running X.
367 * Do this only if the inode is freshly read, because we will lose
368 * the current (updated) content.
370 * A lookup of a mount point directory yield the inode into
371 * the other fs, so we don't care about initialising it. iget()
372 * does this automatically.
375 void umsdos_lookup_patch_new(struct dentry
*dentry
, struct umsdos_info
*info
)
377 struct inode
*inode
= dentry
->d_inode
;
378 struct umsdos_dirent
*entry
= &info
->entry
;
381 * This part of the initialization depends only on i_patched.
383 if (inode
->u
.umsdos_i
.i_patched
)
385 inode
->u
.umsdos_i
.i_patched
= 1;
386 if (S_ISREG (entry
->mode
))
387 entry
->mtime
= inode
->i_mtime
;
388 inode
->i_mode
= entry
->mode
;
389 inode
->i_rdev
= to_kdev_t (entry
->rdev
);
390 inode
->i_atime
= entry
->atime
;
391 inode
->i_ctime
= entry
->ctime
;
392 inode
->i_mtime
= entry
->mtime
;
393 inode
->i_uid
= entry
->uid
;
394 inode
->i_gid
= entry
->gid
;
396 /* #Specification: umsdos / i_nlink
397 * The nlink field of an inode is maintained by the MSDOS file system
398 * for directory and by UMSDOS for other files. The logic is that
399 * MSDOS is already figuring out what to do for directories and
400 * does nothing for other files. For MSDOS, there are no hard links
401 * so all file carry nlink==1. UMSDOS use some info in the
402 * EMD file to plug the correct value.
404 if (!S_ISDIR (entry
->mode
)) {
405 if (entry
->nlink
> 0) {
406 inode
->i_nlink
= entry
->nlink
;
409 "UMSDOS: lookup_patch entry->nlink < 1 ???\n");
413 * The mode may have changed, so patch the inode again.
415 umsdos_patch_dentry_inode(dentry
, info
->f_pos
);
416 umsdos_set_dirinfo_new(dentry
, info
->f_pos
);
424 * Return != 0 if an entry is the pseudo DOS entry in the pseudo root.
427 int umsdos_is_pseudodos (struct inode
*dir
, struct dentry
*dentry
)
429 /* #Specification: pseudo root / DOS hard coded
430 * The pseudo sub-directory DOS in the pseudo root is hard coded.
431 * The name is DOS. This is done this way to help standardised
432 * the umsdos layout. The idea is that from now on /DOS is
433 * a reserved path and nobody will think of using such a path
436 return dir
== pseudo_root
437 && dentry
->d_name
.len
== 3
438 && dentry
->d_name
.name
[0] == 'D'
439 && dentry
->d_name
.name
[1] == 'O'
440 && dentry
->d_name
.name
[2] == 'S';
445 * Check whether a file exists in the current directory.
446 * Return 0 if OK, negative error code if not (ex: -ENOENT).
448 * fills dentry->d_inode with found inode, and increments its count.
449 * if not found, return -ENOENT.
451 /* #Specification: umsdos / lookup
452 * A lookup for a file is done in two steps. First, we
453 * locate the file in the EMD file. If not present, we
454 * return an error code (-ENOENT). If it is there, we
455 * repeat the operation on the msdos file system. If
456 * this fails, it means that the file system is not in
457 * sync with the EMD file. We silently remove this
458 * entry from the EMD file, and return ENOENT.
461 struct dentry
*umsdos_lookup_x (struct inode
*dir
, struct dentry
*dentry
, int nopseudo
)
463 struct dentry
*dret
= NULL
;
466 struct umsdos_info info
;
468 #ifdef UMSDOS_DEBUG_VERBOSE
469 printk("umsdos_lookup_x: looking for %s/%s\n",
470 dentry
->d_parent
->d_name
.name
, dentry
->d_name
.name
);
473 umsdos_startlookup (dir
);
474 if (umsdos_is_pseudodos (dir
, dentry
)) {
475 /* #Specification: pseudo root / lookup(DOS)
476 * A lookup of DOS in the pseudo root will always succeed
477 * and return the inode of the real root.
479 Printk ((KERN_DEBUG
"umsdos_lookup_x: following /DOS\n"));
480 inode
= saved_root
->d_inode
;
484 ret
= umsdos_parse (dentry
->d_name
.name
, dentry
->d_name
.len
, &info
);
486 printk("umsdos_lookup_x: %s/%s parse failed, ret=%d\n",
487 dentry
->d_parent
->d_name
.name
, dentry
->d_name
.name
, ret
);
491 ret
= umsdos_findentry (dentry
->d_parent
, &info
, 0);
494 printk("umsdos_lookup_x: %s/%s findentry failed, ret=%d\n",
495 dentry
->d_parent
->d_name
.name
, dentry
->d_name
.name
, ret
);
498 Printk (("lookup %.*s pos %lu ret %d len %d ",
499 info
.fake
.len
, info
.fake
.fname
, info
.f_pos
, ret
, info
.fake
.len
));
501 /* do a real lookup to get the short name ... */
502 dret
= umsdos_covered(dentry
->d_parent
, info
.fake
.fname
, info
.fake
.len
);
505 printk("umsdos_lookup_x: %s/%s real lookup failed, ret=%d\n",
506 dentry
->d_parent
->d_name
.name
, dentry
->d_name
.name
, ret
);
509 inode
= dret
->d_inode
;
512 umsdos_lookup_patch_new(dret
, &info
);
513 #ifdef UMSDOS_DEBUG_VERBOSE
514 printk("umsdos_lookup_x: found %s/%s, ino=%ld\n",
515 dret
->d_parent
->d_name
.name
, dret
->d_name
.name
, dret
->d_inode
->i_ino
);
518 /* Check for a hard link */
519 if ((info
.entry
.flags
& UMSDOS_HLINK
) &&
520 !inode
->u
.umsdos_i
.i_is_hlink
) {
521 dret
= umsdos_solve_hlink (dret
);
526 inode
= dret
->d_inode
;
528 printk("umsdos_lookup_x: %s/%s negative after link\n",
529 dret
->d_parent
->d_name
.name
, dret
->d_name
.name
);
534 if (inode
== pseudo_root
&& !nopseudo
) {
535 /* #Specification: pseudo root / dir lookup
536 * For the same reason as readdir, a lookup in /DOS for
537 * the pseudo root directory (linux) will fail.
540 * This has to be allowed for resolving hard links
541 * which are recorded independently of the pseudo-root
544 printk("umsdos_lookup_x: skipping DOS/linux\n");
550 * We've found it OK. Now hash the dentry with the inode.
554 d_add (dentry
, inode
);
555 dentry
->d_op
= &umsdos_dentry_operations
;
559 if (dret
&& dret
!= dentry
)
563 umsdos_endlookup (dir
);
567 printk(KERN_WARNING
"UMSDOS: entry %s/%s out of sync, erased\n",
568 dentry
->d_parent
->d_name
.name
, dentry
->d_name
.name
);
569 umsdos_delentry (dentry
->d_parent
, &info
, S_ISDIR (info
.entry
.mode
));
576 * Check whether a file exists in the current directory.
577 * Return 0 if OK, negative error code if not (ex: -ENOENT).
579 * Called by VFS; should fill dentry->d_inode via d_add.
582 struct dentry
*UMSDOS_lookup (struct inode
*dir
, struct dentry
*dentry
)
586 ret
= umsdos_lookup_x (dir
, dentry
, 0);
588 /* Create negative dentry if not found. */
589 if (ret
== ERR_PTR(-ENOENT
)) {
591 "UMSDOS_lookup: converting -ENOENT to negative\n"));
592 d_add (dentry
, NULL
);
593 dentry
->d_op
= &umsdos_dentry_operations
;
599 struct dentry
*umsdos_covered(struct dentry
*parent
, char *name
, int len
)
601 struct dentry
*result
, *dentry
;
606 qstr
.hash
= full_name_hash(name
, len
);
607 result
= ERR_PTR(-ENOMEM
);
608 dentry
= d_alloc(parent
, &qstr
);
610 /* XXXXXXXXXXXXXXXXXXX Race alert! */
611 result
= UMSDOS_rlookup(parent
->d_inode
, dentry
);
626 * Lookup or create a dentry from within the filesystem.
628 * We need to use this instead of lookup_dentry, as the
629 * directory semaphore lock is already held.
631 struct dentry
*umsdos_lookup_dentry(struct dentry
*parent
, char *name
, int len
,
634 struct dentry
*result
, *dentry
;
639 qstr
.hash
= full_name_hash(name
, len
);
640 result
= d_lookup(parent
, &qstr
);
642 result
= ERR_PTR(-ENOMEM
);
643 dentry
= d_alloc(parent
, &qstr
);
646 UMSDOS_rlookup(parent
->d_inode
, dentry
) :
647 UMSDOS_lookup(parent
->d_inode
, dentry
);
662 * Return a path relative to our root.
664 char * umsdos_d_path(struct dentry
*dentry
, char * buffer
, int len
)
666 struct dentry
* old_root
= current
->fs
->root
;
669 /* N.B. not safe -- fix this soon! */
670 current
->fs
->root
= dentry
->d_sb
->s_root
;
671 path
= d_path(dentry
, buffer
, len
);
674 path
++; /* skip leading '/' */
676 if (old_root
->d_inode
== pseudo_root
)
679 path
-= (UMSDOS_PSDROOT_LEN
+1);
680 memcpy(path
, UMSDOS_PSDROOT_NAME
, UMSDOS_PSDROOT_LEN
);
683 current
->fs
->root
= old_root
;
688 * Return the dentry which points to a pseudo-hardlink.
690 * it should try to find file it points to
691 * if file is found, return new dentry/inode
692 * The resolved inode will have i_is_hlink set.
694 * Note: the original dentry is always dput(), even if an error occurs.
697 struct dentry
*umsdos_solve_hlink (struct dentry
*hlink
)
699 /* root is our root for resolving pseudo-hardlink */
700 struct dentry
*base
= hlink
->d_sb
->s_root
;
701 struct dentry
*dentry_dst
;
706 #ifdef UMSDOS_DEBUG_VERBOSE
707 printk("umsdos_solve_hlink: following %s/%s\n",
708 hlink
->d_parent
->d_name
.name
, hlink
->d_name
.name
);
711 dentry_dst
= ERR_PTR (-ENOMEM
);
712 path
= (char *) kmalloc (PATH_MAX
, GFP_KERNEL
);
716 fill_new_filp (&filp
, hlink
);
717 filp
.f_flags
= O_RDONLY
;
719 len
= umsdos_file_read_kmem (&filp
, path
, hlink
->d_inode
->i_size
);
720 if (len
!= hlink
->d_inode
->i_size
)
722 #ifdef UMSDOS_DEBUG_VERBOSE
723 printk ("umsdos_solve_hlink: %s/%s is path %s\n",
724 hlink
->d_parent
->d_name
.name
, hlink
->d_name
.name
, path
);
727 /* start at root dentry */
728 dentry_dst
= dget(base
);
733 pt
++; /* skip leading '/' */
735 if (base
->d_inode
== pseudo_root
)
736 pt
+= (UMSDOS_PSDROOT_LEN
+ 1);
739 struct dentry
*dir
= dentry_dst
, *demd
;
743 while (*pt
!= '\0' && *pt
!= '/') pt
++;
744 len
= (int) (pt
- start
);
745 if (*pt
== '/') *pt
++ = '\0';
748 demd
= umsdos_get_emd_dentry(dir
);
755 #ifdef UMSDOS_DEBUG_VERBOSE
756 printk ("umsdos_solve_hlink: dir %s/%s, name=%s, real=%d\n",
757 dir
->d_parent
->d_name
.name
, dir
->d_name
.name
, start
, real
);
759 dentry_dst
= umsdos_lookup_dentry(dir
, start
, len
, real
);
760 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
764 if (IS_ERR(dentry_dst
))
766 /* not found? stop search ... */
767 if (!dentry_dst
->d_inode
) {
770 if (*pt
== '\0') /* we're finished! */
774 if (!IS_ERR(dentry_dst
)) {
775 struct inode
*inode
= dentry_dst
->d_inode
;
777 inode
->u
.umsdos_i
.i_is_hlink
= 1;
778 #ifdef UMSDOS_DEBUG_VERBOSE
779 printk ("umsdos_solve_hlink: resolved link %s/%s, ino=%ld\n",
780 dentry_dst
->d_parent
->d_name
.name
, dentry_dst
->d_name
.name
, inode
->i_ino
);
783 #ifdef UMSDOS_DEBUG_VERBOSE
784 printk ("umsdos_solve_hlink: resolved link %s/%s negative!\n",
785 dentry_dst
->d_parent
->d_name
.name
, dentry_dst
->d_name
.name
);
790 "umsdos_solve_hlink: err=%ld\n", PTR_ERR(dentry_dst
));
796 dput(hlink
); /* original hlink no longer needed */
800 printk(KERN_WARNING
"umsdos_solve_hlink: failed reading pseudolink!\n");
805 static struct file_operations umsdos_dir_operations
=
807 NULL
, /* lseek - default */
808 dummy_dir_read
, /* read */
809 NULL
, /* write - bad */
810 UMSDOS_readdir
, /* readdir */
811 NULL
, /* poll - default */
812 UMSDOS_ioctl_dir
, /* ioctl - default */
814 NULL
, /* no special open code */
816 NULL
, /* no special release code */
820 struct inode_operations umsdos_dir_inode_operations
=
822 &umsdos_dir_operations
, /* default directory file-ops */
823 UMSDOS_create
, /* create */
824 UMSDOS_lookup
, /* lookup */
825 UMSDOS_link
, /* link */
826 UMSDOS_unlink
, /* unlink */
827 UMSDOS_symlink
, /* symlink */
828 UMSDOS_mkdir
, /* mkdir */
829 UMSDOS_rmdir
, /* rmdir */
830 UMSDOS_mknod
, /* mknod */
831 UMSDOS_rename
, /* rename */
833 NULL
, /* followlink */
834 NULL
, /* get_block */
836 NULL
, /* writepage */
837 NULL
, /* flushpage */
839 NULL
, /* permission */
841 NULL
, /* revalidate */