commit 8f6afc8ba911b7fcbf4a036c631503e1b6199329
Author: Yiannis Pericleous <[EMAIL PROTECTED]>
Date:   Sat Feb 10 19:25:36 2007 -0500

    readdir and seekdir
    
    still need to check mtime and only update file in ic
    if necessary

diff --git a/fs/unionfs/commonfops.c b/fs/unionfs/commonfops.c
index 9e6341d..a2f7f10 100644
--- a/fs/unionfs/commonfops.c
+++ b/fs/unionfs/commonfops.c
@@ -371,7 +371,8 @@ static int __open_dir(struct inode *inode, struct file 
*file)
        struct dentry *hidden_dentry;
        struct file *hidden_file;
        int bindex, bstart, bend;
-
+       struct odf_dentry_info *odi;
+       int err;
        bstart = fbstart(file) = dbstart(file->f_dentry);
        bend = fbend(file) = dbend(file->f_dentry);
 
@@ -397,7 +398,13 @@ static int __open_dir(struct inode *inode, struct file 
*file)
                branchget(inode->i_sb, bindex);
                unionfs_read_unlock(inode->i_sb);
        }
-
+       
+       odi = odf_ic_dir(file->f_dentry);
+       if (IS_ERR(odi))
+               return PTR_ERR(odi);
+       err = odf_cache_dir(file->f_dentry, odi->dentry);
+       /* FIXME: store the dentry somewhere */
+       odf_put_info(odi);
        return 0;
 }
 
diff --git a/fs/unionfs/dirfops.c b/fs/unionfs/dirfops.c
index caf5689..9d9035b 100644
--- a/fs/unionfs/dirfops.c
+++ b/fs/unionfs/dirfops.c
@@ -18,255 +18,129 @@
 
 #include "union.h"
 
