#ifndef HFSPLUS_H #define HFSPLUS_H #include #include #include #include "common.h" #define READ(a, b, c, d) ((*((a)->read))(a, b, c, d)) #define WRITE(a, b, c, d) ((*((a)->write))(a, b, c, d)) #define CLOSE(a) ((*((a)->close))(a)) #define COMPARE(a, b, c) ((*((a)->compare))(b, c)) #define READ_KEY(a, b, c) ((*((a)->keyRead))(b, c)) #define WRITE_KEY(a, b, c, d) ((*((a)->keyWrite))(b, c, d)) #define READ_DATA(a, b, c) ((*((a)->dataRead))(b, c)) struct BTKey { uint16_t keyLength; unsigned char data[0]; } __attribute__((__packed__)); typedef struct BTKey BTKey; typedef BTKey* (*dataReadFunc)(off_t offset, struct io_func_struct* io); typedef void (*keyPrintFunc)(BTKey* toPrint); typedef int (*keyWriteFunc)(off_t offset, BTKey* toWrite, struct io_func_struct* io); typedef int (*compareFunc)(BTKey* left, BTKey* right); #define STR_SIZE(str) (sizeof(uint16_t) + (sizeof(uint16_t) * (str).length)) #ifndef __HFS_FORMAT__ typedef uint32_t HFSCatalogNodeID; enum { kHFSRootParentID = 1, kHFSRootFolderID = 2, kHFSExtentsFileID = 3, kHFSCatalogFileID = 4, kHFSBadBlockFileID = 5, kHFSAllocationFileID = 6, kHFSStartupFileID = 7, kHFSAttributesFileID = 8, kHFSRepairCatalogFileID = 14, kHFSBogusExtentFileID = 15, kHFSFirstUserCatalogNodeID = 16 }; struct HFSUniStr255 { uint16_t length; uint16_t unicode[255]; } __attribute__((__packed__)); typedef struct HFSUniStr255 HFSUniStr255; typedef const HFSUniStr255 *ConstHFSUniStr255Param; struct HFSPlusExtentDescriptor { uint32_t startBlock; uint32_t blockCount; } __attribute__((__packed__)); typedef struct HFSPlusExtentDescriptor HFSPlusExtentDescriptor; typedef HFSPlusExtentDescriptor HFSPlusExtentRecord[8]; struct HFSPlusForkData { uint64_t logicalSize; uint32_t clumpSize; uint32_t totalBlocks; HFSPlusExtentRecord extents; } __attribute__((__packed__)); typedef struct HFSPlusForkData HFSPlusForkData; struct HFSPlusVolumeHeader { uint16_t signature; uint16_t version; uint32_t attributes; uint32_t lastMountedVersion; uint32_t journalInfoBlock; uint32_t createDate; uint32_t modifyDate; uint32_t backupDate; uint32_t checkedDate; uint32_t fileCount; uint32_t folderCount; uint32_t blockSize; uint32_t totalBlocks; uint32_t freeBlocks; uint32_t nextAllocation; uint32_t rsrcClumpSize; uint32_t dataClumpSize; HFSCatalogNodeID nextCatalogID; uint32_t writeCount; uint64_t encodingsBitmap; uint32_t finderInfo[8]; HFSPlusForkData allocationFile; HFSPlusForkData extentsFile; HFSPlusForkData catalogFile; HFSPlusForkData attributesFile; HFSPlusForkData startupFile; } __attribute__((__packed__)); typedef struct HFSPlusVolumeHeader HFSPlusVolumeHeader; enum { kBTLeafNode = -1, kBTIndexNode = 0, kBTHeaderNode = 1, kBTMapNode = 2 }; struct BTNodeDescriptor { uint32_t fLink; uint32_t bLink; int8_t kind; uint8_t height; uint16_t numRecords; uint16_t reserved; } __attribute__((__packed__)); typedef struct BTNodeDescriptor BTNodeDescriptor; #define kHFSCaseFolding 0xCF #define kHFSBinaryCompare 0xBC struct BTHeaderRec { uint16_t treeDepth; uint32_t rootNode; uint32_t leafRecords; uint32_t firstLeafNode; uint32_t lastLeafNode; uint16_t nodeSize; uint16_t maxKeyLength; uint32_t totalNodes; uint32_t freeNodes; uint16_t reserved1; uint32_t clumpSize; // misaligned uint8_t btreeType; uint8_t keyCompareType; uint32_t attributes; // long aligned again uint32_t reserved3[16]; } __attribute__((__packed__)); typedef struct BTHeaderRec BTHeaderRec; struct HFSPlusExtentKey { uint16_t keyLength; uint8_t forkType; uint8_t pad; HFSCatalogNodeID fileID; uint32_t startBlock; } __attribute__((__packed__)); typedef struct HFSPlusExtentKey HFSPlusExtentKey; struct HFSPlusCatalogKey { uint16_t keyLength; HFSCatalogNodeID parentID; HFSUniStr255 nodeName; } __attribute__((__packed__)); typedef struct HFSPlusCatalogKey HFSPlusCatalogKey; #ifndef __MACTYPES__ struct Point { int16_t v; int16_t h; } __attribute__((__packed__)); typedef struct Point Point; struct Rect { int16_t top; int16_t left; int16_t bottom; int16_t right; } __attribute__((__packed__)); typedef struct Rect Rect; /* OSType is a 32-bit value made by packing four 1-byte characters together. */ typedef uint32_t FourCharCode; typedef FourCharCode OSType; #endif /* Finder flags (finderFlags, fdFlags and frFlags) */ enum { kIsOnDesk = 0x0001, /* Files and folders (System 6) */ kColor = 0x000E, /* Files and folders */ kIsShared = 0x0040, /* Files only (Applications only) If */ /* clear, the application needs */ /* to write to its resource fork, */ /* and therefore cannot be shared */ /* on a server */ kHasNoINITs = 0x0080, /* Files only (Extensions/Control */ /* Panels only) */ /* This file contains no INIT resource */ kHasBeenInited = 0x0100, /* Files only. Clear if the file */ /* contains desktop database resources */ /* ('BNDL', 'FREF', 'open', 'kind'...) */ /* that have not been added yet. Set */ /* only by the Finder. */ /* Reserved for folders */ kHasCustomIcon = 0x0400, /* Files and folders */ kIsStationery = 0x0800, /* Files only */ kNameLocked = 0x1000, /* Files and folders */ kHasBundle = 0x2000, /* Files only */ kIsInvisible = 0x4000, /* Files and folders */ kIsAlias = 0x8000 /* Files only */ }; /* Extended flags (extendedFinderFlags, fdXFlags and frXFlags) */ enum { kExtendedFlagsAreInvalid = 0x8000, /* The other extended flags */ /* should be ignored */ kExtendedFlagHasCustomBadge = 0x0100, /* The file or folder has a */ /* badge resource */ kExtendedFlagHasRoutingInfo = 0x0004 /* The file contains routing */ /* info resource */ }; enum { kSymLinkFileType = 0x736C6E6B, /* 'slnk' */ kSymLinkCreator = 0x72686170 /* 'rhap' */ }; struct FileInfo { OSType fileType; /* The type of the file */ OSType fileCreator; /* The file's creator */ uint16_t finderFlags; Point location; /* File's location in the folder. */ uint16_t reservedField; } __attribute__((__packed__)); typedef struct FileInfo FileInfo; struct ExtendedFileInfo { int16_t reserved1[4]; uint16_t extendedFinderFlags; int16_t reserved2; int32_t putAwayFolderID; } __attribute__((__packed__)); typedef struct ExtendedFileInfo ExtendedFileInfo; struct FolderInfo { Rect windowBounds; /* The position and dimension of the */ /* folder's window */ uint16_t finderFlags; Point location; /* Folder's location in the parent */ /* folder. If set to {0, 0}, the Finder */ /* will place the item automatically */ uint16_t reservedField; } __attribute__((__packed__)); typedef struct FolderInfo FolderInfo; struct ExtendedFolderInfo { Point scrollPosition; /* Scroll position (for icon views) */ int32_t reserved1; uint16_t extendedFinderFlags; int16_t reserved2; int32_t putAwayFolderID; } __attribute__((__packed__)); typedef struct ExtendedFolderInfo ExtendedFolderInfo; #ifndef _STAT_H_ #ifndef _SYS_STAT_H #define S_ISUID 0004000 /* set user id on execution */ #define S_ISGID 0002000 /* set group id on execution */ #define S_ISTXT 0001000 /* sticky bit */ #define S_IRWXU 0000700 /* RWX mask for owner */ #define S_IRUSR 0000400 /* R for owner */ #define S_IWUSR 0000200 /* W for owner */ #define S_IXUSR 0000100 /* X for owner */ #define S_IRWXG 0000070 /* RWX mask for group */ #define S_IRGRP 0000040 /* R for group */ #define S_IWGRP 0000020 /* W for group */ #define S_IXGRP 0000010 /* X for group */ #define S_IRWXO 0000007 /* RWX mask for other */ #define S_IROTH 0000004 /* R for other */ #define S_IWOTH 0000002 /* W for other */ #define S_IXOTH 0000001 /* X for other */ #define S_IFMT 0170000 /* type of file mask */ #define S_IFIFO 0010000 /* named pipe (fifo) */ #define S_IFCHR 0020000 /* character special */ #define S_IFDIR 0040000 /* directory */ #define S_IFBLK 0060000 /* block special */ #define S_IFREG 0100000 /* regular */ #define S_IFLNK 0120000 /* symbolic link */ #define S_IFSOCK 0140000 /* socket */ #define S_IFWHT 0160000 /* whiteout */ #endif #endif #define UF_COMPRESSED 040 struct HFSPlusBSDInfo { uint32_t ownerID; uint32_t groupID; uint8_t adminFlags; uint8_t ownerFlags; uint16_t fileMode; union { uint32_t iNodeNum; uint32_t linkCount; uint32_t rawDevice; } special; } __attribute__((__packed__)); typedef struct HFSPlusBSDInfo HFSPlusBSDInfo; enum { kHFSPlusFolderRecord = 0x0001, kHFSPlusFileRecord = 0x0002, kHFSPlusFolderThreadRecord = 0x0003, kHFSPlusFileThreadRecord = 0x0004 }; enum { kHFSFileLockedBit = 0x0000, /* file is locked and cannot be written to */ kHFSFileLockedMask = 0x0001, kHFSThreadExistsBit = 0x0001, /* a file thread record exists for this file */ kHFSThreadExistsMask = 0x0002, kHFSHasAttributesBit = 0x0002, /* object has extended attributes */ kHFSHasAttributesMask = 0x0004, kHFSHasSecurityBit = 0x0003, /* object has security data (ACLs) */ kHFSHasSecurityMask = 0x0008, kHFSHasFolderCountBit = 0x0004, /* only for HFSX, folder maintains a separate sub-folder count */ kHFSHasFolderCountMask = 0x0010, /* (sum of folder records and directory hard links) */ kHFSHasLinkChainBit = 0x0005, /* has hardlink chain (inode or link) */ kHFSHasLinkChainMask = 0x0020, kHFSHasChildLinkBit = 0x0006, /* folder has a child that's a dir link */ kHFSHasChildLinkMask = 0x0040 }; struct HFSPlusCatalogFolder { int16_t recordType; uint16_t flags; uint32_t valence; HFSCatalogNodeID folderID; uint32_t createDate; uint32_t contentModDate; uint32_t attributeModDate; uint32_t accessDate; uint32_t backupDate; HFSPlusBSDInfo permissions; FolderInfo userInfo; ExtendedFolderInfo finderInfo; uint32_t textEncoding; uint32_t folderCount; } __attribute__((__packed__)); typedef struct HFSPlusCatalogFolder HFSPlusCatalogFolder; struct HFSPlusCatalogFile { int16_t recordType; uint16_t flags; uint32_t reserved1; HFSCatalogNodeID fileID; uint32_t createDate; uint32_t contentModDate; uint32_t attributeModDate; uint32_t accessDate; uint32_t backupDate; HFSPlusBSDInfo permissions; FileInfo userInfo; ExtendedFileInfo finderInfo; uint32_t textEncoding; uint32_t reserved2; HFSPlusForkData dataFork; HFSPlusForkData resourceFork; } __attribute__((__packed__)); typedef struct HFSPlusCatalogFile HFSPlusCatalogFile; struct HFSPlusCatalogThread { int16_t recordType; int16_t reserved; HFSCatalogNodeID parentID; HFSUniStr255 nodeName; } __attribute__((__packed__)); typedef struct HFSPlusCatalogThread HFSPlusCatalogThread; enum { kHFSPlusAttrInlineData = 0x10, kHFSPlusAttrForkData = 0x20, kHFSPlusAttrExtents = 0x30 }; struct HFSPlusAttrForkData { uint32_t recordType; uint32_t reserved; HFSPlusForkData theFork; } __attribute__((__packed__)); typedef struct HFSPlusAttrForkData HFSPlusAttrForkData; struct HFSPlusAttrExtents { uint32_t recordType; uint32_t reserved; HFSPlusExtentRecord extents; }; typedef struct HFSPlusAttrExtents HFSPlusAttrExtents; struct HFSPlusAttrData { uint32_t recordType; uint32_t reserved[2]; uint32_t size; uint8_t data[0]; } __attribute__((__packed__)); typedef struct HFSPlusAttrData HFSPlusAttrData; union HFSPlusAttrRecord { uint32_t recordType; HFSPlusAttrData attrData; HFSPlusAttrForkData forkData; HFSPlusAttrExtents overflowExtents; }; typedef union HFSPlusAttrRecord HFSPlusAttrRecord; struct HFSPlusAttrKey { uint16_t keyLength; uint16_t pad; uint32_t fileID; uint32_t startBlock; HFSUniStr255 name; } __attribute__((__packed__)); typedef struct HFSPlusAttrKey HFSPlusAttrKey; enum { kHardLinkFileType = 0x686C6E6B, /* 'hlnk' */ kHFSPlusCreator = 0x6866732B /* 'hfs+' */ }; #endif struct HFSPlusCatalogRecord { int16_t recordType; unsigned char data[0]; } __attribute__((__packed__)); typedef struct HFSPlusCatalogRecord HFSPlusCatalogRecord; struct CatalogRecordList { HFSUniStr255 name; HFSPlusCatalogRecord* record; struct CatalogRecordList* next; }; typedef struct CatalogRecordList CatalogRecordList; struct XAttrList { char* name; struct XAttrList* next; }; typedef struct XAttrList XAttrList; struct Extent { uint32_t startBlock; uint32_t blockCount; struct Extent* next; }; typedef struct Extent Extent; typedef struct { io_func* io; BTHeaderRec *headerRec; compareFunc compare; dataReadFunc keyRead; keyWriteFunc keyWrite; keyPrintFunc keyPrint; dataReadFunc dataRead; } BTree; typedef struct { io_func* image; HFSPlusVolumeHeader* volumeHeader; BTree* extentsTree; BTree* catalogTree; BTree* attrTree; io_func* allocationFile; HFSCatalogNodeID metadataDir; } Volume; typedef struct { HFSCatalogNodeID id; HFSPlusCatalogRecord* catalogRecord; Volume* volume; HFSPlusForkData* forkData; Extent* extents; } RawFile; #ifdef __cplusplus extern "C" { #endif void hfs_panic(const char* panicString); void printUnicode(HFSUniStr255* str); char* unicodeToAscii(HFSUniStr255* str); BTNodeDescriptor* readBTNodeDescriptor(uint32_t num, BTree* tree); BTHeaderRec* readBTHeaderRec(io_func* io); BTree* openBTree(io_func* io, compareFunc compare, dataReadFunc keyRead, keyWriteFunc keyWrite, keyPrintFunc keyPrint, dataReadFunc dataRead); void closeBTree(BTree* tree); off_t getRecordOffset(int num, uint32_t nodeNum, BTree* tree); off_t getNodeNumberFromPointerRecord(off_t offset, io_func* io); void* search(BTree* tree, BTKey* searchKey, int *exact, uint32_t *nodeNumber, int *recordNumber); io_func* openFlatFile(const char* fileName); io_func* openFlatFileRO(const char* fileName); io_func* openRawFile(HFSCatalogNodeID id, HFSPlusForkData* forkData, HFSPlusCatalogRecord* catalogRecord, Volume* volume); BTree* openAttributesTree(io_func* file); size_t getAttribute(Volume* volume, uint32_t fileID, const char* name, uint8_t** data); int setAttribute(Volume* volume, uint32_t fileID, const char* name, uint8_t* data, size_t size); int unsetAttribute(Volume* volume, uint32_t fileID, const char* name); XAttrList* getAllExtendedAttributes(HFSCatalogNodeID CNID, Volume* volume); void flipExtentRecord(HFSPlusExtentRecord* extentRecord); BTree* openExtentsTree(io_func* file); void ASCIIToUnicode(const char* ascii, HFSUniStr255* unistr); void flipCatalogFolder(HFSPlusCatalogFolder* record); void flipCatalogFile(HFSPlusCatalogFile* record); void flipCatalogThread(HFSPlusCatalogThread* record, int out); BTree* openCatalogTree(io_func* file); int updateCatalog(Volume* volume, HFSPlusCatalogRecord* catalogRecord); int move(const char* source, const char* dest, Volume* volume); int removeFile(const char* fileName, Volume* volume); HFSCatalogNodeID newFolder(const char* pathName, Volume* volume); HFSCatalogNodeID newFile(const char* pathName, Volume* volume); int chmodFile(const char* pathName, int mode, Volume* volume); int chownFile(const char* pathName, uint32_t owner, uint32_t group, Volume* volume); int makeSymlink(const char* pathName, const char* target, Volume* volume); HFSCatalogNodeID getMetadataDirectoryID(Volume* volume); HFSPlusCatalogRecord* getRecordByCNID(HFSCatalogNodeID CNID, Volume* volume); HFSPlusCatalogRecord* getLinkTarget(HFSPlusCatalogRecord* record, HFSCatalogNodeID parentID, HFSPlusCatalogKey *key, Volume* volume); CatalogRecordList* getFolderContents(HFSCatalogNodeID CNID, Volume* volume); HFSPlusCatalogRecord* getRecordFromPath(const char* path, Volume* volume, char **name, HFSPlusCatalogKey* retKey); HFSPlusCatalogRecord* getRecordFromPath2(const char* path, Volume* volume, char **name, HFSPlusCatalogKey* retKey, char traverse); HFSPlusCatalogRecord* getRecordFromPath3(const char* path, Volume* volume, char **name, HFSPlusCatalogKey* retKey, char traverse, char returnLink, HFSCatalogNodeID parentID); void releaseCatalogRecordList(CatalogRecordList* list); int isBlockUsed(Volume* volume, uint32_t block); int setBlockUsed(Volume* volume, uint32_t block, int used); int allocate(RawFile* rawFile, off_t size); void flipForkData(HFSPlusForkData* forkData); Volume* openVolume(io_func* io); void closeVolume(Volume *volume); int updateVolume(Volume* volume); int debugBTree(BTree* tree, int displayTree); int addToBTree(BTree* tree, BTKey* searchKey, size_t length, unsigned char* content); int removeFromBTree(BTree* tree, BTKey* searchKey); int32_t FastUnicodeCompare ( register uint16_t str1[], register uint16_t length1, register uint16_t str2[], register uint16_t length2); #ifdef __cplusplus } #endif #endif