// -*- C++ -*-
// File: reiserfs.h
//
// Created: Mon Jan 22 20:43:03 2001
//
// $Id$
//

struct m_reiserfs_super_block
{
  __u32 s_block_count;
  __u32 s_free_blocks;                  /* free blocks count    */
  __u32 s_root_block;           	/* root block number    */
  __u32 s_journal_block;           	/* journal block number    */
  __u32 s_journal_dev;           	/* journal device number  */
  __u32 s_orig_journal_size; 		
  __u32 s_journal_trans_max ;           /* max number of blocks in a transaction.  */
  __u32 s_journal_block_count ;         /* total size of the journal. can change over time  */
  __u32 s_journal_max_batch ;           /* max number of blocks to batch into a trans */
  __u32 s_journal_max_commit_age ;      /* in seconds, how old can an async commit be */
  __u32 s_journal_max_trans_age ;       /* in seconds, how old can a transaction be */
  __u16 s_blocksize;                   	/* block size           */
  __u16 s_oid_maxsize;			/* max size of object id array, see get_objectid() commentary  */
  __u16 s_oid_cursize;			/* current size of object id array */
  __u16 s_state;                       	/* valid or error       */
  char s_magic[12];                     /* reiserfs magic string indicates that file system is reiserfs */
  __u32 s_hash_function_code;		/* indicate, what hash function is being use to sort names in a directory*/
  __u16 s_tree_height;                  /* height of disk tree */
  __u16 s_bmap_nr;                      /* amount of bitmap blocks needed to address each block of file system */
  __u16 s_version;		/* I'd prefer it if this was a string,
                                   something like "3.6.4", and maybe
                                   16 bytes long mostly unused. We
                                   don't need to save bytes in the
                                   superblock. -Hans */
  __u16 s_reserved;
  char s_unused[128] ;			/* zero filled by mkreiserfs */
}__attribute__ ((__packed__)) ;


#include <asm/uaccess.h>


#define REISERFS_SUPER_MAGIC 0x52654973
				/* used by file system utilities that look at the superblock, etc. */
#define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"
#define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs"

static inline int is_reiserfs_magic_string (struct m_reiserfs_super_block * rs)
{
    return (!strncmp (rs->s_magic, REISERFS_SUPER_MAGIC_STRING, 
					  strlen ( REISERFS_SUPER_MAGIC_STRING)) ||
			!strncmp (rs->s_magic, REISER2FS_SUPER_MAGIC_STRING, 
					  strlen ( REISER2FS_SUPER_MAGIC_STRING)));
}

struct offset_m_v1
{
    __u32 k_offset;
    __u32 k_uniqueness;
} __attribute__ ((__packed__)) ;

struct offset_m_v2
{
    __u64 k_offset:60;
    __u64 k_type: 4;
} __attribute__ ((__packed__));


/* Key of an item determines its location in the S+tree, and
   is composed of 4 components */
struct m_key
{
    __u32 k_dir_id;    /* packing locality: by default parent
						  directory object id */
    __u32 k_objectid;  /* object identifier */
    union
	{
		struct offset_m_v1 k_offset_v1;
		struct offset_m_v2 k_offset_v2;
    }  u;
} ;


#define M_KEY_SIZE (sizeof(struct m_key))
#define SHORT_KEY_SIZE (sizeof (__u32) + sizeof (__u32))

#define REISERFS_FULL_KEY_LEN     4
#define REISERFS_SHORT_KEY_LEN    2
#define m_comp_keys(k1,k2)        m__comp_keys((k1), (k2), 1)
#define m_comp_short_keys(k1,k2)  m__comp_keys((k1), (k2), 0)


#define ITEM_VERSION_1 0
#define ITEM_VERSION_2 1

#define TYPE_STAT_DATA 0
#define TYPE_INDIRECT 1
#define TYPE_DIRECT 2
#define TYPE_DIRENTRY 3 
#define TYPE_ANY 15 // FIXME: comment is required

