root/sys/vfs/hpfs/hpfs.h
/*-
 * Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD: src/sys/fs/hpfs/hpfs.h,v 1.1 1999/12/09 19:09:58 semenu Exp $
 */

/*#define HPFS_DEBUG 10*/
typedef u_int32_t lsn_t;        /* Logical Sector Number */
typedef struct {
        lsn_t   lsn1;
        lsn_t   lsn2;
} rsp_t;                        /* Redundant Sector Pointer */
typedef struct {
        u_int32_t cnt;
        lsn_t   lsn;
} sptr_t;                       /* Storage Pointer */

#define SUBLOCK 0x10
#define SUSIZE  DEV_BSIZE
#define SPBLOCK 0x11
#define SPSIZE  DEV_BSIZE
#define BMSIZE  (4 * DEV_BSIZE)
#define HPFS_MAXFILENAME        255

#define SU_MAGIC        ((u_int64_t)0xFA53E9C5F995E849ULL)
struct sublock {
        u_int64_t       su_magic;       
        u_int8_t        su_hpfsver;
        u_int8_t        su_fnctver;
        u_int16_t       unused;
        lsn_t           su_rootfno;     /* Root Fnode */
        u_int32_t       su_btotal;      /* Total blocks */
        u_int32_t       su_badbtotal;   /* Bad Sectors total */
        rsp_t           su_bitmap;
        rsp_t           su_badbl;
        u_long          su_chkdskdate;
        u_long          su_dskoptdate;
        u_int32_t       su_dbbsz;       /* Sectors in DirBlock Band */
        lsn_t           su_dbbstart;
        lsn_t           su_dbbend;
        lsn_t           su_dbbbitmap;
        char            su_volname[0x20];
        lsn_t           su_uidt;        /* Ptr to User ID Table (8 sect) */
};

#define SP_MAGIC        ((u_int64_t)0xFA5229C5F9911849ULL)
#define SP_DIRTY        0x0001
#define SP_SPDBINUSE    0x0002
#define SP_HFINUSE      0x0004
#define SP_BADSECT      0x0008
#define SP_BADBMBL      0x0010
#define SP_FASTFRMT     0x0020
#define SP_OLDHPFS      0x0080
#define SP_IDASD        0x0100
#define SP_RDASD        0x0200
#define SP_DASD         0x0400
#define SP_MMACTIVE     0x0800
#define SP_DCEACLS      0x1000
#define SP_DSADDIRTY    0x2000
struct spblock {
        u_int64_t       sp_magic;
        u_int16_t       sp_flag;
        u_int8_t        sp_mmcontf;
        u_int8_t        unused;
        lsn_t           sp_hf;          /* HotFix list */
        u_int32_t       sp_hfinuse;     /* HotFixes in use */
        u_int32_t       sp_hfavail;     /* HotFixes available */
        u_int32_t       sp_spdbavail;   /* Spare DirBlocks available */
        u_int32_t       sp_spdbmax;     /* Spare DirBlocks maximum */
        lsn_t           sp_cpi;
        u_int32_t       sp_cpinum;
        u_int32_t       sp_suchecksum;
        u_int32_t       sp_spchecksum;
        u_int8_t        reserved[0x3C];
        lsn_t           sp_spdb[0x65];
};

#define DE_SPECIAL      0x0001
#define DE_ACL          0x0002
#define DE_DOWN         0x0004
#define DE_END          0x0008
#define DE_EALIST       0x0010
#define DE_EPERM        0x0020
#define DE_EXPLACL      0x0040
#define DE_NEEDEA       0x0080
#define DE_RONLY        0x0100
#define DE_HIDDEN       0x0200
#define DE_SYSTEM       0x0400
#define DE_VOLLABEL     0x0800
#define DE_DIR          0x1000
#define DE_ARCHIV       0x2000
#define DE_DOWNLSN(dep) (*(lsn_t *)((caddr_t)(dep) + (dep)->de_reclen - sizeof(lsn_t)))
#define DE_NEXTDE(dep)  ((struct hpfsdirent *)((caddr_t)(dep) + (dep)->de_reclen))
typedef struct hpfsdirent {
        u_int16_t       de_reclen;
        u_int16_t       de_flag;
        lsn_t           de_fnode;
        u_long          de_mtime;
        u_int32_t       de_size;
        u_long          de_atime;
        u_long          de_ctime;
        u_int32_t       de_ealen;
        u_int8_t        de_flexflag;
        u_int8_t        de_cpid;
        u_int8_t        de_namelen;
        char            de_name[1];
/*      ...             de_flex; */
/*      lsn_t           de_down; */
} hpfsdirent_t;

