dir.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:20k
- /*
- * linux/fs/umsdos/dir.c
- *
- * Written 1993 by Jacques Gelinas
- * Inspired from linux/fs/msdos/... : Werner Almesberger
- *
- * Extended MS-DOS directory handling functions
- */
- #include <linux/sched.h>
- #include <linux/string.h>
- #include <linux/fs.h>
- #include <linux/msdos_fs.h>
- #include <linux/errno.h>
- #include <linux/stat.h>
- #include <linux/limits.h>
- #include <linux/umsdos_fs.h>
- #include <linux/slab.h>
- #include <linux/pagemap.h>
- #define UMSDOS_SPECIAL_DIRFPOS 3
- extern struct dentry *saved_root;
- extern struct inode *pseudo_root;
- /* #define UMSDOS_DEBUG_VERBOSE 1 */
- /*
- * Dentry operations routines
- */
- /* nothing for now ... */
- static int umsdos_dentry_validate(struct dentry *dentry, int flags)
- {
- return 1;
- }
- /* for now, drop everything to force lookups ... */
- /* ITYM s/everything/& positive/... */
- static int umsdos_dentry_dput(struct dentry *dentry)
- {
- struct inode *inode = dentry->d_inode;
- if (inode) {
- return 1;
- }
- return 0;
- }
- struct dentry_operations umsdos_dentry_operations =
- {
- d_revalidate: umsdos_dentry_validate,
- d_delete: umsdos_dentry_dput,
- };
- struct UMSDOS_DIR_ONCE {
- void *dirbuf;
- filldir_t filldir;
- int count;
- int stop;
- };
- /*
- * Record a single entry the first call.
- * Return -EINVAL the next one.
- * NOTE: filldir DOES NOT use a dentry
- */
- static int umsdos_dir_once ( void *buf,
- const char *name,
- int len,
- loff_t offset,
- ino_t ino,
- unsigned type)
- {
- int ret = -EINVAL;
- struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *) buf;
- if (d->count == 0) {
- PRINTK ((KERN_DEBUG "dir_once :%.*s: offset %Ldn",
- len, name, offset));
- ret = d->filldir (d->dirbuf, name, len, offset, ino, DT_UNKNOWN);
- d->stop = ret < 0;
- d->count = 1;
- }
- return ret;
- }
- /*
- * Read count directory entries from directory filp
- * Return a negative value from linux/errno.h.
- * Return > 0 if success (the number of bytes written by filldir).
- *
- * This function is used by the normal readdir VFS entry point,
- * and in order to get the directory entry from a file's dentry.
- * See umsdos_dentry_to_entry() below.
- */
-
- static int umsdos_readdir_x (struct inode *dir, struct file *filp,
- void *dirbuf, struct umsdos_dirent *u_entry,
- filldir_t filldir)
- {
- struct dentry *demd;
- off_t start_fpos;
- int ret = 0;
- loff_t pos;
- umsdos_startlookup (dir);
- if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS && dir == pseudo_root) {
- /*
- * We don't need to simulate this pseudo directory
- * when umsdos_readdir_x is called for internal operation
- * of umsdos. This is why dirent_in_fs is tested
- */
- /* #Specification: pseudo root / directory /DOS
- * When umsdos operates in pseudo root mode (C:linux is the
- * linux root), it simulate a directory /DOS which points to
- * the real root of the file system.
- */
- Printk ((KERN_WARNING "umsdos_readdir_x: pseudo_root thing UMSDOS_SPECIAL_DIRFPOSn"));
- if (filldir (dirbuf, "DOS", 3,
- UMSDOS_SPECIAL_DIRFPOS, UMSDOS_ROOT_INO, DT_DIR) == 0) {
- filp->f_pos++;
- }
- goto out_end;
- }
- if (filp->f_pos < 2 ||
- (dir->i_ino != UMSDOS_ROOT_INO && filp->f_pos == 32)) {
-
- int last_f_pos = filp->f_pos;
- struct UMSDOS_DIR_ONCE bufk;
- Printk (("umsdos_readdir_x: . or .. /mn/?n"));
- bufk.dirbuf = dirbuf;
- bufk.filldir = filldir;
- bufk.count = 0;
- ret = fat_readdir (filp, &bufk, umsdos_dir_once);
- if (last_f_pos > 0 && filp->f_pos > last_f_pos)
- filp->f_pos = UMSDOS_SPECIAL_DIRFPOS;
- if (u_entry != NULL)
- u_entry->flags = 0;
- goto out_end;
- }
- Printk (("umsdos_readdir_x: normal file /mn/?n"));
- /* get the EMD dentry */
- demd = umsdos_get_emd_dentry(filp->f_dentry);
- ret = PTR_ERR(demd);
- if (IS_ERR(demd))
- goto out_end;
- ret = -EIO;
- if (!demd->d_inode) {
- printk(KERN_WARNING
- "umsdos_readir_x: EMD file %s/%s not foundn",
- demd->d_parent->d_name.name, demd->d_name.name);
- goto out_dput;
- }
- pos = filp->f_pos;
- start_fpos = filp->f_pos;
- if (pos <= UMSDOS_SPECIAL_DIRFPOS + 1)
- pos = 0;
- ret = 0;
- while (pos < demd->d_inode->i_size) {
- off_t cur_f_pos = pos;
- struct dentry *dret;
- struct inode *inode;
- struct umsdos_dirent entry;
- struct umsdos_info info;
- ret = -EIO;
- if (umsdos_emd_dir_readentry (demd, &pos, &entry) != 0)
- break;
- if (entry.name_len == 0)
- continue;
- #ifdef UMSDOS_DEBUG_VERBOSE
- if (entry.flags & UMSDOS_HLINK)
- printk("umsdos_readdir_x: %s/%s is hardlinkn",
- filp->f_dentry->d_name.name, entry.name);
- #endif
- umsdos_parse (entry.name, entry.name_len, &info);
- info.f_pos = cur_f_pos;
- umsdos_manglename (&info);
- /*
- * Do a real lookup on the short name.
- */
- dret = umsdos_covered(filp->f_dentry, info.fake.fname,
- info.fake.len);
- ret = PTR_ERR(dret);
- if (IS_ERR(dret))
- break;
- /*
- * If the file wasn't found, remove it from the EMD.
- */
- inode = dret->d_inode;
- if (!inode)
- goto remove_name;
- #ifdef UMSDOS_DEBUG_VERBOSE
- if (inode->u.umsdos_i.i_is_hlink)
- printk("umsdos_readdir_x: %s/%s already resolved, ino=%ldn",
- dret->d_parent->d_name.name, dret->d_name.name, inode->i_ino);
- #endif
- Printk (("Found %s/%s, ino=%ld, flags=%xn",
- dret->d_parent->d_name.name, info.fake.fname, dret->d_inode->i_ino,
- entry.flags));
- /* check whether to resolve a hard-link */
- if ((entry.flags & UMSDOS_HLINK) &&
- !inode->u.umsdos_i.i_is_hlink) {
- dret = umsdos_solve_hlink (dret);
- ret = PTR_ERR(dret);
- if (IS_ERR(dret))
- break;
- inode = dret->d_inode;
- if (!inode) {
- printk("umsdos_readdir_x: %s/%s negative after linkn",
- dret->d_parent->d_name.name, dret->d_name.name);
- goto clean_up;
- }
- }
- /* #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 (inode != pseudo_root && !(entry.flags & UMSDOS_HIDDEN)) {
- if (filldir (dirbuf, entry.name, entry.name_len,
- cur_f_pos, inode->i_ino, DT_UNKNOWN) < 0) {
- pos = cur_f_pos;
- }
- Printk(("umsdos_readdir_x: got %s/%s, ino=%ldn",
- dret->d_parent->d_name.name, dret->d_name.name, inode->i_ino));
- if (u_entry != NULL)
- *u_entry = entry;
- dput(dret);
- ret = 0;
- break;
- }
- clean_up:
- 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.
- */
- #ifdef UMSDOS_PARANOIA
- printk("umsdos_readdir_x: %s/%s out of sync, erasingn",
- filp->f_dentry->d_name.name, info.entry.name);
- #endif
- ret = umsdos_delentry(filp->f_dentry, &info,
- S_ISDIR(info.entry.mode));
- if (ret)
- printk(KERN_WARNING
- "umsdos_readdir_x: delentry %s, err=%dn",
- info.entry.name, ret);
- goto clean_up;
- }
- /*
- * 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 = 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 %dn",
- dir, filp->f_pos, ret));
- return ret;
- }
- /*
- * Read count directory entries from directory filp.
- * Return a negative value from linux/errno.h.
- * Return 0 or positive if successful.
- */
-
- static int UMSDOS_readdir (struct file *filp, void *dirbuf, filldir_t filldir)
- {
- struct inode *dir = filp->f_dentry->d_inode;
- int ret = 0, count = 0;
- struct UMSDOS_DIR_ONCE bufk;
- bufk.dirbuf = dirbuf;
- bufk.filldir = filldir;
- bufk.stop = 0;
- Printk (("UMSDOS_readdir inn"));
- while (ret == 0 && bufk.stop == 0) {
- struct umsdos_dirent entry;
- bufk.count = 0;
- ret = umsdos_readdir_x (dir, filp, &bufk, &entry,
- umsdos_dir_once);
- if (bufk.count == 0)
- break;
- count += bufk.count;
- }
- Printk (("UMSDOS_readdir out %d count %d pos %Ldn",
- ret, count, filp->f_pos));
- return count ? : ret;
- }
- /*
- * Complete the inode content with info from the EMD file.
- *
- * 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_new(struct dentry *dentry, struct umsdos_info *info)
- {
- struct inode *inode = dentry->d_inode;
- struct umsdos_dirent *entry = &info->entry;
- /*
- * This part of the initialization depends only on i_patched.
- */
- if (inode->u.umsdos_i.i_patched)
- goto out;
- inode->u.umsdos_i.i_patched = 1;
- 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 / 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");
- }
- }
- /*
- * The mode may have changed, so patch the inode again.
- */
- umsdos_patch_dentry_inode(dentry, info->f_pos);
- umsdos_set_dirinfo_new(dentry, info->f_pos);
- out:
- return;
- }
- /*
- * Return != 0 if an entry is the pseudo DOS entry in the pseudo root.
- */
- 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.
- * The name is DOS. This is done this way to help standardised
- * the umsdos layout. The idea is that from now on /DOS is
- * a reserved path and nobody will think of using such a path
- * for a package.
- */
- return dir == pseudo_root
- && dentry->d_name.len == 3
- && dentry->d_name.name[0] == 'D'
- && dentry->d_name.name[1] == 'O'
- && dentry->d_name.name[2] == 'S';
- }
- /*
- * 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.
- */
- struct dentry *umsdos_lookup_x (struct inode *dir, struct dentry *dentry, int nopseudo)
- {
- struct dentry *dret = NULL;
- struct inode *inode;
- int ret = -ENOENT;
- struct umsdos_info info;
- #ifdef UMSDOS_DEBUG_VERBOSE
- printk("umsdos_lookup_x: looking for %s/%sn",
- dentry->d_parent->d_name.name, dentry->d_name.name);
- #endif
- umsdos_startlookup (dir);
- 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.
- */
- Printk ((KERN_DEBUG "umsdos_lookup_x: following /DOSn"));
- inode = saved_root->d_inode;
- goto out_add;
- }
- ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
- if (ret) {
- printk("umsdos_lookup_x: %s/%s parse failed, ret=%dn",
- dentry->d_parent->d_name.name, dentry->d_name.name, ret);
- goto out;
- }
- ret = umsdos_findentry (dentry->d_parent, &info, 0);
- if (ret) {
- if (ret != -ENOENT)
- printk("umsdos_lookup_x: %s/%s findentry failed, ret=%dn",
- dentry->d_parent->d_name.name, dentry->d_name.name, ret);
- goto out;
- }
- Printk (("lookup %.*s pos %lu ret %d len %d ",
- info.fake.len, info.fake.fname, info.f_pos, ret, info.fake.len));
- /* do a real lookup to get the short name ... */
- dret = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
- ret = PTR_ERR(dret);
- if (IS_ERR(dret)) {
- printk("umsdos_lookup_x: %s/%s real lookup failed, ret=%dn",
- dentry->d_parent->d_name.name, dentry->d_name.name, ret);
- goto out;
- }
- inode = dret->d_inode;
- if (!inode)
- goto out_remove;
- umsdos_lookup_patch_new(dret, &info);
- #ifdef UMSDOS_DEBUG_VERBOSE
- printk("umsdos_lookup_x: found %s/%s, ino=%ldn",
- dret->d_parent->d_name.name, dret->d_name.name, dret->d_inode->i_ino);
- #endif
- /* Check for a hard link */
- if ((info.entry.flags & UMSDOS_HLINK) &&
- !inode->u.umsdos_i.i_is_hlink) {
- dret = umsdos_solve_hlink (dret);
- ret = PTR_ERR(dret);
- if (IS_ERR(dret))
- goto out;
- ret = -ENOENT;
- inode = dret->d_inode;
- if (!inode) {
- printk("umsdos_lookup_x: %s/%s negative after linkn",
- dret->d_parent->d_name.name, dret->d_name.name);
- goto out_dput;
- }
- }
- if (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: skipping DOS/linuxn");
- ret = -ENOENT;
- goto out_dput;
- }
- /*
- * We've found it OK. Now hash the dentry with the inode.
- */
- out_add:
- atomic_inc(&inode->i_count);
- d_add (dentry, inode);
- dentry->d_op = &umsdos_dentry_operations;
- ret = 0;
- out_dput:
- if (dret && dret != dentry)
- d_drop(dret);
- dput(dret);
- out:
- umsdos_endlookup (dir);
- return ERR_PTR(ret);
- out_remove:
- printk(KERN_WARNING "UMSDOS: entry %s/%s out of sync, erasedn",
- dentry->d_parent->d_name.name, dentry->d_name.name);
- umsdos_delentry (dentry->d_parent, &info, S_ISDIR (info.entry.mode));
- ret = -ENOENT;
- goto out_dput;
- }
- /*
- * Check whether a file exists in the current directory.
- * Return 0 if OK, negative error code if not (ex: -ENOENT).
- *
- * Called by VFS; should fill dentry->d_inode via d_add.
- */
- struct dentry *UMSDOS_lookup (struct inode *dir, struct dentry *dentry)
- {
- struct dentry *ret;
- ret = umsdos_lookup_x (dir, dentry, 0);
- /* Create negative dentry if not found. */
- if (ret == ERR_PTR(-ENOENT)) {
- Printk ((KERN_DEBUG
- "UMSDOS_lookup: converting -ENOENT to negativen"));
- d_add (dentry, NULL);
- dentry->d_op = &umsdos_dentry_operations;
- ret = NULL;
- }
- return ret;
- }
- struct dentry *umsdos_covered(struct dentry *parent, char *name, int len)
- {
- struct dentry *result, *dentry;
- struct qstr qstr;
- qstr.name = name;
- qstr.len = len;
- qstr.hash = full_name_hash(name, len);
- result = ERR_PTR(-ENOMEM);
- dentry = d_alloc(parent, &qstr);
- if (dentry) {
- /* XXXXXXXXXXXXXXXXXXX Race alert! */
- result = UMSDOS_rlookup(parent->d_inode, dentry);
- d_drop(dentry);
- if (result)
- goto out_fail;
- return dentry;
- }
- out:
- return result;
- out_fail:
- dput(dentry);
- goto out;
- }
- /*
- * 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,
- int real)
- {
- struct dentry *result, *dentry;
- 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 = real ?
- UMSDOS_rlookup(parent->d_inode, dentry) :
- UMSDOS_lookup(parent->d_inode, dentry);
- if (result)
- goto out_fail;
- return dentry;
- }
- }
- out:
- return result;
- out_fail:
- dput(dentry);
- goto out;
- }
- /*
- * Return a path relative to our root.
- */
- char * umsdos_d_path(struct dentry *dentry, char * buffer, int len)
- {
- struct dentry * old_root;
- char * path;
- read_lock(¤t->fs->lock);
- old_root = dget(current->fs->root);
- read_unlock(¤t->fs->lock);
- spin_lock(&dcache_lock);
- path = __d_path(dentry, current->fs->rootmnt, dentry->d_sb->s_root, current->fs->rootmnt, buffer, len); /* FIXME: current->fs->rootmnt */
- spin_unlock(&dcache_lock);
- if (*path == '/')
- path++; /* skip leading '/' */
- if (current->fs->root->d_inode == pseudo_root)
- {
- *(path-1) = '/';
- path -= (UMSDOS_PSDROOT_LEN+1);
- memcpy(path, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN);
- }
- dput(old_root);
- return path;
- }
- /*
- * Return the dentry which points to a pseudo-hardlink.
- *
- * it should try to find file it points to
- * if file is found, return new dentry/inode
- * The resolved inode will have i_is_hlink set.
- *
- * Note: the original dentry is always dput(), even if an error occurs.
- */
- struct dentry *umsdos_solve_hlink (struct dentry *hlink)
- {
- /* root is our root for resolving pseudo-hardlink */
- struct dentry *base = hlink->d_sb->s_root;
- struct dentry *dentry_dst;
- char *path, *pt;
- int len;
- struct address_space *mapping = hlink->d_inode->i_mapping;
- struct page *page;
- page=read_cache_page(mapping,0,(filler_t *)mapping->a_ops->readpage,NULL);
- dentry_dst=(struct dentry *)page;
- if (IS_ERR(page))
- goto out;
- wait_on_page(page);
- if (!Page_Uptodate(page))
- goto async_fail;
- dentry_dst = ERR_PTR(-ENOMEM);
- path = (char *) kmalloc (PATH_MAX, GFP_KERNEL);
- if (path == NULL)
- goto out_release;
- memcpy(path, kmap(page), hlink->d_inode->i_size);
- kunmap(page);
- page_cache_release(page);
- len = hlink->d_inode->i_size;
- /* start at root dentry */
- dentry_dst = dget(base);
- path[len] = ' ';
-
- pt = path;
- if (*path == '/')
- pt++; /* skip leading '/' */
-
- if (base->d_inode == pseudo_root)
- pt += (UMSDOS_PSDROOT_LEN + 1);
-
- while (1) {
- struct dentry *dir = dentry_dst, *demd;
- char *start = pt;
- int real;
- while (*pt != ' ' && *pt != '/') pt++;
- len = (int) (pt - start);
- if (*pt == '/') *pt++ = ' ';
- real = 1;
- demd = umsdos_get_emd_dentry(dir);
- if (!IS_ERR(demd)) {
- if (demd->d_inode)
- real = 0;
- dput(demd);
- }
- #ifdef UMSDOS_DEBUG_VERBOSE
- printk ("umsdos_solve_hlink: dir %s/%s, name=%s, real=%dn",
- dir->d_parent->d_name.name, dir->d_name.name, start, real);
- #endif
- dentry_dst = umsdos_lookup_dentry(dir, start, len, real);
- /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
- if (real)
- d_drop(dir);
- dput (dir);
- if (IS_ERR(dentry_dst))
- break;
- /* not found? stop search ... */
- if (!dentry_dst->d_inode) {
- break;
- }
- if (*pt == ' ') /* we're finished! */
- break;
- } /* end while */
- if (!IS_ERR(dentry_dst)) {
- struct inode *inode = dentry_dst->d_inode;
- if (inode) {
- inode->u.umsdos_i.i_is_hlink = 1;
- #ifdef UMSDOS_DEBUG_VERBOSE
- printk ("umsdos_solve_hlink: resolved link %s/%s, ino=%ldn",
- dentry_dst->d_parent->d_name.name, dentry_dst->d_name.name, inode->i_ino);
- #endif
- } else {
- #ifdef UMSDOS_DEBUG_VERBOSE
- printk ("umsdos_solve_hlink: resolved link %s/%s negative!n",
- dentry_dst->d_parent->d_name.name, dentry_dst->d_name.name);
- #endif
- }
- } else
- printk(KERN_WARNING
- "umsdos_solve_hlink: err=%ldn", PTR_ERR(dentry_dst));
- kfree (path);
- out:
- dput(hlink); /* original hlink no longer needed */
- return dentry_dst;
- async_fail:
- dentry_dst = ERR_PTR(-EIO);
- out_release:
- page_cache_release(page);
- goto out;
- }
- struct file_operations umsdos_dir_operations =
- {
- read: generic_read_dir,
- readdir: UMSDOS_readdir,
- ioctl: UMSDOS_ioctl_dir,
- };
- struct inode_operations umsdos_dir_inode_operations =
- {
- create: UMSDOS_create,
- lookup: UMSDOS_lookup,
- link: UMSDOS_link,
- unlink: UMSDOS_unlink,
- symlink: UMSDOS_symlink,
- mkdir: UMSDOS_mkdir,
- rmdir: UMSDOS_rmdir,
- mknod: UMSDOS_mknod,
- rename: UMSDOS_rename,
- setattr: UMSDOS_notify_change,
- };