#ifndef lf_hfs_h
#define lf_hfs_h
#include <sys/kernel_types.h>
#include "lf_hfs_locks.h"
#include "lf_hfs_format.h"
#include "lf_hfs_catalog.h"
#include "lf_hfs_rangelist.h"
#include "lf_hfs_cnode.h"
#include "lf_hfs_defs.h"
#define HFS_MAX_DEFERED_ALLOC (1024*1024)
#define HFS_MAX_FILES (UINT32_MAX - kHFSFirstUserCatalogNodeID)
#define HFS_BIGFILE_SIZE (400LL * 1024LL * 1024LL)
enum { kMDBSize = 512 };
enum { kMasterDirectoryBlock = 2 };
enum { kMDBOffset = kMasterDirectoryBlock * 512 };
#define kRootDirID kHFSRootFolderID
#define kMaxFreeExtents 10
#define HFS_MAX_DEFRAG_SIZE (104857600) // 100 * 1024 * 1024 (100MB)
#define HFS_INITIAL_DEFRAG_SIZE (20971520) // 20 * 1024 * 1024 (20MB)
#define HFS_AVERAGE_NAME_SIZE 22
#define AVERAGE_HFSDIRENTRY_SIZE (8+HFS_AVERAGE_NAME_SIZE+4)
#define HFS_MINFREE (1)
#define HFS_MAXRESERVE ((u_int64_t)(250*1024*1024))
#define HFS_BT_MAXRESERVE ((u_int64_t)(10*1024*1024))
enum {
HFS_META_DELAY = 100 * 1000, HFS_MAX_META_DELAY = 5000 * 1000 };
#define HFS_META_DELAY_TS ((struct timespec){ 0, HFS_META_DELAY * NSEC_PER_USEC })
typedef struct hfsmount {
u_int32_t hfs_flags;
u_int32_t hfs_logical_block_size;
daddr64_t hfs_logical_block_count;
u_int64_t hfs_logical_bytes;
daddr64_t hfs_partition_avh_sector;
daddr64_t hfs_fs_avh_sector;
u_int32_t hfs_physical_block_size;
u_int32_t hfs_log_per_phys;
struct mount * hfs_mp;
struct vnode * hfs_devvp;
struct vnode * hfs_extents_vp;
struct vnode * hfs_catalog_vp;
struct vnode * hfs_allocation_vp;
struct vnode * hfs_attribute_vp;
struct vnode * hfs_startup_vp;
struct vnode * hfs_attrdata_vp;
struct cnode * hfs_extents_cp;
struct cnode * hfs_catalog_cp;
struct cnode * hfs_allocation_cp;
struct cnode * hfs_attribute_cp;
struct cnode * hfs_startup_cp;
dev_t hfs_raw_dev;
u_int32_t hfs_logBlockSize;
uid_t hfs_uid;
gid_t hfs_gid;
mode_t hfs_dir_mask;
mode_t hfs_file_mask;
u_int32_t hfs_encoding;
time_t hfs_mtime;
u_int32_t hfs_filecount;
u_int32_t hfs_dircount;
u_int32_t freeBlocks;
u_int32_t reclaimBlocks;
u_int32_t tentativeBlocks;
u_int32_t nextAllocation;
u_int32_t sparseAllocation;
u_int32_t vcbNxtCNID;
u_int32_t vcbWrCnt;
u_int64_t encodingsBitmap;
u_int16_t vcbNmFls;
u_int16_t vcbNmRtDirs;
u_int16_t vcbSigWord;
bool hfs_header_dirty;
bool hfs_header_minor_change;
u_int32_t vcbAtrb;
u_int32_t vcbJinfoBlock;
u_int32_t localCreateDate;
time_t hfs_itime;
time_t hfs_btime;
u_int32_t blockSize;
u_int32_t totalBlocks;
u_int32_t allocLimit;
int32_t vcbClpSiz;
u_int32_t vcbFndrInfo[8];
int16_t vcbVBMSt;
int16_t vcbAlBlSt;
u_int8_t vcbVN[256];
u_int32_t volumeNameEncodingHint;
u_int32_t hfsPlusIOPosOffset;
u_int32_t vcbVBMIOSize;
u_int32_t vcbFreeExtCnt;
HFSPlusExtentDescriptor vcbFreeExt[kMaxFreeExtents];
pthread_mutex_t vcbFreeExtLock;
u_int8_t *hfs_summary_table;
u_int32_t hfs_summary_size;
u_int32_t hfs_summary_bytes;
u_int32_t scan_var;
u_int32_t reserveBlocks;
u_int32_t loanedBlocks;
u_int32_t lockedBlocks;
struct cat_desc hfs_private_desc[2];
struct cat_attr hfs_private_attr[2];
u_int32_t hfs_metadata_createdate;
struct journal *jnl; struct vnode *jvp; u_int64_t jnl_start; u_int64_t jnl_size;
u_int64_t hfs_jnlfileid;
u_int64_t hfs_jnlinfoblkid;
pthread_rwlock_t hfs_global_lock;
pthread_t hfs_global_lockowner;
u_int32_t hfs_transaction_nesting;
u_int32_t hfs_notification_conditions;
u_int32_t hfs_freespace_notify_dangerlimit;
u_int32_t hfs_freespace_notify_warninglimit;
u_int32_t hfs_freespace_notify_nearwarninglimit;
u_int32_t hfs_freespace_notify_desiredlevel;
time_t hfs_mount_time;
time_t hfs_last_mounted_mtime;
u_int32_t hfs_metazone_start;
u_int32_t hfs_metazone_end;
u_int32_t hfs_min_alloc_start;
u_int32_t hfs_freed_block_count;
int hfs_overflow_maxblks;
int hfs_catalog_maxblks;
int hfs_defrag_nowait; uint64_t hfs_defrag_max;
#if HFS_SPARSE_DEV
struct vnode * hfs_backingvp;
u_int32_t hfs_last_backingstatfs;
u_int32_t hfs_sparsebandblks;
u_int64_t hfs_backingfs_maxblocks;
#endif
size_t hfs_max_inline_attrsize;
pthread_mutex_t hfs_mutex;
pthread_mutex_t sync_mutex;
enum {
HFS_THAWED,
HFS_WANT_TO_FREEZE, HFS_FREEZING, HFS_FROZEN } hfs_freeze_state;
union {
pthread_t hfs_freezing_thread;
proc_t hfs_freezing_proc;
};
pthread_t hfs_downgrading_thread;
u_int32_t hfs_resize_blocksmoved;
u_int32_t hfs_resize_totalblocks;
u_int32_t hfs_resize_progress;
uuid_t hfs_full_uuid;
pthread_mutex_t hfs_chash_mutex;
u_long hfs_cnodehash;
LIST_HEAD(cnodehashhead, cnode) *hfs_cnodehashtbl;
u_long hfs_idhash;
LIST_HEAD(idhashhead, cat_preflightid) *hfs_idhashtbl;
struct timeval hfs_sync_req_oldest;
pthread_t hfs_syncer_thread;
uint32_t hfs_active_threads;
enum {
HFS_TENTATIVE_BLOCKS = 0,
HFS_LOCKED_BLOCKS = 1,
};
struct rl_head hfs_reserved_ranges[2];
int cur_link_id;
} hfsmount_t;
typedef hfsmount_t ExtendedVCB;
#define vcbLsMod hfs_mtime
#define vcbVolBkUp hfs_btime
#define extentsRefNum hfs_extents_vp
#define catalogRefNum hfs_catalog_vp
#define allocationsRefNum hfs_allocation_vp
#define vcbFilCnt hfs_filecount
#define vcbDirCnt hfs_dircount
static inline void MarkVCBDirty(hfsmount_t *hfsmp)
{
hfsmp->hfs_header_dirty = true;
}
static inline void MarkVCBClean(hfsmount_t *hfsmp)
{
hfsmp->hfs_header_dirty = false;
hfsmp->hfs_header_minor_change = false;
}
static inline bool IsVCBDirty(ExtendedVCB *vcb)
{
return vcb->hfs_header_minor_change || vcb->hfs_header_dirty;
}
static inline void hfs_note_header_minor_change(hfsmount_t *hfsmp)
{
hfsmp->hfs_header_minor_change = true;
}
static inline bool hfs_header_needs_flushing(hfsmount_t *hfsmp)
{
return (hfsmp->hfs_header_dirty
|| ISSET(hfsmp->hfs_catalog_cp->c_flag, C_MODIFIED)
|| ISSET(hfsmp->hfs_extents_cp->c_flag, C_MODIFIED)
|| (hfsmp->hfs_attribute_cp
&& ISSET(hfsmp->hfs_attribute_cp->c_flag, C_MODIFIED))
|| (hfsmp->hfs_allocation_cp
&& ISSET(hfsmp->hfs_allocation_cp->c_flag, C_MODIFIED))
|| (hfsmp->hfs_startup_cp
&& ISSET(hfsmp->hfs_startup_cp->c_flag, C_MODIFIED)));
}
enum privdirtype {
FILE_HARDLINKS,
DIR_HARDLINKS
};
#define HFS_ALLOCATOR_SCAN_INFLIGHT 0x0001
#define HFS_ALLOCATOR_SCAN_COMPLETED 0x0002
#define HFS_READ_ONLY 0x00001
#define HFS_UNKNOWN_PERMS 0x00002
#define HFS_WRITEABLE_MEDIA 0x00004
#define HFS_CLEANED_ORPHANS 0x00008
#define HFS_X 0x00010
#define HFS_CASE_SENSITIVE 0x00020
#define HFS_METADATA_ZONE 0x00080
#define HFS_FRAGMENTED_FREESPACE 0x00100
#define HFS_NEED_JNL_RESET 0x00200
#define HFS_RESIZE_IN_PROGRESS 0x00800
#define HFS_QUOTAS 0x01000
#define HFS_CREATING_BTREE 0x02000
#define HFS_SKIP_UPDATE_NEXT_ALLOCATION 0x04000
#define HFS_XATTR_EXTENTS 0x08000
#define HFS_FOLDERCOUNT 0x10000
#define HFS_IN_CHANGEFS 0x40000
#define HFS_RDONLY_DOWNGRADE 0x80000
#define HFS_DID_CONTIG_SCAN 0x100000
#define HFS_UNMAP 0x200000
#define HFS_SUMMARY_TABLE 0x800000
#define HFS_FEATURE_BARRIER 0x8000000
#define HFS_UPDATE_NEXT_ALLOCATION(hfsmp, new_nextAllocation) \
{ \
if ((hfsmp->hfs_flags & HFS_SKIP_UPDATE_NEXT_ALLOCATION) == 0) \
hfsmp->nextAllocation = new_nextAllocation; \
}
#define INC_FOLDERCOUNT(hfsmp, cattr) \
if ((hfsmp->hfs_flags & HFS_FOLDERCOUNT) && \
(cattr.ca_recflags & kHFSHasFolderCountMask)) \
{ \
cattr.ca_dircount++; \
} \
#define DEC_FOLDERCOUNT(hfsmp, cattr) \
if ((hfsmp->hfs_flags & HFS_FOLDERCOUNT) && \
(cattr.ca_recflags & kHFSHasFolderCountMask) && \
(cattr.ca_dircount > 0)) \
{ \
cattr.ca_dircount--; \
} \
typedef struct filefork FCB;
#define MAKE_INODE_NAME(name, size, linkno) \
(void) snprintf((name), size, "%s%d", HFS_INODE_PREFIX, (linkno))
#define HFS_INODE_PREFIX_LEN 5
#define MAKE_DIRINODE_NAME(name, size, linkno) \
(void) snprintf((name), size, "%s%d", HFS_DIRINODE_PREFIX, (linkno))
#define HFS_DIRINODE_PREFIX_LEN 4
#define MAKE_DELETED_NAME(NAME, size, FID) \
(void) snprintf((NAME), size, "%s%d", HFS_DELETE_PREFIX, (FID))
#define HFS_DELETE_PREFIX_LEN 4
enum { kHFSPlusMaxFileNameBytes = kHFSPlusMaxFileNameChars * 3 };
#define ISHFSPLUS(VCB) ((VCB)->vcbSigWord == kHFSPlusSigWord)
#define VTOVFS(VP) (vp->sFSParams.vnfs_mp)
#define HFSTOVFS(HFSMP) ((HFSMP)->hfs_mp)
#define VCBTOVFS(VCB) (HFSTOVFS(VCB))
#define VTOHFS(vp) ((struct hfsmount *)(vp->sFSParams.vnfs_mp->psHfsmount))
#define VFSTOHFS(mp) ((struct hfsmount *)(mp->psHfsmount))
#define VCBTOHFS(vcb) (vcb)
#define FCBTOHFS(fcb) ((struct hfsmount *)((vnode_mount((fcb)->ff_cp->c_vp))->psHfsmount))
#define VTOVCB(VP) (VTOHFS(VP))
#define VFSTOVCB(MP) (VFSTOHFS(MP))
#define HFSTOVCB(HFSMP) (HFSMP)
#define FCBTOVCB(FCB) (FCBTOHFS(FCB))
#define E_NONE (0)
#define kHFSBlockSize (512)
#define HFS_PRI_SECTOR(blksize) (1024 / (blksize))
#define HFS_PRI_OFFSET(blksize) ((blksize) > 1024 ? 1024 : 0)
#define HFS_ALT_SECTOR(blksize, blkcnt) (((blkcnt) - 1) - (512 / (blksize)))
#define HFS_ALT_OFFSET(blksize) ((blksize) > 1024 ? (blksize) - 1024 : 0)
#define HFS_PHYSBLK_ROUNDDOWN(sector_num, log_per_phys) ((sector_num / log_per_phys) * log_per_phys)
#define SFL_CATALOG 0x0001
#define SFL_EXTENTS 0x0002
#define SFL_BITMAP 0x0004
#define SFL_ATTRIBUTE 0x0008
#define SFL_STARTUP 0x0010
#define SFL_VM_PRIV 0x0020
#define SFL_VALIDMASK (SFL_CATALOG | SFL_EXTENTS | SFL_BITMAP | SFL_ATTRIBUTE | SFL_STARTUP | SFL_VM_PRIV)
typedef enum {
HFS_INCONSISTENCY_DETECTED,
HFS_ROLLBACK_FAILED,
HFS_OP_INCOMPLETE,
HFS_FSCK_FORCED,
} hfs_inconsistency_reason_t;
#define HFS_ERESERVEDNAME (-8)
typedef enum hfs_sync_mode {
HFS_FSYNC,
HFS_FSYNC_FULL,
HFS_FSYNC_BARRIER
} hfs_fsync_mode_t;
typedef enum hfs_flush_mode {
HFS_FLUSH_JOURNAL, HFS_FLUSH_JOURNAL_META, HFS_FLUSH_FULL, HFS_FLUSH_CACHE, HFS_FLUSH_BARRIER, HFS_FLUSH_JOURNAL_BARRIER } hfs_flush_mode_t;
#define HFS_XATTR_SIZE_BITS 31
#define HFS_LINK_MAX 32767
typedef enum {
HFS_UPDATE_FORCE = 0x01,
} hfs_update_options_t;
#define HFS_XATTR_MAXSIZE INT32_MAX
#if DEBUG
#define HFS_CRASH_TEST 1
#else
#define HFS_CRASH_TEST 0
#endif
#if HFS_CRASH_TEST
typedef enum {
CRASH_ABORT_NONE,
CRASH_ABORT_MAKE_DIR,
CRASH_ABORT_JOURNAL_BEFORE_FINISH, CRASH_ABORT_JOURNAL_AFTER_JOURNAL_DATA, CRASH_ABORT_JOURNAL_AFTER_JOURNAL_HEADER, CRASH_ABORT_JOURNAL_IN_BLOCK_DATA, CRASH_ABORT_JOURNAL_AFTER_BLOCK_DATA, CRASH_ABORT_ON_UNMOUNT, CRASH_ABORT_RANDOM, CRASH_ABORT_LAST
} CrashAbort_E;
typedef int (*CrashAbortFunction_FP)(CrashAbort_E eAbort, int iFD, UVFSFileNode psNode, pthread_t pSyncerThread);
extern CrashAbortFunction_FP gpsCrashAbortFunctionArray[];
#define CRASH_ABORT(CrashAbortCondition, psHfsmount, Vnode) \
{ \
if (gpsCrashAbortFunctionArray[(CrashAbortCondition)]) { \
\
pthread_t pSyncerThread = 0; \
if ( ((psHfsmount)->hfs_syncer_thread) && \
((psHfsmount)->hfs_syncer_thread != (void*)1) ) { \
pSyncerThread = (psHfsmount)->hfs_syncer_thread; \
} \
gpsCrashAbortFunctionArray[(CrashAbortCondition)]( \
(CrashAbortCondition), \
(psHfsmount)->hfs_devvp->psFSRecord->iFD, \
(Vnode), pSyncerThread ); \
} \
}
#endif // HFS_CRASH_TEST
#endif