]>
Commit | Line | Data |
---|---|---|
de8ee011 A |
1 | /* Copyright © 2017-2018 Apple Inc. All rights reserved. |
2 | * | |
3 | * lf_hfs.h | |
4 | * livefiles_hfs | |
5 | * | |
6 | * Created by Or Haimovich on 18/3/18. | |
7 | */ | |
8 | ||
9 | #ifndef lf_hfs_h | |
10 | #define lf_hfs_h | |
11 | ||
12 | #include <sys/kernel_types.h> | |
13 | #include "lf_hfs_locks.h" | |
14 | #include "lf_hfs_format.h" | |
15 | #include "lf_hfs_catalog.h" | |
16 | #include "lf_hfs_rangelist.h" | |
17 | #include "lf_hfs_cnode.h" | |
18 | #include "lf_hfs_defs.h" | |
19 | ||
20 | ||
21 | #define HFS_MAX_DEFERED_ALLOC (1024*1024) | |
22 | ||
23 | #define HFS_MAX_FILES (UINT32_MAX - kHFSFirstUserCatalogNodeID) | |
24 | ||
25 | // 400 megs is a "big" file (i.e. one that when deleted | |
26 | // would touch enough data that we should break it into | |
27 | // multiple separate transactions) | |
28 | #define HFS_BIGFILE_SIZE (400LL * 1024LL * 1024LL) | |
29 | ||
30 | enum { kMDBSize = 512 }; /* Size of I/O transfer to read entire MDB */ | |
31 | ||
32 | enum { kMasterDirectoryBlock = 2 }; /* MDB offset on disk in 512-byte blocks */ | |
33 | enum { kMDBOffset = kMasterDirectoryBlock * 512 }; /* MDB offset on disk in bytes */ | |
34 | ||
35 | #define kRootDirID kHFSRootFolderID | |
36 | ||
37 | /* How many free extents to cache per volume */ | |
38 | #define kMaxFreeExtents 10 | |
39 | ||
40 | /* Maximum file size that we're willing to defrag on open */ | |
41 | #define HFS_MAX_DEFRAG_SIZE (104857600) // 100 * 1024 * 1024 (100MB) | |
42 | #define HFS_INITIAL_DEFRAG_SIZE (20971520) // 20 * 1024 * 1024 (20MB) | |
43 | ||
44 | #define HFS_AVERAGE_NAME_SIZE 22 | |
45 | #define AVERAGE_HFSDIRENTRY_SIZE (8+HFS_AVERAGE_NAME_SIZE+4) | |
46 | ||
47 | /* | |
48 | * HFS_MINFREE gives the minimum acceptable percentage | |
49 | * of file system blocks which may be free (but this | |
50 | * minimum will never exceed HFS_MAXRESERVE bytes). If | |
51 | * the free block count drops below this level only the | |
52 | * superuser may continue to allocate blocks. | |
53 | */ | |
54 | #define HFS_MINFREE (1) | |
55 | #define HFS_MAXRESERVE ((u_int64_t)(250*1024*1024)) | |
56 | #define HFS_BT_MAXRESERVE ((u_int64_t)(10*1024*1024)) | |
57 | ||
58 | /* | |
59 | * HFS_META_DELAY is a duration (in usecs) used for triggering the | |
60 | * hfs_syncer() routine. We will back off if writes are in | |
61 | * progress, but... | |
62 | * HFS_MAX_META_DELAY is the maximum time we will allow the | |
63 | * syncer to be delayed. | |
64 | */ | |
65 | enum { | |
66 | HFS_META_DELAY = 100 * 1000, // 0.1 secs | |
67 | //HFS_META_DELAY = 10 * 1000, // 0.01 secs | |
68 | HFS_MAX_META_DELAY = 5000 * 1000 // 5 secs | |
69 | //HFS_MAX_META_DELAY = 1000 * 1000 // 1 secs | |
70 | }; | |
71 | ||
72 | #define HFS_META_DELAY_TS ((struct timespec){ 0, HFS_META_DELAY * NSEC_PER_USEC }) | |
73 | ||
74 | ||
75 | /* This structure describes the HFS specific mount structure data. */ | |
76 | typedef struct hfsmount { | |
77 | u_int32_t hfs_flags; /* see below */ | |
78 | ||
79 | /* Physical Description */ | |
80 | u_int32_t hfs_logical_block_size; /* Logical block size of the disk as reported by ioctl(DKIOCGETBLOCKSIZE), always a multiple of 512 */ | |
81 | daddr64_t hfs_logical_block_count; /* Number of logical blocks on the disk, as reported by ioctl(DKIOCGETBLOCKCOUNT) */ | |
82 | u_int64_t hfs_logical_bytes; /* Number of bytes on the disk device this HFS is mounted on (blockcount * blocksize) */ | |
83 | /* | |
84 | * Regarding the two AVH sector fields below: | |
85 | * Under normal circumstances, the filesystem's notion of the "right" location for the AVH is such that | |
86 | * the partition and filesystem's are in sync. However, during a filesystem resize, HFS proactively | |
87 | * writes a new AVH at the end of the filesystem, assuming that the partition will be resized accordingly. | |
88 | * | |
89 | * However, it is not technically a corruption if the partition size is never modified. As a result, we need | |
90 | * to keep two copies of the AVH around "just in case" the partition size is not modified. | |
91 | */ | |
92 | daddr64_t hfs_partition_avh_sector; /* location of Alt VH w.r.t partition size */ | |
93 | daddr64_t hfs_fs_avh_sector; /* location of Alt VH w.r.t filesystem size */ | |
94 | ||
95 | u_int32_t hfs_physical_block_size; /* Physical block size of the disk as reported by ioctl(DKIOCGETPHYSICALBLOCKSIZE) */ | |
96 | u_int32_t hfs_log_per_phys; /* Number of logical blocks per physical block size */ | |
97 | ||
98 | /* Access to VFS and devices */ | |
99 | struct mount * hfs_mp; /* filesystem vfs structure */ | |
100 | struct vnode * hfs_devvp; /* block device mounted vnode */ | |
101 | struct vnode * hfs_extents_vp; | |
102 | struct vnode * hfs_catalog_vp; | |
103 | struct vnode * hfs_allocation_vp; | |
104 | struct vnode * hfs_attribute_vp; | |
105 | struct vnode * hfs_startup_vp; | |
106 | struct vnode * hfs_attrdata_vp; /* pseudo file */ | |
107 | struct cnode * hfs_extents_cp; | |
108 | struct cnode * hfs_catalog_cp; | |
109 | struct cnode * hfs_allocation_cp; | |
110 | struct cnode * hfs_attribute_cp; | |
111 | struct cnode * hfs_startup_cp; | |
112 | dev_t hfs_raw_dev; /* device mounted */ | |
113 | u_int32_t hfs_logBlockSize; /* Size of buffer cache buffer for I/O */ | |
114 | ||
115 | /* Default values for HFS standard and non-init access */ | |
116 | uid_t hfs_uid; /* uid to set as owner of the files */ | |
117 | gid_t hfs_gid; /* gid to set as owner of the files */ | |
118 | mode_t hfs_dir_mask; /* mask to and with directory protection bits */ | |
119 | mode_t hfs_file_mask; /* mask to and with file protection bits */ | |
120 | u_int32_t hfs_encoding; /* Default encoding for non hfs+ volumes */ | |
121 | ||
122 | /* Persistent fields (on disk, dynamic) */ | |
123 | time_t hfs_mtime; /* file system last modification time */ | |
124 | u_int32_t hfs_filecount; /* number of files in file system */ | |
125 | u_int32_t hfs_dircount; /* number of directories in file system */ | |
126 | u_int32_t freeBlocks; /* free allocation blocks */ | |
127 | u_int32_t reclaimBlocks; /* number of blocks we are reclaiming during resize */ | |
128 | u_int32_t tentativeBlocks; /* tentative allocation blocks -- see note below */ | |
129 | u_int32_t nextAllocation; /* start of next allocation search */ | |
130 | u_int32_t sparseAllocation; /* start of allocations for sparse devices */ | |
131 | u_int32_t vcbNxtCNID; /* next unused catalog node ID - protected by catalog lock */ | |
132 | u_int32_t vcbWrCnt; /* file system write count */ | |
133 | u_int64_t encodingsBitmap; /* in-use encodings */ | |
134 | u_int16_t vcbNmFls; /* HFS Only - root dir file count */ | |
135 | u_int16_t vcbNmRtDirs; /* HFS Only - root dir directory count */ | |
136 | ||
137 | /* Persistent fields (on disk, static) */ | |
138 | u_int16_t vcbSigWord; | |
139 | ||
140 | // Volume will be inconsistent if header is not flushed | |
141 | bool hfs_header_dirty; | |
142 | ||
143 | // Volume header is dirty, but won't be inconsistent if not flushed | |
144 | bool hfs_header_minor_change; | |
145 | ||
146 | u_int32_t vcbAtrb; | |
147 | u_int32_t vcbJinfoBlock; | |
148 | u_int32_t localCreateDate;/* volume create time from volume header (For HFS+, value is in local time) */ | |
149 | time_t hfs_itime; /* file system creation time (creation date of the root folder) */ | |
150 | time_t hfs_btime; /* file system last backup time */ | |
151 | u_int32_t blockSize; /* size of allocation blocks */ | |
152 | u_int32_t totalBlocks; /* total allocation blocks */ | |
153 | u_int32_t allocLimit; /* Do not allocate this block or beyond */ | |
154 | /* | |
155 | * NOTE: When resizing a volume to make it smaller, allocLimit is set to the allocation | |
156 | * block number which will contain the new alternate volume header. At all other times, | |
157 | * allocLimit is set to totalBlocks. The allocation code uses allocLimit instead of | |
158 | * totalBlocks to limit which blocks may be allocated, so that during a resize, we don't | |
159 | * put new content into the blocks we're trying to truncate away. | |
160 | */ | |
161 | int32_t vcbClpSiz; | |
162 | u_int32_t vcbFndrInfo[8]; | |
163 | int16_t vcbVBMSt; /* HFS only */ | |
164 | int16_t vcbAlBlSt; /* HFS only */ | |
165 | ||
166 | /* vcb stuff */ | |
167 | u_int8_t vcbVN[256]; /* volume name in UTF-8 */ | |
168 | u_int32_t volumeNameEncodingHint; | |
169 | u_int32_t hfsPlusIOPosOffset; /* Disk block where HFS+ starts */ | |
170 | u_int32_t vcbVBMIOSize; /* volume bitmap I/O size */ | |
171 | ||
172 | /* cache of largest known free extents */ | |
173 | u_int32_t vcbFreeExtCnt; | |
174 | HFSPlusExtentDescriptor vcbFreeExt[kMaxFreeExtents]; | |
175 | pthread_mutex_t vcbFreeExtLock; | |
176 | ||
177 | /* Summary Table */ | |
178 | u_int8_t *hfs_summary_table; /* Each bit is 1 vcbVBMIOSize of bitmap, byte indexed */ | |
179 | u_int32_t hfs_summary_size; /* number of BITS in summary table defined above (not bytes!) */ | |
180 | u_int32_t hfs_summary_bytes; /* number of BYTES in summary table */ | |
181 | ||
182 | u_int32_t scan_var; /* For initializing the summary table */ | |
183 | ||
184 | ||
185 | u_int32_t reserveBlocks; /* free block reserve */ | |
186 | u_int32_t loanedBlocks; /* blocks on loan for delayed allocations */ | |
187 | u_int32_t lockedBlocks; /* blocks reserved and locked */ | |
188 | ||
189 | /* | |
190 | * HFS+ Private system directories (two). Any access | |
191 | * (besides looking at the cd_cnid) requires holding | |
192 | * the Catalog File lock. | |
193 | */ | |
194 | struct cat_desc hfs_private_desc[2]; | |
195 | struct cat_attr hfs_private_attr[2]; | |
196 | ||
197 | u_int32_t hfs_metadata_createdate; | |
198 | ||
199 | /* Journaling variables: */ | |
200 | struct journal *jnl; // the journal for this volume (if one exists) | |
201 | struct vnode *jvp; // device where the journal lives (may be equal to devvp) | |
202 | u_int64_t jnl_start; // start block of the journal file (so we don't delete it) | |
203 | u_int64_t jnl_size; | |
204 | u_int64_t hfs_jnlfileid; | |
205 | u_int64_t hfs_jnlinfoblkid; | |
206 | pthread_rwlock_t hfs_global_lock; | |
207 | pthread_t hfs_global_lockowner; | |
208 | u_int32_t hfs_transaction_nesting; | |
209 | ||
210 | /* | |
211 | * Notification variables | |
212 | * See comments in hfs mount code for what the | |
213 | * default levels are set to. | |
214 | */ | |
215 | u_int32_t hfs_notification_conditions; | |
216 | u_int32_t hfs_freespace_notify_dangerlimit; | |
217 | u_int32_t hfs_freespace_notify_warninglimit; | |
218 | u_int32_t hfs_freespace_notify_nearwarninglimit; | |
219 | u_int32_t hfs_freespace_notify_desiredlevel; | |
220 | ||
221 | /* time mounted and last mounted mod time "snapshot" */ | |
222 | time_t hfs_mount_time; | |
223 | time_t hfs_last_mounted_mtime; | |
224 | ||
225 | /* Metadata allocation zone variables: */ | |
226 | u_int32_t hfs_metazone_start; | |
227 | u_int32_t hfs_metazone_end; | |
228 | u_int32_t hfs_min_alloc_start; | |
229 | u_int32_t hfs_freed_block_count; | |
230 | int hfs_overflow_maxblks; | |
231 | int hfs_catalog_maxblks; | |
232 | ||
233 | /* defrag-on-open variables */ | |
234 | int hfs_defrag_nowait; //issue defrags now, regardless of whether or not we've gone past 3 min. | |
235 | uint64_t hfs_defrag_max; //maximum file size we'll defragment on this mount | |
236 | ||
237 | #if HFS_SPARSE_DEV | |
238 | /* Sparse device variables: */ | |
239 | struct vnode * hfs_backingvp; | |
240 | u_int32_t hfs_last_backingstatfs; | |
241 | u_int32_t hfs_sparsebandblks; | |
242 | u_int64_t hfs_backingfs_maxblocks; | |
243 | #endif | |
244 | size_t hfs_max_inline_attrsize; | |
245 | ||
246 | pthread_mutex_t hfs_mutex; /* protects access to hfsmount data */ | |
247 | pthread_mutex_t sync_mutex; | |
248 | ||
249 | enum { | |
250 | HFS_THAWED, | |
251 | HFS_WANT_TO_FREEZE, // This state stops hfs_sync from starting | |
252 | HFS_FREEZING, // We're in this state whilst we're flushing | |
253 | HFS_FROZEN // Everything gets blocked in hfs_lock_global | |
254 | } hfs_freeze_state; | |
255 | union { | |
256 | /* | |
257 | * When we're freezing (HFS_FREEZING) but not yet | |
258 | * frozen (HFS_FROZEN), we record the freezing thread | |
259 | * so that we stop other threads from taking locks, | |
260 | * but allow the freezing thread. | |
261 | */ | |
262 | pthread_t hfs_freezing_thread; | |
263 | /* | |
264 | * Once we have frozen (HFS_FROZEN), we record the | |
265 | * process so that if it dies, we can automatically | |
266 | * unfreeze. | |
267 | */ | |
268 | proc_t hfs_freezing_proc; | |
269 | }; | |
270 | ||
271 | pthread_t hfs_downgrading_thread; /* thread who's downgrading to rdonly */ | |
272 | ||
273 | /* Resize variables: */ | |
274 | u_int32_t hfs_resize_blocksmoved; | |
275 | u_int32_t hfs_resize_totalblocks; | |
276 | u_int32_t hfs_resize_progress; | |
277 | ||
278 | /* the full UUID of the volume, not the one stored in finderinfo */ | |
279 | uuid_t hfs_full_uuid; | |
280 | ||
281 | /* Per mount cnode hash variables: */ | |
282 | pthread_mutex_t hfs_chash_mutex; /* protects access to cnode hash table */ | |
283 | u_long hfs_cnodehash; /* size of cnode hash table - 1 */ | |
284 | LIST_HEAD(cnodehashhead, cnode) *hfs_cnodehashtbl; /* base of cnode hash */ | |
285 | ||
286 | /* Per mount fileid hash variables (protected by catalog lock!) */ | |
287 | u_long hfs_idhash; /* size of cnid/fileid hash table -1 */ | |
288 | LIST_HEAD(idhashhead, cat_preflightid) *hfs_idhashtbl; /* base of ID hash */ | |
289 | ||
290 | // Records the oldest outstanding sync request | |
291 | struct timeval hfs_sync_req_oldest; | |
292 | ||
293 | /* Records the syncer thread so that we can avoid the syncer | |
294 | queing more syncs. */ | |
295 | pthread_t hfs_syncer_thread; | |
296 | ||
297 | // Not currently used except for debugging purposes | |
298 | // Since we pass this to OSAddAtomic, this needs to be 4-byte aligned. | |
299 | uint32_t hfs_active_threads; | |
300 | ||
301 | enum { | |
302 | // These are indices into the array below | |
303 | ||
304 | // Tentative ranges can be claimed back at any time | |
305 | HFS_TENTATIVE_BLOCKS = 0, | |
306 | ||
307 | // Locked ranges cannot be claimed back, but the allocation | |
308 | // won't have been written to disk yet | |
309 | HFS_LOCKED_BLOCKS = 1, | |
310 | }; | |
311 | // These lists are not sorted like a range list usually is | |
312 | struct rl_head hfs_reserved_ranges[2]; | |
313 | ||
314 | //General counter of link id | |
315 | int cur_link_id; | |
316 | ||
317 | } hfsmount_t; | |
318 | ||
319 | typedef hfsmount_t ExtendedVCB; | |
320 | ||
321 | ||
322 | /* Aliases for legacy (Mac OS 9) field names */ | |
323 | #define vcbLsMod hfs_mtime | |
324 | #define vcbVolBkUp hfs_btime | |
325 | #define extentsRefNum hfs_extents_vp | |
326 | #define catalogRefNum hfs_catalog_vp | |
327 | #define allocationsRefNum hfs_allocation_vp | |
328 | #define vcbFilCnt hfs_filecount | |
329 | #define vcbDirCnt hfs_dircount | |
330 | ||
331 | static inline void MarkVCBDirty(hfsmount_t *hfsmp) | |
332 | { | |
333 | hfsmp->hfs_header_dirty = true; | |
334 | } | |
335 | ||
336 | static inline void MarkVCBClean(hfsmount_t *hfsmp) | |
337 | { | |
338 | hfsmp->hfs_header_dirty = false; | |
339 | hfsmp->hfs_header_minor_change = false; | |
340 | } | |
341 | ||
342 | static inline bool IsVCBDirty(ExtendedVCB *vcb) | |
343 | { | |
344 | return vcb->hfs_header_minor_change || vcb->hfs_header_dirty; | |
345 | } | |
346 | ||
347 | // Header is changed but won't be inconsistent if we don't write it | |
348 | static inline void hfs_note_header_minor_change(hfsmount_t *hfsmp) | |
349 | { | |
350 | hfsmp->hfs_header_minor_change = true; | |
351 | } | |
352 | ||
353 | // Must header be flushed for volume to be consistent? | |
354 | static inline bool hfs_header_needs_flushing(hfsmount_t *hfsmp) | |
355 | { | |
356 | return (hfsmp->hfs_header_dirty | |
357 | || ISSET(hfsmp->hfs_catalog_cp->c_flag, C_MODIFIED) | |
358 | || ISSET(hfsmp->hfs_extents_cp->c_flag, C_MODIFIED) | |
359 | || (hfsmp->hfs_attribute_cp | |
360 | && ISSET(hfsmp->hfs_attribute_cp->c_flag, C_MODIFIED)) | |
361 | || (hfsmp->hfs_allocation_cp | |
362 | && ISSET(hfsmp->hfs_allocation_cp->c_flag, C_MODIFIED)) | |
363 | || (hfsmp->hfs_startup_cp | |
364 | && ISSET(hfsmp->hfs_startup_cp->c_flag, C_MODIFIED))); | |
365 | } | |
366 | ||
367 | enum privdirtype { | |
368 | FILE_HARDLINKS, | |
369 | DIR_HARDLINKS | |
370 | }; | |
371 | ||
372 | #define HFS_ALLOCATOR_SCAN_INFLIGHT 0x0001 /* scan started */ | |
373 | #define HFS_ALLOCATOR_SCAN_COMPLETED 0x0002 /* initial scan was completed */ | |
374 | ||
375 | /* HFS mount point flags */ | |
376 | #define HFS_READ_ONLY 0x00001 | |
377 | #define HFS_UNKNOWN_PERMS 0x00002 | |
378 | #define HFS_WRITEABLE_MEDIA 0x00004 | |
379 | #define HFS_CLEANED_ORPHANS 0x00008 | |
380 | #define HFS_X 0x00010 | |
381 | #define HFS_CASE_SENSITIVE 0x00020 | |
382 | //#define HFS_STANDARD 0x00040 | |
383 | #define HFS_METADATA_ZONE 0x00080 | |
384 | #define HFS_FRAGMENTED_FREESPACE 0x00100 | |
385 | #define HFS_NEED_JNL_RESET 0x00200 | |
386 | //#define HFS_HAS_SPARSE_DEVICE 0x00400 | |
387 | #define HFS_RESIZE_IN_PROGRESS 0x00800 | |
388 | #define HFS_QUOTAS 0x01000 | |
389 | #define HFS_CREATING_BTREE 0x02000 | |
390 | /* When set, do not update nextAllocation in the mount structure */ | |
391 | #define HFS_SKIP_UPDATE_NEXT_ALLOCATION 0x04000 | |
392 | /* When set, the file system supports extent-based extended attributes */ | |
393 | #define HFS_XATTR_EXTENTS 0x08000 | |
394 | #define HFS_FOLDERCOUNT 0x10000 | |
395 | /* When set, the file system exists on a virtual device, like disk image */ | |
396 | //#define HFS_VIRTUAL_DEVICE 0x20000 | |
397 | /* When set, we're in hfs_changefs, so hfs_sync should do nothing. */ | |
398 | #define HFS_IN_CHANGEFS 0x40000 | |
399 | /* When set, we are in process of downgrading or have downgraded to read-only, | |
400 | * so hfs_start_transaction should return EROFS. | |
401 | */ | |
402 | #define HFS_RDONLY_DOWNGRADE 0x80000 | |
403 | #define HFS_DID_CONTIG_SCAN 0x100000 | |
404 | #define HFS_UNMAP 0x200000 | |
405 | //#define HFS_SSD 0x400000 | |
406 | #define HFS_SUMMARY_TABLE 0x800000 | |
407 | //#define HFS_CS 0x1000000 | |
408 | //#define HFS_CS_METADATA_PIN 0x2000000 | |
409 | #define HFS_FEATURE_BARRIER 0x8000000 /* device supports barrier-only flush */ | |
410 | //#define HFS_CS_SWAPFILE_PIN 0x10000000 | |
411 | ||
412 | /* Macro to update next allocation block in the HFS mount structure. If | |
413 | * the HFS_SKIP_UPDATE_NEXT_ALLOCATION is set, do not update | |
414 | * nextAllocation block. | |
415 | */ | |
416 | #define HFS_UPDATE_NEXT_ALLOCATION(hfsmp, new_nextAllocation) \ | |
417 | { \ | |
418 | if ((hfsmp->hfs_flags & HFS_SKIP_UPDATE_NEXT_ALLOCATION) == 0) \ | |
419 | hfsmp->nextAllocation = new_nextAllocation; \ | |
420 | } | |
421 | ||
422 | /* Macro for incrementing and decrementing the folder count in a cnode | |
423 | * attribute only if the HFS_FOLDERCOUNT bit is set in the mount flags | |
424 | * and kHFSHasFolderCount bit is set in the cnode flags. Currently these | |
425 | * bits are only set for case sensitive HFS+ volumes. | |
426 | */ | |
427 | #define INC_FOLDERCOUNT(hfsmp, cattr) \ | |
428 | if ((hfsmp->hfs_flags & HFS_FOLDERCOUNT) && \ | |
429 | (cattr.ca_recflags & kHFSHasFolderCountMask)) \ | |
430 | { \ | |
431 | cattr.ca_dircount++; \ | |
432 | } \ | |
433 | ||
434 | #define DEC_FOLDERCOUNT(hfsmp, cattr) \ | |
435 | if ((hfsmp->hfs_flags & HFS_FOLDERCOUNT) && \ | |
436 | (cattr.ca_recflags & kHFSHasFolderCountMask) && \ | |
437 | (cattr.ca_dircount > 0)) \ | |
438 | { \ | |
439 | cattr.ca_dircount--; \ | |
440 | } \ | |
441 | ||
442 | typedef struct filefork FCB; | |
443 | ||
444 | /* | |
445 | * Macros for creating item names for our special/private directories. | |
446 | */ | |
447 | #define MAKE_INODE_NAME(name, size, linkno) \ | |
448 | (void) snprintf((name), size, "%s%d", HFS_INODE_PREFIX, (linkno)) | |
449 | #define HFS_INODE_PREFIX_LEN 5 | |
450 | ||
451 | #define MAKE_DIRINODE_NAME(name, size, linkno) \ | |
452 | (void) snprintf((name), size, "%s%d", HFS_DIRINODE_PREFIX, (linkno)) | |
453 | #define HFS_DIRINODE_PREFIX_LEN 4 | |
454 | ||
455 | #define MAKE_DELETED_NAME(NAME, size, FID) \ | |
456 | (void) snprintf((NAME), size, "%s%d", HFS_DELETE_PREFIX, (FID)) | |
457 | #define HFS_DELETE_PREFIX_LEN 4 | |
458 | ||
459 | enum { kHFSPlusMaxFileNameBytes = kHFSPlusMaxFileNameChars * 3 }; | |
460 | ||
461 | ||
462 | /* macro to determine if hfs or hfsplus */ | |
463 | #define ISHFSPLUS(VCB) ((VCB)->vcbSigWord == kHFSPlusSigWord) | |
464 | ||
465 | /* | |
466 | * Various ways to acquire a VFS mount point pointer: | |
467 | */ | |
468 | #define VTOVFS(VP) (vp->sFSParams.vnfs_mp) | |
469 | #define HFSTOVFS(HFSMP) ((HFSMP)->hfs_mp) | |
470 | #define VCBTOVFS(VCB) (HFSTOVFS(VCB)) | |
471 | ||
472 | /* | |
473 | * Various ways to acquire an HFS mount point pointer: | |
474 | */ | |
475 | #define VTOHFS(vp) ((struct hfsmount *)(vp->sFSParams.vnfs_mp->psHfsmount)) | |
476 | #define VFSTOHFS(mp) ((struct hfsmount *)(mp->psHfsmount)) | |
477 | #define VCBTOHFS(vcb) (vcb) | |
478 | #define FCBTOHFS(fcb) ((struct hfsmount *)((vnode_mount((fcb)->ff_cp->c_vp))->psHfsmount)) | |
479 | ||
480 | /* | |
481 | * Various ways to acquire a VCB (legacy) pointer: | |
482 | */ | |
483 | #define VTOVCB(VP) (VTOHFS(VP)) | |
484 | #define VFSTOVCB(MP) (VFSTOHFS(MP)) | |
485 | #define HFSTOVCB(HFSMP) (HFSMP) | |
486 | #define FCBTOVCB(FCB) (FCBTOHFS(FCB)) | |
487 | ||
488 | #define E_NONE (0) | |
489 | #define kHFSBlockSize (512) | |
490 | ||
491 | /* | |
492 | * Macros for getting the MDB/VH sector and offset | |
493 | */ | |
494 | #define HFS_PRI_SECTOR(blksize) (1024 / (blksize)) | |
495 | #define HFS_PRI_OFFSET(blksize) ((blksize) > 1024 ? 1024 : 0) | |
496 | ||
497 | #define HFS_ALT_SECTOR(blksize, blkcnt) (((blkcnt) - 1) - (512 / (blksize))) | |
498 | #define HFS_ALT_OFFSET(blksize) ((blksize) > 1024 ? (blksize) - 1024 : 0) | |
499 | ||
500 | #define HFS_PHYSBLK_ROUNDDOWN(sector_num, log_per_phys) ((sector_num / log_per_phys) * log_per_phys) | |
501 | ||
502 | /* HFS System file locking */ | |
503 | #define SFL_CATALOG 0x0001 | |
504 | #define SFL_EXTENTS 0x0002 | |
505 | #define SFL_BITMAP 0x0004 | |
506 | #define SFL_ATTRIBUTE 0x0008 | |
507 | #define SFL_STARTUP 0x0010 | |
508 | #define SFL_VM_PRIV 0x0020 | |
509 | #define SFL_VALIDMASK (SFL_CATALOG | SFL_EXTENTS | SFL_BITMAP | SFL_ATTRIBUTE | SFL_STARTUP | SFL_VM_PRIV) | |
510 | ||
511 | /* If a runtime corruption is detected, mark the volume inconsistent | |
512 | * bit in the volume attributes. | |
513 | */ | |
514 | typedef enum { | |
515 | HFS_INCONSISTENCY_DETECTED, | |
516 | // Used when unable to rollback an operation that failed | |
517 | HFS_ROLLBACK_FAILED, | |
518 | // Used when the latter part of an operation failed, but we chose not to roll back | |
519 | HFS_OP_INCOMPLETE, | |
520 | // Used when someone told us to force an fsck on next mount | |
521 | HFS_FSCK_FORCED, | |
522 | } hfs_inconsistency_reason_t; | |
523 | ||
524 | #define HFS_ERESERVEDNAME (-8) | |
525 | ||
526 | typedef enum hfs_sync_mode { | |
527 | HFS_FSYNC, | |
528 | HFS_FSYNC_FULL, | |
529 | HFS_FSYNC_BARRIER | |
530 | } hfs_fsync_mode_t; | |
531 | ||
532 | typedef enum hfs_flush_mode { | |
533 | HFS_FLUSH_JOURNAL, // Flush journal | |
534 | HFS_FLUSH_JOURNAL_META, // Flush journal and metadata blocks | |
535 | HFS_FLUSH_FULL, // Flush journal and does a cache flush | |
536 | HFS_FLUSH_CACHE, // Flush track cache to media | |
537 | HFS_FLUSH_BARRIER, // Barrier-only flush to ensure write order | |
538 | HFS_FLUSH_JOURNAL_BARRIER // Flush journal with barrier | |
539 | } hfs_flush_mode_t; | |
540 | ||
541 | /* Number of bits used to represent maximum extended attribute size */ | |
542 | #define HFS_XATTR_SIZE_BITS 31 | |
543 | ||
544 | #define HFS_LINK_MAX 32767 | |
545 | ||
546 | typedef enum { | |
547 | // Push all modifications to disk (including minor ones) | |
548 | HFS_UPDATE_FORCE = 0x01, | |
549 | } hfs_update_options_t; | |
550 | ||
551 | /* | |
552 | * Maximum extended attribute size supported for all extended attributes except | |
553 | * resource fork and finder info. | |
554 | */ | |
555 | #define HFS_XATTR_MAXSIZE INT32_MAX | |
556 | ||
557 | #if DEBUG | |
558 | #define HFS_CRASH_TEST 1 | |
559 | #else | |
560 | #define HFS_CRASH_TEST 0 | |
561 | #endif | |
562 | ||
563 | #if HFS_CRASH_TEST | |
564 | typedef enum { | |
565 | CRASH_ABORT_NONE, | |
566 | CRASH_ABORT_MAKE_DIR, | |
567 | CRASH_ABORT_JOURNAL_BEFORE_FINISH, // Crash driver before journal update starts | |
568 | CRASH_ABORT_JOURNAL_AFTER_JOURNAL_DATA, // Crash driver after the journal data has been written but before the journal header has been updated | |
569 | CRASH_ABORT_JOURNAL_AFTER_JOURNAL_HEADER, // Crash driver after the journal header has been updated but before blocks were written to destination | |
570 | CRASH_ABORT_JOURNAL_IN_BLOCK_DATA, // Crash driver while writing data blocks | |
571 | CRASH_ABORT_JOURNAL_AFTER_BLOCK_DATA, // Crash the driver after the data blocks were written | |
572 | CRASH_ABORT_ON_UNMOUNT, // Crash on unmount | |
573 | CRASH_ABORT_RANDOM, // Crach at random time (introduced by tester) | |
574 | CRASH_ABORT_LAST | |
575 | } CrashAbort_E; | |
576 | ||
577 | typedef int (*CrashAbortFunction_FP)(CrashAbort_E eAbort, int iFD, UVFSFileNode psNode, pthread_t pSyncerThread); | |
578 | ||
579 | extern CrashAbortFunction_FP gpsCrashAbortFunctionArray[]; | |
580 | ||
581 | #define CRASH_ABORT(CrashAbortCondition, psHfsmount, Vnode) \ | |
582 | { \ | |
583 | if (gpsCrashAbortFunctionArray[(CrashAbortCondition)]) { \ | |
584 | \ | |
585 | pthread_t pSyncerThread = 0; \ | |
586 | if ( ((psHfsmount)->hfs_syncer_thread) && \ | |
587 | ((psHfsmount)->hfs_syncer_thread != (void*)1) ) { \ | |
588 | pSyncerThread = (psHfsmount)->hfs_syncer_thread; \ | |
589 | } \ | |
590 | gpsCrashAbortFunctionArray[(CrashAbortCondition)]( \ | |
591 | (CrashAbortCondition), \ | |
592 | (psHfsmount)->hfs_devvp->psFSRecord->iFD, \ | |
593 | (Vnode), pSyncerThread ); \ | |
594 | } \ | |
595 | } | |
596 | ||
597 | #endif // HFS_CRASH_TEST | |
598 | ||
599 | ||
600 | #endif /* lf_hfs_h */ |