/* SPDX-License-Identifier: GPL-2.0 */ /* * linux/fs/hpfs/hpfs.h * * HPFS structures by Chris Smith, 1993 * * a little bit modified by Mikulas Patocka, 1998-1999 */ /* The paper Duncan, Roy Design goals and implementation of the new High Performance File System Microsoft Systems Journal Sept 1989 v4 n5 p1(13) describes what HPFS looked like when it was new, and it is the source of most of the information given here. The rest is conjecture. For definitive information on the Duncan paper, see it, not this file. For definitive information on HPFS, ask somebody else -- this is guesswork. There are certain to be many mistakes. */ #if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN) #error unknown endian #endif /* Notation */ secno; /* sector number, partition relative */ dnode_secno; /* sector number of a dnode */ fnode_secno; /* sector number of an fnode */ anode_secno; /* sector number of an anode */ time32_t; /* 32-bit time_t type */ /* sector 0 */ /* The boot block is very like a FAT boot block, except that the 29h signature byte is 28h instead, and the ID string is "HPFS". */ #define BB_MAGIC … struct hpfs_boot_block { … }; /* sector 16 */ /* The super block has the pointer to the root directory. */ #define SB_MAGIC … struct hpfs_super_block { … }; /* sector 17 */ /* The spare block has pointers to spare sectors. */ #define SP_MAGIC … struct hpfs_spare_block { … }; /* The bad block list is 4 sectors long. The first word must be zero, the remaining words give n_badblocks bad block numbers. I bet you can see it coming... */ #define BAD_MAGIC … /* The hotfix map is 4 sectors long. It looks like secno from[n_spares]; secno to[n_spares]; The to[] list is initialized to point to n_spares preallocated empty sectors. The from[] list contains the sector numbers of bad blocks which have been remapped to corresponding sectors in the to[] list. n_spares_used gives the length of the from[] list. */ /* Sectors 18 and 19 are preallocated and unused. Maybe they're spares for 16 and 17, but simple substitution fails. */ /* The code page info pointed to by the spare block consists of an index block and blocks containing uppercasing tables. I don't know what these are for (CHKDSK, maybe?) -- OS/2 does not seem to use them itself. Linux doesn't use them either. */ /* block pointed to by spareblock->code_page_dir */ #define CP_DIR_MAGIC … struct code_page_directory { … }; /* blocks pointed to by code_page_directory */ #define CP_DATA_MAGIC … struct code_page_data { … }; /* Free space bitmaps are 4 sectors long, which is 16384 bits. 16384 sectors is 8 meg, and each 8 meg band has a 4-sector bitmap. Bit order in the maps is little-endian. 0 means taken, 1 means free. Bit map sectors are marked allocated in the bit maps, and so are sectors off the end of the partition. Band 0 is sectors 0-3fff, its map is in sectors 18-1b. Band 1 is 4000-7fff, its map is in 7ffc-7fff. Band 2 is 8000-ffff, its map is in 8000-8003. The remaining bands have maps in their first (even) or last (odd) 4 sectors -- if the last, partial, band is odd its map is in its last 4 sectors. The bitmap locations are given in a table pointed to by the super block. No doubt they aren't constrained to be at 18, 7ffc, 8000, ...; that is just where they usually are. The "directory band" is a bunch of sectors preallocated for dnodes. It has a 4-sector free space bitmap of its own. Each bit in the map corresponds to one 4-sector dnode, bit 0 of the map corresponding to the first 4 sectors of the directory band. The entire band is marked allocated in the main bitmap. The super block gives the locations of the directory band and its bitmap. ("band" doesn't mean it is 8 meg long; it isn't.) */ /* dnode: directory. 4 sectors long */ /* A directory is a tree of dnodes. The fnode for a directory contains one pointer, to the root dnode of the tree. The fnode never moves, the dnodes do the B-tree thing, splitting and merging as files are added and removed. */ #define DNODE_MAGIC … struct dnode { … }; struct hpfs_dirent { … }; /* B+ tree: allocation info in fnodes and anodes */ /* dnodes point to fnodes which are responsible for listing the sectors assigned to the file. This is done with trees of (length,address) pairs. (Actually triples, of (length, file-address, disk-address) which can represent holes. Find out if HPFS does that.) At any rate, fnodes contain a small tree; if subtrees are needed they occupy essentially a full block in anodes. A leaf-level tree node has 3-word entries giving sector runs, a non-leaf node has 2-word entries giving subtree pointers. A flag in the header says which. */ struct bplus_leaf_node { … }; struct bplus_internal_node { … }; enum { … }; struct bplus_header { … }; static inline bool bp_internal(struct bplus_header *bp) { … } static inline bool bp_fnode_parent(struct bplus_header *bp) { … } /* fnode: root of allocation b+ tree, and EA's */ /* Every file and every directory has one fnode, pointed to by the directory entry and pointing to the file's sectors or directory's root dnode. EA's are also stored here, and there are said to be ACL's somewhere here too. */ #define FNODE_MAGIC … enum { … }; struct fnode { … }; static inline bool fnode_in_anode(struct fnode *p) { … } static inline bool fnode_is_dir(struct fnode *p) { … } /* anode: 99.44% pure allocation tree */ #define ANODE_MAGIC … struct anode { … }; /* extended attributes. A file's EA info is stored as a list of (name,value) pairs. It is usually in the fnode, but (if it's large) it is moved to a single sector run outside the fnode, or to multiple runs with an anode tree that points to them. The value of a single EA is stored along with the name, or (if large) it is moved to a single sector run, or multiple runs pointed to by an anode tree, pointed to by the value field of the (name,value) pair. Flags in the EA tell whether the value is immediate, in a single sector run, or in multiple runs. Flags in the fnode tell whether the EA list is immediate, in a single run, or in multiple runs. */ enum { … }; struct extended_attribute { … }; static inline bool ea_indirect(struct extended_attribute *ea) { … } static inline bool ea_in_anode(struct extended_attribute *ea) { … } /* Local Variables: comment-column: 40 End: */