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/time.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/slab.h>
19 #include <linux/pagemap.h>
20 #include <linux/smp_lock.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
, struct nameidata
*nd
)
38 /* for now, drop everything to force lookups ... */
39 /* ITYM s/everything/& positive/... */
40 static int umsdos_dentry_dput(struct dentry
*dentry
)
42 struct inode
*inode
= dentry
->d_inode
;
49 struct dentry_operations umsdos_dentry_operations
=
51 .d_revalidate
= umsdos_dentry_validate
,
52 .d_delete
= umsdos_dentry_dput
,
55 struct UMSDOS_DIR_ONCE
{
63 * Record a single entry the first call.
64 * Return -EINVAL the next one.
65 * NOTE: filldir DOES NOT use a dentry
68 static int umsdos_dir_once ( void *buf
,
76 struct UMSDOS_DIR_ONCE
*d
= (struct UMSDOS_DIR_ONCE
*) buf
;
79 PRINTK ((KERN_DEBUG
"dir_once :%.*s: offset %Ld\n",
81 ret
= d
->filldir (d
->dirbuf
, name
, len
, offset
, ino
, DT_UNKNOWN
);
90 * Read count directory entries from directory filp
91 * Return a negative value from linux/errno.h.
92 * Return > 0 if success (the number of bytes written by filldir).
94 * This function is used by the normal readdir VFS entry point,
95 * and in order to get the directory entry from a file's dentry.
96 * See umsdos_dentry_to_entry() below.
99 static int umsdos_readdir_x (struct inode
*dir
, struct file
*filp
,
100 void *dirbuf
, struct umsdos_dirent
*u_entry
,
108 umsdos_startlookup (dir
);
110 if (filp
->f_pos
== UMSDOS_SPECIAL_DIRFPOS
&& dir
== pseudo_root
) {
113 * We don't need to simulate this pseudo directory
114 * when umsdos_readdir_x is called for internal operation
115 * of umsdos. This is why dirent_in_fs is tested
117 /* #Specification: pseudo root / directory /DOS
118 * When umsdos operates in pseudo root mode (C:\linux is the
119 * linux root), it simulate a directory /DOS which points to
120 * the real root of the file system.
123 Printk ((KERN_WARNING
"umsdos_readdir_x: pseudo_root thing UMSDOS_SPECIAL_DIRFPOS\n"));
124 if (filldir (dirbuf
, "DOS", 3,
125 UMSDOS_SPECIAL_DIRFPOS
, UMSDOS_ROOT_INO
, DT_DIR
) == 0) {
131 if (filp
->f_pos
< 2 ||
132 (dir
->i_ino
!= UMSDOS_ROOT_INO
&& filp
->f_pos
== 32)) {
134 int last_f_pos
= filp
->f_pos
;
135 struct UMSDOS_DIR_ONCE bufk
;
137 Printk (("umsdos_readdir_x: . or .. /mn/?\n"));
139 bufk
.dirbuf
= dirbuf
;
140 bufk
.filldir
= filldir
;
143 ret
= fat_readdir (filp
, &bufk
, umsdos_dir_once
);
144 if (last_f_pos
> 0 && filp
->f_pos
> last_f_pos
)
145 filp
->f_pos
= UMSDOS_SPECIAL_DIRFPOS
;
151 Printk (("umsdos_readdir_x: normal file /mn/?\n"));
153 /* get the EMD dentry */
154 demd
= umsdos_get_emd_dentry(filp
->f_dentry
);
159 if (!demd
->d_inode
) {
161 "umsdos_readir_x: EMD file %s/%s not found\n",
162 demd
->d_parent
->d_name
.name
, demd
->d_name
.name
);
167 start_fpos
= filp
->f_pos
;
169 if (pos
<= UMSDOS_SPECIAL_DIRFPOS
+ 1)
172 while (pos
< demd
->d_inode
->i_size
) {
173 off_t cur_f_pos
= pos
;
176 struct umsdos_dirent entry
;
177 struct umsdos_info info
;
180 if (umsdos_emd_dir_readentry (demd
, &pos
, &entry
) != 0)
182 if (entry
.name_len
== 0)
184 #ifdef UMSDOS_DEBUG_VERBOSE
185 if (entry
.flags
& UMSDOS_HLINK
)
186 printk("umsdos_readdir_x: %s/%s is hardlink\n",
187 filp
->f_dentry
->d_name
.name
, entry
.name
);
190 umsdos_parse (entry
.name
, entry
.name_len
, &info
);
191 info
.f_pos
= cur_f_pos
;
192 umsdos_manglename (&info
);
194 * Do a real lookup on the short name.
196 dret
= umsdos_covered(filp
->f_dentry
, info
.fake
.fname
,
202 * If the file wasn't found, remove it from the EMD.
204 inode
= dret
->d_inode
;
207 #ifdef UMSDOS_DEBUG_VERBOSE
208 if (UMSDOS_I(inode
)->i_is_hlink
)
209 printk("umsdos_readdir_x: %s/%s already resolved, ino=%ld\n",
210 dret
->d_parent
->d_name
.name
, dret
->d_name
.name
, inode
->i_ino
);
213 Printk (("Found %s/%s, ino=%ld, flags=%x\n",
214 dret
->d_parent
->d_name
.name
, info
.fake
.fname
, dret
->d_inode
->i_ino
,
216 /* check whether to resolve a hard-link */
217 if ((entry
.flags
& UMSDOS_HLINK
) &&
218 !UMSDOS_I(inode
)->i_is_hlink
) {
219 dret
= umsdos_solve_hlink (dret
);
223 inode
= dret
->d_inode
;
225 printk("umsdos_readdir_x: %s/%s negative after link\n",
226 dret
->d_parent
->d_name
.name
, dret
->d_name
.name
);
231 /* #Specification: pseudo root / reading real root
232 * The pseudo root (/linux) is logically
233 * erased from the real root. This means that
234 * ls /DOS, won't show "linux". This avoids
235 * infinite recursion (/DOS/linux/DOS/linux/...) while
236 * walking the file system.
238 if (inode
!= pseudo_root
&& !(entry
.flags
& UMSDOS_HIDDEN
)) {
239 if (filldir (dirbuf
, entry
.name
, entry
.name_len
,
240 cur_f_pos
, inode
->i_ino
, DT_UNKNOWN
) < 0) {
243 Printk(("umsdos_readdir_x: got %s/%s, ino=%ld\n",
244 dret
->d_parent
->d_name
.name
, dret
->d_name
.name
, inode
->i_ino
));
256 /* #Specification: umsdos / readdir / not in MSDOS
257 * During a readdir operation, if the file is not
258 * in the MS-DOS directory any more, the entry is
259 * removed from the EMD file silently.
261 #ifdef UMSDOS_PARANOIA
262 printk("umsdos_readdir_x: %s/%s out of sync, erasing\n",
263 filp
->f_dentry
->d_name
.name
, info
.entry
.name
);
265 ret
= umsdos_delentry(filp
->f_dentry
, &info
,
266 S_ISDIR(info
.entry
.mode
));
269 "umsdos_readdir_x: delentry %s, err=%d\n",
270 info
.entry
.name
, ret
);
274 * If the fillbuf has failed, f_pos is back to 0.
275 * To avoid getting back into the . and .. state
276 * (see comments at the beginning), we put back
277 * the special offset.
280 if (filp
->f_pos
== 0)
281 filp
->f_pos
= start_fpos
;
286 umsdos_endlookup (dir
);
288 Printk ((KERN_DEBUG
"read dir %p pos %Ld ret %d\n",
289 dir
, filp
->f_pos
, ret
));
295 * Read count directory entries from directory filp.
296 * Return a negative value from linux/errno.h.
297 * Return 0 or positive if successful.
300 static int UMSDOS_readdir (struct file
*filp
, void *dirbuf
, filldir_t filldir
)
302 struct inode
*dir
= filp
->f_dentry
->d_inode
;
303 int ret
= 0, count
= 0;
304 struct UMSDOS_DIR_ONCE bufk
;
308 bufk
.dirbuf
= dirbuf
;
309 bufk
.filldir
= filldir
;
312 Printk (("UMSDOS_readdir in\n"));
313 while (ret
== 0 && bufk
.stop
== 0) {
314 struct umsdos_dirent entry
;
317 ret
= umsdos_readdir_x (dir
, filp
, &bufk
, &entry
,
324 Printk (("UMSDOS_readdir out %d count %d pos %Ld\n",
325 ret
, count
, filp
->f_pos
));
326 return count
? : ret
;
331 * Complete the inode content with info from the EMD file.
333 * This function modifies the state of a dir inode. It decides
334 * whether the dir is a UMSDOS or DOS directory. This is done
335 * deeper in umsdos_patch_inode() called at the end of this function.
337 * Because it is does disk access, umsdos_patch_inode() may block.
338 * At the same time, another process may get here to initialise
339 * the same directory inode. There are three cases.
341 * 1) The inode is already initialised. We do nothing.
342 * 2) The inode is not initialised. We lock access and do it.
343 * 3) Like 2 but another process has locked the inode, so we try
344 * to lock it and check right afterward check whether
345 * initialisation is still needed.
348 * Thanks to the "mem" option of the kernel command line, it was
349 * possible to consistently reproduce this problem by limiting
350 * my memory to 4 MB and running X.
352 * Do this only if the inode is freshly read, because we will lose
353 * the current (updated) content.
355 * A lookup of a mount point directory yield the inode into
356 * the other fs, so we don't care about initialising it. iget()
357 * does this automatically.
360 void umsdos_lookup_patch_new(struct dentry
*dentry
, struct umsdos_info
*info
)
362 struct inode
*inode
= dentry
->d_inode
;
363 struct umsdos_dirent
*entry
= &info
->entry
;
366 * This part of the initialization depends only on i_patched.
368 if (UMSDOS_I(inode
)->i_patched
)
370 UMSDOS_I(inode
)->i_patched
= 1;
371 if (S_ISREG (entry
->mode
))
372 entry
->mtime
= inode
->i_mtime
;
373 inode
->i_mode
= entry
->mode
;
374 inode
->i_rdev
= to_kdev_t (entry
->rdev
);
375 inode
->i_atime
= entry
->atime
;
376 inode
->i_ctime
= entry
->ctime
;
377 inode
->i_mtime
= entry
->mtime
;
378 inode
->i_uid
= entry
->uid
;
379 inode
->i_gid
= entry
->gid
;
381 /* #Specification: umsdos / i_nlink
382 * The nlink field of an inode is maintained by the MSDOS file system
383 * for directory and by UMSDOS for other files. The logic is that
384 * MSDOS is already figuring out what to do for directories and
385 * does nothing for other files. For MSDOS, there are no hard links
386 * so all file carry nlink==1. UMSDOS use some info in the
387 * EMD file to plug the correct value.
389 if (!S_ISDIR (entry
->mode
)) {
390 if (entry
->nlink
> 0) {
391 inode
->i_nlink
= entry
->nlink
;
394 "UMSDOS: lookup_patch entry->nlink < 1 ???\n");
398 * The mode may have changed, so patch the inode again.
400 umsdos_patch_dentry_inode(dentry
, info
->f_pos
);
401 umsdos_set_dirinfo_new(dentry
, info
->f_pos
);
409 * Return != 0 if an entry is the pseudo DOS entry in the pseudo root.
412 int umsdos_is_pseudodos (struct inode
*dir
, struct dentry
*dentry
)
414 /* #Specification: pseudo root / DOS hard coded
415 * The pseudo sub-directory DOS in the pseudo root is hard coded.
416 * The name is DOS. This is done this way to help standardised
417 * the umsdos layout. The idea is that from now on /DOS is
418 * a reserved path and nobody will think of using such a path
421 return dir
== pseudo_root
422 && dentry
->d_name
.len
== 3
423 && dentry
->d_name
.name
[0] == 'D'
424 && dentry
->d_name
.name
[1] == 'O'
425 && dentry
->d_name
.name
[2] == 'S';
430 * Check whether a file exists in the current directory.
431 * Return 0 if OK, negative error code if not (ex: -ENOENT).
433 * fills dentry->d_inode with found inode, and increments its count.
434 * if not found, return -ENOENT.
436 /* #Specification: umsdos / lookup
437 * A lookup for a file is done in two steps. First, we
438 * locate the file in the EMD file. If not present, we
439 * return an error code (-ENOENT). If it is there, we
440 * repeat the operation on the msdos file system. If
441 * this fails, it means that the file system is not in
442 * sync with the EMD file. We silently remove this
443 * entry from the EMD file, and return ENOENT.
446 struct dentry
*umsdos_lookup_x (struct inode
*dir
, struct dentry
*dentry
, int nopseudo
)
448 struct dentry
*dret
= NULL
;
451 struct umsdos_info info
;
453 #ifdef UMSDOS_DEBUG_VERBOSE
454 printk("umsdos_lookup_x: looking for %s/%s\n",
455 dentry
->d_parent
->d_name
.name
, dentry
->d_name
.name
);
458 umsdos_startlookup (dir
);
459 if (umsdos_is_pseudodos (dir
, dentry
)) {
460 /* #Specification: pseudo root / lookup(DOS)
461 * A lookup of DOS in the pseudo root will always succeed
462 * and return the inode of the real root.
464 Printk ((KERN_DEBUG
"umsdos_lookup_x: following /DOS\n"));
465 inode
= saved_root
->d_inode
;
469 ret
= umsdos_parse (dentry
->d_name
.name
, dentry
->d_name
.len
, &info
);
471 printk("umsdos_lookup_x: %s/%s parse failed, ret=%d\n",
472 dentry
->d_parent
->d_name
.name
, dentry
->d_name
.name
, ret
);
476 ret
= umsdos_findentry (dentry
->d_parent
, &info
, 0);
479 printk("umsdos_lookup_x: %s/%s findentry failed, ret=%d\n",
480 dentry
->d_parent
->d_name
.name
, dentry
->d_name
.name
, ret
);
483 Printk (("lookup %.*s pos %lu ret %d len %d ",
484 info
.fake
.len
, info
.fake
.fname
, info
.f_pos
, ret
, info
.fake
.len
));
486 /* do a real lookup to get the short name ... */
487 dret
= umsdos_covered(dentry
->d_parent
, info
.fake
.fname
, info
.fake
.len
);
490 printk("umsdos_lookup_x: %s/%s real lookup failed, ret=%d\n",
491 dentry
->d_parent
->d_name
.name
, dentry
->d_name
.name
, ret
);
494 inode
= dret
->d_inode
;
497 umsdos_lookup_patch_new(dret
, &info
);
498 #ifdef UMSDOS_DEBUG_VERBOSE
499 printk("umsdos_lookup_x: found %s/%s, ino=%ld\n",
500 dret
->d_parent
->d_name
.name
, dret
->d_name
.name
, dret
->d_inode
->i_ino
);
503 /* Check for a hard link */
504 if ((info
.entry
.flags
& UMSDOS_HLINK
) &&
505 !UMSDOS_I(inode
)->i_is_hlink
) {
506 dret
= umsdos_solve_hlink (dret
);
511 inode
= dret
->d_inode
;
513 printk("umsdos_lookup_x: %s/%s negative after link\n",
514 dret
->d_parent
->d_name
.name
, dret
->d_name
.name
);
519 if (inode
== pseudo_root
&& !nopseudo
) {
520 /* #Specification: pseudo root / dir lookup
521 * For the same reason as readdir, a lookup in /DOS for
522 * the pseudo root directory (linux) will fail.
525 * This has to be allowed for resolving hard links
526 * which are recorded independently of the pseudo-root
529 printk("umsdos_lookup_x: skipping DOS/linux\n");
535 * We've found it OK. Now hash the dentry with the inode.
538 atomic_inc(&inode
->i_count
);
539 d_add (dentry
, inode
);
540 dentry
->d_op
= &umsdos_dentry_operations
;
544 if (dret
&& dret
!= dentry
)
548 umsdos_endlookup (dir
);
552 printk(KERN_WARNING
"UMSDOS: entry %s/%s out of sync, erased\n",
553 dentry
->d_parent
->d_name
.name
, dentry
->d_name
.name
);
554 umsdos_delentry (dentry
->d_parent
, &info
, S_ISDIR (info
.entry
.mode
));
561 * Check whether a file exists in the current directory.
562 * Return 0 if OK, negative error code if not (ex: -ENOENT).
564 * Called by VFS; should fill dentry->d_inode via d_add.
567 struct dentry
*UMSDOS_lookup (struct inode
*dir
, struct dentry
*dentry
, struct nameidata
*nd
)
571 ret
= umsdos_lookup_x (dir
, dentry
, 0);
573 /* Create negative dentry if not found. */
574 if (ret
== ERR_PTR(-ENOENT
)) {
576 "UMSDOS_lookup: converting -ENOENT to negative\n"));
577 d_add (dentry
, NULL
);
578 dentry
->d_op
= &umsdos_dentry_operations
;
584 struct dentry
*umsdos_covered(struct dentry
*parent
, char *name
, int len
)
586 struct dentry
*result
, *dentry
;
591 qstr
.hash
= full_name_hash(name
, len
);
592 result
= ERR_PTR(-ENOMEM
);
593 dentry
= d_alloc(parent
, &qstr
);
595 /* XXXXXXXXXXXXXXXXXXX Race alert! */
596 result
= UMSDOS_rlookup(parent
->d_inode
, dentry
);
611 * Lookup or create a dentry from within the filesystem.
613 * We need to use this instead of lookup_dentry, as the
614 * directory semaphore lock is already held.
616 struct dentry
*umsdos_lookup_dentry(struct dentry
*parent
, char *name
, int len
,
619 struct dentry
*result
, *dentry
;
624 qstr
.hash
= full_name_hash(name
, len
);
625 result
= d_lookup(parent
, &qstr
);
627 result
= ERR_PTR(-ENOMEM
);
628 dentry
= d_alloc(parent
, &qstr
);
631 UMSDOS_rlookup(parent
->d_inode
, dentry
) :
632 UMSDOS_lookup(parent
->d_inode
, dentry
);
647 * Return a path relative to our root.
649 char * umsdos_d_path(struct dentry
*dentry
, char * buffer
, int len
)
651 struct dentry
* old_root
;
654 read_lock(¤t
->fs
->lock
);
655 old_root
= dget(current
->fs
->root
);
656 read_unlock(¤t
->fs
->lock
);
657 spin_lock(&dcache_lock
);
658 path
= __d_path(dentry
, current
->fs
->rootmnt
, dentry
->d_sb
->s_root
, current
->fs
->rootmnt
, buffer
, len
); /* FIXME: current->fs->rootmnt */
659 spin_unlock(&dcache_lock
);
662 path
++; /* skip leading '/' */
664 if (current
->fs
->root
->d_inode
== pseudo_root
)
667 path
-= (UMSDOS_PSDROOT_LEN
+1);
668 memcpy(path
, UMSDOS_PSDROOT_NAME
, UMSDOS_PSDROOT_LEN
);
676 * Return the dentry which points to a pseudo-hardlink.
678 * it should try to find file it points to
679 * if file is found, return new dentry/inode
680 * The resolved inode will have i_is_hlink set.
682 * Note: the original dentry is always dput(), even if an error occurs.
685 struct dentry
*umsdos_solve_hlink (struct dentry
*hlink
)
687 /* root is our root for resolving pseudo-hardlink */
688 struct dentry
*base
= hlink
->d_sb
->s_root
;
689 struct dentry
*dentry_dst
;
692 struct address_space
*mapping
= hlink
->d_inode
->i_mapping
;
695 page
=read_cache_page(mapping
,0,(filler_t
*)mapping
->a_ops
->readpage
,NULL
);
696 dentry_dst
=(struct dentry
*)page
;
699 wait_on_page_locked(page
);
700 if (!PageUptodate(page
))
703 dentry_dst
= ERR_PTR(-ENOMEM
);
704 path
= (char *) kmalloc (PATH_MAX
, GFP_KERNEL
);
707 memcpy(path
, kmap(page
), hlink
->d_inode
->i_size
);
709 page_cache_release(page
);
711 len
= hlink
->d_inode
->i_size
;
713 /* start at root dentry */
714 dentry_dst
= dget(base
);
719 pt
++; /* skip leading '/' */
721 if (base
->d_inode
== pseudo_root
)
722 pt
+= (UMSDOS_PSDROOT_LEN
+ 1);
725 struct dentry
*dir
= dentry_dst
, *demd
;
729 while (*pt
!= '\0' && *pt
!= '/') pt
++;
730 len
= (int) (pt
- start
);
731 if (*pt
== '/') *pt
++ = '\0';
734 demd
= umsdos_get_emd_dentry(dir
);
741 #ifdef UMSDOS_DEBUG_VERBOSE
742 printk ("umsdos_solve_hlink: dir %s/%s, name=%s, real=%d\n",
743 dir
->d_parent
->d_name
.name
, dir
->d_name
.name
, start
, real
);
745 dentry_dst
= umsdos_lookup_dentry(dir
, start
, len
, real
);
746 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
750 if (IS_ERR(dentry_dst
))
752 /* not found? stop search ... */
753 if (!dentry_dst
->d_inode
) {
756 if (*pt
== '\0') /* we're finished! */
760 if (!IS_ERR(dentry_dst
)) {
761 struct inode
*inode
= dentry_dst
->d_inode
;
763 UMSDOS_I(inode
)->i_is_hlink
= 1;
764 #ifdef UMSDOS_DEBUG_VERBOSE
765 printk ("umsdos_solve_hlink: resolved link %s/%s, ino=%ld\n",
766 dentry_dst
->d_parent
->d_name
.name
, dentry_dst
->d_name
.name
, inode
->i_ino
);
769 #ifdef UMSDOS_DEBUG_VERBOSE
770 printk ("umsdos_solve_hlink: resolved link %s/%s negative!\n",
771 dentry_dst
->d_parent
->d_name
.name
, dentry_dst
->d_name
.name
);
776 "umsdos_solve_hlink: err=%ld\n", PTR_ERR(dentry_dst
));
780 dput(hlink
); /* original hlink no longer needed */
784 dentry_dst
= ERR_PTR(-EIO
);
786 page_cache_release(page
);
791 struct file_operations umsdos_dir_operations
=
793 .read
= generic_read_dir
,
794 .readdir
= UMSDOS_readdir
,
795 .ioctl
= UMSDOS_ioctl_dir
,
798 struct inode_operations umsdos_dir_inode_operations
=
800 .create
= UMSDOS_create
,
801 .lookup
= UMSDOS_lookup
,
803 .unlink
= UMSDOS_unlink
,
804 .symlink
= UMSDOS_symlink
,
805 .mkdir
= UMSDOS_mkdir
,
806 .rmdir
= UMSDOS_rmdir
,
807 .mknod
= UMSDOS_mknod
,
808 .rename
= UMSDOS_rename
,
809 .setattr
= UMSDOS_notify_change
,