Import 2.1.118
[davej-history.git] / fs / umsdos / dir.c
blob5cc8f57277fd5f3d5192607f11db4e34a14aa741
1 /*
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
8 */
10 #include <linux/sched.h>
11 #include <linux/string.h>
12 #include <linux/fs.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 PRINTK(x)
23 #define Printk(x) printk x
25 #define UMSDOS_SPECIAL_DIRFPOS 3
26 extern struct inode *pseudo_root;
29 /* P.T.Waltenberg
30 * I've retained this to facilitate the lookup of some of the hard-wired files/directories UMSDOS
31 * uses. It's easier to do once than hack all the other instances. Probably safer as well
34 /* FIXME: it returns inode with i_count of 0. this should be redesigned to return dentry instead,
35 and correct dentry (with correct d_parent) */
37 int compat_umsdos_real_lookup (struct inode *dir, const char *name, int len, struct inode **inode)
39 int rv;
40 struct dentry *dentry;
41 unsigned long ino;
43 Printk ((KERN_DEBUG "compat_umsdos_real_lookup !!CNTx!!: start\n"));
44 check_inode (dir);
45 dentry = creat_dentry (name, len, NULL, NULL);
46 rv = umsdos_real_lookup (dir, dentry);
47 iput (dir); /* should be here, because umsdos_real_lookup does inc_count(dir) */
49 if (rv) {
50 Printk ((KERN_WARNING "compat_umsdos_real_lookup failed with %d\n", rv));
51 return rv;
54 if (!inode) {
55 Printk ((KERN_ERR "inode should be set here. Arrgh! segfaulting...\n"));
58 ino = dentry->d_inode->i_ino;
59 *inode = dentry->d_inode;
61 dput (dentry); /* we are done with it: FIXME: does this work /mn/ ? */
63 check_dentry (dentry);
64 check_inode (dir);
66 Printk ((KERN_DEBUG "compat_umsdos_real_lookup !!CNTx!!: end\n"));
68 return rv;
72 int compat_msdos_create (struct inode *dir, const char *name, int len, int mode, struct inode **inode)
74 int rv;
75 struct dentry *dentry;
77 check_inode (dir);
78 dentry = creat_dentry (name, len, NULL, NULL);
79 check_dentry (dentry);
80 rv = msdos_create (dir, dentry, mode);
81 check_dentry (dentry);
82 if (inode != NULL)
83 *inode = dentry->d_inode;
85 check_inode (dir);
86 return rv;
91 * So grep * doesn't complain in the presence of directories.
94 int UMSDOS_dir_read (struct file *filp, char *buff, size_t size, loff_t *count)
96 return -EISDIR;
100 struct UMSDOS_DIR_ONCE {
101 void *dirbuf;
102 filldir_t filldir;
103 int count;
104 int stop;
108 * Record a single entry the first call.
109 * Return -EINVAL the next one.
110 * NOTE: filldir DOES NOT use a dentry
113 static int umsdos_dir_once ( void *buf,
114 const char *name,
115 int len,
116 off_t offset,
117 ino_t ino)
119 int ret = -EINVAL;
120 struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *) buf;
122 if (d->count == 0) {
123 PRINTK ((KERN_DEBUG "dir_once :%.*s: offset %Ld\n", dentry->d_len, dentry->d_name, offset));
124 ret = d->filldir (d->dirbuf, name, len, offset, ino);
125 d->stop = ret < 0;
126 d->count = 1;
128 return ret;
133 * Read count directory entries from directory filp
134 * Return a negative value from linux/errno.h.
135 * Return > 0 if success (The amount of byte written by filldir).
137 * This function is used by the normal readdir VFS entry point and by
138 * some function who try to find out info on a file from a pure MSDOS
139 * inode. See umsdos_locate_ancestor() below.
142 static int umsdos_readdir_x (
143 struct inode *dir, /* Point to a description of the super block */
144 struct file *filp, /* Point to a directory which is read */
145 void *dirbuf, /* Will hold count directory entry */
146 /* but filled by the filldir function */
147 int internal_read, /* Called for internal purpose */
148 struct umsdos_dirent *u_entry, /* Optional umsdos entry */
149 int follow_hlink,
150 filldir_t filldir)
152 int ret = 0;
154 umsdos_startlookup (dir);
155 if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS
156 && pseudo_root
157 && dir == pseudo_root
158 && !internal_read) {
160 Printk (("umsdos_readdir_x: what UMSDOS_SPECIAL_DIRFPOS /mn/?\n"));
162 * We don't need to simulate this pseudo directory
163 * when umsdos_readdir_x is called for internal operation
164 * of umsdos. This is why dirent_in_fs is tested
166 /* #Specification: pseudo root / directory /DOS
167 * When umsdos operates in pseudo root mode (C:\linux is the
168 * linux root), it simulate a directory /DOS which points to
169 * the real root of the file system.
171 if (filldir (dirbuf, "DOS", 3, UMSDOS_SPECIAL_DIRFPOS, UMSDOS_ROOT_INO) == 0) {
172 filp->f_pos++;
174 } else if (filp->f_pos < 2 || (dir->i_ino != UMSDOS_ROOT_INO && filp->f_pos == 32)) {
176 /* FIXME: that was in 2.0.x: else if (filp->f_pos < 2 || (dir != dir->i_sb->s_mounted && filp->f_pos == 32))
177 * I'm probably screwing up pseudo-root and stuff with this. It needs proper fix.
181 /* #Specification: readdir / . and ..
182 * The msdos filesystem manage the . and .. entry properly
183 * so the EMD file won't hold any info about it.
185 * In readdir, we assume that for the root directory
186 * the read position will be 0 for ".", 1 for "..". For
187 * a non root directory, the read position will be 0 for "."
188 * and 32 for "..".
191 * This is a trick used by the msdos file system (fs/msdos/dir.c)
192 * to manage . and .. for the root directory of a file system.
193 * Since there is no such entry in the root, fs/msdos/dir.c
194 * use the following:
196 * if f_pos == 0, return ".".
197 * if f_pos == 1, return "..".
199 * So let msdos handle it
201 * Since umsdos entries are much larger, we share the same f_pos.
202 * if f_pos is 0 or 1 or 32, we are clearly looking at . and
203 * ..
205 * As soon as we get f_pos == 2 or f_pos == 64, then back to
206 * 0, but this time we are reading the EMD file.
208 * Well, not so true. The problem, is that UMSDOS_REC_SIZE is
209 * also 64, so as soon as we read the first record in the
210 * EMD, we are back at offset 64. So we set the offset
211 * to UMSDOS_SPECIAL_DIRFPOS(3) as soon as we have read the
212 * .. entry from msdos.
214 * Now (linux 1.3), umsdos_readdir can read more than one
215 * entry even if we limit (umsdos_dir_once) to only one:
216 * It skips over hidden file. So we switch to
217 * UMSDOS_SPECIAL_DIRFPOS as soon as we have read successfully
218 * the .. entry.
220 int last_f_pos = filp->f_pos;
221 struct UMSDOS_DIR_ONCE bufk;
223 Printk (("umsdos_readdir_x: . or .. /mn/?\n"));
225 bufk.dirbuf = dirbuf;
226 bufk.filldir = filldir;
227 bufk.count = 0;
229 ret = fat_readdir (filp, &bufk, umsdos_dir_once);
230 if (last_f_pos > 0 && filp->f_pos > last_f_pos)
231 filp->f_pos = UMSDOS_SPECIAL_DIRFPOS;
232 if (u_entry != NULL)
233 u_entry->flags = 0;
234 } else {
235 struct inode *emd_dir;
237 Printk (("umsdos_readdir_x: normal file /mn/?\n"));
238 emd_dir = umsdos_emd_dir_lookup (dir, 0);
239 if (emd_dir != NULL) {
240 off_t start_fpos = filp->f_pos;
242 Printk (("umsdos_readdir_x: emd_dir->i_ino=%ld\n", emd_dir->i_ino));
243 if (filp->f_pos <= UMSDOS_SPECIAL_DIRFPOS + 1)
244 filp->f_pos = 0;
245 Printk (("f_pos %Ld i_size %ld\n", filp->f_pos, emd_dir->i_size));
246 ret = 0;
247 while (filp->f_pos < emd_dir->i_size) {
248 struct umsdos_dirent entry;
249 off_t cur_f_pos = filp->f_pos;
251 if (umsdos_emd_dir_readentry (emd_dir, filp, &entry) != 0) {
252 ret = -EIO;
253 break;
254 } else if (entry.name_len != 0) {
255 /* #Specification: umsdos / readdir
256 * umsdos_readdir() should fill a struct dirent with
257 * an inode number. The cheap way to get it is to
258 * do a lookup in the MSDOS directory for each
259 * entry processed by the readdir() function.
260 * This is not very efficient, but very simple. The
261 * other way around is to maintain a copy of the inode
262 * number in the EMD file. This is a problem because
263 * this has to be maintained in sync using tricks.
264 * Remember that MSDOS (the OS) does not update the
265 * modification time (mtime) of a directory. There is
266 * no easy way to tell that a directory was modified
267 * during a DOS session and synchronise the EMD file.
269 * Suggestion welcome.
271 * So the easy way is used!
273 struct umsdos_info info;
274 struct inode *inode;
276 int lret;
278 umsdos_parse (entry.name, entry.name_len, &info);
279 info.f_pos = cur_f_pos;
280 umsdos_manglename (&info);
281 lret = compat_umsdos_real_lookup (dir, info.fake.fname, info.fake.len, &inode);
282 Printk (("Cherche inode de %s lret %d flags %d\n", info.fake.fname, lret, entry.flags));
283 if (lret == 0
284 && (entry.flags & UMSDOS_HLINK)
285 && follow_hlink) {
286 struct inode *rinode;
288 Printk ((KERN_DEBUG "umsdos_hlink2inode now\n"));
289 lret = umsdos_hlink2inode (inode, &rinode);
290 inode = rinode;
292 if (lret == 0) {
293 /* #Specification: pseudo root / reading real root
294 * The pseudo root (/linux) is logically
295 * erased from the real root. This mean that
296 * ls /DOS, won't show "linux". This avoids
297 * infinite recursion /DOS/linux/DOS/linux while
298 * walking the file system.
300 if (inode != pseudo_root
301 && (internal_read
302 || !(entry.flags & UMSDOS_HIDDEN))) {
303 Printk ((KERN_DEBUG "filldir now\n"));
304 if (filldir (dirbuf, entry.name, entry.name_len, cur_f_pos, inode->i_ino) < 0) {
305 filp->f_pos = cur_f_pos;
307 Printk (("Trouve ino %ld ", inode->i_ino));
308 if (u_entry != NULL)
309 *u_entry = entry;
310 iput (inode); /* FIXME? */
311 break;
313 Printk ((KERN_DEBUG " dir.c:Putting inode %lu with i_count=%d\n", inode->i_ino, inode->i_count));
314 iput (inode); /* FIXME? */
315 } else {
316 /* #Specification: umsdos / readdir / not in MSDOS
317 * During a readdir operation, if the file is not
318 * in the MSDOS directory anymore, the entry is
319 * removed from the EMD file silently.
321 Printk (("'Silently' removing EMD for file\n"));
322 ret = umsdos_writeentry (dir, emd_dir, &info, 1);
323 if (ret != 0) {
324 break;
330 * If the fillbuf has failed, f_pos is back to 0.
331 * To avoid getting back into the . and .. state
332 * (see comments at the beginning), we put back
333 * the special offset.
335 if (filp->f_pos == 0)
336 filp->f_pos = start_fpos;
337 Printk ((KERN_DEBUG " dir.c:Putting emd_dir %lu with i_count=%d\n", emd_dir->i_ino, emd_dir->i_count));
338 iput (emd_dir); /* FIXME? */
341 umsdos_endlookup (dir);
343 Printk (("read dir %p pos %Ld ret %d\n", dir, filp->f_pos, ret));
344 return ret;
349 * Read count directory entries from directory filp
350 * Return a negative value from linux/errno.h.
351 * Return 0 or positive if successful
354 static int UMSDOS_readdir (
355 struct file *filp, /* Point to a directory which is read */
356 void *dirbuf, /* Will hold directory entries */
357 filldir_t filldir)
359 struct inode *dir = filp->f_dentry->d_inode;
360 int ret = 0;
361 int count = 0;
362 struct UMSDOS_DIR_ONCE bufk;
364 bufk.dirbuf = dirbuf;
365 bufk.filldir = filldir;
366 bufk.stop = 0;
368 Printk (("UMSDOS_readdir in\n"));
369 while (ret == 0 && bufk.stop == 0) {
370 struct umsdos_dirent entry;
372 bufk.count = 0;
373 Printk (("UMSDOS_readdir: calling _x (%p,%p,%p,%d,%p,%d,%p)\n", dir, filp, &bufk, 0, &entry, 1, umsdos_dir_once));
374 ret = umsdos_readdir_x (dir, filp, &bufk, 0, &entry, 1, umsdos_dir_once);
375 if (bufk.count == 0)
376 break;
377 count += bufk.count;
379 Printk (("UMSDOS_readdir out %d count %d pos %Ld\n", ret, count, filp->f_pos));
380 return count ? : ret;
385 * Complete the inode content with info from the EMD file
388 void umsdos_lookup_patch (
389 struct inode *dir,
390 struct inode *inode,
391 struct umsdos_dirent *entry,
392 off_t emd_pos)
395 * This function modify the state of a dir inode. It decides
396 * if the dir is a umsdos dir or a dos dir. This is done
397 * deeper in umsdos_patch_inode() called at the end of this function.
399 * umsdos_patch_inode() may block because it is doing disk access.
400 * At the same time, another process may get here to initialise
401 * the same dir inode. There is 3 cases.
403 * 1-The inode is already initialised. We do nothing.
404 * 2-The inode is not initialised. We lock access and do it.
405 * 3-Like 2 but another process has lock the inode, so we try
406 * to lock it and right after check if initialisation is still
407 * needed.
410 * Thanks to the mem option of the kernel command line, it was
411 * possible to consistently reproduce this problem by limiting
412 * my mem to 4 meg and running X.
415 * Do this only if the inode is freshly read, because we will lose
416 * the current (updated) content.
419 * A lookup of a mount point directory yield the inode into
420 * the other fs, so we don't care about initialising it. iget()
421 * does this automatically.
424 if (inode->i_sb == dir->i_sb && !umsdos_isinit (inode)) {
425 if (S_ISDIR (inode->i_mode))
426 umsdos_lockcreate (inode);
427 if (!umsdos_isinit (inode)) {
428 /* #Specification: umsdos / lookup / inode info
429 * After successfully reading an inode from the MSDOS
430 * filesystem, we use the EMD file to complete it.
431 * We update the following field.
433 * uid, gid, atime, ctime, mtime, mode.
435 * We rely on MSDOS for mtime. If the file
436 * was modified during an MSDOS session, at least
437 * mtime will be meaningful. We do this only for regular
438 * file.
440 * We don't rely on MSDOS for mtime for directory because
441 * the MSDOS directory date is creation time (strange
442 * MSDOS behavior) which fit nowhere in the three UNIX
443 * time stamp.
445 if (S_ISREG (entry->mode))
446 entry->mtime = inode->i_mtime;
447 inode->i_mode = entry->mode;
448 inode->i_rdev = to_kdev_t (entry->rdev);
449 inode->i_atime = entry->atime;
450 inode->i_ctime = entry->ctime;
451 inode->i_mtime = entry->mtime;
452 inode->i_uid = entry->uid;
453 inode->i_gid = entry->gid;
454 /* #Specification: umsdos / conversion mode
455 * The msdos fs can do some inline conversion
456 * of the data of a file. It can translate
457 * silently from MsDOS text file format to Unix
458 * one (crlf -> lf) while reading, and the reverse
459 * while writing. This is activated using the mount
460 * option conv=....
462 * This is not useful for Linux file in promoted
463 * directory. It can even be harmful. For this
464 * reason, the binary (no conversion) mode is
465 * always activated.
467 /* #Specification: umsdos / conversion mode / todo
468 * A flag could be added to file and directories
469 * forcing an automatic conversion mode (as
470 * done with the msdos fs).
472 * This flag could be setup on a directory basis
473 * (instead of file) and all file in it would
474 * logically inherited. If the conversion mode
475 * is active (conv=) then the i_binary flag would
476 * be left untouched in those directories.
478 * It was proposed that the sticky bit was used
479 * to set this. The problem is that new file would
480 * be written incorrectly. The other problem is that
481 * the sticky bit has a meaning for directories. So
482 * another bit should be used (there is some space
483 * in the EMD file for it) and a special utilities
484 * would be used to assign the flag to a directory).
485 * I don't think it is useful to assign this flag
486 * on a single file.
489 MSDOS_I (inode)->i_binary = 1;
490 /* #Specification: umsdos / i_nlink
491 * The nlink field of an inode is maintain by the MSDOS file system
492 * for directory and by UMSDOS for other file. The logic is that
493 * MSDOS is already figuring out what to do for directories and
494 * does nothing for other files. For MSDOS, there are no hard link
495 * so all file carry nlink==1. UMSDOS use some info in the
496 * EMD file to plug the correct value.
498 if (!S_ISDIR (entry->mode)) {
499 if (entry->nlink > 0) {
500 inode->i_nlink = entry->nlink;
501 } else {
502 printk (KERN_ERR "UMSDOS: lookup_patch entry->nlink < 1 ???\n");
505 umsdos_patch_inode (inode, dir, emd_pos);
507 if (S_ISDIR (inode->i_mode))
508 umsdos_unlockcreate (inode);
509 if (inode->u.umsdos_i.i_emd_owner == 0)
510 printk (KERN_WARNING "emd_owner still 0 ???\n");
516 struct UMSDOS_DIRENT_K {
517 off_t f_pos; /* will hold the offset of the entry in EMD */
518 ino_t ino;
523 * Just to record the offset of one entry.
526 static int umsdos_filldir_k (
527 void *buf,
528 const char *name,
529 int len,
530 off_t offset,
531 ino_t ino)
533 struct UMSDOS_DIRENT_K *d = (struct UMSDOS_DIRENT_K *) buf;
535 d->f_pos = offset;
536 d->ino = ino;
537 return 0;
540 struct UMSDOS_DIR_SEARCH {
541 struct umsdos_dirent *entry;
542 int found;
543 ino_t search_ino;
546 static int umsdos_dir_search (
547 void *buf,
548 const char *name,
549 int len,
550 off_t offset,
551 ino_t ino)
553 int ret = 0;
554 struct UMSDOS_DIR_SEARCH *d = (struct UMSDOS_DIR_SEARCH *) buf;
556 if (d->search_ino == ino) {
557 d->found = 1;
558 memcpy (d->entry->name, name, len);
559 d->entry->name[len] = '\0';
560 d->entry->name_len = len;
561 ret = 1; /* So fat_readdir will terminate */
563 return ret;
569 * Locate entry of an inode in a directory.
570 * Return 0 or a negative error code.
572 * Normally, this function must succeed. It means a strange corruption
573 * in the file system if not.
576 int umsdos_inode2entry (
577 struct inode *dir,
578 struct inode *inode,
579 struct umsdos_dirent *entry)
580 { /* Will hold the entry */
581 int ret = -ENOENT;
583 if (pseudo_root && inode == pseudo_root) {
585 * Quick way to find the name.
586 * Also umsdos_readdir_x won't show /linux anyway
588 memcpy (entry->name, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN + 1);
589 entry->name_len = UMSDOS_PSDROOT_LEN;
590 ret = 0;
591 } else {
592 struct inode *emddir = umsdos_emd_dir_lookup (dir, 0);
594 iput (emddir); /* FIXME? */
595 if (emddir == NULL) {
596 /* This is a DOS directory */
597 struct UMSDOS_DIR_SEARCH bufk;
598 struct file filp;
599 struct dentry *i2e;
601 i2e = creat_dentry ("i2e.nul", 7, dir, NULL);
603 fill_new_filp (&filp, i2e);
605 Printk ((KERN_ERR "umsdos_inode2entry emddir==NULL: WARNING: Known filp problem. segfaulting :) fixed ?/mn/\n"));
606 filp.f_reada = 1;
607 filp.f_pos = 0;
608 bufk.entry = entry;
609 bufk.search_ino = inode->i_ino;
610 fat_readdir (&filp, &bufk, umsdos_dir_search);
611 if (bufk.found) {
612 ret = 0;
613 inode->u.umsdos_i.i_dir_owner = dir->i_ino;
614 inode->u.umsdos_i.i_emd_owner = 0;
615 umsdos_setup_dir_inode (inode);
617 } else {
618 /* skip . and .. see umsdos_readdir_x() */
619 struct file filp;
620 struct dentry *i2e;
622 i2e = creat_dentry ("i2e.nn", 6, dir, NULL);
623 fill_new_filp (&filp, i2e);
625 filp.f_reada = 1;
626 filp.f_pos = UMSDOS_SPECIAL_DIRFPOS;
627 Printk ((KERN_ERR "umsdos_inode2entry skip...: WARNING: Known filp problem. segfaulting :) fixed ?/mn/\n"));
628 while (1) {
629 struct UMSDOS_DIRENT_K bufk;
631 if (umsdos_readdir_x (dir, &filp, &bufk
632 ,1, entry, 0, umsdos_filldir_k) < 0) {
633 printk ("UMSDOS: can't locate inode %ld in EMD file???\n"
634 ,inode->i_ino);
635 break;
636 } else if (bufk.ino == inode->i_ino) {
637 ret = 0;
638 umsdos_lookup_patch (dir, inode, entry, bufk.f_pos);
639 break;
644 return ret;
649 * Locate the parent of a directory and the info on that directory
650 * Return 0 or a negative error code.
653 static int umsdos_locate_ancestor (
654 struct inode *dir,
655 struct inode **result,
656 struct umsdos_dirent *entry)
658 int ret;
660 umsdos_patch_inode (dir, NULL, 0);
661 /* FIXME */
662 ret = compat_umsdos_real_lookup (dir, "..", 2, result);
663 Printk (("result %d %p ", ret, *result));
664 if (ret == 0) {
665 struct inode *adir = *result;
667 ret = umsdos_inode2entry (adir, dir, entry);
669 Printk (("\n"));
670 return ret;
675 * Build the path name of an inode (relative to the file system.
676 * This function is need to set (pseudo) hard link.
678 * It uses the same strategy as the standard getcwd().
681 int umsdos_locate_path (
682 struct inode *inode,
683 char *path)
685 int ret = 0;
686 struct inode *dir = inode;
687 struct inode *root_inode;
688 char *bpath = (char *) kmalloc (PATH_MAX, GFP_KERNEL);
690 root_inode = iget (inode->i_sb, UMSDOS_ROOT_INO);
691 if (bpath == NULL) {
692 ret = -ENOMEM;
693 } else {
694 struct umsdos_dirent entry;
695 char *ptbpath = bpath + PATH_MAX - 1;
697 *ptbpath = '\0';
698 Printk (("locate_path mode %x ", inode->i_mode));
699 if (!S_ISDIR (inode->i_mode)) {
700 ret = umsdos_get_dirowner (inode, &dir);
701 Printk (("locate_path ret %d ", ret));
702 if (ret == 0) {
703 ret = umsdos_inode2entry (dir, inode, &entry);
704 if (ret == 0) {
705 ptbpath -= entry.name_len;
706 memcpy (ptbpath, entry.name, entry.name_len);
707 Printk (("ptbpath :%.*s: ", entry.name_len, ptbpath));
710 } else {
711 inc_count (dir);
713 if (ret == 0) {
714 while (dir != root_inode) {
715 struct inode *adir;
717 ret = umsdos_locate_ancestor (dir, &adir, &entry);
718 /* iput (dir); FIXME */
719 dir = NULL;
720 Printk (("ancestor %d ", ret));
721 if (ret == 0) {
722 *--ptbpath = '/';
723 ptbpath -= entry.name_len;
724 memcpy (ptbpath, entry.name, entry.name_len);
725 dir = adir;
726 Printk (("ptbpath :%.*s: ", entry.name_len, ptbpath));
727 } else {
728 break;
732 strcpy (path, ptbpath);
733 kfree (bpath);
735 Printk (("\n"));
736 iput (dir); /* FIXME?? */
737 return ret;
742 * Return != 0 if an entry is the pseudo DOS entry in the pseudo root.
745 int umsdos_is_pseudodos (
746 struct inode *dir,
747 struct dentry *dentry)
749 /* #Specification: pseudo root / DOS hard coded
750 * The pseudo sub-directory DOS in the pseudo root is hard coded.
751 * The name is DOS. This is done this way to help standardised
752 * the umsdos layout. The idea is that from now on /DOS is
753 * a reserved path and nobody will think of using such a path
754 * for a package.
756 return pseudo_root
757 && dir == pseudo_root
758 && dentry->d_name.len == 3
759 && dentry->d_name.name[0] == 'D'
760 && dentry->d_name.name[1] == 'O'
761 && dentry->d_name.name[2] == 'S';
766 * Check if a file exist in the current directory.
767 * Return 0 if ok, negative error code if not (ex: -ENOENT).
770 int umsdos_lookup_x (
771 struct inode *dir,
772 struct dentry *dentry,
773 int nopseudo)
774 { /* Don't care about pseudo root mode */
775 int ret = -ENOENT;
776 struct inode *root_inode;
777 int len = dentry->d_name.len;
778 const char *name = dentry->d_name.name;
780 PRINTK ((KERN_DEBUG "umsdos_lookup_x: /mn/ name=%.*s, dir=%lu (i_count=%d), d_parent=%p\n", (int) dentry->d_name.len, dentry->d_name.name, dir->i_ino, dir->i_count, dentry->d_parent)); /* FIXME /mn/ debug only */
781 if (dentry->d_parent)
782 PRINTK ((KERN_DEBUG " d_parent is %.*s\n", (int) dentry->d_parent->d_name.len, dentry->d_parent->d_name.name)); /* FIXME : delme /mn/ */
784 root_inode = iget (dir->i_sb, UMSDOS_ROOT_INO);
785 Printk ((KERN_ERR "umsdos_lookup_x (CNT!): entering root_count=%d, dir %lu _count=%d\n", root_inode->i_count, dir->i_ino, dir->i_count)); /* FIXME: DEBUG, DELME */
787 d_instantiate (dentry, NULL);
788 umsdos_startlookup (dir);
789 if (len == 1 && name[0] == '.') {
790 d_add (dentry, dir);
791 inc_count (dir);
792 ret = 0;
793 } else if (len == 2 && name[0] == '.' && name[1] == '.') {
794 if (pseudo_root && dir == pseudo_root) {
795 /* #Specification: pseudo root / .. in real root
796 * Whenever a lookup is those in the real root for
797 * the directory .., and pseudo root is active, the
798 * pseudo root is returned.
800 ret = 0;
801 d_add (dentry, pseudo_root);
802 inc_count (pseudo_root);
803 } else {
804 /* #Specification: locating .. / strategy
805 * We use the msdos filesystem to locate the parent directory.
806 * But it is more complicated than that.
808 * We have to step back even further to
809 * get the parent of the parent, so we can get the EMD
810 * of the parent of the parent. Using the EMD file, we can
811 * locate all the info on the parent, such a permissions
812 * and owner.
815 ret = compat_umsdos_real_lookup (dir, "..", 2, &dentry->d_inode);
816 Printk (("ancestor ret %d dir %p *result %p ", ret, dir, dentry->d_inode));
817 if (ret == 0
818 && dentry->d_inode != root_inode
819 && dentry->d_inode != pseudo_root) {
820 struct inode *aadir;
821 struct umsdos_dirent entry;
823 ret = umsdos_locate_ancestor (dentry->d_inode, &aadir, &entry);
824 iput (aadir); /* FIXME */
827 } else if (umsdos_is_pseudodos (dir, dentry)) {
828 /* #Specification: pseudo root / lookup(DOS)
829 * A lookup of DOS in the pseudo root will always succeed
830 * and return the inode of the real root.
832 d_add (dentry, root_inode);
833 inc_count (dentry->d_inode);
834 ret = 0;
835 } else {
836 struct umsdos_info info;
838 ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
839 if (ret == 0)
840 ret = umsdos_findentry (dir, &info, 0);
841 Printk (("lookup %.*s pos %lu ret %d len %d ", info.fake.len, info.fake.fname, info.f_pos, ret
842 ,info.fake.len));
843 if (ret == 0) {
844 /* #Specification: umsdos / lookup
845 * A lookup for a file is done in two step. First, we locate
846 * the file in the EMD file. If not present, we return
847 * an error code (-ENOENT). If it is there, we repeat the
848 * operation on the msdos file system. If this fails, it means
849 * that the file system is not in sync with the emd file.
850 * We silently remove this entry from the emd file,
851 * and return ENOENT.
853 struct inode *inode;
855 ret = compat_umsdos_real_lookup (dir, info.fake.fname, info.fake.len, &inode);
857 Printk ((KERN_DEBUG "umsdos_lookup_x: compat_umsdos_real_lookup for %.*s returned %d with inode=%p\n", info.fake.len, info.fake.fname, ret, inode));
859 if (inode == NULL) {
860 printk (KERN_WARNING "UMSDOS: Erase entry %.*s, out of sync with MsDOS\n"
861 ,info.fake.len, info.fake.fname);
862 umsdos_delentry (dir, &info, S_ISDIR (info.entry.mode));
863 } else {
864 Printk ((KERN_DEBUG "umsdos_lookup_x /mn/ debug: ino=%li\n", inode->i_ino));
866 /* we've found it. now put inode in dentry */
867 d_add (dentry, inode);
869 umsdos_lookup_patch (dir, inode, &info.entry, info.f_pos);
870 Printk (("lookup ino %ld flags %d\n", inode->i_ino, info.entry.flags));
871 if (info.entry.flags & UMSDOS_HLINK) {
872 Printk ((KERN_DEBUG "umsdos_lookup_x: here goes HLINK\n"));
873 ret = umsdos_hlink2inode (inode, &dentry->d_inode);
875 if (pseudo_root && dentry->d_inode == pseudo_root && !nopseudo) {
876 /* #Specification: pseudo root / dir lookup
877 * For the same reason as readdir, a lookup in /DOS for
878 * the pseudo root directory (linux) will fail.
881 * This has to be allowed for resolving hard link
882 * which are recorded independently of the pseudo-root
883 * mode.
885 Printk ((KERN_ERR "umsdos_lookup_x: warning: untested /mn/ Pseudo_root thingy\n"));
886 iput (pseudo_root); /* FIXME?? */
887 d_instantiate (dentry, NULL); /* FIXME: should be dput(dentry) ? */
888 ret = -ENOENT;
893 umsdos_endlookup (dir);
894 PRINTK ((KERN_DEBUG "umsdos_lookup_x: returning %d : name=%.*s (i_count=%d), dir=%lu (i_count=%d)\n", ret, (int) dentry->d_name.len, dentry->d_name.name, dentry->d_inode->i_count, dir->i_ino, dir->i_count));
895 Printk ((KERN_ERR "umsdos_lookup_x (CNT!): exiting root_count=%d, dir %lu _count=%d\n", root_inode->i_count, dir->i_ino, dir->i_count)); /* FIXME: DEBUG, DELME */
896 return ret;
901 * Check if a file exist in the current directory.
902 * Return 0 if ok, negative error code if not (ex: -ENOENT).
907 int UMSDOS_lookup (
908 struct inode *dir,
909 struct dentry *dentry)
911 int ret;
913 check_dentry (dentry);
914 ret = umsdos_lookup_x (dir, dentry, 0);
915 check_dentry (dentry);
917 #if 1
918 if (ret == -ENOENT) {
919 Printk ((KERN_DEBUG "UMSDOS_lookup: converting -ENOENT to negative dentry !\n"));
920 d_add (dentry, NULL); /* create negative dentry if not found */
921 ret = 0;
923 #endif
925 return ret;
931 * Locate the inode pointed by a (pseudo) hard link
932 * Return 0 if ok, a negative error code if not.
935 int umsdos_hlink2inode (struct inode *hlink, struct inode **result)
937 struct inode *root_inode;
938 int ret = -EIO;
939 struct dentry *dentry_src, *dentry_dst;
940 char *path;
942 #if 0 /* FIXME: DELME */
943 Printk (("FIXME: just test. hlink2inode returning -ENOENT\n /mn/\n"));
944 return -ENOENT; /* /mn/ FIXME just for test */
945 #endif
947 path = (char *) kmalloc (PATH_MAX, GFP_KERNEL);
949 root_inode = iget (hlink->i_sb, UMSDOS_ROOT_INO);
950 *result = NULL;
951 if (path == NULL) {
952 ret = -ENOMEM;
953 iput (hlink); /* FIXME? */
954 } else {
955 struct file filp;
956 loff_t offs = 0;
958 dentry_src = creat_dentry ("hlink-mn", 8, hlink, NULL);
960 fill_new_filp (&filp, dentry_src);
961 filp.f_flags = O_RDONLY;
963 Printk (("hlink2inode "));
964 if (umsdos_file_read_kmem (hlink, &filp, path, hlink->i_size, &offs) == hlink->i_size) {
965 struct inode *dir;
966 char *pt = path;
968 dir = root_inode;
969 path[hlink->i_size] = '\0';
970 iput (hlink); /* FIXME? */
971 inc_count (dir);
972 while (1) {
973 char *start = pt;
974 int len;
976 while (*pt != '\0' && *pt != '/')
977 pt++;
978 len = (int) (pt - start);
979 if (*pt == '/')
980 *pt++ = '\0';
981 /* FIXME. /mn/ fixed ? */
983 dentry_dst = creat_dentry (start, len, NULL, NULL);
985 if (dir->u.umsdos_i.i_emd_dir == 0) {
986 /* This is a DOS directory */
988 Printk (("hlink2inode /mn/: doing umsdos_rlookup_x on %.*s\n", (int) dentry_dst->d_name.len, dentry_dst->d_name.name));
989 ret = umsdos_rlookup_x (dir, dentry_dst, 1);
990 } else {
991 Printk (("hlink2inode /mn/: doing umsdos_lookup_x on %.*s\n", (int) dentry_dst->d_name.len, dentry_dst->d_name.name));
992 ret = umsdos_lookup_x (dir, dentry_dst, 1);
994 Printk ((" returned %d\n", ret));
995 *result = dentry_dst->d_inode; /* /mn/ ok ? */
997 Printk (("h2n lookup :%s: -> %d ", start, ret));
998 if (ret == 0 && *pt != '\0') {
999 dir = *result;
1000 } else {
1001 break;
1004 } else {
1005 Printk (("umsdos_hlink2inode: all those iput's() frighten me /mn/. Whatabout dput() ? FIXME!\n"));
1006 iput (hlink); /* FIXME? */
1008 Printk (("hlink2inode ret = %d %p -> %p\n", ret, hlink, *result));
1009 kfree (path);
1011 return ret;
1015 static struct file_operations umsdos_dir_operations =
1017 NULL, /* lseek - default */
1018 UMSDOS_dir_read, /* read */
1019 NULL, /* write - bad */
1020 UMSDOS_readdir, /* readdir */
1021 NULL, /* poll - default */
1022 UMSDOS_ioctl_dir, /* ioctl - default */
1023 NULL, /* mmap */
1024 NULL, /* no special open code */
1025 NULL, /* flush */
1026 NULL, /* no special release code */
1027 NULL /* fsync *//* in original NULL. changed to file_fsync. FIXME? /mn/ */
1030 struct inode_operations umsdos_dir_inode_operations =
1032 &umsdos_dir_operations, /* default directory file-ops */
1033 UMSDOS_create, /* create */
1034 UMSDOS_lookup, /* lookup */
1035 UMSDOS_link, /* link */
1036 UMSDOS_unlink, /* unlink */
1037 UMSDOS_symlink, /* symlink */
1038 UMSDOS_mkdir, /* mkdir */
1039 UMSDOS_rmdir, /* rmdir */
1040 UMSDOS_mknod, /* mknod */
1041 UMSDOS_rename, /* rename */
1042 NULL, /* readlink */
1043 NULL, /* followlink */
1044 generic_readpage, /* readpage *//* in original NULL. changed to generic_readpage. FIXME? /mn/ */
1045 NULL, /* writepage */
1046 fat_bmap, /* bmap *//* in original NULL. changed to fat_bmap. FIXME? /mn/ */
1047 NULL, /* truncate */
1048 NULL, /* permission */
1049 NULL, /* smap */
1050 NULL, /* updatepage */
1051 NULL, /* revalidate */