#define V1_SD_UNIQUENESS 0
#define V1_INDIRECT_UNIQUENESS 0xfffffffe
#define V1_DIRECT_UNIQUENESS 0xffffffff
#define V1_DIRENTRY_UNIQUENESS 500
#define V1_ANY_UNIQUENESS 555 // FIXME: comment is required


extern inline int m_le_key_version (struct m_key * key)
{
    int type;
    type = le16_to_cpu (key->u.k_offset_v2.k_type);
    if (type != TYPE_DIRECT && type != TYPE_INDIRECT && type != TYPE_DIRENTRY)
		return ITEM_VERSION_1;
	else
		return ITEM_VERSION_2;
}

extern inline int uniqueness2type (__u32 uniqueness)
{
    switch (uniqueness)
		{
		case V1_SD_UNIQUENESS: return TYPE_STAT_DATA;
		case V1_INDIRECT_UNIQUENESS: return TYPE_INDIRECT;
		case V1_DIRECT_UNIQUENESS: return TYPE_DIRECT;
		case V1_DIRENTRY_UNIQUENESS: return TYPE_DIRENTRY;
		}
    return TYPE_ANY;
}

#define M_COMP_KEYS m_comp_keys
#define M_COMP_SHORT_KEYS m_comp_short_keys

//#define GET_HASH_VALUE(offset) ((offset) & 0x7fffff80)
#define M_GET_HASH_VALUE(offset) ((offset) & 0x7fffff80LL)

#define JOURNAL_TRANS_HALF 1018   /* must be correct to keep the desc and commit structs at 4k */

#define REISERFS_ROOT_OBJECTID 2
#define REISERFS_ROOT_PARENT_OBJECTID 1

#define JOURNAL_BLOCK_COUNT 8192 /* number of blocks in the journal */

#define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024)

#define SD_OFFSET  0
#define SD_UNIQUENESS 0
#define DOT_OFFSET 1
#define DOT_DOT_OFFSET 2
/*
#define DIRENTRY_UNIQUENESS 500
*/

/* The result of the key compare */
#define FIRST_GREATER 1
#define SECOND_GREATER -1
#define KEYS_IDENTICAL 0
#define KEY_FOUND 1
#define KEY_NOT_FOUND 0

#define ITEM_VERSION_1 0
#define ITEM_VERSION_2 1

/*
#define I_K_KEY_IN_ITEM(p_s_ih, p_s_key, n_blocksize) \
          ( ! M_COMP_SHORT_KEYS(p_s_ih, p_s_key) &&  I_OFF_BYTE_IN_ITEM(p_s_ih, k_offset (p_s_key), n_blocksize) )
*/
struct m_item_head
{
  struct m_key ih_key; 	/* Everything in the tree is found by searching for it based on its key.*/
	union
	{
		__u16 ih_free_space_reserved; /* The free space in the last unformatted node of an indirect item if this
										 is an indirect item.  This equals 0xFFFF iff this is a direct item or
										 stat data item. Note that the key, not this field, is used to determine
										 the item type, and thus which field this union contains. */
		__u16 ih_entry_count;         /* Iff this is a directory item, this field equals the number of directory
										 entries in the directory item. */
	}  u;
	__u16 ih_item_len;           /* total size of the item body                  */
	__u16 ih_item_location;      /* an offset to the item body within the block  */
	__u16 ih_version;	             /* 0 for all old items, 2 for new
									ones. Highest bit is set by fsck
									temporary, cleaned after all done */
} ;

#define M_IH_SIZE (sizeof(struct m_item_head))

struct m_block_head
{
  __u16 blk_level;        /* Level of a block in the tree. */
  __u16 blk_nr_item;      /* Number of keys/items in a block. */
  __u16 blk_free_space;   /* Block free space in bytes. */
  __u16 blk_reserved;
	                      /* dump this in v4/planA */
  struct m_key  blk_right_delim_key; /* kept only for compatibility */
};

