/* -*- c-file-style: "linux" -*-
 *
 * newuserfs -- Linux filesystem through callbacks to a local process
 *
 * Copyright (C) 2001 by Martin Pool <mbp@samba.org>
 */

enum userfs_dirn {
	USERFS_TO_KERN = 0x55537430,    /* USt0 */
	USERFS_FROM_KERN = 0x55536630,  /* USf0 */
};


enum userfs_opcode {
	USERFS_NOOP				= 0,
	USERFS_OP_MOUNT				= 1,
	USERFS_OP_READINODE			= 2,
	USERFS_OP_LOOKUP			= 3,
	USERFS_OP_CREATE			= 4,
	USERFS_OP_READDIR			= 5,
	USERFS_OP_READ				= 6,
	USERFS_NUMOPS
};


/* This is the same as in linux 2.4.9, but we need to count on it being stable */
#define USERFS_NAME_MAX 255


#define USERFS_DATALEN		1024

/*
 * Standard packet header for calls and responses.  These are
 * transmitted with native integer sizes, endianness, and padding.
 *
 * This is followed by nbytes of bulk data if necessary, for example
 * for read and write calls.
 *
 * TODO: Perhaps support versioning or a length field?  It would spoil
 * our nice simple IO model, but might be more extensible.
 * Alternatively the "HELLO" operation could contain a special thing
 * to let the two programs work out if they understand the same
 * protocol or not.
 *
 * XXX: This structure is getting large enough that eventually we may
 * not want to ship the whole thing every time.  We could split it
 * into versions to be used for particular types of operations,
 * e.g. ones requiring stat information.  Alternatively we could go to
 * a full marshalling system, but that's a lot of work just for an
 * optimization.
 */
typedef struct userfs_packet {
	int pk_dirn;
	int pk_seq;
	int pk_op;
	int pk_err;
	int		pk_datalen;

	/** The relevant inode for this call, if any. */
	unsigned long pk_inum;

	/* Also: other fields from struct inode and struct file. */

	/** Must be non-zero if the file exists: high-order bits are
	 * S_IFREG or something similar. */
	int		pk_mode;

	/** TRUE during LOOKUP if the file exists.  It's possible for
	 * it to not exist and not be an error. */
	int		pk_exists;
	
	int		pk_uid, pk_gid;
	int		pk_dev[2]; /* major, minor */
	int		pk_nlink;
	unsigned long long pk_size;
	int		pk_atime, pk_mtime, pk_ctime;
	unsigned long long	pk_blksize, pk_blocks, bk_version;
	int		pk_attr_flags;     

	/* Things relevant to IO operations */
	loff_t		pk_pos;

	/* This is assigned by the OPEN call, and returned on all
	 * future operations through that file handle.  So, if the
	 * filesystem needs to carry over some information it can do
	 * so: the common example is that Unix filesystems
	 * traditionally check access at open time, not for each
	 * operation.  If it's not needed, it can be set to 0.
	 */
	 
	unsigned long	pk_cred_cookie;

	/* When setting/getting attributes, this says which ones we
	 * care about. */
	int		pk_attrmask;

	char		pk_name[USERFS_NAME_MAX+1];

	/* TODO: Perhaps have a field saying what filesystem this is,
	 * in case we eventually support multiple mounts across a
	 * single channel.  I think the kernel has a way for us to get
	 * a dynamic fake device number. */

	/* TODO: We also need space for at least two paths -- two are
	 * needed for creating symlinks.  Should they be directly in
	 * this structure, or stored afterwards? */  

	/* For rename, we need to specify the inode of the source
	 * directory, the name (dentry) of the source file, and the
	 * destination directory and name. */

	/* XXX: Is it enough to just map dentries into names?  They
	 * also have a pointer to their inode, if any, but that is
	 * perhaps not very useful to expose to the server.  dentries
	 * also know who their parent is, but I'm not sure if we need
	 * to expose that either. */

	char		pk_data[USERFS_DATALEN];
} userfs_packet_t;




#define USERFS_SUPER_MAGIC	0x11031976


/* Macros to access through the generic field of unions. */
#define U_SB(sb)	(*(struct userfs_sb_info *)(sb)->u.generic_sbp)
#define U_INO(ino)	(*(struct userfs_inode_info *)(ino)->u.generic_ip)
#define U_SBP(sb)	((struct userfs_sb_info *)(sb)->u.generic_sbp)
#define U_INOP(ino)	((struct userfs_inode_info *)(ino)->u.generic_ip)
#define U_FILEP(file)	((struct userfs_file_info *)(file)->private_data)
#define U_FILE(file)	(*(struct userfs_file_info *)(file)->private_data)

#define USERFS_NAME "userfs"

/* userfs-specific parts of a superblock.
 *
 * Needs to have references to files for doing input and output.
 */
struct userfs_sb_info {
	int s_seqno;
	struct file *s_fromkern_file, *s_tokern_file;
};


#ifdef __KERNEL__
#  define userfs_log(fmt, arg...) printk (__FUNCTION__ ": " fmt "\n" , ##arg)

struct super_operations userfs_super_ops;
struct inode_operations userfs_inode_ops;
struct file_operations userfs_file_ops;

#else /* __KERNEL__ */

#  define userfs_log(fmt, arg...) fprintf (stderr, __FUNCTION__ ": " fmt "\n" , ##arg)


/**
 * Basic callback typ for implementing all operations.
 **/
typedef int (*userfs_packet_cb)(const struct userfs_packet *,
				struct userfs_packet *);

/**
 * Implementers of userspace servers should fill in these structures,
 * which mirror those inside the kernel.
 **/
typedef userfs_packet_cb userfs_dispatch_t[USERFS_NUMOPS];

int userfs_main_loop (userfs_dispatch_t);

#endif /* ! __KERNEL__ */


#ifndef TRUE
#  define TRUE 1
#  define FALSE 0
#endif
