/* $Header:dfs.h 12.0$ */
/* $ACIS:dfs.h 12.0$ */
/* $Source: /ibm/acis/usr/sys/dfs/RCS/dfs.h,v $ */

#if !defined(lint) && !defined(LOCORE) && defined(RCS_HDRS)
static char *rcsiddfs = "$Header:dfs.h 12.0$";
#endif

#ifdef DFS
#ifndef __DFS_HEADER__
#define __DFS_HEADER__

/* NOTE: y must be a power of 2 */
#define ROUND(x,y)	(((x)+((y)-1)) & ~((y)-1))

/*
 * directory entry structure
 */
#define DFS_MAX_NAME_LENGTH	11
#define DFS_MAX_FILE_LENGTH	8
struct dfs_dir {
	u_char	dfs_name[DFS_MAX_NAME_LENGTH];
#define dfs_flag dfs_name[0]
#define DFS_DIR_NOTUSED	0
#define DFS_DIR_ERASED	0xe5
#define DFS_DIR_DIRECTORY 0x2e
	u_char	dfs_attributes;
#define DFS_READ_ONLY	0x01
#define DFS_HIDDEN	0x02
#define DFS_SYSTEM	0x03
#define DFS_VOL_LABLE	0x08
#define DFS_DIRECTORY	0x10
#define DFS_ARCHIVE	0x20
#define DFS_BAD_ATTRIBUTES 0xff
	u_char	dfs_reserved[10];
	unsigned short	dfs_time;
	unsigned short	dfs_date;
	unsigned short	dfs_start;
	long		dfs_size;
};

#define DFS_DIR_MODE		0040000
#define DFS_REG_MODE		0100000
#define dfs_get_time(ddp)	(exchw((ddp)->dfs_time))
#define dfs_get_date(ddp)	(exchw((ddp)->dfs_date))
#define dfs_get_start(ddp)	(exchw((ddp)->dfs_start))
#define dfs_get_size(ddp)	(exchl((ddp)->dfs_size))
#define dfs_put_time(time)	(exchw((time) & 0xffff))
#define dfs_put_date(time)	(exchw(((time) >> 16) & 0xffff))
#define dfs_put_start(start)	(exchw(start))
#define dfs_put_size(size)	(exchl(size))
#define dfs_is_empty(ddp)	(((ddp)->dfs_flag == DFS_DIR_ERASED) || \
					((ddp)->dfs_flag == DFS_DIR_NOTUSED))
#define dfs_is_directory(ddp)	((ddp)->dfs_attributes & DFS_DIRECTORY)
#define dfs_is_volume(ddp)	((ddp)->dfs_attributes & DFS_VOL_LABLE)

#define DFS_ROOT_FID		0
/*
 * time macros
 */
#define DFS_GET_YEAR(date)	((((date) >> 9) & 0x7f) + 80)
#define DFS_GET_MONTH(date)	(((date) >> 5) & 0xf)
#define DFS_GET_DAY(date)	(((date) & 0x1f))
#define DFS_GET_HOUR(time)	(((time) >> 11) & 0x1f)
#define DFS_GET_MIN(time)	(((time) >> 5 ) & 0x3f)
#define DFS_GET_SEC(time)	(((time) & 0x1f))
#define DFS_PUT_YEAR(time,i)	time |= (((i) & 0x7f) << 25)
#define DFS_PUT_MONTH(time,i)	time |= (((i) & 0xf) << 21)
#define DFS_PUT_DAY(time,i)	time |= (((i) & 0x1f) << 16)
#define DFS_PUT_HOUR(time,i)	time |= (((i) & 0x1f) << 11)
#define DFS_PUT_MIN(time,i)	time |= (((i) & 0x3f) << 5)
#define DFS_PUT_SEC(time,i)	time |= (((i) & 0x1f))


#ifdef KERNEL
/*
 * dnode value
 */
struct dnode {
	struct vnode	dv_node;	/* dnode's vnode structure */
	struct dfs_dir	dfs_dir;	/* dos directory for dnode */
	struct vnode	*dfs_parent;	/* pointer to .. */
	struct dnode	*dfs_next;	/* pointer to next on list */
	struct dfs_dir	*dfs_last_dir;	/* used by dfs_search */
	int		dfs_dir_index;	/* used by dfs_search */
	int		dfs_last_index;	/* used by dfs_search */
	unsigned	dfs_locked;	/* dnode is locked */
	int		dfs_lock_cnt;	/* number of times the dnode is locked*/
	u_short		dfs_dir_offset;	/* index into directory entry */
	u_char		dfs_wanted;	/* dnode is wanted */
};

#define VTOD(vp)	((struct dnode *)vp)
#define DTOV(dp)	((struct vnode *)dp)
#define VTODir(vp)	(&VTOD(vp)->dfs_dir)
#endif

/*
 * boot block info
 */
struct dfs_fsinfo {
    u_char	dfsb_jump[3];		/* 0-2: near or far jump */
    u_char	dfsb_oem[8];		/* 3-10: OEM name */
    u_char	dfsb_block_size[2];	/* 11-12: bytes/sector */
    u_char	dfsb_cluster_size;	/* 13: number of sectors/cluster */
    u_char	dfsb_reserved[2];	/* 14-15: reserved sectors */
    u_char	dfsb_fat_copies;	/* 16: number of fat's */
    u_char	dfsb_dir_entries[2];    /* 17-18: number of root directory
				     	 * entires */
    u_char	dfsb_device_size[2];    /* 19-20: number of sectors total */
    u_char	dfsb_media_descriptor;  /* 21: who knows */
    u_char	dfsb_fat_size[2];	/* 22-23: number of sectors per fat */
    u_char	dfsb_sectors[2]; 	/* 24-25: sector size */
    u_char	dfsb_tracks[2];		/* 26-27: number of heads */
    u_char	dfsb_hidden[2];		/* 28-29: number of hidden sectors */
};