#define M_BLKH_SIZE (sizeof(struct m_block_head))


struct m1_stat_data
{
    __u16 sd_mode;	/* file type, permissions */
    __u16 sd_reserved;
    __u32 sd_nlink;	/* number of hard links */
    __u64 sd_size;	/* file size */
    __u32 sd_uid;		/* owner */
    __u32 sd_gid;		/* group */
    __u32 sd_atime;	/* time of last access */
    __u32 sd_mtime;	/* time file was last modified  */
    __u32 sd_ctime;	/* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */
    __u32 sd_blocks;
    union
	{
	__u32 sd_rdev;
	} __attribute__ ((__packed__)) u;
} __attribute__ ((__packed__));

struct m_stat_data
{
    __u16 sd_mode;	/* file type, permissions */
    __u16 sd_reserved;
    __u32 sd_nlink;	/* number of hard links */
    __u64 sd_size;	/* file size */
    __u32 sd_uid;		/* owner */
    __u32 sd_gid;		/* group */
    __u32 sd_atime;	/* time of last access */
    __u32 sd_mtime;	/* time file was last modified  */
    __u32 sd_ctime;	/* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */
    __u32 sd_blocks;
	__u32 sd_rdev;
}__attribute__ ((__packed__));
//
// this is 40 bytes long
//
#define M_SD_SIZE (sizeof(struct m_stat_data))

struct reiserfs_m_de_head
{
  __u32 deh_offset;		/* third component of the directory entry key */
  __u32 deh_dir_id;		/* objectid of the parent directory of the object, that is referenced
					   by directory entry */
  __u32 deh_objectid;		/* objectid of the object, that is referenced by directory entry */
  __u16 deh_location;		/* offset of name in the whole item */
  __u16 deh_state;		/* whether 1) entry contains stat data (for future), and 2) whether
					   entry is hidden (unlinked) */
} ;
#define M_DEH_SIZE sizeof(struct reiserfs_m_de_head)

struct m_disk_child {
  __u32       dc_block_number;              /* Disk child's block number. */
  __u16       dc_size;		            /* Disk child's used space.   */
  __u16       dc_reserved;
};
#define M_DC_SIZE (sizeof(struct m_disk_child))


/* first block written in a commit.  */
struct reiserfs_m_journal_desc {
  __u32 j_trans_id ;			/* id of commit */
  __u32 j_len ;			/* length of commit. len +1 is the commit block */
  __u32 j_mount_id ;				/* mount id of this trans*/
  __u32 j_realblock[JOURNAL_TRANS_HALF] ; /* real locations for each block */
  char j_magic[12] ;
} ;

/* last block written in a commit */
struct reiserfs_m_journal_commit {
  __u32 j_trans_id ;			/* must match j_trans_id from the desc block */
  __u32 j_len ;			/* ditto */
  __u32 j_realblock[JOURNAL_TRANS_HALF] ; /* real locations for each block */
  char j_digest[16] ;			/* md5 sum of all the blocks involved, including desc and commit. not used, kill it */
} ;

/* this header block gets written whenever a transaction is considered fully flushed, and is more recent than the
** last fully flushed transaction.  fully flushed means all the log blocks and all the real blocks are on disk,
** and this transaction does not need to be replayed.
*/
struct reiserfs_m_journal_header {
  __u32 j_last_flush_trans_id ;		/* id of last fully flushed transaction */
  __u32 j_first_unflushed_offset ;      /* offset in the log of where to start replay after a crash */
  __u32 j_mount_id ;
} ;


#define M_MAX_ITEM_LEN(block_size) (block_size - M_BLKH_SIZE - M_IH_SIZE)

#define MIN_ITEM_LEN 1

#define REISERFS_BLOCK_SIZE 4096

