#ifndef _LINUX_IFS_FS_H
#define _LINUX_IFS_FS_H

/*
 * The inheriting filesystem constants/structures
 */

#include <linux/fs.h>
#include <linux/ifs_fs_param.h>

#define Dprintk (void)

#define IFS_SUPER_MAGIC 0x494e /* IN */
#define IFS_ANY_INO 1 /* can be any value outside of IFS_MIN_INO..IFS_MAX_INO */

#define IFS_MIN_INO          2
#define IFS_MAX_INO 0x7ffffff0

#define IFS_UNWHITEOUT	0x53464900	/* unwhiteout ioctl */

#define IFS_ST_NORMAL	0 /* no special attributes */
#define IFS_ST_WHITEOUT	1 /* entry is whited out */
#define IFS_ST_HIDE	2 /* lower levels are hidden */

#define IFS_FF_CACHE	1 /* be an on-demand cache instead of an IFS */

#define IFS_CAN_SB(inode,nth,op) \
  ((inode) && IFS_I(inode)->layer[nth] && IFS_I(inode)->layer[nth]->i_sb && \
    IFS_I(inode)->layer[nth]->i_sb->s_op && \
    IFS_I(inode)->layer[nth]->i_sb->s_op->op)
#define IFS_DO_SB(inode,nth,op,args) \
  IFS_I(inode)->layer[nth]->i_sb->s_op->op args
#define IFS_VAL_SB(inode,nth,op,args) \
  (IFS_CAN_SB(inode,nth,op) ? IFS_DO_SB(inode,nth,op,args) : -EBADF)
#define IFS_OP_SB(inode,nth,op,args) \
  if (IFS_CAN_SB(inode,nth,op)) IFS_DO_SB(inode,nth,op,args)

#define IFS_CAN_INODE(inode,nth,op) \
  ((inode) && IFS_I(inode)->layer[nth] && IFS_I(inode)->layer[nth]->i_op && \
    IFS_I(inode)->layer[nth]->i_op->op)
#define IFS_DO_INODE(inode,nth,op,args) \
  IFS_I(inode)->layer[nth]->i_op->op args
#define IFS_VAL_INODE(inode,nth,op,args) \
  (IFS_CAN_INODE(inode,nth,op) ? IFS_DO_INODE(inode,nth,op,args) : -EBADF)
#define IFS_OP_INODE(inode,nth,op,args) \
  if (IFS_CAN_INODE(inode,nth,op)) IFS_DO_INODE(inode,nth,op,args)

/*
 * KLUDGE ALERT: IFS should use its own struct file and go through the normal
 *               open routines.
 */

#define IFS_CAN_FILE(inode,nth,op) \
  ((inode) && IFS_I(inode)->layer[nth] && IFS_I(inode)->layer[nth]->i_op && \
    IFS_I(inode)->layer[nth]->i_op->default_file_ops && \
    IFS_I(inode)->layer[nth]->i_op->default_file_ops->op)
#define IFS_DO_FILE(inode,nth,op,args) \
    IFS_I(inode)->layer[nth]->i_op->default_file_ops->op args

#define USE_INODE(inode) ((inode)->i_count++)

#define IFS_DOT_NAME(n,l) \
  ((l == 1 || l == 2) && n[0] == '.' && (l == 1 || n[1] == '.'))
#define IFS_DEL_NAME(n,l) \
  (l == 3 && n[2] == '.' && n[0] == '.' && n[1] == '.')

#define IFS_SB(s) (&((s)->u.ifs_sb))
#define IFS_I(i) (&((i)->u.ifs_i))
#define IFS_F(f) (&((f)->u.ifs_f))
#define IFS_NTH(i,n) ((i)->u.ifs_i.layer[n])
#define IFS_LAYERS(i) ((i)->i_sb->u.ifs_sb.layers)

#define IFS_IS_RO(i) (IS_RDONLY(IFS_NTH(i->i_sb->s_mounted,0)))

