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