struct reiserfs_m_inode
{
	struct m_key i_key ;
	int i_data_length;
	__u32 i_data [2];

//	__u32 i_data [REISERFS_N_BLOCKS];
//	M_MAX_ITEM_LEN(REISERFS_BLOCK_SIZE)/sizeof(__u32)];

	__u16 i_mode;	/* file type, permissions */
    __u32 i_uid;		/* owner */
    __u64 i_size;	/* file size */
    __u32 i_atime;	/* time of last access */
    __u32 i_ctime;	/* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */
    __u32 i_mtime;	/* time file was last modified  */
    __u32 i_dtime;	/* time file was last modified  */
    __u32 i_gid;		/* group */
    __u32 i_nlink_count;	/* number of hard links */

    __u32 i_blocks;
	__u32 i_flags;	/* File flags */
	__u32 i_version;	/* File version (for NFS) */
};

struct milo_item
{
	struct m_key ih_key;
	union
	{
		__u16 ih_free_space; 
		__u16 ih_entry_count; 
	} u;
	__u16 ih_item_len;
	__u16 ih_item_location;
	__u16 ih_version;

	__u16 it_Last;
	__u16 it_Number;

	struct m_key ih_r_key;

	union
	{
		struct m1_stat_data sd1;
		struct m_stat_data sd;
		struct reiserfs_m_de_head deh[(M_MAX_ITEM_LEN(REISERFS_BLOCK_SIZE)-M_DEH_SIZE)/M_DEH_SIZE];
		__u32 item[M_MAX_ITEM_LEN(REISERFS_BLOCK_SIZE)/sizeof(__u32)];
		char txt[M_MAX_ITEM_LEN(REISERFS_BLOCK_SIZE)];
	} body;
} ;


struct reiserfs_journal_ptr
{
	__u32 r_BlockNr;
	__u32 j_BlockNr;
};


static struct reiserfs_m_journal_desc * desc;
static struct reiserfs_m_journal_commit * commit;
static struct reiserfs_m_journal_header * jh ;


#define VV_ITEMS(bh)	  	   ((__u32)((bh)->blk_nr_item))
#define VV_CHILD(bh,n_pos)     ((struct m_disk_child *)((char *)(bh)+M_BLKH_SIZE+VV_ITEMS(bh)*M_KEY_SIZE+M_DC_SIZE*(n_pos)))
#define VV_CHILD_NUM(bh,n_pos) ((__u32)VV_CHILD((bh),(n_pos))->dc_block_number)
#define VV_KEY(bh,n_pos)       ((struct m_key *)((char *)(bh)+M_BLKH_SIZE+M_KEY_SIZE*(n_pos)))
#define VV_IHEAD(bh,n_pos)     ((struct m_item_head *)((char *)(bh)+M_BLKH_SIZE+M_IH_SIZE*(n_pos)))
#define VV_ITEM(bh,n_pos)      ((void *)((char *)(bh)+(VV_IHEAD((bh),(n_pos)))->ih_item_location))
#define VV_ITEM_SIZE(bh,n_pos) ((unsigned short)((char *)(bh)+(VV_IHEAD((bh),(n_pos)))->ih_item_len))

#define VV_M_IHEAD(p_i,bh,n_pos) vv_m_ihead((p_i),(bh),(n_pos))

#define m_copy_key(to,from)        memcpy((to), (from), M_KEY_SIZE )
#define m1_copy_key(to,from) {\
if (m_le_key_version (from)== ITEM_VERSION_1)\
{\
	memcpy((to), (from), SHORT_KEY_SIZE ); \
((struct m_key *)(to))->u.k_offset_v2.k_offset=\
	((struct m_key *)(from))->u.k_offset_v1.k_offset;\
((struct m_key *)(to))->u.k_offset_v2.k_type=\
	uniqueness2type(((struct m_key *)(from))->u.k_offset_v1.k_uniqueness);\
}\
else memcpy((to), (from), M_KEY_SIZE );\
}