/*
 * This one is ugly: creation routines have many parts in common. Therefore,
 * everything is handled by a single routine. Unfortunately, we need to access
 * function pointers in the i_op fields of inodes that are only known at run
 * time. This is done by using an offset into i_op and casting everything to
 * ints. A solution involving macros would generate a lot more code and
 * wouldn't be much more readable.
 */

#define IFS_IOP_OFF(op) ((char *) &dummy_ops.op-(char *) &dummy_ops)

#define IFS_MOUNT_MAGIC 0x2a534649 /* "IFS*" */

struct ifs_mpar {
	unsigned long magic; /* must be IFS_MOUNT_MAGIC */
	int flags;	/* IFS-specific mount flags */
	int layers;	/* number of layers */
	char *names[IFS_MAX_LAYERS];
};


/* misc.c */

extern void ifs_lock(struct inode *inode);
extern void ifs_unlock(struct inode *inode);
extern void ifs_lock4(struct inode *i1,struct inode *i2,struct inode *i3,
    struct inode *i4);
extern void ifs_unlock4(struct inode *i1,struct inode *i2,struct inode *i3,
    struct inode *i4);
extern void ifs_adjust_ops(struct inode *ifs_inode);
extern void ifs_init_inode(struct inode *ifs_inode,struct inode **layers);
extern struct inode *ifs_iget(struct super_block *sb,struct inode **res,
    int layers,int *is_new);
extern int ifs_status(struct inode *dir,const char *name,int len);
extern int ifs_whiteout(struct inode *dir,const char *name,int len);
extern int ifs_hide(struct inode *dir,const char *name,int len);
extern int ifs_unwhiteout(struct inode *dir,const char *name,int len);
extern int ifs_user_unwhiteout(struct inode *dir,const char *name,int len);
extern int ifs_unhide(struct inode *dir,const char *name,int len);
extern int ifs_open_file(struct inode *inode,struct file **filp,int flags);
extern void ifs_close_file(struct file *filp);
extern int ifs_empty(struct inode *dir,int ifs_dir);
extern int ifs_purge(struct inode *dir);

/* clone.c */

extern int ifs_build_path(struct inode *dir);
extern int ifs_clone_file(struct inode *inode);
extern int ifs_copy_object(struct inode *object,struct inode *dir,
    const char *name,int len);

/* namei.c */

extern int ifs_lookup(struct inode *dir,const char *name,int len,
    struct inode **result);
extern int ifs_create(struct inode *dir,const char *name,int len,int mode,
    struct inode **result);
extern int ifs_mkdir(struct inode *dir,const char *name,int len,int mode);
extern int ifs_rmdir(struct inode *dir,const char *name,int len);
extern int ifs_unlink(struct inode *dir,const char *name,int len);
extern int ifs_symlink(struct inode *inode,const char *name,int len,
    const char *symname);
extern int ifs_link(struct inode *oldinode,struct inode *dir,const char *name,
    int len);
extern int ifs_mknod(struct inode *dir,const char *name,int len,int mode,
    int rdev);
extern int ifs_rename(struct inode *old_dir,const char *old_name,int old_len,
    struct inode *new_dir,const char *new_name,int new_len);

/* inode.c */

extern void ifs_put_inode(struct inode *inode);
extern void ifs_put_super(struct super_block *sb);
extern void ifs_write_super(struct super_block *sb);
extern struct super_block *ifs_read_super(struct super_block *s,void *data,
    int silent);
extern void ifs_statfs(struct super_block *sb,struct statfs *buf);
extern void ifs_read_inode(struct inode *inode);
extern void ifs_write_inode(struct inode *inode);
extern int ifs_notify_change(int flags,struct inode *inode);

/* dir.c */

extern struct inode_operations ifs_dir_inode_operations;

/* file.c */

extern struct inode_operations ifs_file_inode_operations;
extern void ifs_truncate(struct inode *inode);

/* symlink.c */

extern struct inode_operations ifs_symlink_inode_operations;

#endif
