xref: /kernel/linux/linux-6.6/fs/hpfs/hpfs.h (revision 62306a36)
162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  linux/fs/hpfs/hpfs.h
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  HPFS structures by Chris Smith, 1993
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *  a little bit modified by Mikulas Patocka, 1998-1999
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci/* The paper
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci     Duncan, Roy
1362306a36Sopenharmony_ci     Design goals and implementation of the new High Performance File System
1462306a36Sopenharmony_ci     Microsoft Systems Journal  Sept 1989  v4 n5 p1(13)
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci   describes what HPFS looked like when it was new, and it is the source
1762306a36Sopenharmony_ci   of most of the information given here.  The rest is conjecture.
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci   For definitive information on the Duncan paper, see it, not this file.
2062306a36Sopenharmony_ci   For definitive information on HPFS, ask somebody else -- this is guesswork.
2162306a36Sopenharmony_ci   There are certain to be many mistakes. */
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN)
2462306a36Sopenharmony_ci#error unknown endian
2562306a36Sopenharmony_ci#endif
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/* Notation */
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_citypedef u32 secno;			/* sector number, partition relative */
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_citypedef secno dnode_secno;		/* sector number of a dnode */
3262306a36Sopenharmony_citypedef secno fnode_secno;		/* sector number of an fnode */
3362306a36Sopenharmony_citypedef secno anode_secno;		/* sector number of an anode */
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_citypedef u32 time32_t;		/* 32-bit time_t type */
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/* sector 0 */
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/* The boot block is very like a FAT boot block, except that the
4062306a36Sopenharmony_ci   29h signature byte is 28h instead, and the ID string is "HPFS". */
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#define BB_MAGIC 0xaa55
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistruct hpfs_boot_block
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci  u8 jmp[3];
4762306a36Sopenharmony_ci  u8 oem_id[8];
4862306a36Sopenharmony_ci  u8 bytes_per_sector[2];	/* 512 */
4962306a36Sopenharmony_ci  u8 sectors_per_cluster;
5062306a36Sopenharmony_ci  u8 n_reserved_sectors[2];
5162306a36Sopenharmony_ci  u8 n_fats;
5262306a36Sopenharmony_ci  u8 n_rootdir_entries[2];
5362306a36Sopenharmony_ci  u8 n_sectors_s[2];
5462306a36Sopenharmony_ci  u8 media_byte;
5562306a36Sopenharmony_ci  __le16 sectors_per_fat;
5662306a36Sopenharmony_ci  __le16 sectors_per_track;
5762306a36Sopenharmony_ci  __le16 heads_per_cyl;
5862306a36Sopenharmony_ci  __le32 n_hidden_sectors;
5962306a36Sopenharmony_ci  __le32 n_sectors_l;		/* size of partition */
6062306a36Sopenharmony_ci  u8 drive_number;
6162306a36Sopenharmony_ci  u8 mbz;
6262306a36Sopenharmony_ci  u8 sig_28h;			/* 28h */
6362306a36Sopenharmony_ci  u8 vol_serno[4];
6462306a36Sopenharmony_ci  u8 vol_label[11];
6562306a36Sopenharmony_ci  u8 sig_hpfs[8];		/* "HPFS    " */
6662306a36Sopenharmony_ci  u8 pad[448];
6762306a36Sopenharmony_ci  __le16 magic;			/* aa55 */
6862306a36Sopenharmony_ci};
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci/* sector 16 */
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci/* The super block has the pointer to the root directory. */
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci#define SB_MAGIC 0xf995e849
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistruct hpfs_super_block
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci  __le32 magic;				/* f995 e849 */
8062306a36Sopenharmony_ci  __le32 magic1;			/* fa53 e9c5, more magic? */
8162306a36Sopenharmony_ci  u8 version;				/* version of a filesystem  usually 2 */
8262306a36Sopenharmony_ci  u8 funcversion;			/* functional version - oldest version
8362306a36Sopenharmony_ci  					   of filesystem that can understand
8462306a36Sopenharmony_ci					   this disk */
8562306a36Sopenharmony_ci  __le16 zero;				/* 0 */
8662306a36Sopenharmony_ci  __le32 root;				/* fnode of root directory */
8762306a36Sopenharmony_ci  __le32 n_sectors;			/* size of filesystem */
8862306a36Sopenharmony_ci  __le32 n_badblocks;			/* number of bad blocks */
8962306a36Sopenharmony_ci  __le32 bitmaps;			/* pointers to free space bit maps */
9062306a36Sopenharmony_ci  __le32 zero1;				/* 0 */
9162306a36Sopenharmony_ci  __le32 badblocks;			/* bad block list */
9262306a36Sopenharmony_ci  __le32 zero3;				/* 0 */
9362306a36Sopenharmony_ci  __le32 last_chkdsk;			/* date last checked, 0 if never */
9462306a36Sopenharmony_ci  __le32 last_optimize;			/* date last optimized, 0 if never */
9562306a36Sopenharmony_ci  __le32 n_dir_band;			/* number of sectors in dir band */
9662306a36Sopenharmony_ci  __le32 dir_band_start;			/* first sector in dir band */
9762306a36Sopenharmony_ci  __le32 dir_band_end;			/* last sector in dir band */
9862306a36Sopenharmony_ci  __le32 dir_band_bitmap;		/* free space map, 1 dnode per bit */
9962306a36Sopenharmony_ci  u8 volume_name[32];			/* not used */
10062306a36Sopenharmony_ci  __le32 user_id_table;			/* 8 preallocated sectors - user id */
10162306a36Sopenharmony_ci  u32 zero6[103];			/* 0 */
10262306a36Sopenharmony_ci};
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci/* sector 17 */
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci/* The spare block has pointers to spare sectors.  */
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci#define SP_MAGIC 0xf9911849
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistruct hpfs_spare_block
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci  __le32 magic;				/* f991 1849 */
11462306a36Sopenharmony_ci  __le32 magic1;				/* fa52 29c5, more magic? */
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN
11762306a36Sopenharmony_ci  u8 dirty: 1;				/* 0 clean, 1 "improperly stopped" */
11862306a36Sopenharmony_ci  u8 sparedir_used: 1;			/* spare dirblks used */
11962306a36Sopenharmony_ci  u8 hotfixes_used: 1;			/* hotfixes used */
12062306a36Sopenharmony_ci  u8 bad_sector: 1;			/* bad sector, corrupted disk (???) */
12162306a36Sopenharmony_ci  u8 bad_bitmap: 1;			/* bad bitmap */
12262306a36Sopenharmony_ci  u8 fast: 1;				/* partition was fast formatted */
12362306a36Sopenharmony_ci  u8 old_wrote: 1;			/* old version wrote to partition */
12462306a36Sopenharmony_ci  u8 old_wrote_1: 1;			/* old version wrote to partition (?) */
12562306a36Sopenharmony_ci#else
12662306a36Sopenharmony_ci  u8 old_wrote_1: 1;			/* old version wrote to partition (?) */
12762306a36Sopenharmony_ci  u8 old_wrote: 1;			/* old version wrote to partition */
12862306a36Sopenharmony_ci  u8 fast: 1;				/* partition was fast formatted */
12962306a36Sopenharmony_ci  u8 bad_bitmap: 1;			/* bad bitmap */
13062306a36Sopenharmony_ci  u8 bad_sector: 1;			/* bad sector, corrupted disk (???) */
13162306a36Sopenharmony_ci  u8 hotfixes_used: 1;			/* hotfixes used */
13262306a36Sopenharmony_ci  u8 sparedir_used: 1;			/* spare dirblks used */
13362306a36Sopenharmony_ci  u8 dirty: 1;				/* 0 clean, 1 "improperly stopped" */
13462306a36Sopenharmony_ci#endif
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN
13762306a36Sopenharmony_ci  u8 install_dasd_limits: 1;		/* HPFS386 flags */
13862306a36Sopenharmony_ci  u8 resynch_dasd_limits: 1;
13962306a36Sopenharmony_ci  u8 dasd_limits_operational: 1;
14062306a36Sopenharmony_ci  u8 multimedia_active: 1;
14162306a36Sopenharmony_ci  u8 dce_acls_active: 1;
14262306a36Sopenharmony_ci  u8 dasd_limits_dirty: 1;
14362306a36Sopenharmony_ci  u8 flag67: 2;
14462306a36Sopenharmony_ci#else
14562306a36Sopenharmony_ci  u8 flag67: 2;
14662306a36Sopenharmony_ci  u8 dasd_limits_dirty: 1;
14762306a36Sopenharmony_ci  u8 dce_acls_active: 1;
14862306a36Sopenharmony_ci  u8 multimedia_active: 1;
14962306a36Sopenharmony_ci  u8 dasd_limits_operational: 1;
15062306a36Sopenharmony_ci  u8 resynch_dasd_limits: 1;
15162306a36Sopenharmony_ci  u8 install_dasd_limits: 1;		/* HPFS386 flags */
15262306a36Sopenharmony_ci#endif
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci  u8 mm_contlgulty;
15562306a36Sopenharmony_ci  u8 unused;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci  __le32 hotfix_map;			/* info about remapped bad sectors */
15862306a36Sopenharmony_ci  __le32 n_spares_used;			/* number of hotfixes */
15962306a36Sopenharmony_ci  __le32 n_spares;			/* number of spares in hotfix map */
16062306a36Sopenharmony_ci  __le32 n_dnode_spares_free;		/* spare dnodes unused */
16162306a36Sopenharmony_ci  __le32 n_dnode_spares;		/* length of spare_dnodes[] list,
16262306a36Sopenharmony_ci					   follows in this block*/
16362306a36Sopenharmony_ci  __le32 code_page_dir;			/* code page directory block */
16462306a36Sopenharmony_ci  __le32 n_code_pages;			/* number of code pages */
16562306a36Sopenharmony_ci  __le32 super_crc;			/* on HPFS386 and LAN Server this is
16662306a36Sopenharmony_ci  					   checksum of superblock, on normal
16762306a36Sopenharmony_ci					   OS/2 unused */
16862306a36Sopenharmony_ci  __le32 spare_crc;			/* on HPFS386 checksum of spareblock */
16962306a36Sopenharmony_ci  __le32 zero1[15];			/* unused */
17062306a36Sopenharmony_ci  __le32 spare_dnodes[100];		/* emergency free dnode list */
17162306a36Sopenharmony_ci  __le32 zero2[1];			/* room for more? */
17262306a36Sopenharmony_ci};
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci/* The bad block list is 4 sectors long.  The first word must be zero,
17562306a36Sopenharmony_ci   the remaining words give n_badblocks bad block numbers.
17662306a36Sopenharmony_ci   I bet you can see it coming... */
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci#define BAD_MAGIC 0
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci/* The hotfix map is 4 sectors long.  It looks like
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci       secno from[n_spares];
18362306a36Sopenharmony_ci       secno to[n_spares];
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci   The to[] list is initialized to point to n_spares preallocated empty
18662306a36Sopenharmony_ci   sectors.  The from[] list contains the sector numbers of bad blocks
18762306a36Sopenharmony_ci   which have been remapped to corresponding sectors in the to[] list.
18862306a36Sopenharmony_ci   n_spares_used gives the length of the from[] list. */
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci/* Sectors 18 and 19 are preallocated and unused.
19262306a36Sopenharmony_ci   Maybe they're spares for 16 and 17, but simple substitution fails. */
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci/* The code page info pointed to by the spare block consists of an index
19662306a36Sopenharmony_ci   block and blocks containing uppercasing tables.  I don't know what
19762306a36Sopenharmony_ci   these are for (CHKDSK, maybe?) -- OS/2 does not seem to use them
19862306a36Sopenharmony_ci   itself.  Linux doesn't use them either. */
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci/* block pointed to by spareblock->code_page_dir */
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci#define CP_DIR_MAGIC 0x494521f7
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistruct code_page_directory
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci  __le32 magic;				/* 4945 21f7 */
20762306a36Sopenharmony_ci  __le32 n_code_pages;			/* number of pointers following */
20862306a36Sopenharmony_ci  __le32 zero1[2];
20962306a36Sopenharmony_ci  struct {
21062306a36Sopenharmony_ci    __le16 ix;				/* index */
21162306a36Sopenharmony_ci    __le16 code_page_number;		/* code page number */
21262306a36Sopenharmony_ci    __le32 bounds;			/* matches corresponding word
21362306a36Sopenharmony_ci					   in data block */
21462306a36Sopenharmony_ci    __le32 code_page_data;		/* sector number of a code_page_data
21562306a36Sopenharmony_ci					   containing c.p. array */
21662306a36Sopenharmony_ci    __le16 index;			/* index in c.p. array in that sector*/
21762306a36Sopenharmony_ci    __le16 unknown;			/* some unknown value; usually 0;
21862306a36Sopenharmony_ci    					   2 in Japanese version */
21962306a36Sopenharmony_ci  } array[31];				/* unknown length */
22062306a36Sopenharmony_ci};
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci/* blocks pointed to by code_page_directory */
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci#define CP_DATA_MAGIC 0x894521f7
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cistruct code_page_data
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci  __le32 magic;				/* 8945 21f7 */
22962306a36Sopenharmony_ci  __le32 n_used;			/* # elements used in c_p_data[] */
23062306a36Sopenharmony_ci  __le32 bounds[3];			/* looks a bit like
23162306a36Sopenharmony_ci					     (beg1,end1), (beg2,end2)
23262306a36Sopenharmony_ci					   one byte each */
23362306a36Sopenharmony_ci  __le16 offs[3];			/* offsets from start of sector
23462306a36Sopenharmony_ci					   to start of c_p_data[ix] */
23562306a36Sopenharmony_ci  struct {
23662306a36Sopenharmony_ci    __le16 ix;				/* index */
23762306a36Sopenharmony_ci    __le16 code_page_number;		/* code page number */
23862306a36Sopenharmony_ci    __le16 unknown;			/* the same as in cp directory */
23962306a36Sopenharmony_ci    u8 map[128];			/* upcase table for chars 80..ff */
24062306a36Sopenharmony_ci    __le16 zero2;
24162306a36Sopenharmony_ci  } code_page[3];
24262306a36Sopenharmony_ci  u8 incognita[78];
24362306a36Sopenharmony_ci};
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci/* Free space bitmaps are 4 sectors long, which is 16384 bits.
24762306a36Sopenharmony_ci   16384 sectors is 8 meg, and each 8 meg band has a 4-sector bitmap.
24862306a36Sopenharmony_ci   Bit order in the maps is little-endian.  0 means taken, 1 means free.
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci   Bit map sectors are marked allocated in the bit maps, and so are sectors
25162306a36Sopenharmony_ci   off the end of the partition.
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci   Band 0 is sectors 0-3fff, its map is in sectors 18-1b.
25462306a36Sopenharmony_ci   Band 1 is 4000-7fff, its map is in 7ffc-7fff.
25562306a36Sopenharmony_ci   Band 2 is 8000-ffff, its map is in 8000-8003.
25662306a36Sopenharmony_ci   The remaining bands have maps in their first (even) or last (odd) 4 sectors
25762306a36Sopenharmony_ci     -- if the last, partial, band is odd its map is in its last 4 sectors.
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci   The bitmap locations are given in a table pointed to by the super block.
26062306a36Sopenharmony_ci   No doubt they aren't constrained to be at 18, 7ffc, 8000, ...; that is
26162306a36Sopenharmony_ci   just where they usually are.
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci   The "directory band" is a bunch of sectors preallocated for dnodes.
26462306a36Sopenharmony_ci   It has a 4-sector free space bitmap of its own.  Each bit in the map
26562306a36Sopenharmony_ci   corresponds to one 4-sector dnode, bit 0 of the map corresponding to
26662306a36Sopenharmony_ci   the first 4 sectors of the directory band.  The entire band is marked
26762306a36Sopenharmony_ci   allocated in the main bitmap.   The super block gives the locations
26862306a36Sopenharmony_ci   of the directory band and its bitmap.  ("band" doesn't mean it is
26962306a36Sopenharmony_ci   8 meg long; it isn't.)  */
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci/* dnode: directory.  4 sectors long */
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci/* A directory is a tree of dnodes.  The fnode for a directory
27562306a36Sopenharmony_ci   contains one pointer, to the root dnode of the tree.  The fnode
27662306a36Sopenharmony_ci   never moves, the dnodes do the B-tree thing, splitting and merging
27762306a36Sopenharmony_ci   as files are added and removed.  */
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci#define DNODE_MAGIC   0x77e40aae
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistruct dnode {
28262306a36Sopenharmony_ci  __le32 magic;				/* 77e4 0aae */
28362306a36Sopenharmony_ci  __le32 first_free;			/* offset from start of dnode to
28462306a36Sopenharmony_ci					   first free dir entry */
28562306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN
28662306a36Sopenharmony_ci  u8 root_dnode: 1;			/* Is it root dnode? */
28762306a36Sopenharmony_ci  u8 increment_me: 7;			/* some kind of activity counter? */
28862306a36Sopenharmony_ci					/* Neither HPFS.IFS nor CHKDSK cares
28962306a36Sopenharmony_ci					   if you change this word */
29062306a36Sopenharmony_ci#else
29162306a36Sopenharmony_ci  u8 increment_me: 7;			/* some kind of activity counter? */
29262306a36Sopenharmony_ci					/* Neither HPFS.IFS nor CHKDSK cares
29362306a36Sopenharmony_ci					   if you change this word */
29462306a36Sopenharmony_ci  u8 root_dnode: 1;			/* Is it root dnode? */
29562306a36Sopenharmony_ci#endif
29662306a36Sopenharmony_ci  u8 increment_me2[3];
29762306a36Sopenharmony_ci  __le32 up;				/* (root dnode) directory's fnode
29862306a36Sopenharmony_ci					   (nonroot) parent dnode */
29962306a36Sopenharmony_ci  __le32 self;			/* pointer to this dnode */
30062306a36Sopenharmony_ci  u8 dirent[2028];			/* one or more dirents */
30162306a36Sopenharmony_ci};
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_cistruct hpfs_dirent {
30462306a36Sopenharmony_ci  __le16 length;			/* offset to next dirent */
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN
30762306a36Sopenharmony_ci  u8 first: 1;				/* set on phony ^A^A (".") entry */
30862306a36Sopenharmony_ci  u8 has_acl: 1;
30962306a36Sopenharmony_ci  u8 down: 1;				/* down pointer present (after name) */
31062306a36Sopenharmony_ci  u8 last: 1;				/* set on phony \377 entry */
31162306a36Sopenharmony_ci  u8 has_ea: 1;				/* entry has EA */
31262306a36Sopenharmony_ci  u8 has_xtd_perm: 1;			/* has extended perm list (???) */
31362306a36Sopenharmony_ci  u8 has_explicit_acl: 1;
31462306a36Sopenharmony_ci  u8 has_needea: 1;			/* ?? some EA has NEEDEA set
31562306a36Sopenharmony_ci					   I have no idea why this is
31662306a36Sopenharmony_ci					   interesting in a dir entry */
31762306a36Sopenharmony_ci#else
31862306a36Sopenharmony_ci  u8 has_needea: 1;			/* ?? some EA has NEEDEA set
31962306a36Sopenharmony_ci					   I have no idea why this is
32062306a36Sopenharmony_ci					   interesting in a dir entry */
32162306a36Sopenharmony_ci  u8 has_explicit_acl: 1;
32262306a36Sopenharmony_ci  u8 has_xtd_perm: 1;			/* has extended perm list (???) */
32362306a36Sopenharmony_ci  u8 has_ea: 1;				/* entry has EA */
32462306a36Sopenharmony_ci  u8 last: 1;				/* set on phony \377 entry */
32562306a36Sopenharmony_ci  u8 down: 1;				/* down pointer present (after name) */
32662306a36Sopenharmony_ci  u8 has_acl: 1;
32762306a36Sopenharmony_ci  u8 first: 1;				/* set on phony ^A^A (".") entry */
32862306a36Sopenharmony_ci#endif
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN
33162306a36Sopenharmony_ci  u8 read_only: 1;			/* dos attrib */
33262306a36Sopenharmony_ci  u8 hidden: 1;				/* dos attrib */
33362306a36Sopenharmony_ci  u8 system: 1;				/* dos attrib */
33462306a36Sopenharmony_ci  u8 flag11: 1;				/* would be volume label dos attrib */
33562306a36Sopenharmony_ci  u8 directory: 1;			/* dos attrib */
33662306a36Sopenharmony_ci  u8 archive: 1;			/* dos attrib */
33762306a36Sopenharmony_ci  u8 not_8x3: 1;			/* name is not 8.3 */
33862306a36Sopenharmony_ci  u8 flag15: 1;
33962306a36Sopenharmony_ci#else
34062306a36Sopenharmony_ci  u8 flag15: 1;
34162306a36Sopenharmony_ci  u8 not_8x3: 1;			/* name is not 8.3 */
34262306a36Sopenharmony_ci  u8 archive: 1;			/* dos attrib */
34362306a36Sopenharmony_ci  u8 directory: 1;			/* dos attrib */
34462306a36Sopenharmony_ci  u8 flag11: 1;				/* would be volume label dos attrib */
34562306a36Sopenharmony_ci  u8 system: 1;				/* dos attrib */
34662306a36Sopenharmony_ci  u8 hidden: 1;				/* dos attrib */
34762306a36Sopenharmony_ci  u8 read_only: 1;			/* dos attrib */
34862306a36Sopenharmony_ci#endif
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci  __le32 fnode;				/* fnode giving allocation info */
35162306a36Sopenharmony_ci  __le32 write_date;			/* mtime */
35262306a36Sopenharmony_ci  __le32 file_size;			/* file length, bytes */
35362306a36Sopenharmony_ci  __le32 read_date;			/* atime */
35462306a36Sopenharmony_ci  __le32 creation_date;			/* ctime */
35562306a36Sopenharmony_ci  __le32 ea_size;			/* total EA length, bytes */
35662306a36Sopenharmony_ci  u8 no_of_acls;			/* number of ACL's (low 3 bits) */
35762306a36Sopenharmony_ci  u8 ix;				/* code page index (of filename), see
35862306a36Sopenharmony_ci					   struct code_page_data */
35962306a36Sopenharmony_ci  u8 namelen;				/* file name length */
36062306a36Sopenharmony_ci  u8 name[];				/* file name */
36162306a36Sopenharmony_ci  /* dnode_secno down;	  btree down pointer, if present,
36262306a36Sopenharmony_ci     			  follows name on next word boundary, or maybe it
36362306a36Sopenharmony_ci			  precedes next dirent, which is on a word boundary. */
36462306a36Sopenharmony_ci};
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci/* B+ tree: allocation info in fnodes and anodes */
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci/* dnodes point to fnodes which are responsible for listing the sectors
37062306a36Sopenharmony_ci   assigned to the file.  This is done with trees of (length,address)
37162306a36Sopenharmony_ci   pairs.  (Actually triples, of (length, file-address, disk-address)
37262306a36Sopenharmony_ci   which can represent holes.  Find out if HPFS does that.)
37362306a36Sopenharmony_ci   At any rate, fnodes contain a small tree; if subtrees are needed
37462306a36Sopenharmony_ci   they occupy essentially a full block in anodes.  A leaf-level tree node
37562306a36Sopenharmony_ci   has 3-word entries giving sector runs, a non-leaf node has 2-word
37662306a36Sopenharmony_ci   entries giving subtree pointers.  A flag in the header says which. */
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_cistruct bplus_leaf_node
37962306a36Sopenharmony_ci{
38062306a36Sopenharmony_ci  __le32 file_secno;			/* first file sector in extent */
38162306a36Sopenharmony_ci  __le32 length;			/* length, sectors */
38262306a36Sopenharmony_ci  __le32 disk_secno;			/* first corresponding disk sector */
38362306a36Sopenharmony_ci};
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_cistruct bplus_internal_node
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci  __le32 file_secno;			/* subtree maps sectors < this  */
38862306a36Sopenharmony_ci  __le32 down;				/* pointer to subtree */
38962306a36Sopenharmony_ci};
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_cienum {
39262306a36Sopenharmony_ci	BP_hbff = 1,
39362306a36Sopenharmony_ci	BP_fnode_parent = 0x20,
39462306a36Sopenharmony_ci	BP_binary_search = 0x40,
39562306a36Sopenharmony_ci	BP_internal = 0x80
39662306a36Sopenharmony_ci};
39762306a36Sopenharmony_cistruct bplus_header
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci  u8 flags;				/* bit 0 - high bit of first free entry offset
40062306a36Sopenharmony_ci					   bit 5 - we're pointed to by an fnode,
40162306a36Sopenharmony_ci					   the data btree or some ea or the
40262306a36Sopenharmony_ci					   main ea bootage pointer ea_secno
40362306a36Sopenharmony_ci					   bit 6 - suggest binary search (unused)
40462306a36Sopenharmony_ci					   bit 7 - 1 -> (internal) tree of anodes
40562306a36Sopenharmony_ci						   0 -> (leaf) list of extents */
40662306a36Sopenharmony_ci  u8 fill[3];
40762306a36Sopenharmony_ci  u8 n_free_nodes;			/* free nodes in following array */
40862306a36Sopenharmony_ci  u8 n_used_nodes;			/* used nodes in following array */
40962306a36Sopenharmony_ci  __le16 first_free;			/* offset from start of header to
41062306a36Sopenharmony_ci					   first free node in array */
41162306a36Sopenharmony_ci  union {
41262306a36Sopenharmony_ci	/* (internal) 2-word entries giving subtree pointers */
41362306a36Sopenharmony_ci	DECLARE_FLEX_ARRAY(struct bplus_internal_node, internal);
41462306a36Sopenharmony_ci	/* (external) 3-word entries giving sector runs */
41562306a36Sopenharmony_ci	DECLARE_FLEX_ARRAY(struct bplus_leaf_node, external);
41662306a36Sopenharmony_ci  } u;
41762306a36Sopenharmony_ci};
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_cistatic inline bool bp_internal(struct bplus_header *bp)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	return bp->flags & BP_internal;
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cistatic inline bool bp_fnode_parent(struct bplus_header *bp)
42562306a36Sopenharmony_ci{
42662306a36Sopenharmony_ci	return bp->flags & BP_fnode_parent;
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci/* fnode: root of allocation b+ tree, and EA's */
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci/* Every file and every directory has one fnode, pointed to by the directory
43262306a36Sopenharmony_ci   entry and pointing to the file's sectors or directory's root dnode.  EA's
43362306a36Sopenharmony_ci   are also stored here, and there are said to be ACL's somewhere here too. */
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci#define FNODE_MAGIC 0xf7e40aae
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cienum {FNODE_anode = cpu_to_le16(2), FNODE_dir = cpu_to_le16(256)};
43862306a36Sopenharmony_cistruct fnode
43962306a36Sopenharmony_ci{
44062306a36Sopenharmony_ci  __le32 magic;				/* f7e4 0aae */
44162306a36Sopenharmony_ci  __le32 zero1[2];			/* read history */
44262306a36Sopenharmony_ci  u8 len, name[15];			/* true length, truncated name */
44362306a36Sopenharmony_ci  __le32 up;				/* pointer to file's directory fnode */
44462306a36Sopenharmony_ci  __le32 acl_size_l;
44562306a36Sopenharmony_ci  __le32 acl_secno;
44662306a36Sopenharmony_ci  __le16 acl_size_s;
44762306a36Sopenharmony_ci  u8 acl_anode;
44862306a36Sopenharmony_ci  u8 zero2;				/* history bit count */
44962306a36Sopenharmony_ci  __le32 ea_size_l;			/* length of disk-resident ea's */
45062306a36Sopenharmony_ci  __le32 ea_secno;			/* first sector of disk-resident ea's*/
45162306a36Sopenharmony_ci  __le16 ea_size_s;			/* length of fnode-resident ea's */
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci  __le16 flags;				/* bit 1 set -> ea_secno is an anode */
45462306a36Sopenharmony_ci					/* bit 8 set -> directory.  first & only extent
45562306a36Sopenharmony_ci					   points to dnode. */
45662306a36Sopenharmony_ci  struct bplus_header btree;		/* b+ tree, 8 extents or 12 subtrees */
45762306a36Sopenharmony_ci  union {
45862306a36Sopenharmony_ci    struct bplus_leaf_node external[8];
45962306a36Sopenharmony_ci    struct bplus_internal_node internal[12];
46062306a36Sopenharmony_ci  } u;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci  __le32 file_size;			/* file length, bytes */
46362306a36Sopenharmony_ci  __le32 n_needea;			/* number of EA's with NEEDEA set */
46462306a36Sopenharmony_ci  u8 user_id[16];			/* unused */
46562306a36Sopenharmony_ci  __le16 ea_offs;			/* offset from start of fnode
46662306a36Sopenharmony_ci					   to first fnode-resident ea */
46762306a36Sopenharmony_ci  u8 dasd_limit_treshhold;
46862306a36Sopenharmony_ci  u8 dasd_limit_delta;
46962306a36Sopenharmony_ci  __le32 dasd_limit;
47062306a36Sopenharmony_ci  __le32 dasd_usage;
47162306a36Sopenharmony_ci  u8 ea[316];				/* zero or more EA's, packed together
47262306a36Sopenharmony_ci					   with no alignment padding.
47362306a36Sopenharmony_ci					   (Do not use this name, get here
47462306a36Sopenharmony_ci					   via fnode + ea_offs. I think.) */
47562306a36Sopenharmony_ci};
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_cistatic inline bool fnode_in_anode(struct fnode *p)
47862306a36Sopenharmony_ci{
47962306a36Sopenharmony_ci	return (p->flags & FNODE_anode) != 0;
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_cistatic inline bool fnode_is_dir(struct fnode *p)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	return (p->flags & FNODE_dir) != 0;
48562306a36Sopenharmony_ci}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci/* anode: 99.44% pure allocation tree */
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci#define ANODE_MAGIC 0x37e40aae
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_cistruct anode
49362306a36Sopenharmony_ci{
49462306a36Sopenharmony_ci  __le32 magic;				/* 37e4 0aae */
49562306a36Sopenharmony_ci  __le32 self;				/* pointer to this anode */
49662306a36Sopenharmony_ci  __le32 up;				/* parent anode or fnode */
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci  struct bplus_header btree;		/* b+tree, 40 extents or 60 subtrees */
49962306a36Sopenharmony_ci  union {
50062306a36Sopenharmony_ci    struct bplus_leaf_node external[40];
50162306a36Sopenharmony_ci    struct bplus_internal_node internal[60];
50262306a36Sopenharmony_ci  } u;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci  __le32 fill[3];			/* unused */
50562306a36Sopenharmony_ci};
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci/* extended attributes.
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci   A file's EA info is stored as a list of (name,value) pairs.  It is
51162306a36Sopenharmony_ci   usually in the fnode, but (if it's large) it is moved to a single
51262306a36Sopenharmony_ci   sector run outside the fnode, or to multiple runs with an anode tree
51362306a36Sopenharmony_ci   that points to them.
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci   The value of a single EA is stored along with the name, or (if large)
51662306a36Sopenharmony_ci   it is moved to a single sector run, or multiple runs pointed to by an
51762306a36Sopenharmony_ci   anode tree, pointed to by the value field of the (name,value) pair.
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci   Flags in the EA tell whether the value is immediate, in a single sector
52062306a36Sopenharmony_ci   run, or in multiple runs.  Flags in the fnode tell whether the EA list
52162306a36Sopenharmony_ci   is immediate, in a single run, or in multiple runs. */
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_cienum {EA_indirect = 1, EA_anode = 2, EA_needea = 128 };
52462306a36Sopenharmony_cistruct extended_attribute
52562306a36Sopenharmony_ci{
52662306a36Sopenharmony_ci  u8 flags;				/* bit 0 set -> value gives sector number
52762306a36Sopenharmony_ci					   where real value starts */
52862306a36Sopenharmony_ci					/* bit 1 set -> sector is an anode
52962306a36Sopenharmony_ci					   that points to fragmented value */
53062306a36Sopenharmony_ci					/* bit 7 set -> required ea */
53162306a36Sopenharmony_ci  u8 namelen;				/* length of name, bytes */
53262306a36Sopenharmony_ci  u8 valuelen_lo;			/* length of value, bytes */
53362306a36Sopenharmony_ci  u8 valuelen_hi;			/* length of value, bytes */
53462306a36Sopenharmony_ci  u8 name[];
53562306a36Sopenharmony_ci  /*
53662306a36Sopenharmony_ci    u8 name[namelen];			ascii attrib name
53762306a36Sopenharmony_ci    u8 nul;				terminating '\0', not counted
53862306a36Sopenharmony_ci    u8 value[valuelen];			value, arbitrary
53962306a36Sopenharmony_ci      if this.flags & 1, valuelen is 8 and the value is
54062306a36Sopenharmony_ci        u32 length;			real length of value, bytes
54162306a36Sopenharmony_ci        secno secno;			sector address where it starts
54262306a36Sopenharmony_ci      if this.anode, the above sector number is the root of an anode tree
54362306a36Sopenharmony_ci        which points to the value.
54462306a36Sopenharmony_ci  */
54562306a36Sopenharmony_ci};
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_cistatic inline bool ea_indirect(struct extended_attribute *ea)
54862306a36Sopenharmony_ci{
54962306a36Sopenharmony_ci	return ea->flags & EA_indirect;
55062306a36Sopenharmony_ci}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_cistatic inline bool ea_in_anode(struct extended_attribute *ea)
55362306a36Sopenharmony_ci{
55462306a36Sopenharmony_ci	return ea->flags & EA_anode;
55562306a36Sopenharmony_ci}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci/*
55862306a36Sopenharmony_ci   Local Variables:
55962306a36Sopenharmony_ci   comment-column: 40
56062306a36Sopenharmony_ci   End:
56162306a36Sopenharmony_ci*/
562