#define D_BSIZE (DEV_BSIZE*4)
#define D_MAGIC 0x77E40AAE
#define D_DIRENT(dbp)   ((hpfsdirent_t *)((caddr_t)dbp + sizeof(dirblk_t)))
#define D_DE(dbp, deoff) ((hpfsdirent_t *)((caddr_t)dbp + sizeof(dirblk_t) + (deoff)))
typedef struct dirblk {
        u_int32_t       d_magic;
        u_int32_t       d_freeoff;      /* Offset of first free byte */
        u_int32_t       d_chcnt;        /* Change count */
        lsn_t           d_parent;
        lsn_t           d_self;
} dirblk_t;

/*
 * Allocation Block (ALBLK)
 */
#define AB_HBOFFEO      0x01
#define AB_FNPARENT     0x20
#define AB_SUGGBSCH     0x40
#define AB_NODES        0x80
#define AB_ALLEAF(abp)  ((alleaf_t *)((caddr_t)(abp) + sizeof(alblk_t)))
#define AB_ALNODE(abp)  ((alnode_t *)((caddr_t)(abp) + sizeof(alblk_t)))
#define AB_FREEALP(abp) ((alleaf_t *)((caddr_t)(abp) + (abp)->ab_freeoff))
#define AB_FREEANP(abp) ((alnode_t *)((caddr_t)(abp) + (abp)->ab_freeoff))
#define AB_LASTALP(abp) (AB_ALLEAF(abp) + (abp)->ab_busycnt - 1)
#define AB_LASTANP(abp) (AB_ALNODE(abp) + (abp)->ab_busycnt - 1)
#define AB_ADDNREC(abp, sz, n)  {               \
        (abp)->ab_busycnt += (n);               \
        (abp)->ab_freecnt -= (n);               \
        (abp)->ab_freeoff += (n) * (sz);        \
}
#define AB_RMNREC(abp, sz, n)           {       \
        (abp)->ab_busycnt -= (n);               \
        (abp)->ab_freecnt += (n);               \
        (abp)->ab_freeoff -= (n) * (sz);\
}
#define AB_ADDAL(abp)   AB_ADDNREC(abp,sizeof(alleaf_t), 1)
#define AB_ADDAN(abp)   AB_ADDNREC(abp,sizeof(alnode_t), 1)
#define AB_RMAL(abp)    AB_RMNREC(abp,sizeof(alleaf_t), 1)
#define AB_RMAN(abp)    AB_RMNREC(abp,sizeof(alnode_t), 1)
typedef struct alblk {
        u_int8_t        ab_flag;
        u_int8_t        ab_res[3];
        u_int8_t        ab_freecnt;
        u_int8_t        ab_busycnt;
        u_int16_t       ab_freeoff;
} alblk_t;

/*
 * FNode
 */
#define FNODESIZE       DEV_BSIZE
#define FN_MAGIC        0xF7E40AAE
struct fnode {
        u_int32_t       fn_magic;
        u_int64_t       fn_readhist;
        u_int8_t        fn_namelen;
        char            fn_name[0xF];           /* First 15 symbols or less */
        lsn_t           fn_parent;
        sptr_t          fn_extacl;
        u_int16_t       fn_acllen;
        u_int8_t        fn_extaclflag;
        u_int8_t        fn_histbitcount;
        sptr_t          fn_extea;
        u_int16_t       fn_ealen;               /* Len of EAs in Fnode */
        u_int8_t        fn_exteaflag;           /* EAs in exteas */
        u_int8_t        fn_flag;
        alblk_t         fn_ab;
        u_int8_t        fn_abd[0x60];
        u_int32_t       fn_size;
        u_int32_t       fn_reqea;
        u_int8_t        fn_uid[0x10];
        u_int16_t       fn_intoff;
        u_int8_t        fn_1dasdthr;
        u_int8_t        fn_dasdthr;
        u_int32_t       fn_dasdlim;
        u_int32_t       fn_dasdusage;
        u_int8_t        fn_int[0x13c];
};

#define EA_NAME(eap)    ((char *)(((caddr_t)(eap)) + sizeof(struct ea)))
struct ea {
        u_int8_t        ea_type;        /* 0 - plain val */
                                        /* 1 - sptr to val */
                                        /* 3 - lsn point to AlSec, cont. val */
        u_int8_t        ea_namelen;
        u_int16_t       ea_vallen;
        /*u_int8_t      ea_name[]; */
        /*u_int8_t      ea_val[]; */
};

/*
 * Allocation Block Data (ALNODE)
 *
 * NOTE: AlNodes are used when there are too many fragments
 * to represent the data in the AlBlk
 */
#define AN_SET(anp,nextoff,lsn)         {       \
        (anp)->an_nextoff = (nextoff);          \
        (anp)->an_lsn = (lsn);                  \
}
typedef struct alnode {
        u_int32_t       an_nextoff;     /* next node offset in blocks */
        lsn_t           an_lsn;         /* position of AlSec structure */
} alnode_t;

/*
 * Allocaion  Block Data (ALLEAF)
 *
 * NOTE: Leaves are used to point at contiguous block of data
 * (a fragment or an "extent");
 */
#define AL_SET(alp,off,len,lsn)         {       \
        (alp)->al_off = (off);                  \
        (alp)->al_len = (len);                  \
        (alp)->al_lsn = (lsn);                  \
}
typedef struct alleaf {
        u_int32_t       al_off;         /* offset in blocks */
        u_int32_t       al_len;         /* len in blocks */
        lsn_t           al_lsn;         /* phys position */
} alleaf_t;

/*
 * Allocation Sector
 *
 * NOTE: AlSecs  are not  initialized before use, so they ussually
 * look full of junk. Use the AlBlk  tto validate the data.
 */
#define AS_MAGIC        0x37E40AAE
typedef struct alsec {
        u_int32_t       as_magic;
        lsn_t           as_self;
        lsn_t           as_parent;
        alblk_t         as_ab;
        u_int8_t        as_abd[0x1E0];
} alsec_t;

/*
 * Code Page structures
 */
struct cpdblk {
        u_int16_t       b_country;      /* Country code */
        u_int16_t       b_cpid;         /* CP ID */
        u_int16_t       b_dbcscnt;      /* Count of DBCS ranges in CP */
        char            b_upcase[0x80]; /* Case conversion table */
        u_int16_t       b_dbcsrange;    /* Start/End DBCS range pairs */
        
};

#define CPD_MAGIC       ((u_int32_t)0x894521F7)
struct cpdsec {
        u_int32_t       d_magic;
        u_int16_t       d_cpcnt;        /* CP Data count */
        u_int16_t       d_cpfirst;      /* Index of first CP Data */
        u_int32_t       d_checksum[3];  /* CP Data checksumms */
        u_int16_t       d_offset[3];    /* Offsets of CP Data blocks */
        struct cpdblk   d_cpdblk[3];    /* Array of CP Data Blocks */
};

struct cpiblk {
        u_int16_t       b_country;      /* Country code */
        u_int16_t       b_cpid;         /* CP ID */
        u_int32_t       b_checksum;
        lsn_t           b_cpdsec;       /* Pointer to CP Data Sector */
        u_int16_t       b_vcpid;        /* Volume spec. CP ID */
        u_int16_t       b_dbcscnt;      /* Count of DBCS ranges in CP */
};

#define CPI_MAGIC       ((u_int32_t)0x494521F7)
struct cpisec {
        u_int32_t       s_magic;
        u_int32_t       s_cpicnt;       /* Count of CPI's in this sector */
        u_int32_t       s_cpifirst;     /* Index of first CPI in this sector */
        lsn_t           s_next;         /* Pointer to next CPI Sector */
        struct cpiblk   s_cpi[0x1F];    /* Array of CPI blocks */
};

struct hpfsmount {
        struct sublock  hpm_su;
        struct spblock  hpm_sp;
        struct netexport hpm_export;
        struct mount *  hpm_mp;
        struct vnode *  hpm_devvp;
        cdev_t          hpm_dev;
        uid_t           hpm_uid;
        gid_t           hpm_gid;
        mode_t          hpm_mode;

        lsn_t *         hpm_bmind;
        struct cpdblk * hpm_cpdblk;     /* Array of CP Data Blocks */
        u_char          hpm_u2d[0x80];  /* Unix to DOS Table*/
        u_char          hpm_d2u[0x80];  /* DOS to Unix Table*/

        u_long          hpm_bavail;     /* Blocks available */
        u_long          hpm_dbnum;      /* Data Band number */
        u_int8_t *      hpm_bitmap;
};

#define H_HASHED        0x0001          /* Present in hash */
#define H_PARVALID      0x0002          /* parent info is valid */
#define H_CHANGE        0x0004          /* node date was changed */
#define H_PARCHANGE     0x0008          /* parent node date was changed */
#define H_INVAL         0x0010          /* Invalid node */
struct hpfsnode {
        struct lwkt_token h_interlock;

        LIST_ENTRY(hpfsnode)    h_hash;

        struct hpfsmount *h_hpmp;
        struct fnode    h_fn;
        struct vnode *  h_vp;
        struct vnode *  h_devvp;
        cdev_t          h_dev;
        lsn_t           h_no;
        uid_t           h_uid;
        gid_t           h_gid;
        mode_t          h_mode;
        u_int32_t       h_flag;

        /* parent dir information */
        u_long          h_mtime;
        u_long          h_atime;
        u_long          h_ctime;
        char            h_name[HPFS_MAXFILENAME+1]; /* Used to speedup dirent */
        int             h_namelen;                  /* lookup */
};

/* This overlays the fid structure (see <sys/mount.h>) */
struct hpfid {
        u_int16_t hpfid_len;     /* Length of structure. */
        u_int16_t hpfid_pad;     /* Force 32-bit alignment. */
        lsn_t     hpfid_ino;     /* File number (ino). */
        int32_t   hpfid_gen;     /* Generation number. */
};

#if defined(HPFS_DEBUG)
#define dprintf(a) kprintf a
#if HPFS_DEBUG > 1
#define ddprintf(a) kprintf a
#else
#define ddprintf(a)
#endif
#else
#define dprintf(a)
#define ddprintf(a)
#endif
#ifdef MALLOC_DECLARE
MALLOC_DECLARE(M_HPFSMNT);
MALLOC_DECLARE(M_HPFSNO);
#endif
#define VFSTOHPFS(mp)   ((struct hpfsmount *)((mp)->mnt_data))
#define VTOHP(v)        ((struct hpfsnode *)((v)->v_data))
#define HPTOV(h)        ((struct vnode *)((h)->h_vp))
#define FID(f)          (*((lsn_t *)(f)->fid_data))
#define dbtodoff(dbn)   ((off_t)(dbn) << DEV_BSHIFT)

#define VOP__LOCK(a, b)         vn_lock((a), (b) | LK_FAILRECLAIM)
#define VOP__UNLOCK(a, b)       vn_unlock((a))
#define VGET(a, b, c)           vget((a), (b))
#define VN_LOCK(a, b)           vn_lock((a), (b))
#define LOCKMGR(a, b)           lockmgr((a), (b))

struct vfsconf;

/* Hash routines, too small to be separate header */
void hpfs_hphashinit (void);
int hpfs_hphash_uninit (struct vfsconf *);
struct hpfsnode *hpfs_hphashlookup (cdev_t, lsn_t);
struct hpfsnode *hpfs_hphashget (cdev_t, lsn_t);
struct vnode *hpfs_hphashvget (cdev_t, lsn_t);
void hpfs_hphashins (struct hpfsnode *);
void hpfs_hphashrem (struct hpfsnode *);
extern struct lock hpfs_hphash_lock;