/*++ Copyright (c) 1991 Microsoft Corporation Module Name: HpfsBoot.h Abstract: This module defines globally used procedure and data structures used by Hpfs boot. Author: Gary Kimura [GaryKi] 19-Jul-1991 Revision History: --*/ #ifndef _HPFSBOOT_ #define _HPFSBOOT_ typedef ULONG LBN; typedef LBN *PLBN; typedef ULONG VBN; typedef VBN *PVBN; // // The following structure is a context block used by the exported // procedures in the Hpfs boot package. The context contains our cached // part of the boot mcb structure. The max number must not be smaller than // the maximum number of leafs possible in a pinball allocation sector plus // one. // #define MAXIMUM_NUMBER_OF_BOOT_MCB (41) typedef struct _HPFS_BOOT_MCB { // // The following fields indicate the number of entries in use by // the boot mcb. and the boot mcb itself. The boot mcb is // just a collection of vbn - lbn pairs. The last InUse entry // Lbn's value is ignored, because it is only used to give the // length of the previous run. // ULONG InUse; VBN Vbn[ MAXIMUM_NUMBER_OF_BOOT_MCB ]; LBN Lbn[ MAXIMUM_NUMBER_OF_BOOT_MCB ]; } HPFS_BOOT_MCB, *PHPFS_BOOT_MCB; typedef struct _HPFS_STRUCTURE_CONTEXT { // // The following field contains the fnode lbn of the file // LBN Fnode; // // The following field contains the cached mcb // HPFS_BOOT_MCB BootMcb; } HPFS_STRUCTURE_CONTEXT, *PHPFS_STRUCTURE_CONTEXT; // // Define Hpfs file context structure. // typedef struct _HPFS_FILE_CONTEXT { // // The following field contains the size of the file, in bytes. // ULONG FileSize; } HPFS_FILE_CONTEXT, *PHPFS_FILE_CONTEXT; // // HPFS file system structures // typedef ULONG SIGNATURE; typedef SIGNATURE *PSIGNATURE; typedef ULONG PINBALL_TIME; typedef PINBALL_TIME *PPINBALL_TIME; // // There are only three sectors on the disk that have fixed locations. They // are the boot sector, the super sector, and the spare sector. // #define BOOT_SECTOR_LBN (0) #define SUPER_SECTOR_LBN (16) #define SPARE_SECTOR_LBN (17) typedef struct _SUPER_SECTOR { // // The Super Sector starts with a double signature. // SIGNATURE Signature1; // offset = 0x000 0 SIGNATURE Signature2; // offset = 0x004 4 // // The version and functional version describe the version of // the on-disk file system structures and the oldest version of the // file system that can understand this disk. // UCHAR Version; // offset = 0x008 8 UCHAR FunctionalVersion; // offset = 0x009 9 USHORT Unused1; // offset = 0x00A 10 // // This field denotes the sector containing the FNODE for the root // directory for the volume. // LBN RootDirectoryFnode; // offset = 0x00C 12 // // The follow two fields indicate the number of total sectors on the // volume (good and bad), and the number of bad sectors on the volume. // ULONG NumberOfSectors; // offset = 0x010 16 ULONG NumberOfBadSectors; // offset = 0x014 20 // // This field denotes the sector containing the first level of the // volumes bitmap table. // LBN BitMapIndirect; // offset = 0x018 24 ULONG Unused2; // offset = 0x01C 28 // // This field denotes the sector containing the first bad sector disk // buffer for the volume. // LBN BadSectorList; // offset = 0x020 32 ULONG Unused3; // offset = 0x024 36 // // The following two dates are the time of the last execution of // chkdsk and disk optimize on the volume. // PINBALL_TIME ChkdskDate; // offset = 0x028 40 PINBALL_TIME DiskOptimizeDate; // offset = 0x02C 44 // // The following four fields describe the directory disk buffer pool. // It is a contiguous run on of sectors on the disk set aside for // holding directory disk buffers. PoolSize is the total number of // sectors in the pool. First and Last Sector denote the boundaries // of the pool, and BitMap denotes the start of a small bitmap used to // describe the directory disk buffer pool's current allocation. The // bitmap is 4 contiguous sectors in size, and each bit in the map // corresponds to 1 Directory Disk Buffer (i.e., 4 Sectors worth) // ULONG DirDiskBufferPoolSize; // offset = 0x030 48 LBN DirDiskBufferPoolFirstSector; // offset = 0x034 52 LBN DirDiskBufferPoolLastSector; // offset = 0x038 56 LBN DirDiskBufferPoolBitMap; // offset = 0x03C 60 // // The following field contains the name of the volume // UCHAR VolumeName[32]; // offset = 0x040 64 // // The following field denotes the start of the Small ID (SID) table // which is used to store the Small ID to GUID mappings used on the // volume. The SID table is 8 contiguous sectors in size. // LBN SidTable; // offset = 0x060 96 UCHAR Unused4[512-100]; // offset = 0x064 100 } SUPER_SECTOR; // sizeof = 0x200 512 typedef SUPER_SECTOR *PSUPER_SECTOR; // // Super Sector signatures // #define SUPER_SECTOR_SIGNATURE1 (0xf995e849) #define SUPER_SECTOR_SIGNATURE2 (0xfa53e9c5) // // Super Sector versions // #define SUPER_SECTOR_VERSION (0x02) #define SUPER_SECTOR_FUNC_VERSION (0x02) typedef struct _SPARE_SECTOR { // // The Spare Sector starts with a double signature. // SIGNATURE Signature1; // offset = 0x000 0 SIGNATURE Signature2; // offset = 0x004 4 // // The flags field describe how "clean" the volume is. // UCHAR Flags; // offset = 0x008 8 UCHAR Unused1[3]; // offset = 0x009 9 // // The following three fields describe the hotfix structure for the // volume. The List field is denotes the disk buffer used to store // the hotfix table. The InUse describes how many hotfixes are // currently being used, and MaxSize is the total number of hotfixes // that can be in use at any one time. // LBN HotFixList; // offset = 0x00C 12 ULONG HotFixInUse; // offset = 0x010 16 ULONG HotFixMaxSize; // offset = 0x014 20 // // The following two fields describe the "emergency" pool of spare // directory disk buffers. Free describes how many spare directory // disk buffers are currently available for use. MaxSize is the total // number of spare directory disk buffers available. The actual location // of the spare directory disk buffers is denoted in the table at the // end of the spare sector (i.e., field SpareDirDiskBuffer). // ULONG SpareDirDiskBufferAvailable; // offset = 0x018 24 ULONG SpareDirDiskBufferMaxSize; // offset = 0x01C 28 // // The following two fields describe the code page information used // on the volume. The InfoSector field is the sector of the beginning // Code Page Information Sector, and the InUse field is the total number // of code pages currently in use on the volume. // LBN CodePageInfoSector; // offset = 0x020 32 ULONG CodePageInUse; // offset = 0x024 36 ULONG Unused2[17]; // offset = 0x028 40 // // The following field is an array of LBN's for the spare directory // disk buffers that are for "emergency" use. // LBN SpareDirDiskBuffer[101]; // offset = 0x06C 108 } SPARE_SECTOR; // sizeof = 0x200 512 typedef SPARE_SECTOR *PSPARE_SECTOR; // // Spare Sector signatures // #define SPARE_SECTOR_SIGNATURE1 (0xf9911849) #define SPARE_SECTOR_SIGNATURE2 (0xfa5229c5) // // The on-disk allocation structure is defined using B-Trees. For every // B-Tree block there is an Allocation Header, followed by a list of // either Allocation Leafs or Allocation Nodes. This structure will either // appear in an FNODE or in an AllocationSector. // // The allocation header (called Allocation Block in earlier implementations) // describes a B-tree block. // typedef struct _ALLOCATION_HEADER { // // The following flag describes the state of the B-tree block (e.g., // indicates if the block is a leaf or an internal node. // UCHAR Flags; // offset = 0x000 0 UCHAR Unused[3]; // offset = 0x001 1 // // The following two fields denote the number of free records in the // B-Tree block, and the number of records that are currently in use // UCHAR FreeCount; // offset = 0x004 4 UCHAR OccupiedCount; // offset = 0x005 5 // // The next field contains the offset (in bytes) from the beginning // of the allocation header to the first free byte in the B-Tree block // USHORT FirstFreeByte; // offset = 0x006 6 } ALLOCATION_HEADER; // sizeof = 0x008 8 typedef ALLOCATION_HEADER *PALLOCATION_HEADER; // // Allocation header flags // // NODE - if set this indicates that the B-Tree block contains internal // nodes and not leaf entries. // // BINARY_SEARCH - if set this suggest that a binary search should be used // to search the B-Tree block. // // FNODE_PARENT - if set this indicates that the sector which is the // parent of the sector with this header (not this sector), is an // FNODE. // #define ALLOCATION_BLOCK_NODE (0x80) #define ALLOCATION_BLOCK_BINARY (0x40) #define ALLOCATION_BLOCK_FNODE_PARENT (0x20) // // Immediately following an allocation header are one or more allocation nodes // of allocation leafs. // typedef struct _ALLOCATION_NODE { // // All children of this allocation node will have values less than // the following VBN field. // VBN Vbn; // offset = 0x000 0 // // This is the LBN of the allocation sector refered to by this node // LBN Lbn; // offset = 0x004 4 } ALLOCATION_NODE; // sizeof = 0x008 8 typedef ALLOCATION_NODE *PALLOCATION_NODE; typedef struct _ALLOCATION_LEAF { // // The following field has the starting VBN for this run // VBN Vbn; // offset = 0x000 0 // // This is the length of the run in sectors // ULONG Length; // offset = 0x004 4 // // This is the starting LBN of the run // LBN Lbn; // offset = 0x008 8 } ALLOCATION_LEAF; // sizeof = 0x00C 12 typedef ALLOCATION_LEAF *PALLOCATION_LEAF; // // An allocation sector is an on-disk structure that contains allocation // information. It contains some bookkeeping information, an allocation // header and then an array of either allocation leafs or allocation nodes. // // AllocationSector // +-------------------+ // | bookkeeping | // +- - - - - - - - - -+ // | Allocation Header | // +- - - - - - - - - -+ // | Allocation Leafs | // | or | // | Allocation Nodes | // +-------------------+ // // where the number of allocation leafs that can be stored in a sector is // 40 and the number of nodes is 60. // #define ALLOCATION_NODES_PER_SECTOR (60) #define ALLOCATION_LEAFS_PER_SECTOR (40) typedef struct _ALLOCATION_SECTOR { // // The allocation sector starts off with a signature field // SIGNATURE Signature; // offset = 0x000 0 // // This following two fields contains the LBN of this allocation // sector itself, and the LBN of the parent of this sector (the // parent is either an FNODE or another allocation sector) // LBN Lbn; // offset = 0x004 4 LBN ParentLbn; // offset = 0x008 8 // // The allocation header for the sector // ALLOCATION_HEADER AllocationHeader; // offset = 0x00C 12 // // The remainder of the sector is either an array of allocation leafs // of allocation nodes // union { // offset = 0x014 20 ALLOCATION_NODE Node[ ALLOCATION_NODES_PER_SECTOR ]; ALLOCATION_LEAF Leaf[ ALLOCATION_LEAFS_PER_SECTOR ]; } Allocation; UCHAR Unused[12]; // offset = 0x1F4 500 } ALLOCATION_SECTOR; // sizeof = 0x200 512 typedef ALLOCATION_SECTOR *PALLOCATION_SECTOR; // // The allocation sector signature // #define ALLOCATION_SECTOR_SIGNATURE (0x37e40aae) // // The on-disk FNODE structure is used to describe both files and directories // It contains some fixed data information, the EA and ACL lookup information, // allocation information and then a free space for storing some EAs and // ACLs that fit in the sector // #define ALLOCATION_NODES_PER_FNODE (12) #define ALLOCATION_LEAFS_PER_FNODE (8) typedef struct _FNODE_SECTOR { // // The sector starts with a signature field // SIGNATURE Signature; // offset = 0x000 0 // // The following fields was for history tracking, but in NT Pinball // doesn't need this information. // ULONG Unused1[2]; // offset = 0x004 4 // // The following two fields contain the file name length, and the first // 15 bytes of the filename, as stored in the dirent that references // this fnode. For the root directory theses values are all zeros. // UCHAR FileNameLength; // offset = 0x00C 12 UCHAR FileName[15]; // offset = 0x00D 13 // // The following field denotes the parent directory's FNODE // LBN ParentFnode; // offset = 0x01C 28 // // The following four fields describe the ACL for the file/directory. // // AclDiskAllocationLength holds the number of bytes in the ACL that // are stored outside of this FNODE. If this value is not zero // then AclFnodeLength must be equal to zero. // // AclLbn points to the first sector of the data run or the allocation // sector containing describing the ACL. AclFlags indicates if // it is a data run or an allocation sector. AclLbn is only used // if AclDiskAllocationLength is not zero. // // AclFnodeLength holds the number of bytes in the ACL that are // stored within this FNODE. If value is not zero then // AclDiskAllocationLength must be equal to zero. The ACL, if stored // in the FNODE, is located at AclEaFnodeBuffer in this FNODE sector. // // AclFlags if the data is outside the FNODE this flag indicates whether // ACL is stored in a single data run (AclFlags == 0) or via an // allocation sector (AclFlags != 0). AclFlags is only used if // AclDiskAllocationLength is not zero. // ULONG AclDiskAllocationLength; // offset = 0x020 32 LBN AclLbn; // offset = 0x024 36 USHORT AclFnodeLength; // offset = 0x028 40 UCHAR AclFlags; // offset = 0x02A 42 // // The following field was used for the number of valid history // bits but we don't need this field of NT Pinball // UCHAR Unused2; // offset = 0x02B 43 // // The following four fields describe the EA for the file/directory. // // EaDiskAllocationLength holds the number of bytes in the EA that // are stored outside of this FNODE. If this value is not zero // then EaFnodeLength must be equal to zero. // // EaLbn points to the first sector of the data run or the allocation // sector containing describing the EA. EaFlags indicates if // it is a data run or an allocation sector. EaLbn is only used // if EaDiskAllocationLength is not zero. // // EaFnodeLength holds the number of bytes in the EA that are // stored within this FNODE. If value is not zero then // EaDiskAllocationLength must be equal to zero. The EA, if stored // in the FNODE, is located immediately after the ACL stored in the // AclEaFnodeBuffer. // // EaFlags if the data is outside the FNODE this flag indicates whether // EA is stored in a single data run (EaFlags == 0) or via an // allocation sector (EaFlags != 0). EaFlags is only used if // EaDiskAllocationLength is not zero. // ULONG EaDiskAllocationLength; // offset = 0x02C 44 LBN EaLbn; // offset = 0x030 48 USHORT EaFnodeLength; // offset = 0x034 52 UCHAR EaFlags; // offset = 0x036 54 // // The following byte contains the FNODE flags // UCHAR Flags; // offset = 0x037 55 // // The following two fields describe the top level allocation for // this file/directory // ALLOCATION_HEADER AllocationHeader; // offset = 0x038 56 union { // offset = 0x040 64 ALLOCATION_NODE Node[ ALLOCATION_NODES_PER_FNODE ]; ALLOCATION_LEAF Leaf[ ALLOCATION_LEAFS_PER_FNODE ]; } Allocation; // // The following field contains the valid length of the file. The size // of the file is stored in the dirent. The difference between these two // values is that the file size is the actual size allocated and visible // to the user. The Valid length is the number of bytes that have // had their data zeroed out or modified. (i.e., if a read request // is greater than valid length but less than file size then the file // system must first zero out the data in the file up to and including // data being read. // ULONG ValidDataLength; // offset = 0x0A0 160 // // The following field contains the number of EAs in this file that have // the need ea attribute set. // ULONG NeedEaCount; // offset = 0x0A4 164 UCHAR Unused3[16]; // offset = 0x0A8 168 // // The following field contains the offset, in bytes, from the start of // FNODE to the first ACE stored in the FNODE // USHORT AclBase; // offset = 0x0B8 184 UCHAR Unused4[10]; // offset = 0x0BA 186 // // The following buffer is used to store acl/ea in the FNODE // UCHAR AclEaFnodeBuffer[316]; // offset = 0x0C4 196 } FNODE_SECTOR; // sizeof = 0x200 512 typedef FNODE_SECTOR *PFNODE_SECTOR; // // The FNODE Sector signature // #define FNODE_SECTOR_SIGNATURE (0xf7e40aae) // // The on-disk directory disk buffer is used to contain directory entries. // It contains a fixed header followed by a collection of one or more // dirents. Dirents are variable so size we cannot use a simply C struct // declartion for the entire disk buffer. // typedef struct _DIRECTORY_DISK_BUFFER { // // The disk buffer starts with a signature field // SIGNATURE Signature; // offset = 0x000 0 // // The following field is the offset to the first free byte in this // disk buffer // ULONG FirstFree; // offset = 0x004 4 // // The following field is a change count that is kept around for // bookkeeping purposes. It is incremented whenever we move any // of the entries in this disk buffer. This means for any file if we // remember its offset and its change count we will be able to quickly // locate the dirent again without needing to search from the top // of the directory again. (i.e., only if the remembered change count // and the current change count match). For this to work the file system // in memory will need to keep track of whenever it removes a Directory // Disk Buffer from a directory, and have each saved dirent location // keep this Directory change count, the Directory Disk Buffer Change // Count, LBN and Offset. // // In addition we overload the bit in this value to indicate if this // is the topmost directory disk buffer for the directory (low order bit // = 1) or if it is a lower lever buffer (low order bit = 0). // ULONG ChangeCount; // offset = 0x008 8 // // The following field contains the LBN of either the parent // directory disk buffer containing this disk buffer or the FNODE. // It is the FNODE if this is a topmost disk buffer and a parent // directory disk buffer otherwise. // LBN Parent; // offset = 0x00C 12 // // The following field is the LBN of the sector containing the // start of this disk buffer // LBN Sector; // offset = 0x010 16 // // This following buffer contains the dirents stored in this disk buffer // UCHAR Dirents[2028]; // offset = 0x014 20 } DIRECTORY_DISK_BUFFER; // sizeof = 0x800 2048 typedef DIRECTORY_DISK_BUFFER *PDIRECTORY_DISK_BUFFER; // // Size of Directory Disk Buffer in sectors. // #define DIRECTORY_DISK_BUFFER_SECTORS (4) // // Directory Disk Buffer Signature // #define DIRECTORY_DISK_BUFFER_SIGNATURE (0x77e40aae) typedef struct _PBDIRENT { USHORT DirentSize; // offset = 0x000 0 UCHAR Flags; // offset = 0x002 2 UCHAR FatFlags; // offset = 0x003 3 LBN Fnode; // offset = 0x004 4 PINBALL_TIME LastModificationTime; // offset = 0x008 8 ULONG FileSize; // offset = 0x00C 12 PINBALL_TIME LastAccessTime; // offset = 0x010 16 PINBALL_TIME FnodeCreationTime; // offset = 0x014 20 ULONG EaLength; // offset = 0x018 24 UCHAR ResidentAceCount; // offset = 0x01C 28 UCHAR CodePageIndex; // offset = 0x01D 29 UCHAR FileNameLength; // offset = 0x01E 30 UCHAR FileName[1]; // offset = 0x01F 31 } PBDIRENT; // sizeof = 0x020 32 typedef PBDIRENT *PPBDIRENT; // // Define sizes of .. and End PBDIRENT. // #define SIZEOF_DIR_DOTDOT (sizeof(PBDIRENT) + sizeof(LONG)) #define SIZEOF_DIR_END (sizeof(PBDIRENT)) #define SIZEOF_DIR_MAXPBDIRENT (sizeof(PBDIRENT) + 256 + \ (3*sizeof(PINBALL_ACE)) + sizeof(LBN)) #define DIRENT_FIRST_ENTRY (0x0001) #define DIRENT_ACL (0x0002) #define DIRENT_BTREE_POINTER (0x0004) #define DIRENT_END (0x0008) #define DIRENT_EXPLICIT_ACL (0x0040) #define DIRENT_NEED_EA (0x0080) #define DIRENT_NEW_NAMING_RULES (0x4000) // // The following macros are used to help locate dirents within a Directory // Disk Buffer. GetFirstDirent returns a pointer to the first dirent entry // in the directory disk buffer. GetNextDirent returns a pointer to the // next dirent entry in a directory disk buffer, without checking for the // end of the Directory Disk Buffer. // // PDIRENT // GetFirstDirent ( // IN PDIRECTORY_DISK_BUFFER DirectoryDiskBuffer // ); // // PDIRENT // GetNextDirent ( // IN PDIRENT Dirent // ); // #define GetFirstDirent(DIR) ( \ (PDIRENT)&(DIR)->Dirents[0] \ ) // // This macro blindly returns a pointer to the next Dirent, without checking // for the end of the Directory Disk Buffer, i.e., callers must always check // for the End record in the Directory Disk Buffer. If GetNextDirent is // called with the End record as input, it will return the next free byte // in the buffer. // #define GetNextDirent(ENT) ( \ (PDIRENT)((PUCHAR)(ENT)+(ENT)->DirentSize) \ ) // // The following macros are used to help retrieve the variable fields // within a dirent. GetAceInDirent returns a pointer to the ACE within // the dirent corresponding to the supplied index, or NULL if there isn't // a corresponding ACE. GetBtreePointerInDirent returns the LBN field of // the down B-tree pointer stored in the dirent, or it returns a value of // zero if there isn't a down pointer. SetBtreePointerInDirent sets the // LBN downpointer field. // // PPINBALL_ACE // GetAceInDirent ( // IN PDIRENT Dirent, // IN ULONG Index // (0, 1, or 2) // ); // // LBN // GetBtreePointerInDirent ( // IN PDIRENT Dirent // ); // // VOID // SetBtreePointerInDirent ( // IN OUT PDIRENT Dirent, // IN LBN Blbn // ); // // // // To return a pointer to an ACE in a dirent we need to check to see if the // index is within the resident ace count. The first ace is the address of // the first longword after the filename, the second ace is the second long // word. // #define GetAceInDirent(ENT,I) ( \ ((I) >= 0 && (I) < (ENT)->ResidentAceCount ? \ (PPINBALL_ACE)( \ (LONG)LongAlign((ENT)->FileName[(ENT)->FileNameLength]) + \ (I)*sizeof(PINBALL_ACE) \ ) \ : \ NULL \ ) \ ) // // To return the Btree pointer we need to first check to see if there // is Btree pointer field, otherwise we return NULL. The field, if present, // is located 4 bytes back from the end of the dirent. // #define GetBtreePointerInDirent(ENT) ( \ (FlagOn((ENT)->Flags,DIRENT_BTREE_POINTER) ? \ *(PLBN)(((PUCHAR)(ENT)) + (ENT)->DirentSize - sizeof(LBN)) \ : \ 0 \ ) \ ) // // To set the Btree pointer we assume there is a Btree pointer field. // The field is located 4 bytes back from the end of the dirent. // #define SetBtreePointerInDirent(ENT,BLBN) ( \ *(PLBN)(((PUCHAR)(ENT)) + (ENT)->DirentSize - sizeof(LBN)) = (BLBN) \ ) // // Define file I/O prototypes. // ARC_STATUS HpfsClose ( IN ULONG FileId ); ARC_STATUS HpfsOpen ( IN PCHAR OpenPath, IN OPEN_MODE OpenMode, OUT PULONG FileId ); ARC_STATUS HpfsRead ( IN ULONG FileId, OUT PVOID Buffer, IN ULONG Length, OUT PULONG Count ); ARC_STATUS HpfsSeek ( IN ULONG FileId, IN PLARGE_INTEGER Offset, IN SEEK_MODE SeekMode ); ARC_STATUS HpfsWrite ( IN ULONG FileId, IN PVOID Buffer, IN ULONG Length, OUT PULONG Count ); ARC_STATUS HpfsGetFileInformation ( IN ULONG FileId, OUT PFILE_INFORMATION Buffer ); ARC_STATUS HpfsSetFileInformation ( IN ULONG FileId, IN ULONG AttributeFlags, IN ULONG AttributeMask ); ARC_STATUS HpfsInitialize( VOID ); #endif // _HPFSBOOT_