patch-2.1.121 linux/fs/umsdos/dir.c
Next file: linux/fs/umsdos/emd.c
Previous file: linux/fs/umsdos/check.c
Back to the patch index
Back to the overall index
- Lines: 1481
- Date:
Wed Sep 9 09:01:20 1998
- Orig file:
v2.1.120/linux/fs/umsdos/dir.c
- Orig date:
Sat Sep 5 16:46:41 1998
diff -u --recursive --new-file v2.1.120/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c
@@ -23,65 +23,41 @@
extern struct inode *pseudo_root;
-/* P.T.Waltenberg
- * I've retained this to facilitate the lookup of some of the hard-wired files/directories UMSDOS
- * uses. It's easier to do once than hack all the other instances. Probably safer as well
- */
-
-/*
- * d_dir is directory to search for file, name&len define the file.
- * compat_umsdos_real_lookup returns dentry pointing to wanted file,
- * or NULL if not found. Calling code is respondible to call fin_dentry (result)
- */
-
-struct dentry *compat_umsdos_real_lookup (struct dentry *d_dir, const char *name, int len)
-{
- int rv;
- struct dentry *dentry;
-
- PRINTK ((KERN_DEBUG "compat_umsdos_real_lookup !!CNTx!!: start\n"));
-
- check_dentry_path (d_dir, "compat_umsdos_real_lookup B4 dir");
- dentry = creat_dentry (name, len, NULL, d_dir);
-
-/* check_dentry_path (dentry, "compat_umsdos_real_lookup B4");*/
-
- rv = umsdos_real_lookup (d_dir->d_inode, dentry);
- check_dentry_path (dentry, "compat_umsdos_real_lookup END");
-
- if (rv) {
- printk (KERN_WARNING "compat_umsdos_real_lookup failed with %d\n", rv);
- return NULL;
- }
-
- PRINTK ((KERN_DEBUG "compat_umsdos_real_lookup !!CNTx!!: end\n"));
-
- if (dentry->d_inode) return dentry; /* all OK */
-
- /* otherwise, we have a negative dentry. return NULL */
- Printk ((KERN_DEBUG "compat_umsdos_real_lookup: negative dentry - file not found\n"));
- fin_dentry (dentry);
- return NULL;
-}
-
-
-int compat_msdos_create (struct inode *dir, const char *name, int len, int mode, struct inode **inode)
+/*
+ * This needs to have the parent dentry passed to it.
+ * N.B. Try to get rid of this soon!
+ */
+int compat_msdos_create (struct inode *dir, const char *name, int len,
+ int mode, struct inode **inode)
{
- int rv;
+ int ret;
struct dentry *dentry, *d_dir;
check_inode (dir);
+ ret = -ENOMEM;
d_dir = geti_dentry (dir);
+ if (!d_dir) {
+printk(KERN_ERR "compat_msdos_create: flaky i_dentry didn't work\n");
+ goto out;
+ }
+ dget(d_dir);
dentry = creat_dentry (name, len, NULL, d_dir);
+ dput(d_dir);
+ if (!dentry)
+ goto out;
+
check_dentry_path (dentry, "compat_msdos_create START");
- rv = msdos_create (dir, dentry, mode);
+ ret = msdos_create (dir, dentry, mode);
check_dentry_path (dentry, "compat_msdos_create END");
+ if (ret)
+ goto out;
if (inode != NULL)
*inode = dentry->d_inode;
check_inode (dir);
- return rv;
+out:
+ return ret;
}
@@ -118,7 +94,8 @@
struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *) buf;
if (d->count == 0) {
- PRINTK ((KERN_DEBUG "dir_once :%.*s: offset %Ld\n", len, name, offset));
+ PRINTK ((KERN_DEBUG "dir_once :%.*s: offset %Ld\n",
+ len, name, offset));
ret = d->filldir (d->dirbuf, name, len, offset, ino);
d->stop = ret < 0;
d->count = 1;
@@ -130,32 +107,29 @@
/*
* Read count directory entries from directory filp
* Return a negative value from linux/errno.h.
- * Return > 0 if success (The amount of byte written by filldir).
+ * Return > 0 if success (the number of bytes written by filldir).
*
* This function is used by the normal readdir VFS entry point and by
* some function who try to find out info on a file from a pure MSDOS
* inode. See umsdos_locate_ancestor() below.
*/
-static int umsdos_readdir_x ( struct inode *dir, /* Point to a description of the super block */
- struct file *filp, /* Point to a directory which is read */
- void *dirbuf, /* Will hold count directory entry */
- /* but filled by the filldir function */
- int internal_read, /* Called for internal purpose */
- struct umsdos_dirent *u_entry, /* Optional umsdos entry */
- int follow_hlink,
- filldir_t filldir)
+static int umsdos_readdir_x (struct inode *dir, struct file *filp,
+ void *dirbuf, int internal_read,
+ struct umsdos_dirent *u_entry,
+ int follow_hlink, filldir_t filldir)
{
+ struct dentry *demd;
+ off_t start_fpos;
int ret = 0;
- struct dentry *old_dent;
+ struct file new_filp;
umsdos_startlookup (dir);
- if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS
- && pseudo_root
- && dir == pseudo_root
- && !internal_read) {
- Printk (("umsdos_readdir_x: what UMSDOS_SPECIAL_DIRFPOS /mn/?\n"));
+ if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS &&
+ dir == pseudo_root && !internal_read) {
+
+Printk (("umsdos_readdir_x: what UMSDOS_SPECIAL_DIRFPOS /mn/?\n"));
/*
* We don't need to simulate this pseudo directory
* when umsdos_readdir_x is called for internal operation
@@ -166,55 +140,16 @@
* linux root), it simulate a directory /DOS which points to
* the real root of the file system.
*/
- if (filldir (dirbuf, "DOS", 3, UMSDOS_SPECIAL_DIRFPOS, UMSDOS_ROOT_INO) == 0) {
+ if (filldir (dirbuf, "DOS", 3,
+ UMSDOS_SPECIAL_DIRFPOS, UMSDOS_ROOT_INO) == 0) {
filp->f_pos++;
}
- } else if (filp->f_pos < 2 || (dir->i_ino != UMSDOS_ROOT_INO && filp->f_pos == 32)) {
-
- /* FIXME: that was in 2.0.x: else if (filp->f_pos < 2 || (dir != dir->i_sb->s_mounted && filp->f_pos == 32))
- * I'm probably screwing up pseudo-root and stuff with this. It needs proper fix.
- */
-
+ goto out_end;
+ }
+
+ if (filp->f_pos < 2 ||
+ (dir->i_ino != UMSDOS_ROOT_INO && filp->f_pos == 32)) {
- /* #Specification: readdir / . and ..
- * The msdos filesystem manages the . and .. entry properly
- * so the EMD file won't hold any info about it.
- *
- * In readdir, we assume that for the root directory
- * the read position will be 0 for ".", 1 for "..". For
- * a non root directory, the read position will be 0 for "."
- * and 32 for "..".
- */
- /*
- * This is a trick used by the msdos file system (fs/msdos/dir.c)
- * to manage . and .. for the root directory of a file system.
- * Since there is no such entry in the root, fs/msdos/dir.c
- * use the following:
- *
- * if f_pos == 0, return ".".
- * if f_pos == 1, return "..".
- *
- * So let msdos handle it
- *
- * Since umsdos entries are much larger, we share the same f_pos.
- * if f_pos is 0 or 1 or 32, we are clearly looking at . and
- * ..
- *
- * As soon as we get f_pos == 2 or f_pos == 64, then back to
- * 0, but this time we are reading the EMD file.
- *
- * Well, not so true. The problem, is that UMSDOS_REC_SIZE is
- * also 64, so as soon as we read the first record in the
- * EMD, we are back at offset 64. So we set the offset
- * to UMSDOS_SPECIAL_DIRFPOS(3) as soon as we have read the
- * .. entry from msdos.
- *
- * Now (linux 1.3), umsdos_readdir can read more than one
- * entry even if we limit (umsdos_dir_once) to only one:
- * It skips over hidden file. So we switch to
- * UMSDOS_SPECIAL_DIRFPOS as soon as we have read successfully
- * the .. entry.
- */
int last_f_pos = filp->f_pos;
struct UMSDOS_DIR_ONCE bufk;
@@ -229,112 +164,113 @@
filp->f_pos = UMSDOS_SPECIAL_DIRFPOS;
if (u_entry != NULL)
u_entry->flags = 0;
- } else {
- Printk (("umsdos_readdir_x: normal file /mn/?\n"));
- old_dent = filp->f_dentry; /* save dentry of directory */
+ goto out_end;
+ }
- if (fix_emd_filp (filp) == 0) {
- off_t start_fpos = filp->f_pos;
+ Printk (("umsdos_readdir_x: normal file /mn/?\n"));
- Printk (("umsdos_readdir_x: emd_dir->i_ino=%ld\n", filp->f_dentry->d_inode->i_ino));
- if (filp->f_pos <= UMSDOS_SPECIAL_DIRFPOS + 1)
- filp->f_pos = 0;
- Printk (("f_pos %Ld i_size %ld\n", filp->f_pos, filp->f_dentry->d_inode->i_size));
- ret = 0;
- while (filp->f_pos < filp->f_dentry->d_inode->i_size) {
- struct umsdos_dirent entry;
- off_t cur_f_pos = filp->f_pos;
-
- if (umsdos_emd_dir_readentry (filp, &entry) != 0) {
- ret = -EIO;
- break;
- } else if (entry.name_len != 0) {
- /* #Specification: umsdos / readdir
- * umsdos_readdir() should fill a struct dirent with
- * an inode number. The cheap way to get it is to
- * do a lookup in the MSDOS directory for each
- * entry processed by the readdir() function.
- * This is not very efficient, but very simple. The
- * other way around is to maintain a copy of the inode
- * number in the EMD file. This is a problem because
- * this has to be maintained in sync using tricks.
- * Remember that MSDOS (the OS) does not update the
- * modification time (mtime) of a directory. There is
- * no easy way to tell that a directory was modified
- * during a DOS session and synchronise the EMD file.
- *
- * Suggestion welcome.
- *
- * So the easy way is used!
- */
- struct umsdos_info info;
- struct dentry *d_dir, *dret;
-
- umsdos_parse (entry.name, entry.name_len, &info);
- info.f_pos = cur_f_pos;
- umsdos_manglename (&info);
- d_dir = geti_dentry (dir);
- dret = compat_umsdos_real_lookup (d_dir, info.fake.fname, info.fake.len);
-
- Printk (("Looking for inode of %s dret %p flags %d\n", info.fake.fname, dret, entry.flags));
- if (dret && !IS_ERR(dret)
- && (entry.flags & UMSDOS_HLINK)
- && follow_hlink) {
- dret = umsdos_solve_hlink (dret);
- }
+ /* get the EMD dentry */
+ demd = umsdos_get_emd_dentry(filp->f_dentry);
+ ret = PTR_ERR(demd);
+ if (IS_ERR(demd))
+ goto out_end;
+ ret = 0;
+ if (!demd->d_inode)
+ goto out_dput;
+
+ /* set up our private filp ... */
+ fill_new_filp(&new_filp, demd);
+ new_filp.f_pos = filp->f_pos;
+ start_fpos = filp->f_pos;
+
+ if (new_filp.f_pos <= UMSDOS_SPECIAL_DIRFPOS + 1)
+ new_filp.f_pos = 0;
+Printk (("f_pos %Ld i_size %ld\n", new_filp.f_pos, demd->d_inode->i_size));
+ ret = 0;
+ while (new_filp.f_pos < demd->d_inode->i_size) {
+ off_t cur_f_pos = new_filp.f_pos;
+ struct umsdos_info info;
+ struct dentry *dret;
+ struct umsdos_dirent entry;
+
+ ret = -EIO;
+ if (umsdos_emd_dir_readentry (&new_filp, &entry) != 0)
+ break;
+
+ if (entry.name_len == 0)
+ goto remove_name;
+
+ umsdos_parse (entry.name, entry.name_len, &info);
+ info.f_pos = cur_f_pos;
+ umsdos_manglename (&info);
+ dret = umsdos_lookup_dentry(filp->f_dentry, info.fake.fname,
+ info.fake.len);
+ ret = PTR_ERR(dret);
+ if (IS_ERR(dret))
+ break;
+
+Printk (("Looking for inode of %s/%s, flags=%x\n",
+dret->d_parent->d_name.name, info.fake.fname, entry.flags));
+ if ((entry.flags & UMSDOS_HLINK) && follow_hlink) {
+ dret = umsdos_solve_hlink (dret);
+ ret = PTR_ERR(dret);
+ if (IS_ERR(dret))
+ break;
+ }
- if (dret && !IS_ERR(dret)) {
- /* #Specification: pseudo root / reading real root
- * The pseudo root (/linux) is logically
- * erased from the real root. This means that
- * ls /DOS, won't show "linux". This avoids
- * infinite recursion (/DOS/linux/DOS/linux/...) while
- * walking the file system.
- */
- if (dret->d_inode != pseudo_root
- && (internal_read || !(entry.flags & UMSDOS_HIDDEN))) {
- Printk ((KERN_DEBUG "filldir now\n"));
- if (filldir (dirbuf, entry.name, entry.name_len, cur_f_pos, dret->d_inode->i_ino) < 0) {
- filp->f_pos = cur_f_pos;
- }
- Printk (("Found ino %ld ", dret->d_inode->i_ino));
- if (u_entry != NULL)
- *u_entry = entry;
- fin_dentry (dret);
- break;
- }
- fin_dentry (dret);
- } else {
- /* #Specification: umsdos / readdir / not in MSDOS
- * During a readdir operation, if the file is not
- * in the MS-DOS directory any more, the entry is
- * removed from the EMD file silently.
- */
- Printk (("'Silently' removing EMD for file\n"));
- ret = umsdos_writeentry (dir, filp->f_dentry->d_inode, &info, 1);
- if (ret != 0) {
- break;
- }
- }
- }
+ /* #Specification: pseudo root / reading real root
+ * The pseudo root (/linux) is logically
+ * erased from the real root. This means that
+ * ls /DOS, won't show "linux". This avoids
+ * infinite recursion (/DOS/linux/DOS/linux/...) while
+ * walking the file system.
+ */
+ if (dret->d_inode != pseudo_root &&
+ (internal_read || !(entry.flags & UMSDOS_HIDDEN))) {
+ Printk ((KERN_DEBUG "filldir now\n"));
+ if (filldir (dirbuf, entry.name, entry.name_len,
+ cur_f_pos, dret->d_inode->i_ino) < 0) {
+ new_filp.f_pos = cur_f_pos;
}
- /*
- * If the fillbuf has failed, f_pos is back to 0.
- * To avoid getting back into the . and .. state
- * (see comments at the beginning), we put back
- * the special offset.
- */
- if (filp->f_pos == 0)
- filp->f_pos = start_fpos;
- Printk ((KERN_DEBUG "dir.c: putting emd_dir %lu with i_count=%d\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_count));
-
- fin_dentry (filp->f_dentry);
- filp->f_dentry = old_dent; /* restore dentry of directory */
+Printk (("Found %s/%s(%ld)\n",
+dret->d_parent->d_name.name, dret->d_name.name, dret->d_inode->i_ino));
+ if (u_entry != NULL)
+ *u_entry = entry;
+ dput(dret);
+ break;
}
+ dput(dret);
+ continue;
+
+ remove_name:
+ /* #Specification: umsdos / readdir / not in MSDOS
+ * During a readdir operation, if the file is not
+ * in the MS-DOS directory any more, the entry is
+ * removed from the EMD file silently.
+ */
+ Printk (("'Silently' removing EMD for file\n"));
+ ret = umsdos_delentry(filp->f_dentry, &info, 1);
+ if (ret)
+ break;
+ continue;
}
+ /*
+ * If the fillbuf has failed, f_pos is back to 0.
+ * To avoid getting back into the . and .. state
+ * (see comments at the beginning), we put back
+ * the special offset.
+ */
+ filp->f_pos = new_filp.f_pos;
+ if (filp->f_pos == 0)
+ filp->f_pos = start_fpos;
+out_dput:
+ dput(demd);
+
+out_end:
umsdos_endlookup (dir);
- Printk ((KERN_DEBUG "read dir %p pos %Ld ret %d\n", dir, filp->f_pos, ret));
+ Printk ((KERN_DEBUG "read dir %p pos %Ld ret %d\n",
+ dir, filp->f_pos, ret));
return ret;
}
@@ -345,13 +281,10 @@
* Return 0 or positive if successful.
*/
-static int UMSDOS_readdir ( struct file *filp, /* Point to a directory which is read. */
- void *dirbuf, /* Will hold directory entries */
- filldir_t filldir)
+static int UMSDOS_readdir (struct file *filp, void *dirbuf, filldir_t filldir)
{
struct inode *dir = filp->f_dentry->d_inode;
- int ret = 0;
- int count = 0;
+ int ret = 0, count = 0;
struct UMSDOS_DIR_ONCE bufk;
bufk.dirbuf = dirbuf;
@@ -363,148 +296,112 @@
struct umsdos_dirent entry;
bufk.count = 0;
- PRINTK (("UMSDOS_readdir: calling _x (%p,%p,%p,%d,%p,%d,%p)\n", dir, filp, &bufk, 0, &entry, 1, umsdos_dir_once));
- ret = umsdos_readdir_x (dir, filp, &bufk, 0, &entry, 1, umsdos_dir_once);
+ PRINTK (("UMSDOS_readdir: calling _x (%p,%p,%p,%d,%p,%d,%p)\n",
+ dir, filp, &bufk, 0, &entry, 1, umsdos_dir_once));
+ ret = umsdos_readdir_x (dir, filp, &bufk, 0, &entry, 1,
+ umsdos_dir_once);
if (bufk.count == 0)
break;
count += bufk.count;
}
- /* FIXME: do we first need to deallocate old dentry ? look/check. see also all other instances of fix_emd_filp */
- Printk (("UMSDOS_readdir out %d count %d pos %Ld\n", ret, count, filp->f_pos));
+ Printk (("UMSDOS_readdir out %d count %d pos %Ld\n",
+ ret, count, filp->f_pos));
return count ? : ret;
}
/*
* Complete the inode content with info from the EMD file.
- */
-
-void umsdos_lookup_patch ( struct inode *dir,
- struct inode *inode,
- struct umsdos_dirent *entry,
- off_t emd_pos)
-{
- /*
- * This function modifies the state of a dir inode. It decides
- * whether the dir is a UMSDOS or DOS directory. This is done
- * deeper in umsdos_patch_inode() called at the end of this function.
- *
- * Because it is does disk access, umsdos_patch_inode() may block.
- * At the same time, another process may get here to initialise
- * the same directory inode. There are three cases.
- *
- * 1) The inode is already initialised. We do nothing.
- * 2) The inode is not initialised. We lock access and do it.
- * 3) Like 2 but another process has locked the inode, so we try
- * to lock it and check right afterward check whether
- * initialisation is still needed.
- *
- *
- * Thanks to the "mem" option of the kernel command line, it was
- * possible to consistently reproduce this problem by limiting
- * my memory to 4 MB and running X.
- */
- /*
- * Do this only if the inode is freshly read, because we will lose
- * the current (updated) content.
- */
- /*
- * A lookup of a mount point directory yield the inode into
- * the other fs, so we don't care about initialising it. iget()
- * does this automatically.
+ *
+ * This function modifies the state of a dir inode. It decides
+ * whether the dir is a UMSDOS or DOS directory. This is done
+ * deeper in umsdos_patch_inode() called at the end of this function.
+ *
+ * Because it is does disk access, umsdos_patch_inode() may block.
+ * At the same time, another process may get here to initialise
+ * the same directory inode. There are three cases.
+ *
+ * 1) The inode is already initialised. We do nothing.
+ * 2) The inode is not initialised. We lock access and do it.
+ * 3) Like 2 but another process has locked the inode, so we try
+ * to lock it and check right afterward check whether
+ * initialisation is still needed.
+ *
+ *
+ * Thanks to the "mem" option of the kernel command line, it was
+ * possible to consistently reproduce this problem by limiting
+ * my memory to 4 MB and running X.
+ *
+ * Do this only if the inode is freshly read, because we will lose
+ * the current (updated) content.
+ *
+ * A lookup of a mount point directory yield the inode into
+ * the other fs, so we don't care about initialising it. iget()
+ * does this automatically.
+ */
+
+void umsdos_lookup_patch (struct inode *dir, struct inode *inode,
+ struct umsdos_dirent *entry, off_t emd_pos)
+{
+ if (inode->i_sb != dir->i_sb)
+ goto out;
+ if (umsdos_isinit (inode))
+ goto out;
+
+ if (S_ISDIR (inode->i_mode))
+ umsdos_lockcreate (inode);
+ if (umsdos_isinit (inode))
+ goto out_unlock;
+
+ if (S_ISREG (entry->mode))
+ entry->mtime = inode->i_mtime;
+ inode->i_mode = entry->mode;
+ inode->i_rdev = to_kdev_t (entry->rdev);
+ inode->i_atime = entry->atime;
+ inode->i_ctime = entry->ctime;
+ inode->i_mtime = entry->mtime;
+ inode->i_uid = entry->uid;
+ inode->i_gid = entry->gid;
+
+ MSDOS_I (inode)->i_binary = 1;
+ /* #Specification: umsdos / i_nlink
+ * The nlink field of an inode is maintained by the MSDOS file system
+ * for directory and by UMSDOS for other files. The logic is that
+ * MSDOS is already figuring out what to do for directories and
+ * does nothing for other files. For MSDOS, there are no hard links
+ * so all file carry nlink==1. UMSDOS use some info in the
+ * EMD file to plug the correct value.
*/
-
- if (inode->i_sb == dir->i_sb && !umsdos_isinit (inode)) {
- if (S_ISDIR (inode->i_mode))
- umsdos_lockcreate (inode);
- if (!umsdos_isinit (inode)) {
- /* #Specification: umsdos / lookup / inode info
- * After successfully reading an inode from the MSDOS
- * filesystem, we use the EMD file to complete it.
- * We update the following field.
- *
- * uid, gid, atime, ctime, mtime, mode.
- *
- * We rely on MSDOS for mtime. If the file
- * was modified during an MSDOS session, at least
- * mtime will be meaningful. We do this only for regular
- * file.
- *
- * We don't rely on MS-DOS for mtime for directories
- * because the MS-DOS date on a directory is its
- * creation time (strange MSDOS behavior) which
- * corresponds to none of the three Unix time stamps.
- */
- if (S_ISREG (entry->mode))
- entry->mtime = inode->i_mtime;
- inode->i_mode = entry->mode;
- inode->i_rdev = to_kdev_t (entry->rdev);
- inode->i_atime = entry->atime;
- inode->i_ctime = entry->ctime;
- inode->i_mtime = entry->mtime;
- inode->i_uid = entry->uid;
- inode->i_gid = entry->gid;
- /* #Specification: umsdos / conversion mode
- * The msdos filesystem can do some inline conversion
- * of the data of a file. It can translate silently
- * from the MS-DOS text file format to the Unix one
- * (CRLF -> LF) while reading, and the reverse
- * while writing. This is activated using the mount
- * option conv=....
- *
- * This is not useful for Linux files in a promoted
- * directory. It can even be harmful. For this
- * reason, the binary (no conversion) mode is
- * always activated.
- */
- /* #Specification: umsdos / conversion mode / todo
- * A flag could be added to file and directories
- * forcing an automatic conversion mode (as
- * done with the msdos filesystem).
- *
- * This flag could be setup on a directory basis
- * (instead of file) and all files in it would
- * logically inherit it. If the conversion mode
- * is active (conv=) then the i_binary flag would
- * be left untouched in those directories.
- *
- * It was proposed that the sticky bit be used to set
- * this. A problem with that is that new files would
- * be written incorrectly. The other problem is that
- * the sticky bit has a meaning for directories. So
- * another bit should be used (there is some space
- * in the EMD file for it) and a special utility
- * would be used to assign the flag to a directory).
- * I don't think it is useful to assign this flag
- * on a single file.
- */
-
- MSDOS_I (inode)->i_binary = 1;
- /* #Specification: umsdos / i_nlink
- * The nlink field of an inode is maintained by the MSDOS file system
- * for directory and by UMSDOS for other files. The logic is that
- * MSDOS is already figuring out what to do for directories and
- * does nothing for other files. For MSDOS, there are no hard links
- * so all file carry nlink==1. UMSDOS use some info in the
- * EMD file to plug the correct value.
- */
- if (!S_ISDIR (entry->mode)) {
- if (entry->nlink > 0) {
- inode->i_nlink = entry->nlink;
- } else {
- printk (KERN_ERR "UMSDOS: lookup_patch entry->nlink < 1 ???\n");
- }
- }
- umsdos_patch_inode (inode, dir, emd_pos);
+ if (!S_ISDIR (entry->mode)) {
+ if (entry->nlink > 0) {
+ inode->i_nlink = entry->nlink;
+ } else {
+ printk (KERN_ERR
+ "UMSDOS: lookup_patch entry->nlink < 1 ???\n");
}
- if (S_ISDIR (inode->i_mode))
- umsdos_unlockcreate (inode);
- if (inode->u.umsdos_i.i_emd_owner == 0)
- printk (KERN_WARNING "UMSDOS: emd_owner still 0?\n");
}
+ umsdos_patch_inode (inode, dir, emd_pos);
+
+out_unlock:
+ if (S_ISDIR (inode->i_mode))
+ umsdos_unlockcreate (inode);
+ if (inode->u.umsdos_i.i_emd_owner == 0)
+ printk (KERN_WARNING "UMSDOS: emd_owner still 0?\n");
+out:
+ return;
}
+/*
+ * The preferred interface to the above routine ...
+ */
+void umsdos_lookup_patch_new(struct dentry *dentry, struct umsdos_dirent *entry,
+ off_t emd_pos)
+{
+ umsdos_lookup_patch(dentry->d_parent->d_inode, dentry->d_inode, entry,
+ emd_pos);
+}
+
struct UMSDOS_DIRENT_K {
off_t f_pos; /* will hold the offset of the entry in EMD */
@@ -557,18 +454,21 @@
/*
- * Locate entry of an inode in a directory.
+ * Locate the directory entry for a dentry in its parent directory.
* Return 0 or a negative error code.
*
* Normally, this function must succeed. It means a strange corruption
* in the file system if not.
*/
-int umsdos_inode2entry ( struct inode *dir,
- struct inode *inode,
- struct umsdos_dirent *entry) /* Will hold the entry */
+int umsdos_dentry_to_entry(struct dentry *dentry, struct umsdos_dirent *entry)
{
- int ret = -ENOENT;
+ struct dentry *parent = dentry->d_parent;
+ struct inode *inode = dentry->d_inode;
+ int ret = -ENOENT, err;
+ struct file filp;
+ struct UMSDOS_DIR_SEARCH bufsrch;
+ struct UMSDOS_DIRENT_K bufk;
if (pseudo_root && inode == pseudo_root) {
/*
@@ -578,155 +478,115 @@
memcpy (entry->name, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN + 1);
entry->name_len = UMSDOS_PSDROOT_LEN;
ret = 0;
- } else {
- struct inode *emddir = umsdos_emd_dir_lookup (dir, 0);
+ goto out;
+ }
- /* iput (emddir); / * FIXME? */
- if (emddir == NULL) {
- /* This is a DOS directory. */
- struct UMSDOS_DIR_SEARCH bufk;
- struct file filp;
- struct dentry *i2e;
-
- i2e = creat_dentry ("@i2e.nul@", 9, dir, NULL);
-
- fill_new_filp (&filp, i2e);
-
- Printk ((KERN_ERR "umsdos_inode2entry emddir==NULL: WARNING: Known filp problem. segfaulting :) fixed ?/mn/\n"));
- filp.f_reada = 1;
- filp.f_pos = 0;
- bufk.entry = entry;
- bufk.search_ino = inode->i_ino;
- fat_readdir (&filp, &bufk, umsdos_dir_search);
- if (bufk.found) {
- ret = 0;
- inode->u.umsdos_i.i_dir_owner = dir->i_ino;
- inode->u.umsdos_i.i_emd_owner = 0;
- umsdos_setup_dir_inode (inode);
- }
- } else {
- /* skip . and .. see umsdos_readdir_x() */
- struct file filp;
- struct dentry *i2e;
-
- i2e = creat_dentry ("@i2e.nn@", 8, dir, NULL);
- fill_new_filp (&filp, i2e);
-
- filp.f_reada = 1;
- filp.f_pos = UMSDOS_SPECIAL_DIRFPOS;
- Printk ((KERN_ERR "umsdos_inode2entry skip...: WARNING: Known filp problem. segfaulting :) fixed ?/mn/\n"));
- while (1) {
- struct UMSDOS_DIRENT_K bufk;
- struct dentry *old_dent;
-
- old_dent = filp.f_dentry;
- if (umsdos_readdir_x (dir, &filp, &bufk, 1, entry, 0, umsdos_filldir_k) < 0) {
- printk ("UMSDOS: can't locate inode %ld in EMD file???\n", inode->i_ino);
- break;
- } else if (bufk.ino == inode->i_ino) {
- ret = 0;
- filp.f_dentry = old_dent;
- umsdos_lookup_patch (dir, inode, entry, bufk.f_pos);
- break;
- }
- }
+ /* initialize the file */
+ fill_new_filp (&filp, parent);
+
+ if (!umsdos_have_emd(parent)) {
+ /* This is a DOS directory. */
+ filp.f_pos = 0;
+ bufsrch.entry = entry;
+ bufsrch.search_ino = inode->i_ino;
+ fat_readdir (&filp, &bufsrch, umsdos_dir_search);
+ if (bufsrch.found) {
+ ret = 0;
+ inode->u.umsdos_i.i_dir_owner = parent->d_inode->i_ino;
+ inode->u.umsdos_i.i_emd_owner = 0;
+if (!S_ISDIR(inode->i_mode))
+printk("UMSDOS: %s/%s not a directory!\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+ /* N.B. why call this? not always a dir ... */
+ umsdos_setup_dir(dentry);
+ }
+ goto out;
+ }
+
+ /* skip . and .. see umsdos_readdir_x() */
+ filp.f_pos = UMSDOS_SPECIAL_DIRFPOS;
+ while (1) {
+ err = umsdos_readdir_x (parent->d_inode, &filp, &bufk, 1,
+ entry, 0, umsdos_filldir_k);
+ if (err < 0) {
+ printk ("UMSDOS: can't locate inode %ld in EMD??\n",
+ inode->i_ino);
+ break;
+ }
+ if (bufk.ino == inode->i_ino) {
+ ret = 0;
+ umsdos_lookup_patch_new(dentry, entry, bufk.f_pos);
+ break;
}
}
+out:
return ret;
}
-
/*
- * Locate the parent of a directory and the info on that directory
- * Return 0 or a negative error code.
+ * Deprecated. Try to get rid of this soon!
*/
-
-static int umsdos_locate_ancestor ( struct inode *dir,
- struct inode **result,
- struct umsdos_dirent *entry)
+int umsdos_inode2entry (struct inode *dir, struct inode *inode,
+ struct umsdos_dirent *entry)
{
- int ret=-99;
- struct dentry *dret, *d_dir = creat_dentry ("@d_dir2@", 7, dir, NULL);
-
- umsdos_patch_inode (dir, NULL, 0);
- /* FIXME */
- dret = compat_umsdos_real_lookup (d_dir, "..", 2);
- Printk (("result %p %p ", dret, *result));
- if (dret) {
- struct inode *adir;
- *result = dret->d_inode;
- adir = *result;
+ int ret = -ENOENT;
+ struct inode *emddir;
+ struct dentry *i2e;
+ struct file filp;
+ struct UMSDOS_DIR_SEARCH bufsrch;
+ struct UMSDOS_DIRENT_K bufk;
- ret = umsdos_inode2entry (adir, dir, entry);
- fin_dentry (dret);
+ if (pseudo_root && inode == pseudo_root) {
+ /*
+ * Quick way to find the name.
+ * Also umsdos_readdir_x won't show /linux anyway
+ */
+ memcpy (entry->name, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN + 1);
+ entry->name_len = UMSDOS_PSDROOT_LEN;
+ ret = 0;
+ goto out;
}
- Printk (("\n"));
- return ret;
-}
-
-
-/*
- * Build the path name of an inode (relative to the file system.
- * This function is need to set (pseudo) hard link.
- *
- * It uses the same strategy as the standard getcwd().
- */
-int umsdos_locate_path ( struct inode *inode,
- char *path)
-{
- int ret = 0;
- struct inode *dir = inode;
- struct inode *root_inode;
- char *bpath = (char *) kmalloc (PATH_MAX, GFP_KERNEL);
+ emddir = umsdos_emd_dir_lookup (dir, 0);
+ if (emddir == NULL) {
+ /* This is a DOS directory. */
+ i2e = creat_dentry ("@i2e.nul@", 9, dir, NULL);
+ fill_new_filp (&filp, i2e);
+ filp.f_reada = 1;
+ filp.f_pos = 0;
+ bufsrch.entry = entry;
+ bufsrch.search_ino = inode->i_ino;
+ fat_readdir (&filp, &bufsrch, umsdos_dir_search);
+ if (bufsrch.found) {
+ ret = 0;
+ inode->u.umsdos_i.i_dir_owner = dir->i_ino;
+ inode->u.umsdos_i.i_emd_owner = 0;
+ umsdos_setup_dir_inode (inode);
+ }
+ goto out;
+ }
- root_inode = iget (inode->i_sb, UMSDOS_ROOT_INO);
- if (bpath == NULL) {
- ret = -ENOMEM;
- } else {
- struct umsdos_dirent entry;
- char *ptbpath = bpath + PATH_MAX - 1;
+ /* skip . and .. see umsdos_readdir_x() */
- *ptbpath = '\0';
- Printk (("locate_path mode %x ", inode->i_mode));
- if (!S_ISDIR (inode->i_mode)) {
- ret = umsdos_get_dirowner (inode, &dir);
- Printk (("locate_path ret %d ", ret));
- if (ret == 0) {
- ret = umsdos_inode2entry (dir, inode, &entry);
- if (ret == 0) {
- ptbpath -= entry.name_len;
- memcpy (ptbpath, entry.name, entry.name_len);
- Printk (("ptbpath :%.*s: ", entry.name_len, ptbpath));
- }
- }
- } else {
- inc_count (dir);
+ i2e = creat_dentry ("@i2e.nn@", 8, dir, NULL);
+ fill_new_filp (&filp, i2e);
+ filp.f_reada = 1;
+ filp.f_pos = UMSDOS_SPECIAL_DIRFPOS;
+ while (1) {
+ if (umsdos_readdir_x (dir, &filp, &bufk, 1,
+ entry, 0, umsdos_filldir_k) < 0) {
+ printk ("UMSDOS: can't locate inode %ld in EMD??\n",
+ inode->i_ino);
+ break;
}
- if (ret == 0) {
- while (dir != root_inode) {
- struct inode *adir;
-
- ret = umsdos_locate_ancestor (dir, &adir, &entry);
- /* iput (dir); FIXME */
- dir = NULL;
- Printk (("ancestor %d ", ret));
- if (ret == 0) {
- *--ptbpath = '/';
- ptbpath -= entry.name_len;
- memcpy (ptbpath, entry.name, entry.name_len);
- dir = adir;
- Printk (("ptbpath :%.*s: ", entry.name_len, ptbpath));
- } else {
- break;
- }
- }
+ if (bufk.ino == inode->i_ino) {
+ ret = 0;
+ umsdos_lookup_patch (dir, inode, entry, bufk.f_pos);
+ break;
}
- strcpy (path, ptbpath);
- kfree (bpath);
}
- Printk (("\n"));
- /* iput (dir); / * FIXME?? */
+ iput (emddir);
+out:
return ret;
}
@@ -735,8 +595,7 @@
* Return != 0 if an entry is the pseudo DOS entry in the pseudo root.
*/
-int umsdos_is_pseudodos ( struct inode *dir,
- struct dentry *dentry)
+int umsdos_is_pseudodos (struct inode *dir, struct dentry *dentry)
{
/* #Specification: pseudo root / DOS hard coded
* The pseudo sub-directory DOS in the pseudo root is hard coded.
@@ -745,8 +604,7 @@
* a reserved path and nobody will think of using such a path
* for a package.
*/
- return pseudo_root
- && dir == pseudo_root
+ return dir == pseudo_root
&& dentry->d_name.len == 3
&& dentry->d_name.name[0] == 'D'
&& dentry->d_name.name[1] == 'O'
@@ -755,150 +613,126 @@
/*
- * Check if a file exists in the current directory.
+ * Check whether a file exists in the current directory.
* Return 0 if OK, negative error code if not (ex: -ENOENT).
*
* fills dentry->d_inode with found inode, and increments its count.
* if not found, return -ENOENT.
*/
+/* #Specification: umsdos / lookup
+ * A lookup for a file is done in two steps. First, we
+ * locate the file in the EMD file. If not present, we
+ * return an error code (-ENOENT). If it is there, we
+ * repeat the operation on the msdos file system. If
+ * this fails, it means that the file system is not in
+ * sync with the EMD file. We silently remove this
+ * entry from the EMD file, and return ENOENT.
+ */
-int umsdos_lookup_x ( struct inode *dir,
- struct dentry *dentry,
- int nopseudo) /* Don't care about pseudo root mode */
+int umsdos_lookup_x (struct inode *dir, struct dentry *dentry, int nopseudo)
{
- int ret = -ENOENT;
- struct inode *root_inode;
- int len = dentry->d_name.len;
const char *name = dentry->d_name.name;
-
-
-#if UMS_DEBUG
- 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 */
- if (dentry->d_parent)
- Printk ((KERN_DEBUG " d_parent is %.*s\n", (int) dentry->d_parent->d_name.len, dentry->d_parent->d_name.name)); /* FIXME : delme /mn/ */
-#endif
-
- root_inode = iget (dir->i_sb, UMSDOS_ROOT_INO);
- Printk ((KERN_ERR "umsdos_lookup_x (CNT!): entering root_count+1=%d, dir %lu _count=%d\n", root_inode->i_count, dir->i_ino, dir->i_count)); /* FIXME: DEBUG, DELME */
+ int len = dentry->d_name.len;
+ struct dentry *dret = NULL;
+ struct inode *inode;
+ int ret = -ENOENT;
+ struct umsdos_info info;
- dentry->d_inode = NULL;
umsdos_startlookup (dir);
+ /* this shouldn't happen ... */
if (len == 1 && name[0] == '.') {
- d_add (dentry, dir);
- inc_count (dir);
- ret = 0;
- } else if (len == 2 && name[0] == '.' && name[1] == '.') {
- if (pseudo_root && dir == pseudo_root) {
- /* #Specification: pseudo root / .. in real root
- * Whenever a lookup is those in the real root for
- * the directory .., and pseudo root is active, the
- * pseudo root is returned.
- */
- ret = 0;
- d_add (dentry, pseudo_root);
- inc_count (pseudo_root);
- } else {
- /* #Specification: locating .. / strategy
- * We use the msdos filesystem to locate the parent directory,
- * but it is more complicated than that:
- *
- * we have to step back even further to
- * get the parent of the parent, so we can get the EMD
- * of the parent of the parent. Using the EMD file, we
- * can locate all the info on the parent, such as
- * permissions and ownership.
- */
- struct dentry *dret, *d_dir = creat_dentry ("@d_dir3@", 5, dir, NULL);
-
-
- dret = compat_umsdos_real_lookup (d_dir, "..", 2);
- Printk (("ancestor ret %p dir %p *result %p ", dret, dir, dentry->d_inode));
- if (dret
- && dentry->d_inode != root_inode
- && dentry->d_inode != pseudo_root) {
- struct inode *aadir;
- struct umsdos_dirent entry;
-
- Printk ((KERN_ERR "WARNING: umsdos_lookup_x: this won't work!\n"));
-
- dentry->d_inode = dret->d_inode; /* FIXME! this should be rewritten ! it won't work this way! */
+ printk("umsdos_lookup_x: UMSDOS broken, please report!\n");
+ goto out;
+ }
- ret = umsdos_locate_ancestor (dentry->d_inode, &aadir, &entry);
- fin_dentry (dret);
- }
- }
- } else if (umsdos_is_pseudodos (dir, dentry)) {
+ /* this shouldn't happen ... */
+ if (len == 2 && name[0] == '.' && name[1] == '.') {
+ printk("umsdos_lookup_x: UMSDOS broken, please report!\n");
+ goto out;
+ }
+
+ if (umsdos_is_pseudodos (dir, dentry)) {
/* #Specification: pseudo root / lookup(DOS)
* A lookup of DOS in the pseudo root will always succeed
* and return the inode of the real root.
*/
- d_add (dentry, root_inode);
- inc_count (dentry->d_inode); /* FIXME?! */
- ret = 0;
- } else {
- struct umsdos_info info;
+ inode = iget(dir->i_sb, UMSDOS_ROOT_INO);
+ if (inode)
+ goto out_add;
+ ret = -ENOMEM;
+ goto out;
+ }
- ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
- if (ret == 0)
- ret = umsdos_findentry (dir, &info, 0);
- Printk (("lookup %.*s pos %lu ret %d len %d ", info.fake.len, info.fake.fname, info.f_pos, ret, info.fake.len));
- if (ret == 0) {
- /* #Specification: umsdos / lookup
- * A lookup for a file is done in two steps. First, we
- * locate the file in the EMD file. If not present, we
- * return an error code (-ENOENT). If it is there, we
- * repeat the operation on the msdos file system. If
- * this fails, it means that the file system is not in
- * sync with the EMD file. We silently remove this
- * entry from the EMD file, and return ENOENT.
- */
- struct dentry *dret, *dir_dentry;
-
- dir_dentry = geti_dentry (dir);
- dret = compat_umsdos_real_lookup (dir_dentry, info.fake.fname, info.fake.len);
-
-
- PRINTK ((KERN_DEBUG "umsdos_lookup_x: compat_umsdos_real_lookup for %.*s returned %p\n", info.fake.len, info.fake.fname, dret));
-
- if (dret == NULL) {
- printk (KERN_WARNING "UMSDOS: Erase entry %.*s, out of sync with MS-DOS\n", info.fake.len, info.fake.fname);
- umsdos_delentry (dir, &info, S_ISDIR (info.entry.mode));
- } else {
- Printk ((KERN_DEBUG "umsdos_lookup_x /mn/ debug: ino=%li\n", dret->d_inode->i_ino));
-
- umsdos_lookup_patch (dir, dret->d_inode, &info.entry, info.f_pos);
- Printk (("lookup ino %ld flags %d\n", dret->d_inode->i_ino, info.entry.flags));
- if (info.entry.flags & UMSDOS_HLINK) {
- dret = umsdos_solve_hlink (dret);
- }
- if (pseudo_root && dret->d_inode == pseudo_root && !nopseudo) {
- /* #Specification: pseudo root / dir lookup
- * For the same reason as readdir, a lookup in /DOS for
- * the pseudo root directory (linux) will fail.
- */
- /*
- * This has to be allowed for resolving hard links
- * which are recorded independently of the pseudo-root
- * mode.
- */
- Printk ((KERN_ERR "umsdos_lookup_x: warning: untested /mn/ Pseudo_root thingy\n"));
- /* iput (pseudo_root); / * FIXME?? */
- d_instantiate (dentry, NULL); /* negative lookup */
- ret = -ENOENT;
- } else {
- /* We've found it OK. Now put inode in dentry. */
- inc_count (dret->d_inode); /* lookup should return incremented i_count */
- d_add (dentry, dret->d_inode);
- }
- fin_dentry (dret);
- }
- }
+ ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
+ if (ret)
+ goto out;
+ ret = umsdos_findentry (dentry->d_parent, &info, 0);
+Printk (("lookup %.*s pos %lu ret %d len %d ",
+info.fake.len, info.fake.fname, info.f_pos, ret, info.fake.len));
+ if (ret)
+ goto out;
+
+
+ dret = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname,
+ info.fake.len);
+ ret = PTR_ERR(dret);
+ if (IS_ERR(dret))
+ goto out;
+ if (!dret->d_inode)
+ goto out_remove;
+
+ umsdos_lookup_patch_new(dret, &info.entry, info.f_pos);
+
+ /* Check for a hard link */
+ if (info.entry.flags & UMSDOS_HLINK) {
+Printk (("checking hard link %s/%s, ino=%ld, flags=%x\n",
+dret->d_parent->d_name.name, dret->d_name.name,
+dret->d_inode->i_ino, info.entry.flags));
+ dret = umsdos_solve_hlink (dret);
+ ret = PTR_ERR(dret);
+ if (IS_ERR(dret))
+ goto out;
+ }
+ /* N.B. can dentry be negative after resolving hlinks? */
+
+ if (pseudo_root && dret->d_inode == pseudo_root && !nopseudo) {
+ /* #Specification: pseudo root / dir lookup
+ * For the same reason as readdir, a lookup in /DOS for
+ * the pseudo root directory (linux) will fail.
+ */
+ /*
+ * This has to be allowed for resolving hard links
+ * which are recorded independently of the pseudo-root
+ * mode.
+ */
+ Printk (("umsdos_lookup_x: untested Pseudo_root\n"));
+ ret = -ENOENT;
+ goto out_dput;
+ } else {
+ /* We've found it OK. Now put inode in dentry. */
+ inode = dret->d_inode;
}
+
+ /*
+ * Hash the dentry with the inode.
+ */
+out_add:
+ inode->i_count++;
+ d_add (dentry, inode);
+ ret = 0;
+
+out_dput:
+ dput(dret);
+out:
umsdos_endlookup (dir);
- iput (root_inode); /* pair to iget() above.WHY is it not needed ?! */
- 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));
- 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 */
return ret;
+
+out_remove:
+ printk(KERN_WARNING "UMSDOS: entry %s/%s out of sync, erased\n",
+ dentry->d_name.name, info.fake.fname);
+ umsdos_delentry (dentry->d_parent, &info, S_ISDIR (info.entry.mode));
+ ret = -ENOENT;
+ goto out;
}
@@ -911,118 +745,164 @@
*
*/
-int UMSDOS_lookup ( struct inode *dir,
- struct dentry *dentry)
+int UMSDOS_lookup (struct inode *dir, struct dentry *dentry)
{
int ret;
ret = umsdos_lookup_x (dir, dentry, 0);
+ /* Create negative dentry if not found. */
if (ret == -ENOENT) {
- Printk ((KERN_DEBUG "UMSDOS_lookup: converting -ENOENT to negative dentry !\n"));
- d_add (dentry, NULL); /* Create negative dentry if not found. */
+ Printk ((KERN_DEBUG
+ "UMSDOS_lookup: converting -ENOENT to negative\n"));
+ d_add (dentry, NULL);
ret = 0;
}
-
return ret;
}
/*
+ * Lookup or create a dentry from within the filesystem.
+ *
+ * We need to use this instead of lookup_dentry, as the
+ * directory semaphore lock is already held.
+ */
+struct dentry *umsdos_lookup_dentry(struct dentry *parent, char *name, int len)
+{
+ struct dentry *result, *dentry;
+ int error;
+ struct qstr qstr;
+
+ qstr.name = name;
+ qstr.len = len;
+ qstr.hash = full_name_hash(name, len);
+ result = d_lookup(parent, &qstr);
+ if (!result) {
+ result = ERR_PTR(-ENOMEM);
+ dentry = d_alloc(parent, &qstr);
+ if (dentry) {
+ result = dentry;
+ error = umsdos_real_lookup(parent->d_inode, result);
+ if (error)
+ goto out_fail;
+ }
+ }
+out:
+ return result;
+
+out_fail:
+ dput(result);
+ result = ERR_PTR(error);
+ goto out;
+}
+
+
+/*
* gets dentry which points to pseudo-hardlink
*
* it should try to find file it points to
- * if file is found, it should dput() original dentry and return new one (with d_count = i_count = 1)
+ * if file is found, it should dput() original dentry and return new one
+ * (with d_count = i_count = 1)
* Otherwise, it should return with error, with dput()ed original dentry.
*
*/
struct dentry *umsdos_solve_hlink (struct dentry *hlink)
{
- struct dentry *base = hlink->d_sb->s_root; /* root is our root for resolving pseudo-hardlink */
- struct dentry *final = NULL;
- struct inode *result;
+ /* root is our root for resolving pseudo-hardlink */
+ struct dentry *base = hlink->d_sb->s_root;
+ struct dentry *final, *dir, *dentry_dst;
+ char *path, *pt;
+ unsigned long len;
int ret = -EIO;
- struct dentry *dentry_dst, *d_dir;
- char *path;
+ struct file filp;
check_dentry_path (hlink, "HLINK BEGIN hlink");
+ final = ERR_PTR (-ENOMEM);
path = (char *) kmalloc (PATH_MAX, GFP_KERNEL);
+ if (path == NULL)
+ goto out;
- result = NULL;
-
- if (path == NULL) {
- final = ERR_PTR (-ENOMEM);
- } else {
- struct file filp;
- fill_new_filp (&filp, hlink);
- filp.f_flags = O_RDONLY;
- filp.f_pos = 0;
+ fill_new_filp (&filp, hlink);
+ filp.f_flags = O_RDONLY;
+ filp.f_pos = 0;
+
+ Printk (("hlink2inode "));
+ len = umsdos_file_read_kmem (&filp, path, hlink->d_inode->i_size);
+ if (len != hlink->d_inode->i_size)
+ goto out_noread;
+
+ /* start at root dentry */
+ dir = dget(base);
+ path[hlink->d_inode->i_size] = '\0';
+ pt = path;
+ while (1) {
+ char *start = pt;
+ int len;
+
+ while (*pt != '\0' && *pt != '/') pt++;
+ len = (int) (pt - start);
+ if (*pt == '/') *pt++ = '\0';
- Printk (("hlink2inode "));
- if (umsdos_file_read_kmem (&filp, path, hlink->d_inode->i_size) == hlink->d_inode->i_size) {
- struct inode *dir;
- char *pt = path;
-
- dir = base->d_inode; /* start at root inode */
- path[hlink->d_inode->i_size] = '\0';
- inc_count (dir); /* since we're going to iput() it in the loop below... */
-
- while (1) {
- char *start = pt;
- int len;
-
- while (*pt != '\0' && *pt != '/') pt++;
- len = (int) (pt - start);
- if (*pt == '/') *pt++ = '\0';
-
- d_dir = geti_dentry (dir);
- dentry_dst = creat_dentry (start, len, NULL, d_dir);
- if (dir->u.umsdos_i.i_emd_dir == 0) {
- /* This is a DOS directory */
-
- Printk (("hlink2inode /mn/: doing umsdos_rlookup_x on %.*s\n", (int) dentry_dst->d_name.len, dentry_dst->d_name.name));
- ret = umsdos_rlookup_x (dir, dentry_dst, 1);
- } else {
- Printk (("hlink2inode /mn/: doing umsdos_lookup_x on %.*s\n", (int) dentry_dst->d_name.len, dentry_dst->d_name.name));
- ret = umsdos_lookup_x (dir, dentry_dst, 1);
- }
-
- iput (dir); /* dir no longer needed */
- Printk ((" returned %d\n", ret));
- result = dentry_dst->d_inode;
- inc_count (result); /* we need inode to survive. We'll iput it in next loop */
-
- fin_dentry (dentry_dst); /* no longer needed - this is pair to creat_dentry */
-
- Printk (("h2n lookup :%s: -> %d ", start, ret));
-
- if (ret != 0) {
- iput (result); /* we have no longer any use for it... */
- final = ERR_PTR (ret); /* path componenet not found ! */
- break;
- } else {
- if (*pt != '\0') {
- dir = result;
- } else { /* we're finished! */
- final = creat_dentry (hlink->d_name.name, hlink->d_name.len, result, hlink->d_parent);
- break;
- }
- }
- } /* end while */
+ dentry_dst = umsdos_lookup_dentry(dir, start, len);
+ if (IS_ERR(dentry_dst))
+ break;
+ if (dir->d_inode->u.umsdos_i.i_emd_dir == 0) {
+ /* This is a DOS directory */
+ ret = umsdos_rlookup_x (dir->d_inode, dentry_dst, 1);
} else {
- Printk (("umsdos_solve_hlink: failed reading pseudolink!\n"));
+ ret = umsdos_lookup_x (dir->d_inode, dentry_dst, 1);
}
-
- Printk (("hlink2inode ret = %d %p -> %p\n", ret, hlink, result));
- kfree (path);
+ Printk ((" returned %d\n", ret));
+ dput (dir); /* dir no longer needed */
+ dir = dentry_dst;
+
+ Printk (("h2n lookup :%s: -> %d ", start, ret));
+ final = ERR_PTR (ret);
+ if (ret != 0) {
+ /* path component not found! */
+ break;
+ }
+ if (*pt == '\0') { /* we're finished! */
+ final = umsdos_lookup_dentry(hlink->d_parent,
+ (char *) hlink->d_name.name,
+ hlink->d_name.len);
+ break;
+ }
+ } /* end while */
+ /*
+ * See whether we found the path ...
+ */
+ if (!IS_ERR(final)) {
+ if (!final->d_inode) {
+ d_instantiate(final, dir->d_inode);
+ /* we need inode to survive. */
+ dir->d_inode->i_count++;
+ } else {
+ printk ("umsdos_solve_hlink: %s/%s already exists\n",
+ final->d_parent->d_name.name,
+ final->d_name.name);
+ }
+printk ("umsdos_solve_hlink: ret = %d, %s/%s -> %s/%s\n",
+ret, hlink->d_parent->d_name.name, hlink->d_name.name,
+final->d_parent->d_name.name, final->d_name.name);
}
+ dput(dir);
- fin_dentry (hlink); /* original hlink no longer needed */
+out_free:
+ kfree (path);
+
+out:
+ dput(hlink); /* original hlink no longer needed */
check_dentry_path (hlink, "HLINK FIN hlink");
check_dentry_path (final, "HLINK RET final");
return final;
+
+out_noread:
+ printk("umsdos_solve_hlink: failed reading pseudolink!\n");
+ goto out_free;
}
@@ -1038,7 +918,7 @@
NULL, /* no special open code */
NULL, /* flush */
NULL, /* no special release code */
- NULL /* fsync *//* in original NULL. changed to file_fsync. FIXME? /mn/ */
+ NULL /* fsync */
};
struct inode_operations umsdos_dir_inode_operations =
@@ -1055,9 +935,9 @@
UMSDOS_rename, /* rename */
NULL, /* readlink */
NULL, /* followlink */
- generic_readpage, /* readpage *//* in original NULL. changed to generic_readpage. FIXME? /mn/ */
+ generic_readpage, /* readpage */
NULL, /* writepage */
- fat_bmap, /* bmap *//* in original NULL. changed to fat_bmap. FIXME? /mn/ */
+ fat_bmap, /* bmap */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov