{ File: HFSVolumes.p Contains: On-disk data structures for HFS and HFS Plus volumes. Version: Technology: Mac OS 8.1 Release: Universal Interfaces 3.4.2 Copyright: © 1984-2002 by Apple Computer, Inc. All rights reserved. Bugs?: For bug reports, consult the following page on the World Wide Web: http://www.freepascal.org/bugs.html } { Modified for use with Free Pascal Version 200 Please report any bugs to } {$mode macpas} {$packenum 1} {$macro on} {$inline on} {$CALLING MWPASCAL} unit HFSVolumes; interface {$setc UNIVERSAL_INTERFACES_VERSION := $0342} {$setc GAP_INTERFACES_VERSION := $0200} {$ifc not defined USE_CFSTR_CONSTANT_MACROS} {$setc USE_CFSTR_CONSTANT_MACROS := TRUE} {$endc} {$ifc defined CPUPOWERPC and defined CPUI386} {$error Conflicting initial definitions for CPUPOWERPC and CPUI386} {$endc} {$ifc defined FPC_BIG_ENDIAN and defined FPC_LITTLE_ENDIAN} {$error Conflicting initial definitions for FPC_BIG_ENDIAN and FPC_LITTLE_ENDIAN} {$endc} {$ifc not defined __ppc__ and defined CPUPOWERPC} {$setc __ppc__ := 1} {$elsec} {$setc __ppc__ := 0} {$endc} {$ifc not defined __i386__ and defined CPUI386} {$setc __i386__ := 1} {$elsec} {$setc __i386__ := 0} {$endc} {$ifc defined __ppc__ and __ppc__ and defined __i386__ and __i386__} {$error Conflicting definitions for __ppc__ and __i386__} {$endc} {$ifc defined __ppc__ and __ppc__} {$setc TARGET_CPU_PPC := TRUE} {$setc TARGET_CPU_X86 := FALSE} {$elifc defined __i386__ and __i386__} {$setc TARGET_CPU_PPC := FALSE} {$setc TARGET_CPU_X86 := TRUE} {$elsec} {$error Neither __ppc__ nor __i386__ is defined.} {$endc} {$setc TARGET_CPU_PPC_64 := FALSE} {$ifc defined FPC_BIG_ENDIAN} {$setc TARGET_RT_BIG_ENDIAN := TRUE} {$setc TARGET_RT_LITTLE_ENDIAN := FALSE} {$elifc defined FPC_LITTLE_ENDIAN} {$setc TARGET_RT_BIG_ENDIAN := FALSE} {$setc TARGET_RT_LITTLE_ENDIAN := TRUE} {$elsec} {$error Neither FPC_BIG_ENDIAN nor FPC_LITTLE_ENDIAN are defined.} {$endc} {$setc ACCESSOR_CALLS_ARE_FUNCTIONS := TRUE} {$setc CALL_NOT_IN_CARBON := FALSE} {$setc OLDROUTINENAMES := FALSE} {$setc OPAQUE_TOOLBOX_STRUCTS := TRUE} {$setc OPAQUE_UPP_TYPES := TRUE} {$setc OTCARBONAPPLICATION := TRUE} {$setc OTKERNEL := FALSE} {$setc PM_USE_SESSION_APIS := TRUE} {$setc TARGET_API_MAC_CARBON := TRUE} {$setc TARGET_API_MAC_OS8 := FALSE} {$setc TARGET_API_MAC_OSX := TRUE} {$setc TARGET_CARBON := TRUE} {$setc TARGET_CPU_68K := FALSE} {$setc TARGET_CPU_MIPS := FALSE} {$setc TARGET_CPU_SPARC := FALSE} {$setc TARGET_OS_MAC := TRUE} {$setc TARGET_OS_UNIX := FALSE} {$setc TARGET_OS_WIN32 := FALSE} {$setc TARGET_RT_MAC_68881 := FALSE} {$setc TARGET_RT_MAC_CFM := FALSE} {$setc TARGET_RT_MAC_MACHO := TRUE} {$setc TYPED_FUNCTION_POINTERS := TRUE} {$setc TYPE_BOOL := FALSE} {$setc TYPE_EXTENDED := FALSE} {$setc TYPE_LONGLONG := TRUE} uses MacTypes,Files,Finder; {$ALIGN MAC68K} { Signatures used to differentiate between HFS and HFS Plus volumes } const kHFSSigWord = $4244; { 'BD' in ASCII } kHFSPlusSigWord = $482B; { 'H+' in ASCII } kHFSPlusVersion = $0004; { will change as format changes (version 4 shipped with Mac OS 8.1) } kHFSPlusMountVersion = $382E3130 (* '8.10' *); { will change as implementations change ('8.10' in Mac OS 8.1) } { CatalogNodeID is used to track catalog objects } type HFSCatalogNodeID = UInt32; const kHFSMaxVolumeNameChars = 27; kHFSMaxFileNameChars = 31; kHFSPlusMaxFileNameChars = 255; { Extent overflow file data structures } { HFS Extent key } type HFSExtentKeyPtr = ^HFSExtentKey; HFSExtentKey = record keyLength: SInt8; { length of key, excluding this field } forkType: SInt8; { 0 = data fork, FF = resource fork } fileID: HFSCatalogNodeID; { file ID } startBlock: UInt16; { first file allocation block number in this extent } end; { HFS Plus Extent key } HFSPlusExtentKeyPtr = ^HFSPlusExtentKey; HFSPlusExtentKey = record keyLength: UInt16; { length of key, excluding this field } forkType: SInt8; { 0 = data fork, FF = resource fork } pad: SInt8; { make the other fields align on 32-bit boundary } fileID: HFSCatalogNodeID; { file ID } startBlock: UInt32; { first file allocation block number in this extent } end; { Number of extent descriptors per extent record } const kHFSExtentDensity = 3; kHFSPlusExtentDensity = 8; { HFS extent descriptor } type HFSExtentDescriptorPtr = ^HFSExtentDescriptor; HFSExtentDescriptor = record startBlock: UInt16; { first allocation block } blockCount: UInt16; { number of allocation blocks } end; { HFS Plus extent descriptor } HFSPlusExtentDescriptorPtr = ^HFSPlusExtentDescriptor; HFSPlusExtentDescriptor = record startBlock: UInt32; { first allocation block } blockCount: UInt32; { number of allocation blocks } end; { HFS extent record } HFSExtentRecord = array [0..2] of HFSExtentDescriptor; { HFS Plus extent record } HFSPlusExtentRecord = array [0..7] of HFSPlusExtentDescriptor; { Fork data info (HFS Plus only) - 80 bytes } HFSPlusForkDataPtr = ^HFSPlusForkData; HFSPlusForkData = record logicalSize: UInt64; { fork's logical size in bytes } clumpSize: UInt32; { fork's clump size in bytes } totalBlocks: UInt32; { total blocks used by this fork } extents: HFSPlusExtentRecord; { initial set of extents } end; { Permissions info (HFS Plus only) - 16 bytes } HFSPlusPermissionsPtr = ^HFSPlusPermissions; HFSPlusPermissions = record ownerID: UInt32; { user or group ID of file/folder owner } groupID: UInt32; { additional user of group ID } permissions: UInt32; { permissions (bytes: unused, owner, group, everyone) } specialDevice: UInt32; { UNIX: device for character or block special file } end; { Catalog file data structures } const kHFSRootParentID = 1; { Parent ID of the root folder } kHFSRootFolderID = 2; { Folder ID of the root folder } kHFSExtentsFileID = 3; { File ID of the extents file } kHFSCatalogFileID = 4; { File ID of the catalog file } kHFSBadBlockFileID = 5; { File ID of the bad allocation block file } kHFSAllocationFileID = 6; { File ID of the allocation file (HFS Plus only) } kHFSStartupFileID = 7; { File ID of the startup file (HFS Plus only) } kHFSAttributesFileID = 8; { File ID of the attribute file (HFS Plus only) } kHFSBogusExtentFileID = 15; { Used for exchanging extents in extents file } kHFSFirstUserCatalogNodeID = 16; { HFS catalog key } type HFSCatalogKeyPtr = ^HFSCatalogKey; HFSCatalogKey = record keyLength: SInt8; { key length (in bytes) } reserved: SInt8; { reserved (set to zero) } parentID: HFSCatalogNodeID; { parent folder ID } nodeName: Str31; { catalog node name } end; { HFS Plus catalog key } HFSPlusCatalogKeyPtr = ^HFSPlusCatalogKey; HFSPlusCatalogKey = record keyLength: UInt16; { key length (in bytes) } parentID: HFSCatalogNodeID; { parent folder ID } nodeName: HFSUniStr255; { catalog node name } end; { Catalog record types } const { HFS Catalog Records } kHFSFolderRecord = $0100; { Folder record } kHFSFileRecord = $0200; { File record } kHFSFolderThreadRecord = $0300; { Folder thread record } kHFSFileThreadRecord = $0400; { File thread record } { HFS Plus Catalog Records } kHFSPlusFolderRecord = 1; { Folder record } kHFSPlusFileRecord = 2; { File record } kHFSPlusFolderThreadRecord = 3; { Folder thread record } kHFSPlusFileThreadRecord = 4; { File thread record } { Catalog file record flags } kHFSFileLockedBit = $0000; { file is locked and cannot be written to } kHFSFileLockedMask = $0001; kHFSThreadExistsBit = $0001; { a file thread record exists for this file } kHFSThreadExistsMask = $0002; { HFS catalog folder record - 70 bytes } type HFSCatalogFolderPtr = ^HFSCatalogFolder; HFSCatalogFolder = record recordType: SInt16; { record type } flags: UInt16; { folder flags } valence: UInt16; { folder valence } folderID: HFSCatalogNodeID; { folder ID } createDate: UInt32; { date and time of creation } modifyDate: UInt32; { date and time of last modification } backupDate: UInt32; { date and time of last backup } userInfo: DInfo; { Finder information } finderInfo: DXInfo; { additional Finder information } reserved: array [0..3] of UInt32; { reserved - set to zero } end; { HFS Plus catalog folder record - 88 bytes } HFSPlusCatalogFolderPtr = ^HFSPlusCatalogFolder; HFSPlusCatalogFolder = record recordType: SInt16; { record type = HFS Plus folder record } flags: UInt16; { file flags } valence: UInt32; { folder's valence (limited to 2^16 in Mac OS) } folderID: HFSCatalogNodeID; { folder ID } createDate: UInt32; { date and time of creation } contentModDate: UInt32; { date and time of last content modification } attributeModDate: UInt32; { date and time of last attribute modification } accessDate: UInt32; { date and time of last access (Rhapsody only) } backupDate: UInt32; { date and time of last backup } permissions: HFSPlusPermissions; { permissions (for Rhapsody) } userInfo: DInfo; { Finder information } finderInfo: DXInfo; { additional Finder information } textEncoding: UInt32; { hint for name conversions } reserved: UInt32; { reserved - set to zero } end; { HFS catalog file record - 102 bytes } HFSCatalogFilePtr = ^HFSCatalogFile; HFSCatalogFile = record recordType: SInt16; { record type } flags: SInt8; { file flags } fileType: SInt8; { file type (unused ?) } userInfo: FInfo; { Finder information } fileID: HFSCatalogNodeID; { file ID } dataStartBlock: UInt16; { not used - set to zero } dataLogicalSize: SInt32; { logical EOF of data fork } dataPhysicalSize: SInt32; { physical EOF of data fork } rsrcStartBlock: UInt16; { not used - set to zero } rsrcLogicalSize: SInt32; { logical EOF of resource fork } rsrcPhysicalSize: SInt32; { physical EOF of resource fork } createDate: UInt32; { date and time of creation } modifyDate: UInt32; { date and time of last modification } backupDate: UInt32; { date and time of last backup } finderInfo: FXInfo; { additional Finder information } clumpSize: UInt16; { file clump size (not used) } dataExtents: HFSExtentRecord; { first data fork extent record } rsrcExtents: HFSExtentRecord; { first resource fork extent record } reserved: UInt32; { reserved - set to zero } end; { HFS Plus catalog file record - 248 bytes } HFSPlusCatalogFilePtr = ^HFSPlusCatalogFile; HFSPlusCatalogFile = record recordType: SInt16; { record type = HFS Plus file record } flags: UInt16; { file flags } reserved1: UInt32; { reserved - set to zero } fileID: HFSCatalogNodeID; { file ID } createDate: UInt32; { date and time of creation } contentModDate: UInt32; { date and time of last content modification } attributeModDate: UInt32; { date and time of last attribute modification } accessDate: UInt32; { date and time of last access (Rhapsody only) } backupDate: UInt32; { date and time of last backup } permissions: HFSPlusPermissions; { permissions (for Rhapsody) } userInfo: FInfo; { Finder information } finderInfo: FXInfo; { additional Finder information } textEncoding: UInt32; { hint for name conversions } reserved2: UInt32; { reserved - set to zero } { start on double long (64 bit) boundry } dataFork: HFSPlusForkData; { size and block data for data fork } resourceFork: HFSPlusForkData; { size and block data for resource fork } end; { HFS catalog thread record - 46 bytes } HFSCatalogThreadPtr = ^HFSCatalogThread; HFSCatalogThread = record recordType: SInt16; { record type } reserved: array [0..1] of SInt32; { reserved - set to zero } parentID: HFSCatalogNodeID; { parent ID for this catalog node } nodeName: Str31; { name of this catalog node } end; { HFS Plus catalog thread record -- maximum 520 bytes } HFSPlusCatalogThreadPtr = ^HFSPlusCatalogThread; HFSPlusCatalogThread = record recordType: SInt16; { record type } reserved: SInt16; { reserved - set to zero } parentID: HFSCatalogNodeID; { parent ID for this catalog node } nodeName: HFSUniStr255; { name of this catalog node (variable length) } end; { These are the types of records in the attribute B-tree. The values were chosen so that they wouldn't conflict with the catalog record types. } const kHFSPlusAttrInlineData = $10; { if size < kAttrOverflowSize } kHFSPlusAttrForkData = $20; { if size >= kAttrOverflowSize } kHFSPlusAttrExtents = $30; { overflow extents for large attributes } { HFSPlusAttrInlineData For small attributes, whose entire value is stored within this one B-tree record. There would not be any other records for this attribute. } type HFSPlusAttrInlineDataPtr = ^HFSPlusAttrInlineData; HFSPlusAttrInlineData = record recordType: UInt32; { = kHFSPlusAttrInlineData } reserved: UInt32; logicalSize: UInt32; { size in bytes of userData } userData: packed array [0..1] of UInt8; { variable length; space allocated is a multiple of 2 bytes } end; { HFSPlusAttrForkData For larger attributes, whose value is stored in allocation blocks. If the attribute has more than 8 extents, there will be additonal records (of type HFSPlusAttrExtents) for this attribute. } HFSPlusAttrForkDataPtr = ^HFSPlusAttrForkData; HFSPlusAttrForkData = record recordType: UInt32; { = kHFSPlusAttrForkData } reserved: UInt32; theFork: HFSPlusForkData; { size and first extents of value } end; { HFSPlusAttrExtents This record contains information about overflow extents for large, fragmented attributes. } HFSPlusAttrExtentsPtr = ^HFSPlusAttrExtents; HFSPlusAttrExtents = record recordType: UInt32; { = kHFSPlusAttrExtents } reserved: UInt32; extents: HFSPlusExtentRecord; { additional extents } end; { A generic Attribute Record } HFSPlusAttrRecordPtr = ^HFSPlusAttrRecord; HFSPlusAttrRecord = record case SInt16 of 0: ( recordType: UInt32; ); 1: ( inlineData: HFSPlusAttrInlineData; ); 2: ( forkData: HFSPlusAttrForkData; ); 3: ( overflowExtents: HFSPlusAttrExtents; ); end; { Key and node lengths } const kHFSPlusExtentKeyMaximumLength = 10; kHFSExtentKeyMaximumLength = 7; kHFSPlusCatalogKeyMaximumLength = 516; kHFSPlusCatalogKeyMinimumLength = 6; kHFSCatalogKeyMaximumLength = 37; kHFSCatalogKeyMinimumLength = 6; kHFSPlusCatalogMinNodeSize = 4096; kHFSPlusExtentMinNodeSize = 512; kHFSPlusAttrMinNodeSize = 4096; { HFS and HFS Plus volume attribute bits } { Bits 0-6 are reserved (always cleared by MountVol call) } kHFSVolumeHardwareLockBit = 7; { volume is locked by hardware } kHFSVolumeUnmountedBit = 8; { volume was successfully unmounted } kHFSVolumeSparedBlocksBit = 9; { volume has bad blocks spared } kHFSVolumeNoCacheRequiredBit = 10; { don't cache volume blocks (i.e. RAM or ROM disk) } kHFSBootVolumeInconsistentBit = 11; { boot volume is inconsistent (System 7.6 and later) } { Bits 12-14 are reserved for future use } kHFSVolumeSoftwareLockBit = 15; { volume is locked by software } kHFSVolumeHardwareLockMask = $80; kHFSVolumeUnmountedMask = $0100; kHFSVolumeSparedBlocksMask = $0200; kHFSVolumeNoCacheRequiredMask = $0400; kHFSBootVolumeInconsistentMask = $0800; kHFSVolumeSoftwareLockMask = $8000; kHFSMDBAttributesMask = $8380; kHFSCatalogNodeIDsReusedBit = 12; { nextCatalogID wrapped around } kHFSCatalogNodeIDsReusedMask = $1000; { Master Directory Block (HFS only) - 162 bytes } { Stored at sector #2 (3rd sector) } type HFSMasterDirectoryBlockPtr = ^HFSMasterDirectoryBlock; HFSMasterDirectoryBlock = record { These first fields are also used by MFS } drSigWord: UInt16; { volume signature } drCrDate: UInt32; { date and time of volume creation } drLsMod: UInt32; { date and time of last modification } drAtrb: UInt16; { volume attributes } drNmFls: UInt16; { number of files in root folder } drVBMSt: UInt16; { first block of volume bitmap } drAllocPtr: UInt16; { start of next allocation search } drNmAlBlks: UInt16; { number of allocation blocks in volume } drAlBlkSiz: UInt32; { size (in bytes) of allocation blocks } drClpSiz: UInt32; { default clump size } drAlBlSt: UInt16; { first allocation block in volume } drNxtCNID: UInt32; { next unused catalog node ID } drFreeBks: UInt16; { number of unused allocation blocks } drVN: Str27; { volume name } { Master Directory Block extensions for HFS } drVolBkUp: UInt32; { date and time of last backup } drVSeqNum: UInt16; { volume backup sequence number } drWrCnt: UInt32; { volume write count } drXTClpSiz: UInt32; { clump size for extents overflow file } drCTClpSiz: UInt32; { clump size for catalog file } drNmRtDirs: UInt16; { number of directories in root folder } drFilCnt: UInt32; { number of files in volume } drDirCnt: UInt32; { number of directories in volume } drFndrInfo: array [0..7] of SInt32; { information used by the Finder } drEmbedSigWord: UInt16; { embedded volume signature (formerly drVCSize) } drEmbedExtent: HFSExtentDescriptor; { embedded volume location and size (formerly drVBMCSize and drCtlCSize) } drXTFlSize: UInt32; { size of extents overflow file } drXTExtRec: HFSExtentRecord; { extent record for extents overflow file } drCTFlSize: UInt32; { size of catalog file } drCTExtRec: HFSExtentRecord; { extent record for catalog file } end; { HFSPlusVolumeHeader (HFS Plus only) - 512 bytes } { Stored at sector #2 (3rd sector) and second-to-last sector. } HFSPlusVolumeHeaderPtr = ^HFSPlusVolumeHeader; HFSPlusVolumeHeader = record signature: UInt16; { volume signature == 'H+' } version: UInt16; { current version is kHFSPlusVersion } attributes: UInt32; { volume attributes } lastMountedVersion: UInt32; { implementation version which last mounted volume } reserved: UInt32; { reserved - set to zero } createDate: UInt32; { date and time of volume creation } modifyDate: UInt32; { date and time of last modification } backupDate: UInt32; { date and time of last backup } checkedDate: UInt32; { date and time of last disk check } fileCount: UInt32; { number of files in volume } folderCount: UInt32; { number of directories in volume } blockSize: UInt32; { size (in bytes) of allocation blocks } totalBlocks: UInt32; { number of allocation blocks in volume (includes this header and VBM } freeBlocks: UInt32; { number of unused allocation blocks } nextAllocation: UInt32; { start of next allocation search } rsrcClumpSize: UInt32; { default resource fork clump size } dataClumpSize: UInt32; { default data fork clump size } nextCatalogID: HFSCatalogNodeID; { next unused catalog node ID } writeCount: UInt32; { volume write count } encodingsBitmap: UInt64; { which encodings have been use on this volume } finderInfo: packed array [0..31] of UInt8; { information used by the Finder } allocationFile: HFSPlusForkData; { allocation bitmap file } extentsFile: HFSPlusForkData; { extents B-tree file } catalogFile: HFSPlusForkData; { catalog B-tree file } attributesFile: HFSPlusForkData; { extended attributes B-tree file } startupFile: HFSPlusForkData; { boot file } end; { ---------- HFS and HFS Plus B-tree structures ---------- } { BTNodeDescriptor -- Every B-tree node starts with these fields. } BTNodeDescriptorPtr = ^BTNodeDescriptor; BTNodeDescriptor = record fLink: UInt32; { next node at this level } bLink: UInt32; { previous node at this level } kind: SInt8; { kind of node (leaf, index, header, map) } height: SInt8; { zero for header, map; child is one more than parent } numRecords: UInt16; { number of records in this node } reserved: UInt16; { reserved; set to zero } end; { Constants for BTNodeDescriptor kind } const kBTLeafNode = -1; kBTIndexNode = 0; kBTHeaderNode = 1; kBTMapNode = 2; { BTHeaderRec -- The first record of a B-tree header node } type BTHeaderRecPtr = ^BTHeaderRec; BTHeaderRec = record treeDepth: UInt16; { maximum height (usually leaf nodes) } rootNode: UInt32; { node number of root node } leafRecords: UInt32; { number of leaf records in all leaf nodes } firstLeafNode: UInt32; { node number of first leaf node } lastLeafNode: UInt32; { node number of last leaf node } nodeSize: UInt16; { size of a node, in bytes } maxKeyLength: UInt16; { reserved } totalNodes: UInt32; { total number of nodes in tree } freeNodes: UInt32; { number of unused (free) nodes in tree } reserved1: UInt16; { unused } clumpSize: UInt32; { reserved } btreeType: SInt8; { reserved } reserved2: SInt8; { reserved } attributes: UInt32; { persistent attributes about the tree } reserved3: array [0..15] of UInt32; { reserved } end; { Constants for BTHeaderRec attributes } const kBTBadCloseMask = $00000001; { reserved } kBTBigKeysMask = $00000002; { key length field is 16 bits } kBTVariableIndexKeysMask = $00000004; { keys in index nodes are variable length } {$ALIGN MAC68K} end.