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/slab.h>
19 #include <linux/pagemap.h>
21 #define UMSDOS_SPECIAL_DIRFPOS 3
22 extern struct dentry *saved_root;
23 extern struct inode *pseudo_root;
25 /* #define UMSDOS_DEBUG_VERBOSE 1 */
28 * Dentry operations routines
31 /* nothing for now ... */
32 static int umsdos_dentry_validate(struct dentry *dentry, int flags)
37 /* for now, drop everything to force lookups ... */
38 /* ITYM s/everything/& positive/... */
39 static int umsdos_dentry_dput(struct dentry *dentry)
41 struct inode *inode = dentry->d_inode;
48 struct dentry_operations umsdos_dentry_operations =
50 d_revalidate: umsdos_dentry_validate,
51 d_delete: umsdos_dentry_dput,
54 struct UMSDOS_DIR_ONCE {
62 * Record a single entry the first call.
63 * Return -EINVAL the next one.
64 * NOTE: filldir DOES NOT use a dentry
67 static int umsdos_dir_once ( void *buf,
75 struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *) buf;
78 PRINTK ((KERN_DEBUG "dir_once :%.*s: offset %Ld\n",
80 ret = d->filldir (d->dirbuf, name, len, offset, ino, DT_UNKNOWN);
89 * Read count directory entries from directory filp
90 * Return a negative value from linux/errno.h.
91 * Return > 0 if success (the number of bytes written by filldir).
93 * This function is used by the normal readdir VFS entry point,
94 * and in order to get the directory entry from a file's dentry.
95 * See umsdos_dentry_to_entry() below.
98 static int umsdos_readdir_x (struct inode *dir, struct file *filp,
99 void *dirbuf, struct umsdos_dirent *u_entry,
107 umsdos_startlookup (dir);
109 if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS && dir == pseudo_root) {
112 * We don't need to simulate this pseudo directory
113 * when umsdos_readdir_x is called for internal operation
114 * of umsdos. This is why dirent_in_fs is tested
116 /* #Specification: pseudo root / directory /DOS
117 * When umsdos operates in pseudo root mode (C:\linux is the
118 * linux root), it simulate a directory /DOS which points to
119 * the real root of the file system.
122 Printk ((KERN_WARNING "umsdos_readdir_x: pseudo_root thing UMSDOS_SPECIAL_DIRFPOS\n"));
123 if (filldir (dirbuf, "DOS", 3,
124 UMSDOS_SPECIAL_DIRFPOS, UMSDOS_ROOT_INO, DT_DIR) == 0) {
130 if (filp->f_pos < 2 ||
131 (dir->i_ino != UMSDOS_ROOT_INO && filp->f_pos == 32)) {
133 int last_f_pos = filp->f_pos;
134 struct UMSDOS_DIR_ONCE bufk;
136 Printk (("umsdos_readdir_x: . or .. /mn/?\n"));
138 bufk.dirbuf = dirbuf;
139 bufk.filldir = filldir;
142 ret = fat_readdir (filp, &bufk, umsdos_dir_once);
143 if (last_f_pos > 0 && filp->f_pos > last_f_pos)
144 filp->f_pos = UMSDOS_SPECIAL_DIRFPOS;
150 Printk (("umsdos_readdir_x: normal file /mn/?\n"));
152 /* get the EMD dentry */
153 demd = umsdos_get_emd_dentry(filp->f_dentry);
158 if (!demd->d_inode) {
160 "umsdos_readir_x: EMD file %s/%s not found\n",
161 demd->d_parent->d_name.name, demd->d_name.name);
166 start_fpos = filp->f_pos;
168 if (pos <= UMSDOS_SPECIAL_DIRFPOS + 1)
171 while (pos < demd->d_inode->i_size) {
172 off_t cur_f_pos = pos;
175 struct umsdos_dirent entry;
176 struct umsdos_info info;
179 if (umsdos_emd_dir_readentry (demd, &pos, &entry) != 0)
181 if (entry.name_len == 0)
183 #ifdef UMSDOS_DEBUG_VERBOSE
184 if (entry.flags & UMSDOS_HLINK)
185 printk("umsdos_readdir_x: %s/%s is hardlink\n",
186 filp->f_dentry->d_name.name, entry.name);
189 umsdos_parse (entry.name, entry.name_len, &info);
190 info.f_pos = cur_f_pos;
191 umsdos_manglename (&info);
193 * Do a real lookup on the short name.
195 dret = umsdos_covered(filp->f_dentry, info.fake.fname,
201 * If the file wasn't found, remove it from the EMD.
203 inode = dret->d_inode;
206 #ifdef UMSDOS_DEBUG_VERBOSE
207 if (inode->u.umsdos_i.i_is_hlink)
208 printk("umsdos_readdir_x: %s/%s already resolved, ino=%ld\n",
209 dret->d_parent->d_name.name, dret->d_name.name, inode->i_ino);
212 Printk (("Found %s/%s, ino=%ld, flags=%x\n",
213 dret->d_parent->d_name.name, info.fake.fname, dret->d_inode->i_ino,
215 /* check whether to resolve a hard-link */
216 if ((entry.flags & UMSDOS_HLINK) &&
217 !inode->u.umsdos_i.i_is_hlink) {
218 dret = umsdos_solve_hlink (dret);
222 inode = dret->d_inode;
224 printk("umsdos_readdir_x: %s/%s negative after link\n",
225 dret->d_parent->d_name.name, dret->d_name.name);
230 /* #Specification: pseudo root / reading real root
231 * The pseudo root (/linux) is logically
232 * erased from the real root. This means that
233 * ls /DOS, won't show "linux". This avoids
234 * infinite recursion (/DOS/linux/DOS/linux/...) while
235 * walking the file system.
237 if (inode != pseudo_root && !(entry.flags & UMSDOS_HIDDEN)) {
238 if (filldir (dirbuf, entry.name, entry.name_len,
239 cur_f_pos, inode->i_ino, DT_UNKNOWN) < 0) {
242 Printk(("umsdos_readdir_x: got %s/%s, ino=%ld\n",
243 dret->d_parent->d_name.name, dret->d_name.name, inode->i_ino));
255 /* #Specification: umsdos / readdir / not in MSDOS
256 * During a readdir operation, if the file is not
257 * in the MS-DOS directory any more, the entry is
258 * removed from the EMD file silently.
260 #ifdef UMSDOS_PARANOIA
261 printk("umsdos_readdir_x: %s/%s out of sync, erasing\n",
262 filp->f_dentry->d_name.name, info.entry.name);
264 ret = umsdos_delentry(filp->f_dentry, &info,
265 S_ISDIR(info.entry.mode));
268 "umsdos_readdir_x: delentry %s, err=%d\n",
269 info.entry.name, ret);
273 * If the fillbuf has failed, f_pos is back to 0.
274 * To avoid getting back into the . and .. state
275 * (see comments at the beginning), we put back
276 * the special offset.
279 if (filp->f_pos == 0)
280 filp->f_pos = start_fpos;
285 umsdos_endlookup (dir);
287 Printk ((KERN_DEBUG "read dir %p pos %Ld ret %d\n",
288 dir, filp->f_pos, ret));
294 * Read count directory entries from directory filp.
295 * Return a negative value from linux/errno.h.
296 * Return 0 or positive if successful.
299 static int UMSDOS_readdir (struct file *filp, void *dirbuf, filldir_t filldir)
301 struct inode *dir = filp->f_dentry->d_inode;
302 int ret = 0, count = 0;
303 struct UMSDOS_DIR_ONCE bufk;
305 bufk.dirbuf = dirbuf;
306 bufk.filldir = filldir;
309 Printk (("UMSDOS_readdir in\n"));
310 while (ret == 0 && bufk.stop == 0) {
311 struct umsdos_dirent entry;
314 ret = umsdos_readdir_x (dir, filp, &bufk, &entry,
320 Printk (("UMSDOS_readdir out %d count %d pos %Ld\n",
321 ret, count, filp->f_pos));
322 return count ? : ret;
327 * Complete the inode content with info from the EMD file.
329 * This function modifies the state of a dir inode. It decides
330 * whether the dir is a UMSDOS or DOS directory. This is done
331 * deeper in umsdos_patch_inode() called at the end of this function.
333 * Because it is does disk access, umsdos_patch_inode() may block.
334 * At the same time, another process may get here to initialise
335 * the same directory inode. There are three cases.
337 * 1) The inode is already initialised. We do nothing.
338 * 2) The inode is not initialised. We lock access and do it.
339 * 3) Like 2 but another process has locked the inode, so we try
340 * to lock it and check right afterward check whether
341 * initialisation is still needed.
344 * Thanks to the "mem" option of the kernel command line, it was
345 * possible to consistently reproduce this problem by limiting
346 * my memory to 4 MB and running X.
348 * Do this only if the inode is freshly read, because we will lose
349 * the current (updated) content.
351 * A lookup of a mount point directory yield the inode into
352 * the other fs, so we don't care about initialising it. iget()
353 * does this automatically.
356 void umsdos_lookup_patch_new(struct dentry *dentry, struct umsdos_info *info)
358 struct inode *inode = dentry->d_inode;
359 struct umsdos_dirent *entry = &info->entry;
362 * This part of the initialization depends only on i_patched.
364 if (inode->u.umsdos_i.i_patched)
366 inode->u.umsdos_i.i_patched = 1;
367 if (S_ISREG (entry->mode))
368 entry->mtime = inode->i_mtime;
369 inode->i_mode = entry->mode;
370 inode->i_rdev = to_kdev_t (entry->rdev);
371 inode->i_atime = entry->atime;
372 inode->i_ctime = entry->ctime;
373 inode->i_mtime = entry->mtime;
374 inode->i_uid = entry->uid;
375 inode->i_gid = entry->gid;
377 /* #Specification: umsdos / i_nlink
378 * The nlink field of an inode is maintained by the MSDOS file system
379 * for directory and by UMSDOS for other files. The logic is that
380 * MSDOS is already figuring out what to do for directories and
381 * does nothing for other files. For MSDOS, there are no hard links
382 * so all file carry nlink==1. UMSDOS use some info in the
383 * EMD file to plug the correct value.
385 if (!S_ISDIR (entry->mode)) {
386 if (entry->nlink > 0) {
387 inode->i_nlink = entry->nlink;
390 "UMSDOS: lookup_patch entry->nlink < 1 ???\n");
394 * The mode may have changed, so patch the inode again.
396 umsdos_patch_dentry_inode(dentry, info->f_pos);
397 umsdos_set_dirinfo_new(dentry, info->f_pos);
405 * Return != 0 if an entry is the pseudo DOS entry in the pseudo root.
408 int umsdos_is_pseudodos (struct inode *dir, struct dentry *dentry)
410 /* #Specification: pseudo root / DOS hard coded
411 * The pseudo sub-directory DOS in the pseudo root is hard coded.
412 * The name is DOS. This is done this way to help standardised
413 * the umsdos layout. The idea is that from now on /DOS is
414 * a reserved path and nobody will think of using such a path
417 return dir == pseudo_root
418 && dentry->d_name.len == 3
419 && dentry->d_name.name[0] == 'D'
420 && dentry->d_name.name[1] == 'O'
421 && dentry->d_name.name[2] == 'S';
426 * Check whether a file exists in the current directory.
427 * Return 0 if OK, negative error code if not (ex: -ENOENT).
429 * fills dentry->d_inode with found inode, and increments its count.
430 * if not found, return -ENOENT.
432 /* #Specification: umsdos / lookup
433 * A lookup for a file is done in two steps. First, we
434 * locate the file in the EMD file. If not present, we
435 * return an error code (-ENOENT). If it is there, we
436 * repeat the operation on the msdos file system. If
437 * this fails, it means that the file system is not in
438 * sync with the EMD file. We silently remove this
439 * entry from the EMD file, and return ENOENT.
442 struct dentry *umsdos_lookup_x (struct inode *dir, struct dentry *dentry, int nopseudo)
444 struct dentry *dret = NULL;
447 struct umsdos_info info;
449 #ifdef UMSDOS_DEBUG_VERBOSE
450 printk("umsdos_lookup_x: looking for %s/%s\n",
451 dentry->d_parent->d_name.name, dentry->d_name.name);
454 umsdos_startlookup (dir);
455 if (umsdos_is_pseudodos (dir, dentry)) {
456 /* #Specification: pseudo root / lookup(DOS)
457 * A lookup of DOS in the pseudo root will always succeed
458 * and return the inode of the real root.
460 Printk ((KERN_DEBUG "umsdos_lookup_x: following /DOS\n"));
461 inode = saved_root->d_inode;
465 ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
467 printk("umsdos_lookup_x: %s/%s parse failed, ret=%d\n",
468 dentry->d_parent->d_name.name, dentry->d_name.name, ret);
472 ret = umsdos_findentry (dentry->d_parent, &info, 0);
475 printk("umsdos_lookup_x: %s/%s findentry failed, ret=%d\n",
476 dentry->d_parent->d_name.name, dentry->d_name.name, ret);
479 Printk (("lookup %.*s pos %lu ret %d len %d ",
480 info.fake.len, info.fake.fname, info.f_pos, ret, info.fake.len));
482 /* do a real lookup to get the short name ... */
483 dret = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
486 printk("umsdos_lookup_x: %s/%s real lookup failed, ret=%d\n",
487 dentry->d_parent->d_name.name, dentry->d_name.name, ret);
490 inode = dret->d_inode;
493 umsdos_lookup_patch_new(dret, &info);
494 #ifdef UMSDOS_DEBUG_VERBOSE
495 printk("umsdos_lookup_x: found %s/%s, ino=%ld\n",
496 dret->d_parent->d_name.name, dret->d_name.name, dret->d_inode->i_ino);
499 /* Check for a hard link */
500 if ((info.entry.flags & UMSDOS_HLINK) &&
501 !inode->u.umsdos_i.i_is_hlink) {
502 dret = umsdos_solve_hlink (dret);
507 inode = dret->d_inode;
509 printk("umsdos_lookup_x: %s/%s negative after link\n",
510 dret->d_parent->d_name.name, dret->d_name.name);
515 if (inode == pseudo_root && !nopseudo) {
516 /* #Specification: pseudo root / dir lookup
517 * For the same reason as readdir, a lookup in /DOS for
518 * the pseudo root directory (linux) will fail.
521 * This has to be allowed for resolving hard links
522 * which are recorded independently of the pseudo-root
525 printk("umsdos_lookup_x: skipping DOS/linux\n");
531 * We've found it OK. Now hash the dentry with the inode.
534 atomic_inc(&inode->i_count);
535 d_add (dentry, inode);
536 dentry->d_op = &umsdos_dentry_operations;
540 if (dret && dret != dentry)
544 umsdos_endlookup (dir);
548 printk(KERN_WARNING "UMSDOS: entry %s/%s out of sync, erased\n",
549 dentry->d_parent->d_name.name, dentry->d_name.name);
550 umsdos_delentry (dentry->d_parent, &info, S_ISDIR (info.entry.mode));
557 * Check whether a file exists in the current directory.
558 * Return 0 if OK, negative error code if not (ex: -ENOENT).
560 * Called by VFS; should fill dentry->d_inode via d_add.
563 struct dentry *UMSDOS_lookup (struct inode *dir, struct dentry *dentry)
567 ret = umsdos_lookup_x (dir, dentry, 0);
569 /* Create negative dentry if not found. */
570 if (ret == ERR_PTR(-ENOENT)) {
572 "UMSDOS_lookup: converting -ENOENT to negative\n"));
573 d_add (dentry, NULL);
574 dentry->d_op = &umsdos_dentry_operations;
580 struct dentry *umsdos_covered(struct dentry *parent, char *name, int len)
582 struct dentry *result, *dentry;
587 qstr.hash = full_name_hash(name, len);
588 result = ERR_PTR(-ENOMEM);
589 dentry = d_alloc(parent, &qstr);
591 /* XXXXXXXXXXXXXXXXXXX Race alert! */
592 result = UMSDOS_rlookup(parent->d_inode, dentry);
607 * Lookup or create a dentry from within the filesystem.
609 * We need to use this instead of lookup_dentry, as the
610 * directory semaphore lock is already held.
612 struct dentry *umsdos_lookup_dentry(struct dentry *parent, char *name, int len,
615 struct dentry *result, *dentry;
620 qstr.hash = full_name_hash(name, len);
621 result = d_lookup(parent, &qstr);
623 result = ERR_PTR(-ENOMEM);
624 dentry = d_alloc(parent, &qstr);
627 UMSDOS_rlookup(parent->d_inode, dentry) :
628 UMSDOS_lookup(parent->d_inode, dentry);
643 * Return a path relative to our root.
645 char * umsdos_d_path(struct dentry *dentry, char * buffer, int len)
647 struct dentry * old_root;
650 read_lock(¤t->fs->lock);
651 old_root = dget(current->fs->root);
652 read_unlock(¤t->fs->lock);
653 spin_lock(&dcache_lock);
654 path = __d_path(dentry, current->fs->rootmnt, dentry->d_sb->s_root, current->fs->rootmnt, buffer, len); /* FIXME: current->fs->rootmnt */
655 spin_unlock(&dcache_lock);
661 path++; /* skip leading '/' */
663 if (current->fs->root->d_inode == pseudo_root)
666 path -= (UMSDOS_PSDROOT_LEN+1);
667 memcpy(path, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN);
675 * Return the dentry which points to a pseudo-hardlink.
677 * it should try to find file it points to
678 * if file is found, return new dentry/inode
679 * The resolved inode will have i_is_hlink set.
681 * Note: the original dentry is always dput(), even if an error occurs.
684 struct dentry *umsdos_solve_hlink (struct dentry *hlink)
686 /* root is our root for resolving pseudo-hardlink */
687 struct dentry *base = hlink->d_sb->s_root;
688 struct dentry *dentry_dst;
691 struct address_space *mapping = hlink->d_inode->i_mapping;
694 page=read_cache_page(mapping,0,(filler_t *)mapping->a_ops->readpage,NULL);
695 dentry_dst=(struct dentry *)page;
699 if (!Page_Uptodate(page))
702 dentry_dst = ERR_PTR(-ENOMEM);
703 path = (char *) kmalloc (PATH_MAX, GFP_KERNEL);
706 memcpy(path, kmap(page), hlink->d_inode->i_size);
708 page_cache_release(page);
710 len = hlink->d_inode->i_size;
712 /* start at root dentry */
713 dentry_dst = dget(base);
718 pt++; /* skip leading '/' */
720 if (base->d_inode == pseudo_root)
721 pt += (UMSDOS_PSDROOT_LEN + 1);
724 struct dentry *dir = dentry_dst, *demd;
728 while (*pt != '\0' && *pt != '/') pt++;
729 len = (int) (pt - start);
730 if (*pt == '/') *pt++ = '\0';
733 demd = umsdos_get_emd_dentry(dir);
740 #ifdef UMSDOS_DEBUG_VERBOSE
741 printk ("umsdos_solve_hlink: dir %s/%s, name=%s, real=%d\n",
742 dir->d_parent->d_name.name, dir->d_name.name, start, real);
744 dentry_dst = umsdos_lookup_dentry(dir, start, len, real);
745 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
749 if (IS_ERR(dentry_dst))
751 /* not found? stop search ... */
752 if (!dentry_dst->d_inode) {
755 if (*pt == '\0') /* we're finished! */
759 if (!IS_ERR(dentry_dst)) {
760 struct inode *inode = dentry_dst->d_inode;
762 inode->u.umsdos_i.i_is_hlink = 1;
763 #ifdef UMSDOS_DEBUG_VERBOSE
764 printk ("umsdos_solve_hlink: resolved link %s/%s, ino=%ld\n",
765 dentry_dst->d_parent->d_name.name, dentry_dst->d_name.name, inode->i_ino);
768 #ifdef UMSDOS_DEBUG_VERBOSE
769 printk ("umsdos_solve_hlink: resolved link %s/%s negative!\n",
770 dentry_dst->d_parent->d_name.name, dentry_dst->d_name.name);
775 "umsdos_solve_hlink: err=%ld\n", PTR_ERR(dentry_dst));
779 dput(hlink); /* original hlink no longer needed */
783 dentry_dst = ERR_PTR(-EIO);
785 page_cache_release(page);
790 struct file_operations umsdos_dir_operations =
792 read: generic_read_dir,
793 readdir: UMSDOS_readdir,
794 ioctl: UMSDOS_ioctl_dir,
797 struct inode_operations umsdos_dir_inode_operations =
799 create: UMSDOS_create,
800 lookup: UMSDOS_lookup,
802 unlink: UMSDOS_unlink,
803 symlink: UMSDOS_symlink,
807 rename: UMSDOS_rename,
808 setattr: UMSDOS_notify_change,