master
  1/*
  2 * Copyright (c) 2000-2023 Apple Inc. All rights reserved.
  3 *
  4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  5 * 
  6 * This file contains Original Code and/or Modifications of Original Code
  7 * as defined in and that are subject to the Apple Public Source License
  8 * Version 2.0 (the 'License'). You may not use this file except in
  9 * compliance with the License. The rights granted to you under the License
 10 * may not be used to create, or enable the creation or redistribution of,
 11 * unlawful or unlicensed copies of an Apple operating system, or to
 12 * circumvent, violate, or enable the circumvention or violation of, any
 13 * terms of an Apple operating system software license agreement.
 14 * 
 15 * Please obtain a copy of the License at
 16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
 17 * 
 18 * The Original Code and all software distributed under the License are
 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 23 * Please see the License for the specific language governing rights and
 24 * limitations under the License.
 25 * 
 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
 27 */
 28#ifndef __HFS_FORMAT__
 29#define __HFS_FORMAT__
 30
 31#include <sys/types.h>
 32#include <sys/appleapiopts.h>
 33#include "hfs_unistr.h"
 34
 35/*
 36 * hfs_format.h
 37 *
 38 * This file describes the on-disk format for HFS and HFS Plus volumes.
 39 *
 40 * Note: Starting with MacOS 10.9, definition of struct HFSUniStr255 exists in hfs_unistr.h
 41 *
 42 */
 43
 44#ifdef __cplusplus
 45extern "C" {
 46#endif
 47
 48/* some on-disk hfs structures have 68K alignment (misaligned) */
 49
 50/* Signatures used to differentiate between HFS and HFS Plus volumes */
 51enum {
 52	kHFSSigWord		= 0x4244,	/* 'BD' in ASCII */
 53	kHFSPlusSigWord		= 0x482B,	/* 'H+' in ASCII */
 54	kHFSXSigWord		= 0x4858,	/* 'HX' in ASCII */
 55
 56	kHFSPlusVersion		= 0x0004,	/* 'H+' volumes are version 4 only */
 57	kHFSXVersion		= 0x0005,	/* 'HX' volumes start with version 5 */
 58
 59	kHFSPlusMountVersion	= 0x31302E30,	/* '10.0' for Mac OS X */
 60	kHFSJMountVersion	= 0x4846534a,	/* 'HFSJ' for journaled HFS+ on OS X */
 61	kFSKMountVersion	= 0x46534b21	/* 'FSK!' for failed journal replay */
 62};
 63
 64
 65#ifdef __APPLE_API_PRIVATE
 66/*
 67 * Mac OS X has two special directories on HFS+ volumes for hardlinked files
 68 * and hardlinked directories as well as for open-unlinked files.
 69 *
 70 * These directories and their contents are not exported from the filesystem
 71 * under Mac OS X.
 72 */
 73#define HFSPLUSMETADATAFOLDER       "\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80HFS+ Private Data"
 74#define HFSPLUS_DIR_METADATA_FOLDER ".HFS+ Private Directory Data\xd"
 75
 76/*
 77 * Files in the "HFS+ Private Data" folder have one of the following prefixes
 78 * followed by a decimal number (no leading zeros) for the file ID.
 79 *
 80 * Note: Earlier version of Mac OS X used a 32 bit random number for the link
 81 * ref number instead of the file id.
 82 *
 83 * e.g.  iNode7182000 and temp3296
 84 */
 85#define HFS_INODE_PREFIX	"iNode"
 86#define HFS_DELETE_PREFIX	"temp"
 87
 88/*
 89 * Files in the ".HFS+ Private Directory Data" folder have the following 
 90 * prefix followed by a decimal number (no leading zeros) for the file ID.
 91 *
 92 * e.g. dir_555
 93 */
 94#define HFS_DIRINODE_PREFIX	"dir_"
 95
 96/*
 97 * Hardlink inodes save the head of the link chain in
 98 * an extended attribute named FIRST_LINK_XATTR_NAME.
 99 * The attribute data is the decimal value in ASCII
100 * of the cnid for the first link in the chain.
101 *
102 * This extended attribute is private (i.e. its not
103 * exported in the getxattr/listxattr POSIX APIs).
104 */
105#define FIRST_LINK_XATTR_NAME	"com.apple.system.hfs.firstlink"
106#define FIRST_LINK_XATTR_REC_SIZE (sizeof(HFSPlusAttrData) - 2 + 12)
107
108/*
109 * The name space ID for generating an HFS volume UUID
110 *
111 * B3E20F39-F292-11D6-97A4-00306543ECAC
112 */
113#define HFS_UUID_NAMESPACE_ID  "\xB3\xE2\x0F\x39\xF2\x92\x11\xD6\x97\xA4\x00\x30\x65\x43\xEC\xAC"
114
115#endif /* __APPLE_API_PRIVATE */
116
117/*
118 * Indirect link files (hard links) have the following type/creator.
119 */
120enum {
121	kHardLinkFileType = 0x686C6E6B,  /* 'hlnk' */
122	kHFSPlusCreator   = 0x6866732B   /* 'hfs+' */
123};
124
125
126/*
127 *	File type and creator for symbolic links
128 */
129enum {
130      kSymLinkFileType  = 0x736C6E6B, /* 'slnk' */
131      kSymLinkCreator   = 0x72686170  /* 'rhap' */
132};
133
134
135enum {
136	kHFSMaxVolumeNameChars		= 27,
137	kHFSMaxFileNameChars		= 31,
138	kHFSPlusMaxFileNameChars	= 255
139};
140
141
142/* Extent overflow file data structures */
143
144/* HFS Extent key */
145struct HFSExtentKey {
146	u_int8_t 	keyLength;	/* length of key, excluding this field */
147	u_int8_t 	forkType;	/* 0 = data fork, FF = resource fork */
148	u_int32_t 	fileID;		/* file ID */
149	u_int16_t 	startBlock;	/* first file allocation block number in this extent */
150} __attribute__((aligned(2), packed));
151typedef struct HFSExtentKey HFSExtentKey;
152
153/* HFS Plus Extent key */
154struct HFSPlusExtentKey {
155	u_int16_t 	keyLength;		/* length of key, excluding this field */
156	u_int8_t 	forkType;		/* 0 = data fork, FF = resource fork */
157	u_int8_t 	pad;			/* make the other fields align on 32-bit boundary */
158	u_int32_t 	fileID;			/* file ID */
159	u_int32_t 	startBlock;		/* first file allocation block number in this extent */
160} __attribute__((aligned(2), packed));
161typedef struct HFSPlusExtentKey HFSPlusExtentKey;
162
163/* Number of extent descriptors per extent record */
164enum {
165	kHFSExtentDensity	= 3,
166	kHFSPlusExtentDensity	= 8
167};
168
169/* HFS extent descriptor */
170struct HFSExtentDescriptor {
171	u_int16_t 	startBlock;		/* first allocation block */
172	u_int16_t 	blockCount;		/* number of allocation blocks */
173} __attribute__((aligned(2), packed));
174typedef struct HFSExtentDescriptor HFSExtentDescriptor;
175
176/* HFS Plus extent descriptor */
177struct HFSPlusExtentDescriptor {
178	u_int32_t 	startBlock;		/* first allocation block */
179	u_int32_t 	blockCount;		/* number of allocation blocks */
180} __attribute__((aligned(2), packed));
181typedef struct HFSPlusExtentDescriptor HFSPlusExtentDescriptor;
182
183/* HFS extent record */
184typedef HFSExtentDescriptor HFSExtentRecord[3];
185
186/* HFS Plus extent record */
187typedef HFSPlusExtentDescriptor HFSPlusExtentRecord[8];
188
189
190/* Finder information */
191struct FndrFileInfo {
192	u_int32_t 	fdType;		/* file type */
193	u_int32_t 	fdCreator;	/* file creator */
194	u_int16_t 	fdFlags;	/* Finder flags */
195	struct {
196	    int16_t	v;		/* file's location */
197	    int16_t	h;
198	} fdLocation;
199	int16_t 	opaque;
200} __attribute__((aligned(2), packed));
201typedef struct FndrFileInfo FndrFileInfo;
202
203struct FndrDirInfo {
204	struct {			/* folder's window rectangle */
205	    int16_t	top;
206	    int16_t	left;
207	    int16_t	bottom;
208	    int16_t	right;
209	} frRect;
210	unsigned short 	frFlags;	/* Finder flags */
211	struct {
212	    u_int16_t	v;		/* folder's location */
213	    u_int16_t	h;
214	} frLocation;
215	int16_t 	opaque;
216} __attribute__((aligned(2), packed));
217typedef struct FndrDirInfo FndrDirInfo;
218
219struct FndrOpaqueInfo {
220	int8_t opaque[16];
221} __attribute__((aligned(2), packed));
222typedef struct FndrOpaqueInfo FndrOpaqueInfo;
223
224struct FndrExtendedDirInfo {
225	u_int32_t document_id;
226	u_int32_t date_added;
227	u_int16_t extended_flags;
228	u_int16_t reserved3;
229	u_int32_t write_gen_counter;
230} __attribute__((aligned(2), packed));
231
232struct FndrExtendedFileInfo {
233	u_int32_t document_id;
234	u_int32_t date_added;
235	u_int16_t extended_flags;
236	u_int16_t reserved2;
237	u_int32_t write_gen_counter;
238} __attribute__((aligned(2), packed));
239
240/* HFS Plus Fork data info - 80 bytes */
241struct HFSPlusForkData {
242	u_int64_t 		logicalSize;	/* fork's logical size in bytes */
243	u_int32_t 		clumpSize;	/* fork's clump size in bytes */
244	u_int32_t 		totalBlocks;	/* total blocks used by this fork */
245	HFSPlusExtentRecord 	extents;	/* initial set of extents */
246} __attribute__((aligned(2), packed));
247typedef struct HFSPlusForkData HFSPlusForkData;
248
249
250/* Mac OS X has 16 bytes worth of "BSD" info.
251 *
252 * Note:  Mac OS 9 implementations and applications
253 * should preserve, but not change, this information.
254 */
255struct HFSPlusBSDInfo {
256	u_int32_t 	ownerID;	/* user-id of owner or hard link chain previous link */
257	u_int32_t 	groupID;	/* group-id of owner or hard link chain next link */
258	u_int8_t 	adminFlags;	/* super-user changeable flags */
259	u_int8_t 	ownerFlags;	/* owner changeable flags */
260	u_int16_t 	fileMode;	/* file type and permission bits */
261	union {
262	    u_int32_t	iNodeNum;	/* indirect node number (hard links only) */
263	    u_int32_t	linkCount;	/* links that refer to this indirect node */
264	    u_int32_t	rawDevice;	/* special file device (FBLK and FCHR only) */
265	} special;
266} __attribute__((aligned(2), packed));
267typedef struct HFSPlusBSDInfo HFSPlusBSDInfo;
268
269/*
270 * Hardlink "links" resolve to an inode
271 * and the actual uid/gid comes from that
272 * inode.
273 *
274 * We repurpose the links's uid/gid fields
275 * for the hardlink link chain. The chain
276 * consists of a doubly linked list of file
277 * ids.
278 */
279 
280#define hl_firstLinkID     reserved1         /* Valid only if HasLinkChain flag is set (indirect nodes only) */
281
282#define hl_prevLinkID      bsdInfo.ownerID   /* Valid only if HasLinkChain flag is set */
283#define hl_nextLinkID      bsdInfo.groupID   /* Valid only if HasLinkChain flag is set */
284
285#define hl_linkReference   bsdInfo.special.iNodeNum
286#define hl_linkCount       bsdInfo.special.linkCount
287
288
289/* Catalog file data structures */
290
291enum {
292	kHFSRootParentID		= 1,	/* Parent ID of the root folder */
293	kHFSRootFolderID		= 2,	/* Folder ID of the root folder */
294	kHFSExtentsFileID		= 3,	/* File ID of the extents file */
295	kHFSCatalogFileID		= 4,	/* File ID of the catalog file */
296	kHFSBadBlockFileID		= 5,	/* File ID of the bad allocation block file */
297	kHFSAllocationFileID		= 6,	/* File ID of the allocation file (HFS Plus only) */
298	kHFSStartupFileID		= 7,	/* File ID of the startup file (HFS Plus only) */
299	kHFSAttributesFileID		= 8,	/* File ID of the attribute file (HFS Plus only) */
300	kHFSAttributeDataFileID         = 13,	/* Used in Mac OS X runtime for extent based attributes */
301	                                        /* kHFSAttributeDataFileID is never stored on disk. */
302	kHFSRepairCatalogFileID		= 14,	/* Used when rebuilding Catalog B-tree */
303	kHFSBogusExtentFileID		= 15,	/* Used for exchanging extents in extents file */
304	kHFSFirstUserCatalogNodeID	= 16
305};
306
307/* HFS catalog key */
308struct HFSCatalogKey {
309	u_int8_t 	keyLength;		/* key length (in bytes) */
310	u_int8_t 	reserved;		/* reserved (set to zero) */
311	u_int32_t 	parentID;		/* parent folder ID */
312	u_int8_t 	nodeName[kHFSMaxFileNameChars + 1]; /* catalog node name */
313} __attribute__((aligned(2), packed));
314typedef struct HFSCatalogKey HFSCatalogKey;
315
316/* HFS Plus catalog key */
317struct HFSPlusCatalogKey {
318	u_int16_t 		keyLength;	/* key length (in bytes) */
319	u_int32_t 		parentID;	/* parent folder ID */
320	HFSUniStr255 		nodeName;	/* catalog node name */
321} __attribute__((aligned(2), packed));
322typedef struct HFSPlusCatalogKey HFSPlusCatalogKey;
323
324/* Catalog record types */
325enum {
326	/* HFS Catalog Records */
327	kHFSFolderRecord		= 0x0100,	/* Folder record */
328	kHFSFileRecord			= 0x0200,	/* File record */
329	kHFSFolderThreadRecord		= 0x0300,	/* Folder thread record */
330	kHFSFileThreadRecord		= 0x0400,	/* File thread record */
331
332	/* HFS Plus Catalog Records */
333	kHFSPlusFolderRecord		= 1,		/* Folder record */
334	kHFSPlusFileRecord		= 2,		/* File record */
335	kHFSPlusFolderThreadRecord	= 3,		/* Folder thread record */
336	kHFSPlusFileThreadRecord	= 4		/* File thread record */
337};
338
339
340/* Catalog file record flags */
341enum {
342	kHFSFileLockedBit	= 0x0000,	/* file is locked and cannot be written to */
343	kHFSFileLockedMask	= 0x0001,
344
345	kHFSThreadExistsBit	= 0x0001,	/* a file thread record exists for this file */
346	kHFSThreadExistsMask	= 0x0002,
347
348	kHFSHasAttributesBit	= 0x0002,	/* object has extended attributes */
349	kHFSHasAttributesMask	= 0x0004,
350
351	kHFSHasSecurityBit	= 0x0003,	/* object has security data (ACLs) */
352	kHFSHasSecurityMask	= 0x0008,
353
354	kHFSHasFolderCountBit	= 0x0004,	/* only for HFSX, folder maintains a separate sub-folder count */
355	kHFSHasFolderCountMask	= 0x0010,	/* (sum of folder records and directory hard links) */
356
357	kHFSHasLinkChainBit	= 0x0005,	/* has hardlink chain (inode or link) */
358	kHFSHasLinkChainMask	= 0x0020,
359
360	kHFSHasChildLinkBit	= 0x0006,	/* folder has a child that's a dir link */
361	kHFSHasChildLinkMask	= 0x0040,
362
363	kHFSHasDateAddedBit     = 0x0007,	/* File/Folder has the date-added stored in the finder info. */
364	kHFSHasDateAddedMask    = 0x0080, 
365
366	kHFSFastDevPinnedBit    = 0x0008,       /* this file has been pinned to the fast-device by the hot-file code on cooperative fusion */
367	kHFSFastDevPinnedMask   = 0x0100,
368
369	kHFSDoNotFastDevPinBit  = 0x0009,       /* this file can not be pinned to the fast-device */
370	kHFSDoNotFastDevPinMask = 0x0200,
371
372	kHFSFastDevCandidateBit  = 0x000a,      /* this item is a potential candidate for fast-dev pinning (as are any of its descendents */
373	kHFSFastDevCandidateMask = 0x0400,
374
375	kHFSAutoCandidateBit     = 0x000b,      /* this item was automatically marked as a fast-dev candidate by the kernel */
376	kHFSAutoCandidateMask    = 0x0800,
377
378	kHFSCatExpandedTimesBit  = 0x000c,		/* this item has expanded timestamps */
379	kHFSCatExpandedTimesMask = 0x1000
380
381	// There are only 3 flag bits remaining: 0x2000, 0x4000, 0x8000
382};
383
384
385/* HFS catalog folder record - 70 bytes */
386struct HFSCatalogFolder {
387	int16_t 		recordType;		/* == kHFSFolderRecord */
388	u_int16_t 		flags;			/* folder flags */
389	u_int16_t 		valence;		/* folder valence */
390	u_int32_t		folderID;		/* folder ID */
391	u_int32_t 		createDate;		/* date and time of creation */
392	u_int32_t 		modifyDate;		/* date and time of last modification */
393	u_int32_t 		backupDate;		/* date and time of last backup */
394	FndrDirInfo 		userInfo;		/* Finder information */
395	FndrOpaqueInfo		finderInfo;		/* additional Finder information */
396	u_int32_t 		reserved[4];		/* reserved - initialized as zero */
397} __attribute__((aligned(2), packed));
398typedef struct HFSCatalogFolder HFSCatalogFolder;
399
400/* HFS Plus catalog folder record - 88 bytes */
401struct HFSPlusCatalogFolder {
402	int16_t 		recordType;		/* == kHFSPlusFolderRecord */
403	u_int16_t 		flags;			/* file flags */
404	u_int32_t 		valence;		/* folder's item count */
405	u_int32_t 		folderID;		/* folder ID */
406	u_int32_t 		createDate;		/* date and time of creation */
407	u_int32_t 		contentModDate;		/* date and time of last content modification */
408	u_int32_t 		attributeModDate;	/* date and time of last attribute modification */
409	u_int32_t 		accessDate;		/* date and time of last access (MacOS X only) */
410	u_int32_t 		backupDate;		/* date and time of last backup */
411	HFSPlusBSDInfo		bsdInfo;		/* permissions (for MacOS X) */
412	FndrDirInfo 		userInfo;		/* Finder information */
413	FndrOpaqueInfo	 	finderInfo;		/* additional Finder information */
414	u_int32_t 		textEncoding;		/* hint for name conversions */
415	u_int32_t 		folderCount;		/* number of enclosed folders, active when HasFolderCount is set */
416} __attribute__((aligned(2), packed));
417typedef struct HFSPlusCatalogFolder HFSPlusCatalogFolder;
418
419/* HFS catalog file record - 102 bytes */
420struct HFSCatalogFile {
421	int16_t 		recordType;		/* == kHFSFileRecord */
422	u_int8_t 		flags;			/* file flags */
423	int8_t 			fileType;		/* file type (unused ?) */
424	FndrFileInfo 		userInfo;		/* Finder information */
425	u_int32_t 		fileID;			/* file ID */
426	u_int16_t 		dataStartBlock;		/* not used - set to zero */
427	int32_t 		dataLogicalSize;	/* logical EOF of data fork */
428	int32_t 		dataPhysicalSize;	/* physical EOF of data fork */
429	u_int16_t		rsrcStartBlock;		/* not used - set to zero */
430	int32_t			rsrcLogicalSize;	/* logical EOF of resource fork */
431	int32_t			rsrcPhysicalSize;	/* physical EOF of resource fork */
432	u_int32_t		createDate;		/* date and time of creation */
433	u_int32_t		modifyDate;		/* date and time of last modification */
434	u_int32_t		backupDate;		/* date and time of last backup */
435	FndrOpaqueInfo		finderInfo;		/* additional Finder information */
436	u_int16_t		clumpSize;		/* file clump size (not used) */
437	HFSExtentRecord		dataExtents;		/* first data fork extent record */
438	HFSExtentRecord		rsrcExtents;		/* first resource fork extent record */
439	u_int32_t		reserved;		/* reserved - initialized as zero */
440} __attribute__((aligned(2), packed));
441typedef struct HFSCatalogFile HFSCatalogFile;
442
443/* HFS Plus catalog file record - 248 bytes */
444struct HFSPlusCatalogFile {
445	int16_t 		recordType;		/* == kHFSPlusFileRecord */
446	u_int16_t 		flags;			/* file flags */
447	u_int32_t 		reserved1;		/* reserved - initialized as zero */
448	u_int32_t 		fileID;			/* file ID */
449	u_int32_t 		createDate;		/* date and time of creation */
450	u_int32_t 		contentModDate;		/* date and time of last content modification */
451	u_int32_t 		attributeModDate;	/* date and time of last attribute modification */
452	u_int32_t 		accessDate;		/* date and time of last access (MacOS X only) */
453	u_int32_t 		backupDate;		/* date and time of last backup */
454	HFSPlusBSDInfo 		bsdInfo;		/* permissions (for MacOS X) */
455	FndrFileInfo 		userInfo;		/* Finder information */
456	FndrOpaqueInfo	 	finderInfo;		/* additional Finder information */
457	u_int32_t 		textEncoding;		/* hint for name conversions */
458	u_int32_t 		reserved2;		/* reserved - initialized as zero */
459
460	/* Note: these start on double long (64 bit) boundary */
461	HFSPlusForkData 	dataFork;		/* size and block data for data fork */
462	HFSPlusForkData 	resourceFork;		/* size and block data for resource fork */
463} __attribute__((aligned(2), packed));
464typedef struct HFSPlusCatalogFile HFSPlusCatalogFile;
465
466/* HFS catalog thread record - 46 bytes */
467struct HFSCatalogThread {
468	int16_t 	recordType;		/* == kHFSFolderThreadRecord or kHFSFileThreadRecord */
469	int32_t 	reserved[2];		/* reserved - initialized as zero */
470	u_int32_t 	parentID;		/* parent ID for this catalog node */
471	u_int8_t 	nodeName[kHFSMaxFileNameChars + 1]; /* name of this catalog node */
472} __attribute__((aligned(2), packed));
473typedef struct HFSCatalogThread HFSCatalogThread;
474
475/* HFS Plus catalog thread record -- 264 bytes */
476struct HFSPlusCatalogThread {
477	int16_t 	recordType;		/* == kHFSPlusFolderThreadRecord or kHFSPlusFileThreadRecord */
478	int16_t 	reserved;		/* reserved - initialized as zero */
479	u_int32_t 	parentID;		/* parent ID for this catalog node */
480	HFSUniStr255 	nodeName;		/* name of this catalog node (variable length) */
481} __attribute__((aligned(2), packed));
482typedef struct HFSPlusCatalogThread HFSPlusCatalogThread;
483
484#ifdef __APPLE_API_UNSTABLE
485/*
486 * 	These are the types of records in the attribute B-tree.  The values were
487 * 	chosen so that they wouldn't conflict with the catalog record types.
488 */
489enum {
490	kHFSPlusAttrInlineData	= 0x10,   /* attributes whose data fits in a b-tree node */
491	kHFSPlusAttrForkData	= 0x20,   /* extent based attributes (data lives in extents) */
492	kHFSPlusAttrExtents	= 0x30    /* overflow extents for large attributes */
493};
494
495
496/*
497 *  	HFSPlusAttrForkData
498 * 	For larger attributes, whose value is stored in allocation blocks.
499 * 	If the attribute has more than 8 extents, there will be additional
500 * 	records (of type HFSPlusAttrExtents) for this attribute.
501 */
502struct HFSPlusAttrForkData {
503	u_int32_t 	recordType;		/* == kHFSPlusAttrForkData*/
504	u_int32_t 	reserved;
505	HFSPlusForkData theFork;		/* size and first extents of value*/
506} __attribute__((aligned(2), packed));
507typedef struct HFSPlusAttrForkData HFSPlusAttrForkData;
508
509/*
510 * 	HFSPlusAttrExtents
511 * 	This record contains information about overflow extents for large,
512 * 	fragmented attributes.
513 */
514struct HFSPlusAttrExtents {
515	u_int32_t 		recordType;	/* == kHFSPlusAttrExtents*/
516	u_int32_t 		reserved;
517	HFSPlusExtentRecord	extents;	/* additional extents*/
518} __attribute__((aligned(2), packed));
519typedef struct HFSPlusAttrExtents HFSPlusAttrExtents;
520
521/*
522 * Atrributes B-tree Data Record
523 *
524 * For small attributes, whose entire value is stored
525 * within a single B-tree record.
526 */
527struct HFSPlusAttrData {
528	u_int32_t    recordType;   /* == kHFSPlusAttrInlineData */
529	u_int32_t    reserved[2];
530	u_int32_t    attrSize;     /* size of attribute data in bytes */
531	u_int8_t     attrData[2];  /* variable length */
532} __attribute__((aligned(2), packed));
533typedef struct HFSPlusAttrData HFSPlusAttrData;
534
535
536/* HFSPlusAttrInlineData is obsolete use HFSPlusAttrData instead */
537struct HFSPlusAttrInlineData {
538	u_int32_t 	recordType;
539	u_int32_t 	reserved;
540	u_int32_t 	logicalSize;
541	u_int8_t 	userData[2];
542} __attribute__((aligned(2), packed));
543typedef struct HFSPlusAttrInlineData HFSPlusAttrInlineData;
544
545
546/* A generic Attribute Record */
547union HFSPlusAttrRecord {
548	u_int32_t 		recordType;
549	HFSPlusAttrInlineData 	inlineData;   /* NOT USED */
550	HFSPlusAttrData 	attrData;
551	HFSPlusAttrForkData 	forkData;
552	HFSPlusAttrExtents 	overflowExtents;
553};
554typedef union HFSPlusAttrRecord HFSPlusAttrRecord;
555
556/* Attribute key */
557enum { kHFSMaxAttrNameLen = 127 };
558struct HFSPlusAttrKey {
559	u_int16_t     keyLength;       /* key length (in bytes) */
560	u_int16_t     pad;	       /* set to zero */
561	u_int32_t     fileID;          /* file associated with attribute */
562	u_int32_t     startBlock;      /* first allocation block number for extents */
563	u_int16_t     attrNameLen;     /* number of unicode characters */
564	u_int16_t     attrName[kHFSMaxAttrNameLen];   /* attribute name (Unicode) */
565} __attribute__((aligned(2), packed));
566typedef struct HFSPlusAttrKey HFSPlusAttrKey;
567
568#define kHFSPlusAttrKeyMaximumLength   (sizeof(HFSPlusAttrKey) - sizeof(u_int16_t))
569#define kHFSPlusAttrKeyMinimumLength   (kHFSPlusAttrKeyMaximumLength - kHFSMaxAttrNameLen*sizeof(u_int16_t))
570
571#endif /* __APPLE_API_UNSTABLE */
572
573
574/* Key and node lengths */
575enum {
576	kHFSPlusExtentKeyMaximumLength = sizeof(HFSPlusExtentKey) - sizeof(u_int16_t),
577	kHFSExtentKeyMaximumLength	= sizeof(HFSExtentKey) - sizeof(u_int8_t),
578	kHFSPlusCatalogKeyMaximumLength = sizeof(HFSPlusCatalogKey) - sizeof(u_int16_t),
579	kHFSPlusCatalogKeyMinimumLength = kHFSPlusCatalogKeyMaximumLength - sizeof(HFSUniStr255) + sizeof(u_int16_t),
580	kHFSCatalogKeyMaximumLength	= sizeof(HFSCatalogKey) - sizeof(u_int8_t),
581	kHFSCatalogKeyMinimumLength	= kHFSCatalogKeyMaximumLength - (kHFSMaxFileNameChars + 1) + sizeof(u_int8_t),
582	kHFSPlusCatalogMinNodeSize	= 4096,
583	kHFSPlusExtentMinNodeSize	= 512,
584	kHFSPlusAttrMinNodeSize		= 4096
585};
586
587/* HFS and HFS Plus volume attribute bits */
588enum {
589	/* Bits 0-6 are reserved (always cleared by MountVol call) */
590	kHFSVolumeHardwareLockBit	= 7,		/* volume is locked by hardware */
591	kHFSVolumeUnmountedBit		= 8,		/* volume was successfully unmounted */
592	kHFSVolumeSparedBlocksBit	= 9,		/* volume has bad blocks spared */
593	kHFSVolumeNoCacheRequiredBit = 10,		/* don't cache volume blocks (i.e. RAM or ROM disk) */
594	kHFSBootVolumeInconsistentBit = 11,		/* boot volume is inconsistent (System 7.6 and later) */
595	kHFSCatalogNodeIDsReusedBit = 12,
596	kHFSVolumeJournaledBit = 13,			/* this volume has a journal on it */
597	kHFSVolumeInconsistentBit = 14,			/* serious inconsistencies detected at runtime */
598	kHFSVolumeSoftwareLockBit	= 15,		/* volume is locked by software */
599	/*
600	 * HFS only has 16 bits of attributes in the MDB, but HFS Plus has 32 bits.
601	 * Therefore, bits 16-31 can only be used on HFS Plus.
602	 */
603	kHFSUnusedNodeFixBit = 31,				/* Unused nodes in the Catalog B-tree have been zero-filled.  See Radar #6947811. */
604	kHFSContentProtectionBit = 30,			/* Volume has per-file content protection */
605	kHFSExpandedTimesBit = 29,				/* Volume has expanded / non-MacOS native timestamps */
606
607	/***  Keep these in sync with the bits above ! ****/
608	kHFSVolumeHardwareLockMask		= 0x00000080,
609	kHFSVolumeUnmountedMask			= 0x00000100,
610	kHFSVolumeSparedBlocksMask		= 0x00000200,
611	kHFSVolumeNoCacheRequiredMask 	= 0x00000400,
612	kHFSBootVolumeInconsistentMask	= 0x00000800,
613	kHFSCatalogNodeIDsReusedMask 	= 0x00001000,
614	kHFSVolumeJournaledMask			= 0x00002000,
615	kHFSVolumeInconsistentMask 		= 0x00004000,
616	kHFSVolumeSoftwareLockMask		= 0x00008000,
617	
618	/* Bits 16-31 are allocated from high to low */
619
620	kHFSExpandedTimesMask			= 0x20000000,
621	kHFSContentProtectionMask 		= 0x40000000,
622	kHFSUnusedNodeFixMask 			= 0x80000000,
623	
624	kHFSMDBAttributesMask			= 0x8380
625};
626
627enum {
628	kHFSUnusedNodesFixDate 			= 0xc5ef2480,   /* March 25, 2009 (aka 3320784000) */
629	kHFSUnusedNodesFixExpandedDate 	= 0x49c97400    /* March 25, 2009 (akai 1237939200) - BSD epoch-relative */
630};
631
632/* HFS Master Directory Block - 162 bytes */
633/* Stored at sector #2 (3rd sector) and second-to-last sector. */
634struct HFSMasterDirectoryBlock {
635	u_int16_t 		drSigWord;	/* == kHFSSigWord */
636	u_int32_t 		drCrDate;	/* date and time of volume creation */
637	u_int32_t 		drLsMod;	/* date and time of last modification */
638	u_int16_t 		drAtrb;		/* volume attributes */
639	u_int16_t 		drNmFls;	/* number of files in root folder */
640	u_int16_t 		drVBMSt;	/* first block of volume bitmap */
641	u_int16_t 		drAllocPtr;	/* start of next allocation search */
642	u_int16_t 		drNmAlBlks;	/* number of allocation blocks in volume */
643	u_int32_t 		drAlBlkSiz;	/* size (in bytes) of allocation blocks */
644	u_int32_t 		drClpSiz;	/* default clump size */
645	u_int16_t 		drAlBlSt;	/* first allocation block in volume */
646	u_int32_t 		drNxtCNID;	/* next unused catalog node ID */
647	u_int16_t 		drFreeBks;	/* number of unused allocation blocks */
648	u_int8_t 		drVN[kHFSMaxVolumeNameChars + 1];  /* volume name */
649	u_int32_t 		drVolBkUp;	/* date and time of last backup */
650	u_int16_t 		drVSeqNum;	/* volume backup sequence number */
651	u_int32_t 		drWrCnt;	/* volume write count */
652	u_int32_t 		drXTClpSiz;	/* clump size for extents overflow file */
653	u_int32_t 		drCTClpSiz;	/* clump size for catalog file */
654	u_int16_t 		drNmRtDirs;	/* number of directories in root folder */
655	u_int32_t 		drFilCnt;	/* number of files in volume */
656	u_int32_t 		drDirCnt;	/* number of directories in volume */
657	u_int32_t 		drFndrInfo[8];	/* information used by the Finder */
658	u_int16_t 		drEmbedSigWord;	/* embedded volume signature (formerly drVCSize) */
659	HFSExtentDescriptor	drEmbedExtent;	/* embedded volume location and size (formerly drVBMCSize and drCtlCSize) */
660	u_int32_t		drXTFlSize;	/* size of extents overflow file */
661	HFSExtentRecord		drXTExtRec;	/* extent record for extents overflow file */
662	u_int32_t 		drCTFlSize;	/* size of catalog file */
663	HFSExtentRecord 	drCTExtRec;	/* extent record for catalog file */
664} __attribute__((aligned(2), packed));
665typedef struct HFSMasterDirectoryBlock	HFSMasterDirectoryBlock;
666
667
668#ifdef __APPLE_API_UNSTABLE
669#define SET_HFS_TEXT_ENCODING(hint)  \
670	(0x656e6300 | ((hint) & 0xff))
671#define GET_HFS_TEXT_ENCODING(hint)  \
672	(((hint) & 0xffffff00) == 0x656e6300 ? (hint) & 0x000000ff : 0xffffffffU)
673#endif /* __APPLE_API_UNSTABLE */
674
675
676/* HFS Plus Volume Header - 512 bytes */
677/* Stored at sector #2 (3rd sector) and second-to-last sector. */
678struct HFSPlusVolumeHeader {
679	u_int16_t 	signature;		/* == kHFSPlusSigWord */
680	u_int16_t 	version;		/* == kHFSPlusVersion */
681	u_int32_t 	attributes;		/* volume attributes */
682	u_int32_t 	lastMountedVersion;	/* implementation version which last mounted volume */
683	u_int32_t 	journalInfoBlock;	/* block addr of journal info (if volume is journaled, zero otherwise) */
684
685	u_int32_t 	createDate;		/* date and time of volume creation */
686	u_int32_t 	modifyDate;		/* date and time of last modification */
687	u_int32_t 	backupDate;		/* date and time of last backup */
688	u_int32_t 	checkedDate;		/* date and time of last disk check */
689
690	u_int32_t 	fileCount;		/* number of files in volume */
691	u_int32_t 	folderCount;		/* number of directories in volume */
692
693	u_int32_t 	blockSize;		/* size (in bytes) of allocation blocks */
694	u_int32_t 	totalBlocks;		/* number of allocation blocks in volume (includes this header and VBM*/
695	u_int32_t 	freeBlocks;		/* number of unused allocation blocks */
696
697	u_int32_t 	nextAllocation;		/* start of next allocation search */
698	u_int32_t 	rsrcClumpSize;		/* default resource fork clump size */
699	u_int32_t 	dataClumpSize;		/* default data fork clump size */
700	u_int32_t 	nextCatalogID;		/* next unused catalog node ID */
701
702	u_int32_t 	writeCount;		/* volume write count */
703	u_int64_t 	encodingsBitmap;	/* which encodings have been use  on this volume */
704
705	u_int8_t 	finderInfo[32];		/* information used by the Finder */
706
707	HFSPlusForkData	 allocationFile;	/* allocation bitmap file */
708	HFSPlusForkData  extentsFile;		/* extents B-tree file */
709	HFSPlusForkData  catalogFile;		/* catalog B-tree file */
710	HFSPlusForkData  attributesFile;	/* extended attributes B-tree file */
711	HFSPlusForkData	 startupFile;		/* boot file (secondary loader) */
712} __attribute__((aligned(2), packed));
713typedef struct HFSPlusVolumeHeader HFSPlusVolumeHeader;
714
715
716/* B-tree structures */
717
718enum BTreeKeyLimits{
719	kMaxKeyLength	= 520
720};
721
722union BTreeKey{
723	u_int8_t	length8;
724	u_int16_t	length16;
725	u_int8_t	rawData [kMaxKeyLength+2];
726};
727typedef union BTreeKey BTreeKey;
728
729/* BTNodeDescriptor -- Every B-tree node starts with these fields. */
730struct BTNodeDescriptor {
731	u_int32_t	fLink;			/* next node at this level*/
732	u_int32_t 	bLink;			/* previous node at this level*/
733	int8_t 		kind;			/* kind of node (leaf, index, header, map)*/
734	u_int8_t 	height;			/* zero for header, map; child is one more than parent*/
735	u_int16_t 	numRecords;		/* number of records in this node*/
736	u_int16_t 	reserved;		/* reserved - initialized as zero */
737} __attribute__((aligned(2), packed));
738typedef struct BTNodeDescriptor BTNodeDescriptor;
739
740/* Constants for BTNodeDescriptor kind */
741enum {
742	kBTLeafNode	= -1,
743	kBTIndexNode	= 0,
744	kBTHeaderNode	= 1,
745	kBTMapNode	= 2
746};
747
748/* BTHeaderRec -- The first record of a B-tree header node */
749struct BTHeaderRec {
750	u_int16_t	treeDepth;		/* maximum height (usually leaf nodes) */
751	u_int32_t 	rootNode;		/* node number of root node */
752	u_int32_t 	leafRecords;		/* number of leaf records in all leaf nodes */
753	u_int32_t 	firstLeafNode;		/* node number of first leaf node */
754	u_int32_t 	lastLeafNode;		/* node number of last leaf node */
755	u_int16_t 	nodeSize;		/* size of a node, in bytes */
756	u_int16_t 	maxKeyLength;		/* reserved */
757	u_int32_t 	totalNodes;		/* total number of nodes in tree */
758	u_int32_t 	freeNodes;		/* number of unused (free) nodes in tree */
759	u_int16_t 	reserved1;		/* unused */
760	u_int32_t 	clumpSize;		/* reserved */
761	u_int8_t 	btreeType;		/* reserved */
762	u_int8_t 	keyCompareType;		/* Key string Comparison Type */
763	u_int32_t 	attributes;		/* persistent attributes about the tree */
764	u_int32_t 	reserved3[16];		/* reserved */
765} __attribute__((aligned(2), packed));
766typedef struct BTHeaderRec BTHeaderRec;
767
768/* Constants for BTHeaderRec attributes */
769enum {
770	kBTBadCloseMask		 = 0x00000001,	/* reserved */
771	kBTBigKeysMask		 = 0x00000002,	/* key length field is 16 bits */
772	kBTVariableIndexKeysMask = 0x00000004	/* keys in index nodes are variable length */
773};
774
775
776/* Catalog Key Name Comparison Type */
777enum {
778	kHFSCaseFolding   = 0xCF,  /* case folding (case-insensitive) */
779	kHFSBinaryCompare = 0xBC  /* binary compare (case-sensitive) */
780};
781
782#ifdef __cplusplus
783}
784#endif
785
786#include <uuid/uuid.h>
787
788#ifdef __cplusplus
789extern "C" {
790#endif
791
792/* JournalInfoBlock - Structure that describes where our journal lives */
793
794// the original size of the reserved field in the JournalInfoBlock was
795// 32*sizeof(u_int32_t).  To keep the total size of the structure the 
796// same we subtract the size of new fields (currently: ext_jnl_uuid and
797// machine_uuid).  If you add additional fields, place them before the
798// reserved field and subtract their size in this macro.
799//
800#define JIB_RESERVED_SIZE  ((32*sizeof(u_int32_t)) - sizeof(uuid_string_t) - 48)
801
802struct JournalInfoBlock {
803	u_int32_t	flags;
804    	u_int32_t       device_signature[8];  // signature used to locate our device.
805	u_int64_t       offset;               // byte offset to the journal on the device
806	u_int64_t       size;                 // size in bytes of the journal
807	uuid_string_t   ext_jnl_uuid;
808	char            machine_serial_num[48];
809	char    	reserved[JIB_RESERVED_SIZE];
810} __attribute__((aligned(2), packed));
811typedef struct JournalInfoBlock JournalInfoBlock;
812
813enum {
814    kJIJournalInFSMask          = 0x00000001,
815    kJIJournalOnOtherDeviceMask = 0x00000002,
816    kJIJournalNeedInitMask      = 0x00000004
817};
818
819//
820// This the content type uuid for "external journal" GPT 
821// partitions.  Each instance of a partition also has a
822// uuid that uniquely identifies that instance.
823//
824#define EXTJNL_CONTENT_TYPE_UUID "4A6F7572-6E61-11AA-AA11-00306543ECAC"
825
826
827#ifdef __cplusplus
828}
829#endif
830
831#endif /* __HFS_FORMAT__ */