#define dfs_get_word(cp)	(((cp)[1] << 8) | ((cp)[0]))
#define dfs_get_long(sp)	((exchw((sp)[1]) << 16) | exchw((sp)[0]))

struct dfs_mount_tab {
	struct dfs_mount_tab *dmp_last;
	struct dfs_mount_tab *dmp_next;
	u_short	dmp_dev;
	u_short	dmp_ext;
};

#define FAT_PAGES	4  /* number of unsigned to hold all the fat pages */
struct dfs_vfs_info {
/*	struct buf	*dfs_bp;
#define dfs_vfat	dfs_bp->b_un.b_addr */
	char		*dfs_vfat;
	struct vnode	*dfs_vdevvp;
	struct dfs_mount_tab *dfs_vmp;
	int		dfs_vrefcnt;
	unsigned long	dfs_vfat_bits[FAT_PAGES];
	unsigned	dfs_vfat_want;
	uid_t		dfs_vuid;
	gid_t		dfs_vgid;
	u_short		dfs_vmnt;
	u_short		dfs_vdev;
	u_short		dfs_vext;
	u_short		dfs_veof;
	u_short		dfs_vmin_eof;
	u_short		dfs_vfirst_cluster;
	u_short		dfs_vfat_entries;
	u_short		dfs_vfat_entry_size;	/* 12 bit or 16 bit */
	u_short		dfs_vcluster_size;
	u_short		dfs_vfat_copies;
	u_short		dfs_vfat_start;
	u_short		dfs_vfat_pages;
	u_short		dfs_vdir_start;
	u_short		dfs_vdir_size;
	u_short		dfs_vdata_start;
};

#define VFSTODFS(vfs)		((struct dfs_vfs_info*)(vfs)->vfs_data)
#define dfs_get_mnt_flags(vfs)	(VFSTODFS(vfs)->dfs_vmnt)
#define dfs_get_dev(vfs)	(VFSTODFS(vfs)->dfs_vdev)
#define dfs_cluster_size(vfs)	(VFSTODFS(vfs)->dfs_vcluster_size)

#define DFS_EOF_12		0xfff
#define DFS_MIN_EOF_12		0xff8
#define DFS_EOF_16		0xffff
#define DFS_MIN_EOF_16		0xfff8
#define DFS_FREE		0x0
#define DFS_FIRST_CLUSTER	2
#define DFS_IS_EOF(dfs,cluster)	(((cluster) & (dfs)->dfs_vmin_eof) == \
							(dfs)->dfs_vmin_eof)
/*
 *  possible optimization: subtract dfs_vfirst_cluster*dfs_vcluster_size from
 * dfs_vdata_start in mount to avoid the calculation here.
 */
#define CLTOBLKS(dfs,cluster)	((dfs)->dfs_vdata_start + \
		 ((cluster)-(dfs)->dfs_vfirst_cluster)*(dfs)->dfs_vcluster_size)
#define DFS_GET_MAGIC(cp)	(*(u_short *)((cp)+(DFS_BSIZE-sizeof(short))))
#define DFS_MAGIC		0x55aa

/*
 * partition table
 */
struct dfs_part_tab {
	u_char	boot_id;
	u_char	start_sector[3];
	u_char	sys_id;
	u_char	end_sector[3];
	u_short rel_start[2];
	u_short rel_size[2];
};

#define DFS_GET_PART(cp)	((struct dfs_part_tab *)((char *)(cp)+ \
				    (DFS_BSIZE-(sizeof(struct dfs_part_tab)* \
					      DFS_NUMBER_PART+sizeof(short)))))
#define DFS_NUMBER_PART		4	/* number of partitions in part table */
#define DFS_DOS_12		1
#define DFS_DOS_16		4
#define DFS_DOS_EXT		5

/*
 * Dnode lookup defines
 */

#define DFS_HASH_SIZE      16
#define dfs_table_hash(fid) \
    (((fid) & 0xf) ^ (((fid) >> 4) & 0xf) ^ (((fid) >> 8) & 0xf) ^ \
						      (((fid) >> 12) & 0xf))

#define DFS_BSIZE	512
#define DFS_BITS_PER_BYTE 8

/*
 * mount flags
 */
#define DFS_DST			0x001	/* make dst adjustment */
#define DFS_HIDE_HIDDEN		0x002	/* hide hidden and system files */
#define DFS_CHANGE_USER		0x004	/* allow def_uid to change */
#define DFS_CHANGE_GROUP	0x008	/* allow def_gid to change */
#define DFS_UPPER		0x010	/* show dos files as upper case */
#define DFS_NOMAP_NAME		0x020	/* make dos mappings exact */
#define DFS_NOEXECUTE		0x040	/* don't allow execute bits on dos */
#define DFS_USER		0x080	/* only allow user access */
#define DFS_GROUP		0x100	/* only allow group access */

struct dfs_fid {
	u_short	dfid_len;
	u_short	dfid_start;
};

#endif !__DFS_HEADER__
#endif DFS
