Find file
Fetching contributors…
Cannot retrieve contributors at this time
598 lines (496 sloc) 17.2 KB
#ifndef HFSPLUS_H
#define HFSPLUS_H
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#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;
/* 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 */
#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+' */
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" {
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