File: /usr/src/linux/fs/umsdos/dir.c

1     /*
2      *  linux/fs/umsdos/dir.c
3      *
4      *  Written 1993 by Jacques Gelinas
5      *      Inspired from linux/fs/msdos/... : Werner Almesberger
6      *
7      *  Extended MS-DOS directory handling functions
8      */
9     
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/slab.h>
19     #include <linux/pagemap.h>
20     
21     #define UMSDOS_SPECIAL_DIRFPOS	3
22     extern struct dentry *saved_root;
23     extern struct inode *pseudo_root;
24     
25     /* #define UMSDOS_DEBUG_VERBOSE 1 */
26     
27     /*
28      * Dentry operations routines
29      */
30     
31     /* nothing for now ... */
32     static int umsdos_dentry_validate(struct dentry *dentry, int flags)
33     {
34     	return 1;
35     }
36     
37     /* for now, drop everything to force lookups ... */
38     /* ITYM s/everything/& positive/... */
39     static int umsdos_dentry_dput(struct dentry *dentry)
40     {
41     	struct inode *inode = dentry->d_inode;
42     	if (inode) {
43     		return 1;
44     	}
45     	return 0;
46     }
47     
48     struct dentry_operations umsdos_dentry_operations =
49     {
50     	d_revalidate:	umsdos_dentry_validate,
51     	d_delete:	umsdos_dentry_dput,
52     };
53     
54     struct UMSDOS_DIR_ONCE {
55     	void *dirbuf;
56     	filldir_t filldir;
57     	int count;
58     	int stop;
59     };
60     
61     /*
62      * Record a single entry the first call.
63      * Return -EINVAL the next one.
64      * NOTE: filldir DOES NOT use a dentry
65      */
66     
67     static int umsdos_dir_once (	void *buf,
68     				const char *name,
69     				int len,
70     				loff_t offset,
71     				ino_t ino,
72     				unsigned type)
73     {
74     	int ret = -EINVAL;
75     	struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *) buf;
76     
77     	if (d->count == 0) {
78     		PRINTK ((KERN_DEBUG "dir_once :%.*s: offset %Ld\n", 
79     			len, name, offset));
80     		ret = d->filldir (d->dirbuf, name, len, offset, ino, DT_UNKNOWN);
81     		d->stop = ret < 0;
82     		d->count = 1;
83     	}
84     	return ret;
85     }
86     
87     
88     /*
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).
92      * 
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.
96      */
97      
98     static int umsdos_readdir_x (struct inode *dir, struct file *filp,
99     				void *dirbuf, struct umsdos_dirent *u_entry,
100     				filldir_t filldir)
101     {
102     	struct dentry *demd;
103     	off_t start_fpos;
104     	int ret = 0;
105     	loff_t pos;
106     
107     	umsdos_startlookup (dir);
108     
109     	if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS && dir == pseudo_root) {
110     
111     		/*
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
115     		 */
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.
120     		 */
121     
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) {
125     			filp->f_pos++;
126     		}
127     		goto out_end;
128     	}
129     
130     	if (filp->f_pos < 2 || 
131     	    (dir->i_ino != UMSDOS_ROOT_INO && filp->f_pos == 32)) {
132     	
133     		int last_f_pos = filp->f_pos;
134     		struct UMSDOS_DIR_ONCE bufk;
135     
136     		Printk (("umsdos_readdir_x: . or .. /mn/?\n"));
137     
138     		bufk.dirbuf = dirbuf;
139     		bufk.filldir = filldir;
140     		bufk.count = 0;
141     
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;
145     		if (u_entry != NULL)
146     			u_entry->flags = 0;
147     		goto out_end;
148     	}
149     
150     	Printk (("umsdos_readdir_x: normal file /mn/?\n"));
151     
152     	/* get the EMD dentry */
153     	demd = umsdos_get_emd_dentry(filp->f_dentry);
154     	ret = PTR_ERR(demd);
155     	if (IS_ERR(demd))
156     		goto out_end;
157     	ret = -EIO;
158     	if (!demd->d_inode) {
159     		printk(KERN_WARNING 
160     			"umsdos_readir_x: EMD file %s/%s not found\n",
161     			demd->d_parent->d_name.name, demd->d_name.name);
162     		goto out_dput;
163     	}
164     
165     	pos = filp->f_pos;
166     	start_fpos = filp->f_pos;
167     
168     	if (pos <= UMSDOS_SPECIAL_DIRFPOS + 1)
169     		pos = 0;
170     	ret = 0;
171     	while (pos < demd->d_inode->i_size) {
172     		off_t cur_f_pos = pos;
173     		struct dentry *dret;
174     		struct inode *inode;
175     		struct umsdos_dirent entry;
176     		struct umsdos_info info;
177     
178     		ret = -EIO;
179     		if (umsdos_emd_dir_readentry (demd, &pos, &entry) != 0)
180     			break;
181     		if (entry.name_len == 0)
182     			continue;
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);
187     #endif
188     
189     		umsdos_parse (entry.name, entry.name_len, &info);
190     		info.f_pos = cur_f_pos;
191     		umsdos_manglename (&info);
192     		/*
193     		 * Do a real lookup on the short name.
194     		 */
195     		dret = umsdos_covered(filp->f_dentry, info.fake.fname,
196     						 info.fake.len);
197     		ret = PTR_ERR(dret);
198     		if (IS_ERR(dret))
199     			break;
200     		/*
201     		 * If the file wasn't found, remove it from the EMD.
202     		 */
203     		inode = dret->d_inode;
204     		if (!inode)
205     			goto remove_name;
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);
210     #endif
211     
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,
214     entry.flags));
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);
219     			ret = PTR_ERR(dret);
220     			if (IS_ERR(dret))
221     				break;
222     			inode = dret->d_inode;
223     			if (!inode) {
224     printk("umsdos_readdir_x: %s/%s negative after link\n",
225     dret->d_parent->d_name.name, dret->d_name.name);
226     				goto clean_up;
227     			}
228     		}
229     
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.
236     		 */
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) {
240     				pos = cur_f_pos;
241     			}
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));
244     			if (u_entry != NULL)
245     				*u_entry = entry;
246     			dput(dret);
247     			ret = 0;
248     			break;
249     		}
250     	clean_up:
251     		dput(dret);
252     		continue;
253     
254     	remove_name:
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.
259     		 */
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);
263     #endif
264     		ret = umsdos_delentry(filp->f_dentry, &info, 
265     					S_ISDIR(info.entry.mode));
266     		if (ret)
267     			printk(KERN_WARNING 
268     				"umsdos_readdir_x: delentry %s, err=%d\n",
269     				info.entry.name, ret);
270     		goto clean_up;
271     	}
272     	/*
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.
277     	 */
278     	filp->f_pos = pos;
279     	if (filp->f_pos == 0)
280     		filp->f_pos = start_fpos;
281     out_dput:
282     	dput(demd);
283     
284     out_end:
285     	umsdos_endlookup (dir);
286     	
287     	Printk ((KERN_DEBUG "read dir %p pos %Ld ret %d\n",
288     		dir, filp->f_pos, ret));
289     	return ret;
290     }
291     
292     
293     /*
294      * Read count directory entries from directory filp.
295      * Return a negative value from linux/errno.h.
296      * Return 0 or positive if successful.
297      */
298      
299     static int UMSDOS_readdir (struct file *filp, void *dirbuf, filldir_t filldir)
300     {
301     	struct inode *dir = filp->f_dentry->d_inode;
302     	int ret = 0, count = 0;
303     	struct UMSDOS_DIR_ONCE bufk;
304     
305     	bufk.dirbuf = dirbuf;
306     	bufk.filldir = filldir;
307     	bufk.stop = 0;
308     
309     	Printk (("UMSDOS_readdir in\n"));
310     	while (ret == 0 && bufk.stop == 0) {
311     		struct umsdos_dirent entry;
312     
313     		bufk.count = 0;
314     		ret = umsdos_readdir_x (dir, filp, &bufk, &entry, 
315     					umsdos_dir_once);
316     		if (bufk.count == 0)
317     			break;
318     		count += bufk.count;
319     	}
320     	Printk (("UMSDOS_readdir out %d count %d pos %Ld\n", 
321     		ret, count, filp->f_pos));
322     	return count ? : ret;
323     }
324     
325     
326     /*
327      * Complete the inode content with info from the EMD file.
328      *
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.
332      * 
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.
336      * 
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.
342      * 
343      * 
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.
347      *
348      * Do this only if the inode is freshly read, because we will lose
349      * the current (updated) content.
350      *
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.
354      */
355     
356     void umsdos_lookup_patch_new(struct dentry *dentry, struct umsdos_info *info)
357     {
358     	struct inode *inode = dentry->d_inode;
359     	struct umsdos_dirent *entry = &info->entry;
360     
361     	/*
362     	 * This part of the initialization depends only on i_patched.
363     	 */
364     	if (inode->u.umsdos_i.i_patched)
365     		goto out;
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;
376     
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.
384     	 */
385     	if (!S_ISDIR (entry->mode)) {
386     		if (entry->nlink > 0) {
387     			inode->i_nlink = entry->nlink;
388     		} else {
389     			printk (KERN_ERR 
390     				"UMSDOS:  lookup_patch entry->nlink < 1 ???\n");
391     		}
392     	}
393     	/*
394     	 * The mode may have changed, so patch the inode again.
395     	 */
396     	umsdos_patch_dentry_inode(dentry, info->f_pos);
397     	umsdos_set_dirinfo_new(dentry, info->f_pos);
398     
399     out:
400     	return;
401     }
402     
403     
404     /*
405      * Return != 0 if an entry is the pseudo DOS entry in the pseudo root.
406      */
407     
408     int umsdos_is_pseudodos (struct inode *dir, struct dentry *dentry)
409     {
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
415     	 * for a package.
416     	 */
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';
422     }
423     
424     
425     /*
426      * Check whether a file exists in the current directory.
427      * Return 0 if OK, negative error code if not (ex: -ENOENT).
428      *
429      * fills dentry->d_inode with found inode, and increments its count.
430      * if not found, return -ENOENT.
431      */
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.
440      */
441     
442     struct dentry *umsdos_lookup_x (struct inode *dir, struct dentry *dentry, int nopseudo)
443     {				
444     	struct dentry *dret = NULL;
445     	struct inode *inode;
446     	int ret = -ENOENT;
447     	struct umsdos_info info;
448     
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);
452     #endif
453     
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.
459     		 */
460     		Printk ((KERN_DEBUG "umsdos_lookup_x: following /DOS\n"));
461     		inode = saved_root->d_inode;
462     		goto out_add;
463     	}
464     
465     	ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
466     	if (ret) {
467     printk("umsdos_lookup_x: %s/%s parse failed, ret=%d\n", 
468     dentry->d_parent->d_name.name, dentry->d_name.name, ret);
469     		goto out;
470     	}
471     
472     	ret = umsdos_findentry (dentry->d_parent, &info, 0);
473     	if (ret) {
474     if (ret != -ENOENT)
475     printk("umsdos_lookup_x: %s/%s findentry failed, ret=%d\n", 
476     dentry->d_parent->d_name.name, dentry->d_name.name, ret);
477     		goto out;
478     	}
479     Printk (("lookup %.*s pos %lu ret %d len %d ", 
480     info.fake.len, info.fake.fname, info.f_pos, ret, info.fake.len));
481     
482     	/* do a real lookup to get the short name ... */
483     	dret = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
484     	ret = PTR_ERR(dret);
485     	if (IS_ERR(dret)) {
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);
488     		goto out;
489     	}
490     	inode = dret->d_inode;
491     	if (!inode)
492     		goto out_remove;
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);
497     #endif
498     
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);
503     		ret = PTR_ERR(dret);
504     		if (IS_ERR(dret))
505     			goto out;
506     		ret = -ENOENT;
507     		inode = dret->d_inode;
508     		if (!inode) {
509     printk("umsdos_lookup_x: %s/%s negative after link\n", 
510     dret->d_parent->d_name.name, dret->d_name.name);
511     			goto out_dput;
512     		}
513     	}
514     
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.
519     		 */
520     		/*
521     		 * This has to be allowed for resolving hard links
522     		 * which are recorded independently of the pseudo-root
523     		 * mode.
524     		 */
525     printk("umsdos_lookup_x: skipping DOS/linux\n");
526     		ret = -ENOENT;
527     		goto out_dput;
528     	}
529     
530     	/*
531     	 * We've found it OK.  Now hash the dentry with the inode.
532     	 */
533     out_add:
534     	atomic_inc(&inode->i_count);
535     	d_add (dentry, inode);
536     	dentry->d_op = &umsdos_dentry_operations;
537     	ret = 0;
538     
539     out_dput:
540     	if (dret && dret != dentry)
541     		d_drop(dret);
542     	dput(dret);
543     out:
544     	umsdos_endlookup (dir);
545     	return ERR_PTR(ret);
546     
547     out_remove:
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));
551     	ret = -ENOENT;
552     	goto out_dput;
553     }
554     
555     
556     /*
557      * Check whether a file exists in the current directory.
558      * Return 0 if OK, negative error code if not (ex: -ENOENT).
559      * 
560      * Called by VFS; should fill dentry->d_inode via d_add.
561      */
562     
563     struct dentry *UMSDOS_lookup (struct inode *dir, struct dentry *dentry)
564     {
565     	struct dentry *ret;
566     
567     	ret = umsdos_lookup_x (dir, dentry, 0);
568     
569     	/* Create negative dentry if not found. */
570     	if (ret == ERR_PTR(-ENOENT)) {
571     		Printk ((KERN_DEBUG 
572     			"UMSDOS_lookup: converting -ENOENT to negative\n"));
573     		d_add (dentry, NULL);
574     		dentry->d_op = &umsdos_dentry_operations;
575     		ret = NULL;
576     	}
577     	return ret;
578     }
579     
580     struct dentry *umsdos_covered(struct dentry *parent, char *name, int len)
581     {
582     	struct dentry *result, *dentry;
583     	struct qstr qstr;
584     
585     	qstr.name = name;
586     	qstr.len  = len;
587     	qstr.hash = full_name_hash(name, len);
588     	result = ERR_PTR(-ENOMEM);
589     	dentry = d_alloc(parent, &qstr);
590     	if (dentry) {
591     		/* XXXXXXXXXXXXXXXXXXX Race alert! */
592     		result = UMSDOS_rlookup(parent->d_inode, dentry);
593     		d_drop(dentry);
594     		if (result)
595     			goto out_fail;
596     		return dentry;
597     	}
598     out:
599     	return result;
600     
601     out_fail:
602     	dput(dentry);
603     	goto out;
604     }
605     
606     /*
607      * Lookup or create a dentry from within the filesystem.
608      *
609      * We need to use this instead of lookup_dentry, as the 
610      * directory semaphore lock is already held.
611      */
612     struct dentry *umsdos_lookup_dentry(struct dentry *parent, char *name, int len,
613     					int real)
614     {
615     	struct dentry *result, *dentry;
616     	struct qstr qstr;
617     
618     	qstr.name = name;
619     	qstr.len  = len;
620     	qstr.hash = full_name_hash(name, len);
621     	result = d_lookup(parent, &qstr);
622     	if (!result) {
623     		result = ERR_PTR(-ENOMEM);
624     		dentry = d_alloc(parent, &qstr);
625     		if (dentry) {
626     			result = real ?
627     				UMSDOS_rlookup(parent->d_inode, dentry) :
628     				UMSDOS_lookup(parent->d_inode, dentry);
629     			if (result)
630     				goto out_fail;
631     			return dentry;
632     		}
633     	}
634     out:
635     	return result;
636     
637     out_fail:
638     	dput(dentry);
639     	goto out;
640     }
641     
642     /*
643      * Return a path relative to our root.
644      */
645     char * umsdos_d_path(struct dentry *dentry, char * buffer, int len)
646     {
647     	struct dentry * old_root;
648     	char * path;
649     
650     	read_lock(&current->fs->lock);
651     	old_root = dget(current->fs->root);
652     	read_unlock(&current->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);
656     
657     	if (*path == '/')
658     		path++; /* skip leading '/' */
659     
660     	if (current->fs->root->d_inode == pseudo_root)
661     	{
662     		*(path-1) = '/';
663     		path -= (UMSDOS_PSDROOT_LEN+1);
664     		memcpy(path, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN);
665     	}
666     	dput(old_root);
667     
668     	return path;
669     }
670     
671     /*
672      * Return the dentry which points to a pseudo-hardlink.
673      *
674      * it should try to find file it points to
675      * if file is found, return new dentry/inode
676      * The resolved inode will have i_is_hlink set.
677      *
678      * Note: the original dentry is always dput(), even if an error occurs.
679      */
680     
681     struct dentry *umsdos_solve_hlink (struct dentry *hlink)
682     {
683     	/* root is our root for resolving pseudo-hardlink */
684     	struct dentry *base = hlink->d_sb->s_root;
685     	struct dentry *dentry_dst;
686     	char *path, *pt;
687     	int len;
688     	struct address_space *mapping = hlink->d_inode->i_mapping;
689     	struct page *page;
690     
691     	page=read_cache_page(mapping,0,(filler_t *)mapping->a_ops->readpage,NULL);
692     	dentry_dst=(struct dentry *)page;
693     	if (IS_ERR(page))
694     		goto out;
695     	wait_on_page(page);
696     	if (!Page_Uptodate(page))
697     		goto async_fail;
698     
699     	dentry_dst = ERR_PTR(-ENOMEM);
700     	path = (char *) kmalloc (PATH_MAX, GFP_KERNEL);
701     	if (path == NULL)
702     		goto out_release;
703     	memcpy(path, kmap(page), hlink->d_inode->i_size);
704     	kunmap(page);
705     	page_cache_release(page);
706     
707     	len = hlink->d_inode->i_size;
708     
709     	/* start at root dentry */
710     	dentry_dst = dget(base);
711     	path[len] = '\0';
712     	
713     	pt = path;
714     	if (*path == '/')
715     		pt++; /* skip leading '/' */
716     	
717     	if (base->d_inode == pseudo_root)
718     		pt += (UMSDOS_PSDROOT_LEN + 1);
719     	
720     	while (1) {
721     		struct dentry *dir = dentry_dst, *demd;
722     		char *start = pt;
723     		int real;
724     
725     		while (*pt != '\0' && *pt != '/') pt++;
726     		len = (int) (pt - start);
727     		if (*pt == '/') *pt++ = '\0';
728     
729     		real = 1;
730     		demd = umsdos_get_emd_dentry(dir);
731     		if (!IS_ERR(demd)) {
732     			if (demd->d_inode)
733     				real = 0;
734     			dput(demd);
735     		}
736     
737     #ifdef UMSDOS_DEBUG_VERBOSE
738     printk ("umsdos_solve_hlink: dir %s/%s, name=%s, real=%d\n",
739     dir->d_parent->d_name.name, dir->d_name.name, start, real);
740     #endif
741     		dentry_dst = umsdos_lookup_dentry(dir, start, len, real);
742     /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
743     		if (real)
744     			d_drop(dir);
745     		dput (dir);
746     		if (IS_ERR(dentry_dst))
747     			break;
748     		/* not found? stop search ... */
749     		if (!dentry_dst->d_inode) {
750     			break;
751     		}
752     		if (*pt == '\0')	/* we're finished! */
753     			break;
754     	} /* end while */
755     
756     	if (!IS_ERR(dentry_dst)) {
757     		struct inode *inode = dentry_dst->d_inode;
758     		if (inode) {
759     			inode->u.umsdos_i.i_is_hlink = 1;
760     #ifdef UMSDOS_DEBUG_VERBOSE
761     printk ("umsdos_solve_hlink: resolved link %s/%s, ino=%ld\n",
762     dentry_dst->d_parent->d_name.name, dentry_dst->d_name.name, inode->i_ino);
763     #endif
764     		} else {
765     #ifdef UMSDOS_DEBUG_VERBOSE
766     printk ("umsdos_solve_hlink: resolved link %s/%s negative!\n",
767     dentry_dst->d_parent->d_name.name, dentry_dst->d_name.name);
768     #endif
769     		}
770     	} else
771     		printk(KERN_WARNING
772     			"umsdos_solve_hlink: err=%ld\n", PTR_ERR(dentry_dst));
773     	kfree (path);
774     
775     out:
776     	dput(hlink);	/* original hlink no longer needed */
777     	return dentry_dst;
778     
779     async_fail:
780     	dentry_dst = ERR_PTR(-EIO);
781     out_release:
782     	page_cache_release(page);
783     	goto out;
784     }	
785     
786     
787     struct file_operations umsdos_dir_operations =
788     {
789     	read:		generic_read_dir,
790     	readdir:	UMSDOS_readdir,
791     	ioctl:		UMSDOS_ioctl_dir,
792     };
793     
794     struct inode_operations umsdos_dir_inode_operations =
795     {
796     	create:		UMSDOS_create,
797     	lookup:		UMSDOS_lookup,
798     	link:		UMSDOS_link,
799     	unlink:		UMSDOS_unlink,
800     	symlink:	UMSDOS_symlink,
801     	mkdir:		UMSDOS_mkdir,
802     	rmdir:		UMSDOS_rmdir,
803     	mknod:		UMSDOS_mknod,
804     	rename:		UMSDOS_rename,
805     	setattr:	UMSDOS_notify_change,
806     };
807