-/* Make sure our rdstate is playing by the rules. */
-static void verify_rdstate_offset(struct unionfs_dir_state *rdstate)
-{
-       BUG_ON(rdstate->offset >= DIREOF);
-       BUG_ON(rdstate->cookie >= MAXRDCOOKIE);
-}
-
-struct unionfs_getdents_callback {
-       struct unionfs_dir_state *rdstate;
-       void *dirent;
-       struct dentry *dir;
-       int entries_written;
-       int filldir_called;
-       int filldir_error;
-       filldir_t filldir;
-       struct super_block *sb;
-};
-
-/* based on generic filldir in fs/readir.c */
-static int unionfs_filldir(void *dirent, const char *name, int namelen,
-                          loff_t offset, u64 ino, unsigned int d_type)
+static int unionfs_readdir(struct file *file, void *dirent, filldir_t filldir)
 {
-       struct unionfs_getdents_callback *buf = dirent;
-       struct filldir_node *found = NULL;
-       struct odf_dentry_info *odi = NULL;
        int err = 0;
-       int is_wh_entry = 0;
-       int odf_flag = ODF_LOOKUP_FILE;
+       struct file *odf_file = NULL;
+       struct inode *inode = NULL;
+       struct odf_dentry_info *odi = NULL;
+       loff_t size;    
+       mm_segment_t oldfs;
+       /* dirent */
+       u64 ino;
+       char *name = NULL;
+       int namelen, magic;
+       unsigned int d_type;
 
-       buf->filldir_called++;  
+       if ((err = unionfs_file_revalidate(file, 0)))
+               goto out;
 
-       /* odf check whiteouts */
-       if (d_type == DT_DIR)
-               odf_flag = ODF_LOOKUP_DIR;
-       odi = __odf_lookup(buf->dir, name, namelen, odf_flag, 0);
+       inode = file->f_dentry->d_inode;
+
+       /* Get the odf/ic file */
+       /* FIXME: this should be saved somewhere, also check mtime */
+       odi = odf_ic_dir(file->f_dentry);
        if (IS_ERR(odi)){
                err = PTR_ERR(odi);
-               odi = NULL;
                goto out;
        }
-       if (odi && odi->whiteout)
+       dget(odi->dentry);
+       mntget(UNIONFS_SB(file->f_dentry->d_sb)->odf->mnt);
+       odf_file = dentry_open(odi->dentry,
+                       UNIONFS_SB(file->f_dentry->d_sb)->odf->mnt,
+                       O_RDONLY);
+       if (IS_ERR(odf_file)){
+               err = PTR_ERR(odf_file);
+               odf_file = NULL;
                goto out;
-
-       if ((namelen > UNIONFS_WHLEN) &&
-           !strncmp(name, UNIONFS_WHPFX, UNIONFS_WHLEN)) {
-               name += UNIONFS_WHLEN;
-               namelen -= UNIONFS_WHLEN;
-               is_wh_entry = 1;
        }
-
-       found = find_filldir_node(buf->rdstate, name, namelen);
-
-       if (found)
+       
+       /* check EOF */
+       size = odi->dentry->d_inode->i_size;
+       if (file->f_pos >= size)
                goto out;
 
-       /* if 'name' isn't a whiteout, filldir it. */
-       if (!is_wh_entry) {
-               off_t pos = rdstate2offset(buf->rdstate);
-               u64 unionfs_ino = ino;
-
-               if (!err) {
-                       err = buf->filldir(buf->dirent, name, namelen, pos,
-                                          unionfs_ino, d_type);
-                       buf->rdstate->offset++;
-                       verify_rdstate_offset(buf->rdstate);
-               }
+       odf_file->f_pos = file->f_pos;
+       
+       /* read the next dirent */
+       oldfs = get_fs();
+       set_fs(KERNEL_DS);
+       
+       err = odf_file->f_op->read(odf_file, (char*)&magic,
+                               sizeof(int), &odf_file->f_pos);
+       if (err != sizeof(int)) {
+               err = -EIO;
+               goto out;
        }
-       /* If we did fill it, stuff it in our hash, otherwise return an error */
-       if (err) {
-               buf->filldir_error = err;
+       /* check if we're reading at the correct offset */
+       if (magic != ODF_DIRENT_MAGIC) {
+               err = -EFAULT;
                goto out;
        }
-       buf->entries_written++;
-       if ((err = add_filldir_node(buf->rdstate, name, namelen,
-                                   buf->rdstate->bindex, is_wh_entry)))
-               buf->filldir_error = err;
-
-out:
-       odf_put_info(odi);
-       return err;
-}
-
-static int unionfs_readdir(struct file *file, void *dirent, filldir_t filldir)
-{
-       int err = 0;
-       struct file *hidden_file = NULL;
-       struct inode *inode = NULL;
-       struct unionfs_getdents_callback buf;
-       struct unionfs_dir_state *uds;
-       int bend;
-       loff_t offset;
-
-       unionfs_read_lock(file->f_dentry->d_sb);
-       if ((err = unionfs_file_revalidate(file, 0)))
+       
+       err = odf_file->f_op->read(odf_file, (char*)&namelen,
+                               sizeof(int), &odf_file->f_pos);
+       if (err != sizeof(int)) {
+               err = -EIO;
+               goto out;
+       }
+       if (namelen <= 0) {
+               err = -EFAULT;
+               goto out;
+       }
+       
+       name = kmalloc(namelen, GFP_KERNEL);
+       if (!name) {
+               err = -ENOMEM;
+               goto out;
+       }
+       err = odf_file->f_op->read(odf_file, (char*)name,
+                               namelen, &odf_file->f_pos);
+       if (err != namelen) {
+               err = -EIO;
                goto out;
-
-       inode = file->f_dentry->d_inode;
-
-       uds = UNIONFS_F(file)->rdstate;
-       if (!uds) {
-               if (file->f_pos == DIREOF) {
-                       goto out;
-               } else if (file->f_pos > 0) {
-                       uds = find_rdstate(inode, file->f_pos);
-                       if (!uds) {
-                               err = -ESTALE;
-                               goto out;
-                       }
-                       UNIONFS_F(file)->rdstate = uds;
-               } else {
-                       init_rdstate(file);
-                       uds = UNIONFS_F(file)->rdstate;
-               }
        }
-       bend = fbend(file);
-
-       while (uds->bindex <= bend) {
-               hidden_file = unionfs_lower_file_idx(file, uds->bindex);
-               if (!hidden_file) {
-                       uds->bindex++;
-                       uds->dirpos = 0;
-                       continue;
-               }
-
-               /* prepare callback buffer */
-               buf.filldir_called = 0;
-               buf.filldir_error = 0;
-               buf.entries_written = 0;
-               buf.dir = file->f_dentry;
-               buf.dirent = dirent;
-               buf.filldir = filldir;
-               buf.rdstate = uds;
-               buf.sb = inode->i_sb;
-
-               /* Read starting from where we last left off. */
-               offset = vfs_llseek(hidden_file, uds->dirpos, SEEK_SET);
-               if (offset < 0) {
-                       err = offset;
-                       goto out;
-               }
-               err = vfs_readdir(hidden_file, unionfs_filldir, &buf);
-
-               /* Save the position for when we continue. */
-               offset = vfs_llseek(hidden_file, 0, SEEK_CUR);
-               if (offset < 0) {
-                       err = offset;
-                       goto out;
-               }
-               uds->dirpos = offset;
 
-               /* Copy the atime. */
-               fsstack_copy_attr_atime(inode, hidden_file->f_dentry->d_inode);
+       err = odf_file->f_op->read(odf_file, (char*)&ino,
+                               sizeof(u64), &odf_file->f_pos);
+       if (err != sizeof(u64)) {
+               err = -EIO;
+               goto out;
+       }
+       err = odf_file->f_op->read(odf_file, (char*)&d_type,
+                       sizeof(unsigned int), &odf_file->f_pos);
+       if (err != sizeof(unsigned int)) {
+               err = -EIO;
+               goto out;
+       }
 
-               if (err < 0)
-                       goto out;
+       set_fs(oldfs);
 
-               if (buf.filldir_error)
-                       break;
+       /* filldir */
+       err = filldir(dirent, name, namelen, odf_file->f_pos, ino, d_type);
 
-               if (!buf.entries_written) {
-                       uds->bindex++;
-                       uds->dirpos = 0;
-               }
-       }
+       /* Copy the atime. */
+       fsstack_copy_attr_atime(inode, odi->dentry->d_inode);
 
-       if (!buf.filldir_error && uds->bindex >= bend) {
-               /* Save the number of hash entries for next time. */
-               UNIONFS_I(inode)->hashsize = uds->hashentries;
-               free_rdstate(uds);
-               UNIONFS_F(file)->rdstate = NULL;
-               file->f_pos = DIREOF;
-       } else
-               file->f_pos = rdstate2offset(uds);
+       /* save the file position */
+       file->f_pos = odf_file->f_pos;
 
 out:
-       unionfs_read_unlock(file->f_dentry->d_sb);
+       kfree(name);
+       if (odf_file)
+               filp_close(odf_file, NULL);
+       odf_put_info(odi);
        return err;
 }
 
-/* This is not meant to be a generic repositioning function.  If you do
- * things that aren't supported, then we return EINVAL.
- *
- * What is allowed:
- *  (1) seeking to the same position that you are currently at
- *     This really has no effect, but returns where you are.
- *  (2) seeking to the beginning of the file
- *     This throws out all state, and lets you begin again.
- */
 static loff_t unionfs_dir_llseek(struct file *file, loff_t offset, int origin)
 {
-       struct unionfs_dir_state *rdstate;
        loff_t err;
 
-       unionfs_read_lock(file->f_dentry->d_sb);
        if ((err = unionfs_file_revalidate(file, 0)))
-               goto out;
+               return err;
 
-       rdstate = UNIONFS_F(file)->rdstate;
-
-       /* We let users seek to their current position, but not anywhere else. 
*/
-       if (!offset) {
-               switch (origin) {
-               case SEEK_SET:
-                       if (rdstate) {
-                               free_rdstate(rdstate);
-                               UNIONFS_F(file)->rdstate = NULL;
-                       }
-                       init_rdstate(file);
-                       err = 0;
-                       break;
-               case SEEK_CUR:
-                       err = file->f_pos;
-                       break;
-               case SEEK_END:
-                       /* Unsupported, because we would break everything.  */
-                       err = -EINVAL;
-                       break;
-               }
-       } else {
-               switch (origin) {
-               case SEEK_SET:
-                       if (rdstate) {
-                               if (offset == rdstate2offset(rdstate))
-                                       err = offset;
-                               else if (file->f_pos == DIREOF)
-                                       err = DIREOF;
-                               else
-                                       err = -EINVAL;
-                       } else {
-                               rdstate = find_rdstate(file->f_dentry->d_inode,
-                                                       offset);
-                               if (rdstate) {
-                                       UNIONFS_F(file)->rdstate = rdstate;
-                                       err = rdstate->offset;
-                               } else
-                                       err = -EINVAL;
-                       }
-                       break;
-               case SEEK_CUR:
-               case SEEK_END:
-                       /* Unsupported, because we would break everything.  */
-                       err = -EINVAL;
-                       break;
-               }
-       }
-
-out:
-       unionfs_read_unlock(file->f_dentry->d_sb);
-       return err;
+       return generic_file_llseek(file, offset, origin);
 }
 
 /* Trimmed directory options, we shouldn't pass everything down since
diff --git a/fs/unionfs/dirhelper.c b/fs/unionfs/dirhelper.c
index d3edd0d..00ed474 100644
--- a/fs/unionfs/dirhelper.c
+++ b/fs/unionfs/dirhelper.c
@@ -129,11 +129,13 @@ out:
 
 #define RD_NONE 0
 #define RD_CHECK_EMPTY 1
+#define RD_CACHE_ODF 2
 /* The callback structure for check_empty. */
 struct unionfs_rdutil_callback {
        int err;
        int filldir_called;
        struct dentry *dir;
+       struct file *filp;
        struct unionfs_dir_state *rdstate;
        int mode;
 };
@@ -144,46 +146,73 @@ static int readdir_util_callback(void *dirent, const char 
*name, int namelen,
 {
        int err = 0;
        struct unionfs_rdutil_callback *buf = dirent;
-       int whiteout = 0;
+       int whiteout = 0, magic = ODF_DIRENT_MAGIC;
        struct filldir_node *found;
        struct odf_dentry_info *odi = NULL;
+       mm_segment_t oldfs;
 
-       buf->filldir_called = 1;
+       if (buf->mode == RD_CHECK_EMPTY)
+               buf->filldir_called = 1;
+       else
+               buf->filldir_called++;
 
-       if (name[0] == '.' && (namelen == 1 || (name[1] == '.' && namelen == 
2)))
+       if (name[0] == '.' 
+               && (namelen == 1 || (name[1] == '.' && namelen == 2))
+               && buf->mode == RD_CHECK_EMPTY)
                goto out;
 
        /* check odf */
-       odi = __odf_lookup(buf->dir, name, namelen, 0, 0);
+       odi = __odf_lookup(UNIONFS_D(buf->dir)->odf_info, name, namelen, 0, 0);
        if (IS_ERR(odi)){
                odi = NULL;
                goto out;
        }
-       if ((odi && !odi->whiteout) || !odi)
-               err = -ENOTEMPTY;
-       goto out; /* FIXME: bypass old code */
-
-       if (namelen > UNIONFS_WHLEN &&
-                       !strncmp(name, UNIONFS_WHPFX, UNIONFS_WHLEN)) {
-               namelen -= UNIONFS_WHLEN;
-               name += UNIONFS_WHLEN;
-               whiteout = 1;
+       if ((odi && !odi->whiteout) || !odi) {
+               if (buf->mode == RD_CHECK_EMPTY) {
+                       err = -ENOTEMPTY;
+                       goto out;
+               }
        }
-
+       if (odi && odi->whiteout)
+               whiteout = 1;
        found = find_filldir_node(buf->rdstate, name, namelen);
        /* If it was found in the table there was a previous whiteout. */
        if (found)
                goto out;
 
-       /* If it wasn't found and isn't a whiteout, the directory isn't empty. 
*/
-       err = -ENOTEMPTY;
-       if ((buf->mode == RD_CHECK_EMPTY) && !whiteout)
-               goto out;
-
        err = add_filldir_node(buf->rdstate, name, namelen,
                               buf->rdstate->bindex, whiteout);
+       if (buf->mode != RD_CACHE_ODF || !buf->filp)
+               goto out;
 
+       oldfs = get_fs();
+       set_fs(KERNEL_DS);
+       err = buf->filp->f_op->write(buf->filp, (char*)&magic,
+                               sizeof(int), &buf->filp->f_pos);
+       if (err != sizeof(int))
+               goto out;
+       err = buf->filp->f_op->write(buf->filp, (char*)&namelen,
+                               sizeof(int), &buf->filp->f_pos);
+       if (err != sizeof(int))
+               goto out;
+       err = buf->filp->f_op->write(buf->filp, (char*)name,
+                               namelen, &buf->filp->f_pos);
+       if (err != namelen)
+               goto out;
+       err = buf->filp->f_op->write(buf->filp, (char*)&ino,
+                       sizeof(u64), &buf->filp->f_pos);
+       if (err != sizeof(u64))
+               goto out;
+       err =buf->filp->f_op->write(buf->filp, (char*)&d_type,
+                       sizeof(unsigned int), &buf->filp->f_pos);
+       if (err != sizeof(unsigned int))
+               goto out;
+       set_fs(oldfs);
+       err = 0;
 out:
+       if (err > 0)
+               err = -EIO;
+
        odf_put_info(odi);
        buf->err = err;
        return err;
@@ -257,6 +286,7 @@ int check_empty(struct dentry *dentry, struct 
unionfs_dir_state **namelist)
                do {
                        buf->filldir_called = 0;
                        buf->dir = dentry;
+                       buf->filp = NULL;
                        buf->rdstate->bindex = bindex;
                        err = vfs_readdir(hidden_file,
                                          readdir_util_callback, buf);
@@ -288,3 +318,108 @@ out:
        return err;
 }
 
+/* Cache contents of dir to an odf/ic file */
+int odf_cache_dir(struct dentry *d_upper, struct dentry *d_odf)
+{
+       int err = 0;
+       struct dentry *hidden_dentry = NULL;
+       struct super_block *sb;
+       struct file *hidden_file, *odf_file = NULL;
+       struct unionfs_rdutil_callback *buf = NULL;
+       int bindex, bstart, bend, bopaque;
+
+       sb = d_upper->d_sb;
+
+       unionfs_read_lock(sb);
+
+       BUG_ON(!S_ISDIR(d_upper->d_inode->i_mode));
+
+       if ((err = unionfs_partial_lookup(d_upper)))
+               goto out;
+
+       dget(d_odf);
+       mntget(UNIONFS_SB(sb)->odf->mnt);
+       odf_file = dentry_open(d_odf,
+                       UNIONFS_SB(sb)->odf->mnt,
+                       O_TRUNC|O_CREAT|O_WRONLY);
+       if (IS_ERR(odf_file)){
+               err = PTR_ERR(odf_file);
+               odf_file = NULL;
+               goto out;
+       }
+
+       bstart = dbstart(d_upper);
+       bend = dbend(d_upper);
+       bopaque = dbopaque(d_upper);
+       if (0 <= bopaque && bopaque < bend)
+               bend = bopaque;
+
+       buf = kmalloc(sizeof(struct unionfs_rdutil_callback), GFP_KERNEL);
+       if (!buf) {
+               err = -ENOMEM;
+               goto out;
+       }
+       buf->err = 0;
+       buf->mode = RD_CACHE_ODF;
+       buf->rdstate = alloc_rdstate(d_upper->d_inode, bstart);
+       if (!buf->rdstate) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       /* Process the hidden directories with rdutil_callback as a filldir. */
+       for (bindex = bstart; bindex <= bend; bindex++) {
+               hidden_dentry = unionfs_lower_dentry_idx(d_upper, bindex);
+               if (!hidden_dentry)
+                       continue;
+               if (!hidden_dentry->d_inode)
+                       continue;
+               if (!S_ISDIR(hidden_dentry->d_inode->i_mode))
+                       continue;
+
+               dget(hidden_dentry);
+               mntget(unionfs_lower_mnt_idx(d_upper, bindex));
+               branchget(sb, bindex);
+               hidden_file =
+                   dentry_open(hidden_dentry, unionfs_lower_mnt_idx(d_upper, 
bindex),
+                               O_RDONLY);
+               if (IS_ERR(hidden_file)) {
+                       err = PTR_ERR(hidden_file);
+                       dput(hidden_dentry);
+                       branchput(sb, bindex);
+                       goto out;
+               }
+
+               do {
+                       buf->filldir_called = 0;
+                       buf->dir = d_upper;
+                       buf->filp = odf_file;
+                       buf->rdstate->bindex = bindex;
+                       err = vfs_readdir(hidden_file,
+                                         readdir_util_callback, buf);
+                       if (buf->err)
+                               err = buf->err;
+               } while ((err >= 0) && buf->filldir_called);
+
+               /* fput calls dput for hidden_dentry */
+               fput(hidden_file);
+               branchput(sb, bindex);
+
+               if (err < 0)
+                       goto out;
+       }
+
+out:
+       if (buf) {
+               if (buf->rdstate)
+                       free_rdstate(buf->rdstate);
+               kfree(buf);
+       }
+
+       if (odf_file)
+               filp_close(odf_file, NULL);
+
+       unionfs_read_unlock(sb);
+
+       return err;
+}
diff --git a/fs/unionfs/odf.c b/fs/unionfs/odf.c
index 66d089c..eaeb2be 100644
--- a/fs/unionfs/odf.c
+++ b/fs/unionfs/odf.c
@@ -227,9 +227,9 @@ int odf_lookup(struct dentry *parent, struct dentry 
*dentry, int flags)
 {      
        int err = 0;
        UNIONFS_D(dentry)->odf_info = __odf_lookup(
-                               parent, 
-                               dentry->d_name.name, 
-                               dentry->d_name.len, 
+                               UNIONFS_D(parent)->odf_info,
+                               dentry->d_name.name,
+                               dentry->d_name.len,
                                flags,
                                UNIONFS_D(dentry)->odf_info);
        if (IS_ERR(UNIONFS_D(dentry)->odf_info)){
@@ -239,16 +239,15 @@ int odf_lookup(struct dentry *parent, struct dentry 
*dentry, int flags)
        return err;
 }
 
-struct odf_dentry_info *__odf_lookup(struct dentry *parent, const char *name, 
+struct odf_dentry_info *__odf_lookup(struct odf_dentry_info *parent, const 
char *name, 
                                        int len, int flags,  struct 
odf_dentry_info *old_odi)
 {
        struct dentry *odf_dentry;
        struct odf_dentry_info *odi = old_odi;
-       struct inode *odf_i_dir = UNIONFS_D(parent)->odf_info->dentry->d_inode;
+       struct inode *odf_i_dir = parent->dentry->d_inode;
        int err = 0;
        
-       odf_dentry = lookup_one_len(name, 
-                       UNIONFS_D(parent)->odf_info->dentry, len);
+       odf_dentry = lookup_one_len(name, parent->dentry, len);
        
        /* if create flags are set, remove existing whiteout */
        if (!IS_ERR(odf_dentry) 
@@ -258,8 +257,7 @@ struct odf_dentry_info *__odf_lookup(struct dentry *parent, 
const char *name,
                if (__odf_is_wh(odf_dentry->d_inode)){
                        vfs_unlink(odf_i_dir, odf_dentry);
                        //dput(odf_dentry);
-                       odf_dentry = lookup_one_len(name,
-                               UNIONFS_D(parent)->odf_info->dentry, len);
+                       odf_dentry = lookup_one_len(name, parent->dentry, len);
                }
        }
 
@@ -275,7 +273,7 @@ struct odf_dentry_info *__odf_lookup(struct dentry *parent, 
const char *name,
                        BUG_ON(len==1 || (name[1]=='.'&&len==2));
        
                /* FIXME need to check hardlinks before create */
-               odf_lock(UNIONFS_D(parent)->odf_info); /* lock parent */
+               odf_lock(parent); /* lock parent */
 
                if (flags & ODF_LOOKUP_FILE)
                        err = vfs_create(odf_i_dir, odf_dentry, S_IRWXUGO, 0 );
@@ -285,7 +283,7 @@ struct odf_dentry_info *__odf_lookup(struct dentry *parent, 
const char *name,
 
                else {
                        dput(odf_dentry);
-                       odf_unlock(UNIONFS_D(parent)->odf_info);
+                       odf_unlock(parent);
                        goto out;
                }
                if (err) {
@@ -295,7 +293,7 @@ struct odf_dentry_info *__odf_lookup(struct dentry *parent, 
const char *name,
                        goto out;
                }
 
-               odf_unlock(UNIONFS_D(parent)->odf_info);
+               odf_unlock(parent);
 
                /* set opaqueness to 0 or -1 */
                __odf_set_opaque(odf_dentry->d_inode,
@@ -312,6 +310,66 @@ out:
        return odi;
 }
 
+struct odf_dentry_info *odf_ic_dir(struct dentry *dir)
+{
+       struct odf_dentry_info *odi_dir, *odis[4], *odi_ic, *odi_ret = NULL;
+       u64 ino;
+       int breakdown[4];
+       char name[6];
+       int i, err = 0;
+
+       if (!S_ISDIR(dir->d_inode->i_mode)) {
+               err = -ENOTDIR;
+               goto out;
+       }
+       odi_ic = UNIONFS_SB(dir->d_sb)->odf->odi_ic;
+       odi_dir = UNIONFS_D(dir)->odf_info;
+       if (!odi_dir) {
+               err = -ENOENT;
+               goto out;
+       }
+       
+       ino = odi_dir->inum;
+       for (i = 3; i >= 0; i--) {
+               breakdown[i] = ino & 0xFFFF;
+               ino >>= 16;
+               odis[i] = NULL;
+       }
+
+       memset(name,0,6);
+       sprintf(name, "%d", breakdown[0]);
+       odis[0] = __odf_lookup(odi_ic, name, strlen(name), ODF_LOOKUP_DIR, 
NULL);
+       if (IS_ERR(odis[0])) {
+               err = PTR_ERR(odis[0]);
+               odis[0] = NULL;
+               goto out;
+       }
+       for (i = 1; i < 4; i++) {
+               memset(name,0,6);
+               sprintf(name, "%x", breakdown[i]);
+               odis[i] = __odf_lookup(odis[i-1], name, strlen(name), 
ODF_LOOKUP_DIR, NULL);
+               if (IS_ERR(odis[i])) {
+                       err = PTR_ERR(odis[i]);
+                       odis[i] = NULL;
+                       goto out;
+               }
+       }
+       
+       odi_ret = __odf_lookup(odis[3], "content", 7, ODF_LOOKUP_FILE, NULL);
+       if (IS_ERR(odi_ret)) {
+               err = PTR_ERR(odi_ret);
+               odi_ret = NULL;
+               goto out;
+       }
+
+out:
+       for (i = 0; i < 4; i++)
+               odf_put_info(odis[i]);
+       if (err) 
+               return ERR_PTR(err);
+       return odi_ret;
+}
+
 /*
  * Unlinks the file from odf if exist, creates a new file with
  * the same name and sets its whiteout flag
diff --git a/fs/unionfs/odf.h b/fs/unionfs/odf.h
index 2be1dc2..5299a59 100644
--- a/fs/unionfs/odf.h
+++ b/fs/unionfs/odf.h
@@ -32,6 +32,8 @@
 #define ODF_OPQ_BASE 26 /* 0x04000000, bits 26 - 30 */
 #define ODF_OPQ_BITS 5
 
+#define ODF_DIRENT_MAGIC 0x0DFD1300
+
 /* super */
 struct odf_sb_info* odf_read_super(char *odffile);
 void odf_put_super(struct odf_sb_info *osi);
@@ -41,7 +43,9 @@ int odf_putoptions(struct super_block* sb_union, struct 
unionfs_dentry_info *hid
 
 /* lookup */
 int odf_lookup(struct dentry *parent, struct dentry *dentry, int flags);
-struct odf_dentry_info *__odf_lookup(struct dentry *parent, const char *name, 
int len, int flags, struct odf_dentry_info *old_odi);
+struct odf_dentry_info *__odf_lookup(struct odf_dentry_info *parent, const 
char *name, int len, int flags, struct odf_dentry_info *old_odi);
+struct odf_dentry_info *odf_ic_dir(struct dentry *dir);
+
 struct odf_dentry_info *odf_getpath(char *path);
 struct odf_dentry_info *odf_fill_info(struct odf_dentry_info *odi, struct 
dentry *odf_dentry);
 struct odf_dentry_info *odf_alloc_info(struct dentry *odf_dentry);
@@ -68,6 +72,8 @@ int __odf_is_opaque(struct inode *i);
 int __odf_get_opaque(struct inode *i);
 int __odf_set_opaque(struct inode *i, int branch);
 
+int odf_cache_dir(struct dentry *d_upper, struct dentry *d_odf);
+
 /* Macros for locking an odf dentry info. */
 static inline void odf_lock(struct odf_dentry_info *odi)
 {
_______________________________________________
unionfs-cvs mailing list: http://unionfs.filesystems.org/
[email protected]
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs-cvs

Reply via email to