From 927b7b56409ec17628727d7cd92ae5683d73e2de Mon Sep 17 00:00:00 2001 From: Apple Date: Thu, 19 Nov 2020 01:07:08 +0000 Subject: [PATCH] hfs-556.41.1.tar.gz --- CopyHFSMeta/DeviceWrapper.c | 4 + CopyHFSMeta/Gather.c | 9 +- CopyHFSMeta/ScanExtents.c | 3 - CopyHFSMeta/SparseBundle.c | 3 +- CopyHFSMeta/dump.c | 2 +- core/.open_source_exclude | 2 - core/BTreeMiscOps.c | 2 +- core/FileExtentMapping.c | 6 +- core/VolumeAllocation.c | 4 +- core/hfs.h | 1 - core/hfs_catalog.c | 4 +- core/hfs_cnode.c | 2 + core/hfs_cnode.h | 9 +- core/hfs_cprotect.c | 24 +- core/hfs_fsctl.h | 3 + core/hfs_iokit.cpp | 13 + core/hfs_journal.c | 12 +- core/hfs_readwrite.c | 17 +- core/hfs_vfsops.c | 41 +- core/hfs_vfsutils.c | 14 +- core/hfs_vnops.c | 57 +- core/hfs_xattr.c | 13 +- fsck_hfs/cache.c | 2 +- fsck_hfs/dfalib/BTreeAllocate.c | 4 +- fsck_hfs/dfalib/HardLinkCheck.c | 12 +- fsck_hfs/dfalib/SBTree.c | 8 +- fsck_hfs/dfalib/SDevice.c | 4 +- fsck_hfs/dfalib/SExtents.c | 8 +- fsck_hfs/dfalib/SRebuildBTree.c | 6 +- fsck_hfs/dfalib/SRepair.c | 18 +- fsck_hfs/dfalib/SStubs.c | 3 +- fsck_hfs/dfalib/SUtils.c | 10 +- fsck_hfs/dfalib/SVerify1.c | 30 +- fsck_hfs/dfalib/VolumeBitmapCheck.c | 2 +- fsck_hfs/dfalib/dirhardlink.c | 25 +- fsck_hfs/dfalib/fsck_journal.c | 2 +- fsck_hfs/dfalib/hfs_endian.c | 2 +- fsck_hfs/fsck_hfs.c | 10 +- fsck_hfs/utilities.c | 4 +- hfs.xcodeproj/project.pbxproj | 992 ++++++++++++------ hfs_util/hfsutil_jnl.c | 14 +- hfs_util/hfsutil_main.c | 49 +- livefiles_cs_plugin/lf_cs.h | 34 + livefiles_cs_plugin/lf_cs_checksum.c | 139 +++ livefiles_cs_plugin/lf_cs_checksum.h | 64 ++ livefiles_cs_plugin/lf_cs_disk_format.h | 452 ++++++++ livefiles_cs_plugin/lf_cs_logging.c | 57 + livefiles_cs_plugin/lf_cs_logging.h | 40 + livefiles_cs_plugin/lf_cs_vfsops.c | 656 ++++++++++++ livefiles_cs_plugin/livefiles_cs_tester.c | 157 +++ .../livefiles_cs_tester.entitlements | 10 + livefiles_hfs_plugin/lf_hfs.h | 4 +- livefiles_hfs_plugin/lf_hfs_catalog.c | 4 +- livefiles_hfs_plugin/lf_hfs_chash.c | 49 +- livefiles_hfs_plugin/lf_hfs_cnode.c | 14 +- livefiles_hfs_plugin/lf_hfs_fsops_handler.c | 11 +- livefiles_hfs_plugin/lf_hfs_journal.c | 4 +- livefiles_hfs_plugin/lf_hfs_link.c | 2 +- livefiles_hfs_plugin/lf_hfs_vfsops.c | 213 +--- livefiles_hfs_plugin/lf_hfs_vnode.c | 2 + livefiles_hfs_plugin/lf_hfs_xattr.c | 10 +- mount_hfs/mount_hfs.c | 14 +- newfs_hfs/makehfs.c | 12 +- newfs_hfs/newfs_hfs.c | 48 +- tests/cases/test-external-jnl.c | 42 +- tests/cases/test-key-roll.c | 14 +- tests/cases/test-lf-cs-plugin.c | 350 ++++++ tests/disk-image.m | 41 +- tests/gen-custom-dmg.sh | 9 + tests/gen-test-plist.sh | 6 +- tests/generate-compressed-image.c | 303 ++++++ tests/hfs-tests.entitlements | 2 + 72 files changed, 3474 insertions(+), 739 deletions(-) delete mode 100644 core/.open_source_exclude create mode 100644 livefiles_cs_plugin/lf_cs.h create mode 100644 livefiles_cs_plugin/lf_cs_checksum.c create mode 100644 livefiles_cs_plugin/lf_cs_checksum.h create mode 100644 livefiles_cs_plugin/lf_cs_disk_format.h create mode 100644 livefiles_cs_plugin/lf_cs_logging.c create mode 100644 livefiles_cs_plugin/lf_cs_logging.h create mode 100644 livefiles_cs_plugin/lf_cs_vfsops.c create mode 100644 livefiles_cs_plugin/livefiles_cs_tester.c create mode 100644 livefiles_cs_plugin/livefiles_cs_tester.entitlements create mode 100644 tests/cases/test-lf-cs-plugin.c create mode 100755 tests/gen-custom-dmg.sh create mode 100644 tests/generate-compressed-image.c diff --git a/CopyHFSMeta/DeviceWrapper.c b/CopyHFSMeta/DeviceWrapper.c index 74dd4b6..a058143 100644 --- a/CopyHFSMeta/DeviceWrapper.c +++ b/CopyHFSMeta/DeviceWrapper.c @@ -140,6 +140,10 @@ InitDeviceWrapper(const char *path, DeviceInfo_t *devp) } ctx.pathname = strdup(rawname); + if (ctx.pathname == NULL) { + warn("Cannot strdup the pathname"); + goto done; + } retctx = malloc(sizeof(ctx)); if (retctx == NULL) { warn("Cannot allocate space for device context"); diff --git a/CopyHFSMeta/Gather.c b/CopyHFSMeta/Gather.c index 27c4c7a..30e1559 100644 --- a/CopyHFSMeta/Gather.c +++ b/CopyHFSMeta/Gather.c @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include "hfsmeta.h" #include "Data.h" @@ -51,7 +53,7 @@ WriteExtent(gzFile outf, DeviceInfo_t *devp, off_t start, off_t len) if (nread != amt) { warnx("Tried to read %zu bytes, only read %zd", amt, nread); } - nwritten = gzwrite(outf, (char*)buffer, amt); + nwritten = gzwrite(outf, (char*)buffer, (unsigned)amt); if (nwritten == -1) { warn("tried to gzwrite %zu bytes", amt); return -1; @@ -73,6 +75,7 @@ WriteGatheredData(const char *pathname, VolumeObjects_t *vop) HFSDataObject *objs = NULL, *op; ExtentList_t *ep; int i; + size_t len; hdr.version = S32(kHFSInfoHeaderVersion); hdr.deviceBlockSize = S32((uint32_t)vop->devp->blockSize); @@ -111,7 +114,9 @@ WriteGatheredData(const char *pathname, VolumeObjects_t *vop) } gzwrite(outf, &hdr, sizeof(hdr)); - gzwrite(outf, objs, sizeof(HFSDataObject) * vop->count); + len = sizeof(HFSDataObject) * vop->count; + assert(len < UINT_MAX); + gzwrite(outf, objs, (unsigned)len); int count = 0; for (ep = vop->list; diff --git a/CopyHFSMeta/ScanExtents.c b/CopyHFSMeta/ScanExtents.c index 470a699..25e5a55 100644 --- a/CopyHFSMeta/ScanExtents.c +++ b/CopyHFSMeta/ScanExtents.c @@ -194,7 +194,6 @@ ScanExtents(VolumeObjects_t *vop, int useAltHdr) off_t vBlockSize; size_t nodeSize; size_t bufferSize; - int blocksPerNode; void *nodePtr = NULL; unsigned int nodeNum = 0; @@ -227,10 +226,8 @@ ScanExtents(VolumeObjects_t *vop, int useAltHdr) * does mean it is less efficient than it should be. */ if (nodeSize < vBlockSize) { - blocksPerNode = 1; // 1 block will hold multiple nodes bufferSize = vBlockSize; } else { - blocksPerNode = nodeSize / vBlockSize; bufferSize = nodeSize; } diff --git a/CopyHFSMeta/SparseBundle.c b/CopyHFSMeta/SparseBundle.c index 2d966c4..8c7c2da 100644 --- a/CopyHFSMeta/SparseBundle.c +++ b/CopyHFSMeta/SparseBundle.c @@ -176,7 +176,8 @@ doSparseWrite(IOWrapper_t *context, off_t offset, void *buffer, off_t len) free(bandName); bandName = NULL; ctx->cfd = fd; - ctx->cBandNum = bandNum; + assert(bandNum < INT_MAX); + ctx->cBandNum = (int)bandNum; } else { fd = ctx->cfd; } diff --git a/CopyHFSMeta/dump.c b/CopyHFSMeta/dump.c index 67067e4..5e09607 100644 --- a/CopyHFSMeta/dump.c +++ b/CopyHFSMeta/dump.c @@ -53,7 +53,7 @@ DumpData(const void *data, size_t len) if (*tmp) allzeroes = 0; } - for (i = gap; i >= 0; i--) { + for (i = (int)gap; i >= 0; i--) { printf(" "); if (i % 2 == 1) printf(" "); diff --git a/core/.open_source_exclude b/core/.open_source_exclude deleted file mode 100644 index 0c36529..0000000 --- a/core/.open_source_exclude +++ /dev/null @@ -1,2 +0,0 @@ -hfs_key_roll.c -hfs_key_roll.h diff --git a/core/BTreeMiscOps.c b/core/BTreeMiscOps.c index a8682ef..4f89b78 100644 --- a/core/BTreeMiscOps.c +++ b/core/BTreeMiscOps.c @@ -527,7 +527,7 @@ OSStatus CheckInsertParams (FCB *filePtr, BTreeControlBlockPtr btreePtr; if (filePtr == nil) return paramErr; - + if (recordLen == 0) return paramErr; btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr; if (btreePtr == nil) return fsBTInvalidFileErr; if (iterator == nil) return paramErr; diff --git a/core/FileExtentMapping.c b/core/FileExtentMapping.c index 1ea93f9..a4e177b 100644 --- a/core/FileExtentMapping.c +++ b/core/FileExtentMapping.c @@ -221,7 +221,7 @@ static OSErr FindExtentRecord( struct BTreeIterator *btIterator = NULL; FSBufferDescriptor btRecord; OSErr err; - u_int16_t btRecordSize; + u_int16_t btRecordSize = 0; err = noErr; if (foundHint) @@ -348,7 +348,7 @@ static OSErr CreateExtentRecord( { struct BTreeIterator *btIterator = NULL; FSBufferDescriptor btRecord; - u_int16_t btRecordSize; + u_int16_t btRecordSize = 0; int lockflags; OSErr err; @@ -1025,7 +1025,7 @@ OSErr ExtendFileC ( int allowFlushTxns; u_int32_t actualStartBlock; u_int32_t actualNumBlocks; - u_int32_t numExtentsPerRecord; + u_int32_t numExtentsPerRecord = 0; int64_t maximumBytes; int64_t availbytes; int64_t peof; diff --git a/core/VolumeAllocation.c b/core/VolumeAllocation.c index f26811c..fabe691 100644 --- a/core/VolumeAllocation.c +++ b/core/VolumeAllocation.c @@ -160,7 +160,9 @@ Optimization Routines #include #include -#if !HFS_ALLOC_TEST +#if HFS_ALLOC_TEST +#define KERNEL_DEBUG_CONSTANT(x, a, b, c, d, e) do {} while (0) +#else // !HFS_ALLOC_TEST #include "hfs_macos_defs.h" #include diff --git a/core/hfs.h b/core/hfs.h index 786199c..c450aea 100644 --- a/core/hfs.h +++ b/core/hfs.h @@ -1002,7 +1002,6 @@ typedef struct hfs_zone_entry { hfs_zone_kind_t hze_kind; size_t hze_elem_size; const char * hze_name; - boolean_t hze_noencrypt; } hfs_zone_entry_t; typedef struct hfs_zone { diff --git a/core/hfs_catalog.c b/core/hfs_catalog.c index d48a106..1f6765a 100644 --- a/core/hfs_catalog.c +++ b/core/hfs_catalog.c @@ -444,7 +444,7 @@ cat_convertkey( { int std_hfs = HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord; HFSPlusCatalogKey * pluskey = NULL; - u_int32_t encoding; + u_int32_t encoding = 0; cnid_t cnid = 0; int err = 0; @@ -3507,7 +3507,7 @@ cat_getdirentries(struct hfsmount *hfsmp, u_int32_t entrycnt, directoryhint_t *d void * buffer; int bufsize; int maxlinks; - int result; + int result = 0; int index; int have_key; int extended; diff --git a/core/hfs_cnode.c b/core/hfs_cnode.c index 12b126c..ee37f2f 100644 --- a/core/hfs_cnode.c +++ b/core/hfs_cnode.c @@ -64,6 +64,8 @@ static int hfs_isordered(struct cnode *, struct cnode *); extern int hfs_removefile_callback(struct buf *bp, void *hfsmp); +uint32_t _hfs_max_origins = MAX_CACHED_ORIGINS_DEFAULT; +uint32_t _hfs_max_file_origins = MAX_CACHED_FILE_ORIGINS_DEFAULT; __inline__ int hfs_checkdeleted (struct cnode *cp) { return ((cp->c_flag & (C_DELETED | C_NOEXISTS)) ? ENOENT : 0); diff --git a/core/hfs_cnode.h b/core/hfs_cnode.h index 088c445..19ba70d 100644 --- a/core/hfs_cnode.h +++ b/core/hfs_cnode.h @@ -131,8 +131,13 @@ struct linkorigin { }; typedef struct linkorigin linkorigin_t; -#define MAX_CACHED_ORIGINS 10 -#define MAX_CACHED_FILE_ORIGINS 8 +extern uint32_t _hfs_max_origins; +extern uint32_t _hfs_max_file_origins; + +#define MAX_CACHED_ORIGINS_DEFAULT 10 +#define MAX_CACHED_ORIGINS (_hfs_max_origins) +#define MAX_CACHED_FILE_ORIGINS_DEFAULT 8 +#define MAX_CACHED_FILE_ORIGINS (_hfs_max_file_origins) /* * The cnode is used to represent each active (or recently active) diff --git a/core/hfs_cprotect.c b/core/hfs_cprotect.c index 3fa485b..937595b 100644 --- a/core/hfs_cprotect.c +++ b/core/hfs_cprotect.c @@ -74,6 +74,11 @@ void cpkp_init(cp_key_pair_t *cpkp, uint16_t max_pers_key_len, { cpkp->cpkp_max_pers_key_len = max_pers_key_len; cpkp->cpkp_pers_key_len = 0; + + cpx_t embedded_cpx = cpkp_cpx(cpkp); + /* XNU requires us to allocate the AES context separately */ + cpx_alloc_ctx (embedded_cpx); + cpx_init(cpkp_cpx(cpkp), max_cached_key_len); // Default to using offsets @@ -449,7 +454,7 @@ int cp_setup_newentry (struct hfsmount *hfsmp, struct cnode *dcp, */ int cpx_gentempkeys(cpx_t *pcpx, __unused struct hfsmount *hfsmp) { - cpx_t cpx = cpx_alloc(CP_MAX_KEYSIZE); + cpx_t cpx = cpx_alloc(CP_MAX_KEYSIZE, true); cpx_set_key_len(cpx, CP_MAX_KEYSIZE); read_random(cpx_key(cpx), CP_MAX_KEYSIZE); @@ -661,7 +666,7 @@ cp_vnode_setclass(struct vnode *vp, cp_key_class_t newclass) goto out; } - cp_key_pair_t *cpkp; + cp_key_pair_t *cpkp = NULL; cprotect_t new_entry = cp_entry_alloc(NULL, 0, CP_MAX_KEYSIZE, &cpkp); if (!new_entry) { @@ -1570,7 +1575,7 @@ cp_entry_alloc(cprotect_t old, uint16_t pers_key_len, size += 4; // Extra for magic2 #endif - cp_entry = hfs_malloc(size); + cp_entry = hfs_mallocz(size); if (old) { memcpy(cp_entry, old, offsetof(struct cprotect, cp_keys)); @@ -1579,8 +1584,6 @@ cp_entry_alloc(cprotect_t old, uint16_t pers_key_len, // We don't copy the key roll context cp_entry->cp_key_roll_ctx = NULL; #endif - } else { - bzero(cp_entry, offsetof(struct cprotect, cp_keys)); } #if DEBUG @@ -1617,6 +1620,13 @@ cp_entry_dealloc(__unused hfsmount_t *hfsmp, struct cprotect *entry) size_t entry_size = (sizeof(struct cprotect) - sizeof(cp_key_pair_t) + cpkp_sizex(&entry->cp_keys)); + + /* + * We are freeing the HFS cprotect, which contains the memory for 'cpx' + * Don't forget to release the CPX AES context + */ + cpx_t embedded_cpx = cpkp_cpx(&entry->cp_keys); + cpx_free_ctx (embedded_cpx); #if DEBUG hfs_assert(entry->cp_magic1 == cp_magic1); @@ -1665,7 +1675,7 @@ static int cp_read_xattr_v4(__unused hfsmount_t *hfsmp, struct cp_xattr_v4 *xatt } /* set up entry with information from xattr */ - cp_key_pair_t *cpkp; + cp_key_pair_t *cpkp = NULL; cprotect_t entry; if (ISSET(options, CP_GET_XATTR_BASIC_INFO)) { @@ -1753,7 +1763,7 @@ int cp_read_xattr_v5(hfsmount_t *hfsmp, struct cp_xattr_v5 *xattr, } #endif - cp_key_pair_t *cpkp; + cp_key_pair_t *cpkp = NULL; cprotect_t entry; /* diff --git a/core/hfs_fsctl.h b/core/hfs_fsctl.h index 0b89b25..ea397d5 100644 --- a/core/hfs_fsctl.h +++ b/core/hfs_fsctl.h @@ -373,6 +373,9 @@ enum { #define HFSIOC_FORCE_ENABLE_DEFRAG _IOWR('h', 49, u_int32_t) +/* NOTE: fsctl selector 'h' 50 is defined in XNU */ + + /* These fsctls are ported from apfs. */ #ifndef APFSIOC_SET_NEAR_LOW_DISK #define APFSIOC_SET_NEAR_LOW_DISK _IOW('J', 17, u_int32_t) diff --git a/core/hfs_iokit.cpp b/core/hfs_iokit.cpp index 5908364..eb2d703 100644 --- a/core/hfs_iokit.cpp +++ b/core/hfs_iokit.cpp @@ -37,6 +37,7 @@ #include "hfs_iokit.h" #include "hfs.h" #include "hfs_dbg.h" +#include "hfs_cnode.h" #ifndef panic_on_assert bool panic_on_assert; @@ -122,6 +123,18 @@ bool com_apple_filesystems_hfs::start(IOService *provider) hfs_sysctl_register(); + uint32_t num_cpus; + size_t sz = sizeof(num_cpus); + + if (sysctlbyname("hw.physicalcpu", &num_cpus, &sz, NULL, 0) == 0) { + if ((2 * num_cpus) > MAX_CACHED_ORIGINS_DEFAULT) { + _hfs_max_origins = 2 * num_cpus; + _hfs_max_file_origins = 2 * num_cpus; + } else if ((2 * num_cpus) > MAX_CACHED_FILE_ORIGINS_DEFAULT) { + _hfs_max_file_origins = 2 * num_cpus; + } + } + return true; } diff --git a/core/hfs_journal.c b/core/hfs_journal.c index f1e6ee6..6900da5 100644 --- a/core/hfs_journal.c +++ b/core/hfs_journal.c @@ -2916,6 +2916,14 @@ journal_modify_block_end(journal *jnl, struct buf *bp, void (*func)(buf_t bp, vo * corresponding write to the btree. */ task_update_logical_writes(current_task(), (2 * bsize), TASK_WRITE_METADATA, vp); + /* + * Update the physical writes counter for metadata writes. + * We use (2 * bsize) to account for the write to the on-disk journal + * followed by write to actual location later. + */ + task_update_physical_writes(current_task(), TASK_PHYSICAL_WRITE_METADATA, + (2 * bsize), + TASK_BALANCE_CREDIT); if (func) { void (*old_func)(buf_t, void *)=NULL, *old_arg=NULL; @@ -3881,11 +3889,11 @@ end_transaction(transaction *tr, int force_it, errno_t (*callback)(void*), void lock_oldstart(jnl); /* - * Because old_start is locked above, we can cast away the volatile qualifier before passing it to memcpy. + * Because old_start is locked above, we can cast away the volatile qualifier before passing it to memmove. * slide everyone else down and put our latest guy in the last * entry in the old_start array */ - memcpy(__CAST_AWAY_QUALIFIER(&jnl->old_start[0], volatile, void *), __CAST_AWAY_QUALIFIER(&jnl->old_start[1], volatile, void *), sizeof(jnl->old_start)-sizeof(jnl->old_start[0])); + memmove(__CAST_AWAY_QUALIFIER(&jnl->old_start[0], volatile, void *), __CAST_AWAY_QUALIFIER(&jnl->old_start[1], volatile, void *), sizeof(jnl->old_start)-sizeof(jnl->old_start[0])); jnl->old_start[sizeof(jnl->old_start)/sizeof(jnl->old_start[0]) - 1] = tr->journal_start | 0x8000000000000000LL; unlock_oldstart(jnl); diff --git a/core/hfs_readwrite.c b/core/hfs_readwrite.c index 99092aa..d7a070e 100644 --- a/core/hfs_readwrite.c +++ b/core/hfs_readwrite.c @@ -354,7 +354,7 @@ hfs_vnop_write(struct vnop_write_args *ap) off_t filebytes; off_t offset; ssize_t resid; - int eflags; + int eflags = 0; int ioflag = ap->a_ioflag; int retval = 0; int lockflags; @@ -1556,10 +1556,14 @@ hfs_vnop_ioctl( struct vnop_ioctl_args /* { { struct vnode *file_vp; cnid_t cnid; - int outlen; - char *bufptr; int error; int flags = 0; + char *bufptr; +#ifdef VN_GETPATH_NEW + size_t outlen; +#else // VN_GETPATH_NEW + int outlen; +#endif // VN_GETPATH_NEW /* Caller must be owner of file system. */ vfsp = vfs_statfs(HFSTOVFS(hfsmp)); @@ -1579,14 +1583,15 @@ hfs_vnop_ioctl( struct vnop_ioctl_args /* { /* We need to call hfs_vfs_vget to leverage the code that will * fix the origin list for us if needed, as opposed to calling - * hfs_vget, since we will need the parent for build_path call. + * hfs_vget, since we will need the parent for vn_getpath_ext call. */ if ((error = hfs_vfs_vget(HFSTOVFS(hfsmp), cnid, &file_vp, context))) { return (error); } - error = build_path(file_vp, bufptr, sizeof(pathname_t), &outlen, flags, context); + outlen = sizeof(pathname_t); + error = vn_getpath_ext(file_vp, NULLVP, bufptr, &outlen, flags); vnode_put(file_vp); return (error); @@ -5364,7 +5369,7 @@ hfs_relocate(struct vnode *vp, u_int32_t blockHint, kauth_cred_t cred, u_int32_t growsize; u_int32_t nextallocsave; daddr64_t sector_a, sector_b; - int eflags; + int eflags = 0; off_t newbytes; int retval; int lockflags = 0; diff --git a/core/hfs_vfsops.c b/core/hfs_vfsops.c index 6ceab54..2859ac2 100644 --- a/core/hfs_vfsops.c +++ b/core/hfs_vfsops.c @@ -140,7 +140,7 @@ extern struct vnodeopv_desc hfs_std_vnodeop_opv_desc; static int hfs_flushMDB(struct hfsmount *hfsmp, int waitfor, int altflush); #endif -/* not static so we can re-use in hfs_readwrite.c for build_path calls */ +/* not static so we can re-use in hfs_readwrite.c for vn_getpath_ext calls */ int hfs_vfs_vget(struct mount *mp, ino64_t ino, struct vnode **vpp, vfs_context_t context); static int hfs_changefs(struct mount *mp, struct hfs_mount_args *args); @@ -1218,6 +1218,16 @@ hfs_mountfs(struct vnode *devvp, struct mount *mp, struct hfs_mount_args *args, goto error_exit; } + if (phys_blksize < log_blksize) { + /* + * In the off chance that the phys_blksize is SMALLER than the logical + * then don't let that happen. Pretend that the PHYSICALBLOCKSIZE + * ioctl was not supported. + */ + phys_blksize = log_blksize; + } + + /* Switch to 512 byte sectors (temporarily) */ if (log_blksize > 512) { u_int32_t size512 = 512; @@ -1288,6 +1298,7 @@ hfs_mountfs(struct vnode *devvp, struct mount *mp, struct hfs_mount_args *args, goto error_exit; } } + /* * At this point: * minblksize is the minimum physical block size @@ -1296,6 +1307,7 @@ hfs_mountfs(struct vnode *devvp, struct mount *mp, struct hfs_mount_args *args, */ mdb_offset = (daddr64_t)HFS_PRI_SECTOR(log_blksize); + if ((retval = (int)buf_meta_bread(devvp, HFS_PHYSBLK_ROUNDDOWN(mdb_offset, (phys_blksize/log_blksize)), phys_blksize, cred, &bp))) { @@ -3220,7 +3232,7 @@ hfs_sysctl(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp, /* * hfs_vfs_vget is not static since it is used in hfs_readwrite.c to support - * the build_path ioctl. We use it to leverage the code below that updates + * the vn_getpath_ext. We use it to leverage the code below that updates * the origin list cache if necessary */ @@ -4258,17 +4270,36 @@ hfs_vfs_getattr(struct mount *mp, struct vfs_attr *fsap, __unused vfs_context_t } #endif + /* + * Some of these attributes can be expensive to query if we're + * backed by a disk image; hfs_freeblks() has to ask the backing + * store, and this might involve a trip to a network file server. + * Only ask for them if the caller really wants them. Preserve old + * behavior for file systems not backed by a disk image. + */ +#if HFS_SPARSE_DEV + const int diskimage = (hfsmp->hfs_backingvp != NULL); +#else + const int diskimage = 0; +#endif + VFSATTR_RETURN(fsap, f_objcount, (u_int64_t)hfsmp->vcbFilCnt + (u_int64_t)hfsmp->vcbDirCnt); VFSATTR_RETURN(fsap, f_filecount, (u_int64_t)hfsmp->vcbFilCnt); VFSATTR_RETURN(fsap, f_dircount, (u_int64_t)hfsmp->vcbDirCnt); VFSATTR_RETURN(fsap, f_maxobjcount, (u_int64_t)0xFFFFFFFF); VFSATTR_RETURN(fsap, f_iosize, (size_t)cluster_max_io_size(mp, 0)); VFSATTR_RETURN(fsap, f_blocks, (u_int64_t)hfsmp->totalBlocks); - VFSATTR_RETURN(fsap, f_bfree, (u_int64_t)hfs_freeblks(hfsmp, 0)); - VFSATTR_RETURN(fsap, f_bavail, (u_int64_t)hfs_freeblks(hfsmp, 1)); + if (VFSATTR_WANTED(fsap, f_bfree) || !diskimage) { + VFSATTR_RETURN(fsap, f_bfree, (u_int64_t)hfs_freeblks(hfsmp, 0)); + } + if (VFSATTR_WANTED(fsap, f_bavail) || !diskimage) { + VFSATTR_RETURN(fsap, f_bavail, (u_int64_t)hfs_freeblks(hfsmp, 1)); + } VFSATTR_RETURN(fsap, f_bsize, (u_int32_t)vcb->blockSize); /* XXX needs clarification */ - VFSATTR_RETURN(fsap, f_bused, hfsmp->totalBlocks - hfs_freeblks(hfsmp, 1)); + if (VFSATTR_WANTED(fsap, f_bused) || !diskimage) { + VFSATTR_RETURN(fsap, f_bused, hfsmp->totalBlocks - hfs_freeblks(hfsmp, 1)); + } VFSATTR_RETURN(fsap, f_files, (u_int64_t)HFS_MAX_FILES); VFSATTR_RETURN(fsap, f_ffree, (u_int64_t)hfs_free_cnids(hfsmp)); diff --git a/core/hfs_vfsutils.c b/core/hfs_vfsutils.c index fa2d856..6aeac8d 100644 --- a/core/hfs_vfsutils.c +++ b/core/hfs_vfsutils.c @@ -4403,21 +4403,17 @@ void *hfs_mallocz(size_t size) // -- Zone allocator-related structures and routines -- hfs_zone_entry_t hfs_zone_entries[HFS_NUM_ZONES] = { - { HFS_CNODE_ZONE, sizeof(struct cnode), "HFS node", true }, - { HFS_FILEFORK_ZONE, sizeof(struct filefork), "HFS fork", true }, - { HFS_DIRHINT_ZONE, sizeof(struct directoryhint), "HFS dirhint", true } + { HFS_CNODE_ZONE, sizeof(struct cnode), "HFS node" }, + { HFS_FILEFORK_ZONE, sizeof(struct filefork), "HFS fork" }, + { HFS_DIRHINT_ZONE, sizeof(struct directoryhint), "HFS dirhint" } }; hfs_zone_t hfs_zones[HFS_NUM_ZONES]; void hfs_init_zones(void) { for (int i = 0; i < HFS_NUM_ZONES; i++) { - hfs_zones[i].hz_zone = zinit(hfs_zone_entries[i].hze_elem_size, 1024 * 1024, PAGE_SIZE, hfs_zone_entries[i].hze_name); - hfs_zones[i].hz_elem_size = hfs_zone_entries[i].hze_elem_size; - - zone_change(hfs_zones[i].hz_zone, Z_CALLERACCT, false); - if (hfs_zone_entries[i].hze_noencrypt) - zone_change(hfs_zones[i].hz_zone, Z_NOENCRYPT, true); + hfs_zones[i].hz_zone = zone_create(hfs_zone_entries[i].hze_name, + hfs_zone_entries[i].hze_elem_size, ZC_NOENCRYPT); } } diff --git a/core/hfs_vnops.c b/core/hfs_vnops.c index db88785..237f071 100644 --- a/core/hfs_vnops.c +++ b/core/hfs_vnops.c @@ -4672,16 +4672,6 @@ relock: tdcp = VTOC(tdvp); tcp = tvp ? VTOC(tvp) : NULL; - - /* - * If caller requested an exclusive rename (VFS_RENAME_EXCL) and 'tcp' exists - * then we must fail the operation. - */ - if (tcp && rename_exclusive) { - error = EEXIST; - goto out; - } - // // if the item is tracked but doesn't have a document_id, assign one and generate an fsevent for it // @@ -5102,9 +5092,24 @@ relock: struct FndrExtendedDirInfo *tfip = (struct FndrExtendedDirInfo *)((char *)&tcp->c_attr.ca_finderinfo + 16); if (ffip->document_id && tfip->document_id) { - // both documents are tracked. only save a tombstone from tcp and do nothing else. - doc_tombstone_save(tdvp, tvp, tcnp, hfs_get_document_id(tcp), - tcp->c_fileid); + // Both documents are tracked. `tvp` is deleted and `fvp` is + // renamed on top of it. Send FSE_DOCID_CHANGED for both inodes, + // clear tombstone of `old_doc_vp` and save tombstone of `fvp`. + add_fsevent(FSE_DOCID_CHANGED, vfs_context_current(), + FSE_ARG_DEV, hfsmp->hfs_raw_dev, + FSE_ARG_INO, (ino64_t)tcp->c_fileid, // src inode # + FSE_ARG_INO, (ino64_t)0ULL, // dst inode # + FSE_ARG_INT32, (uint32_t)tfip->document_id, + FSE_ARG_DONE); + add_fsevent(FSE_DOCID_CHANGED, vfs_context_current(), + FSE_ARG_DEV, hfsmp->hfs_raw_dev, + FSE_ARG_INO, (ino64_t)fcp->c_fileid, // src inode # + FSE_ARG_INO, (ino64_t)tcp->c_fileid, // dst inode # + FSE_ARG_INT32, (uint32_t)ffip->document_id, + FSE_ARG_DONE); + doc_tombstone_clear(doc_tombstone_get(), &old_doc_vp); + doc_tombstone_save(tdvp, fvp, tcnp, hfs_get_document_id(fcp), + fcp->c_fileid); } else { struct doc_tombstone *ut; ut = doc_tombstone_get(); @@ -5148,9 +5153,16 @@ relock: /* * When fvp matches tvp they could be case variants * or matching hard links. + * If the caller requested an exclusive rename (VFS_RENAME_EXCL), + * we allow rename when the target already exists when the following + * conditions are met: + * 1. the volume is case insensitive + * 2. source and target directories are the same + * 3. source and target files are the same + * 4. name only differs in case */ if (fvp == tvp) { - if (!(fcp->c_flag & C_HARDLINK)) { + if (!rename_exclusive && !(fcp->c_flag & C_HARDLINK)) { /* * If they're not hardlinks, then fvp == tvp must mean we * are using case-insensitive HFS because case-sensitive would @@ -5193,8 +5205,12 @@ relock: * op was dir1/fred -> dir1/bob * That would fail/do nothing. */ + goto skip_rm; /* case-variant hardlink in the same dir */ - } else { + } else if (rename_exclusive) { + error = EEXIST; + goto out; + } else { goto out; /* matching hardlink, nothing to do */ } } @@ -6353,12 +6369,17 @@ hfs_update(struct vnode *vp, int options) if (__builtin_expect(kdebug_enable & KDEBUG_TRACE, 0)) { long dbg_parms[NUMPARMS]; - int dbg_namelen; + int err; +#ifdef VN_GETPATH_NEW + size_t dbg_namelen; +#else // VN_GETPATH_NEW + int dbg_namelen; +#endif // VN_GETPATH_NEW dbg_namelen = NUMPARMS * sizeof(long); - vn_getpath(vp, (char *)dbg_parms, &dbg_namelen); + err = vn_getpath_ext(vp, NULLVP, (char *)dbg_parms, &dbg_namelen, 0); - if (dbg_namelen < (int)sizeof(dbg_parms)) + if (!err && (dbg_namelen < (int)sizeof(dbg_parms))) memset((char *)dbg_parms + dbg_namelen, 0, sizeof(dbg_parms) - dbg_namelen); kdebug_lookup_gen_events(dbg_parms, dbg_namelen, (void *)vp, TRUE); diff --git a/core/hfs_xattr.c b/core/hfs_xattr.c index 0d3dcd3..311b901 100644 --- a/core/hfs_xattr.c +++ b/core/hfs_xattr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2017 Apple Inc. All rights reserved. + * Copyright (c) 2004-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -1080,6 +1080,12 @@ int hfs_setxattr_internal (struct cnode *cp, const void *data_ptr, size_t attrsi /* If it won't fit inline then use extent-based attributes. */ if (attrsize > hfsmp->hfs_max_inline_attrsize) { +#if (TARGET_OS_OSX && TARGET_CPU_ARM64) + printf("hfs_setxattr: non-inline attributes are not supported\n"); + //NOTE: ENOTSUP will fool XNU into thinking we need AppleDouble files... + result = EPERM; + goto exit; +#else int blkcnt; int extentblks; u_int32_t *keystartblk; @@ -1180,6 +1186,7 @@ int hfs_setxattr_internal (struct cnode *cp, const void *data_ptr, size_t attrsi extentblks = count_extent_blocks(blkcnt, recp->overflowExtents.extents); blkcnt -= extentblks; } +#endif //(TARGET_OS_OSX && TARGET_CPU_ARM64) } else { /* Inline data */ if (exists) { result = remove_attribute_records(hfsmp, iterator); @@ -2429,7 +2436,7 @@ read_attr_data(struct hfsmount *hfsmp, uio_t uio, size_t datasize, HFSPlusExtent /* * Write an extent based attribute. */ -static int +__unused static int write_attr_data(struct hfsmount *hfsmp, uio_t uio, size_t datasize, HFSPlusExtentDescriptor *extents) { vnode_t evp = hfsmp->hfs_attrdata_vp; @@ -2479,7 +2486,7 @@ write_attr_data(struct hfsmount *hfsmp, uio_t uio, size_t datasize, HFSPlusExten /* * Allocate blocks for an extent based attribute. */ -static int +__unused static int alloc_attr_blks(struct hfsmount *hfsmp, size_t attrsize, size_t extentbufsize, HFSPlusExtentDescriptor *extents, int *blocks) { int blkcnt; diff --git a/fsck_hfs/cache.c b/fsck_hfs/cache.c index a5ce2b6..26c8a4a 100644 --- a/fsck_hfs/cache.c +++ b/fsck_hfs/cache.c @@ -179,7 +179,7 @@ void CalculateCacheSizes(uint64_t cacheSize, uint32_t *calcBlockSize, uint32_t * } *calcBlockSize = blockSize; - *calcTotalBlocks = cacheSize / blockSize; + *calcTotalBlocks = (uint32_t)(cacheSize / blockSize); out: return; diff --git a/fsck_hfs/dfalib/BTreeAllocate.c b/fsck_hfs/dfalib/BTreeAllocate.c index f85a014..f096887 100644 --- a/fsck_hfs/dfalib/BTreeAllocate.c +++ b/fsck_hfs/dfalib/BTreeAllocate.c @@ -315,7 +315,7 @@ OSStatus ExtendBTree (BTreeControlBlockPtr btreePtr, //////////////////// Calc New Total Number Of Nodes ///////////////////////// - newTotalNodes = filePtr->fcbLogicalSize / nodeSize; //¥¥ hack! + newTotalNodes = (UInt32)(filePtr->fcbLogicalSize / nodeSize); //¥¥ hack! //¥¥ do we wish to perform any verification of newTotalNodes at this point? btreePtr->totalNodes = newTotalNodes; //¥¥ do we need to update freeNodes here too? @@ -534,7 +534,7 @@ UInt32 CalcMapBits (BTreeControlBlockPtr btreePtr) { UInt32 mapBits; - mapBits = M_HeaderMapRecordSize (btreePtr->nodeSize) << 3; + mapBits = (UInt32)(M_HeaderMapRecordSize (btreePtr->nodeSize) << 3); while (mapBits < btreePtr->totalNodes) mapBits += M_MapRecordSize (btreePtr->nodeSize) << 3; diff --git a/fsck_hfs/dfalib/HardLinkCheck.c b/fsck_hfs/dfalib/HardLinkCheck.c index bc1787d..91dde7b 100755 --- a/fsck_hfs/dfalib/HardLinkCheck.c +++ b/fsck_hfs/dfalib/HardLinkCheck.c @@ -802,8 +802,18 @@ RepairHardLinkChains(SGlobPtr gp, Boolean isdir) flags = rec.hfsPlusFolder.flags; li = hash_search(inodeID, slots, slotsUsed, linkInfo); } else { + long ref_num; + inodeID = rec.hfsPlusFile.fileID; - link_ref_num = atol((char*)&filename[prefixlen]); + ref_num = atol((char*)&filename[prefixlen]); + if (ref_num < 0 || ref_num > UINT32_MAX) { + result = EINVAL; + if (fsckGetVerbosity(gp->context) >= kDebugLog) { + plog ("\tLink reference num=%ld is invalid for inode=%u result=%d\n", ref_num, inodeID, result); + } + break; + } + link_ref_num = (UInt32)ref_num; flags = rec.hfsPlusFile.flags; li = hash_search(link_ref_num, slots, slotsUsed, linkInfo); } diff --git a/fsck_hfs/dfalib/SBTree.c b/fsck_hfs/dfalib/SBTree.c index 517cddc..e2e83fe 100644 --- a/fsck_hfs/dfalib/SBTree.c +++ b/fsck_hfs/dfalib/SBTree.c @@ -357,7 +357,7 @@ SetEndOfForkProc ( SFCB *filePtr, FSSize minEOF, FSSize maxEOF ) if ( filePtr->fcbFileID == kHFSRepairCatalogFileID) flags |= kEFNoExtOvflwMask; - result = ExtendFileC ( vcb, filePtr, (bytesToAdd+511)>>9, flags, &actualSectorsAdded ); + result = ExtendFileC ( vcb, filePtr, (UInt32)((bytesToAdd+511)>>9), flags, &actualSectorsAdded ); ReturnIfError(result); filePtr->fcbLogicalSize = filePtr->fcbPhysicalSize; // new B-tree looks at fcbEOF @@ -388,7 +388,7 @@ SetEndOfForkProc ( SFCB *filePtr, FSSize minEOF, FSSize maxEOF ) // Zero newly allocated portion of HFS+ private file. if ( result == noErr ) - result = ZeroFileBlocks( vcb, filePtr, fileSize - actualSectorsAdded, actualSectorsAdded ); + result = ZeroFileBlocks( vcb, filePtr, (UInt32)(fileSize - actualSectorsAdded), actualSectorsAdded ); } } else if ( vcb->vcbSignature == kHFSSigWord ) @@ -399,7 +399,7 @@ SetEndOfForkProc ( SFCB *filePtr, FSSize minEOF, FSSize maxEOF ) MarkVCBDirty( vcb ); result = FlushAlternateVolumeControlBlock( vcb, false ); if ( result == noErr ) - result = ZeroFileBlocks( vcb, filePtr, fileSize - actualSectorsAdded, actualSectorsAdded ); + result = ZeroFileBlocks( vcb, filePtr, (UInt32)(fileSize - actualSectorsAdded), actualSectorsAdded ); } else if ( filePtr->fcbFileID == kHFSCatalogFileID || filePtr->fcbFileID == kHFSRepairCatalogFileID ) { @@ -407,7 +407,7 @@ SetEndOfForkProc ( SFCB *filePtr, FSSize minEOF, FSSize maxEOF ) MarkVCBDirty( vcb ); result = FlushAlternateVolumeControlBlock( vcb, false ); if ( result == noErr ) - result = ZeroFileBlocks( vcb, filePtr, fileSize - actualSectorsAdded, actualSectorsAdded ); + result = ZeroFileBlocks( vcb, filePtr, (UInt32)(fileSize - actualSectorsAdded), actualSectorsAdded ); } } diff --git a/fsck_hfs/dfalib/SDevice.c b/fsck_hfs/dfalib/SDevice.c index c8225a6..67dab52 100644 --- a/fsck_hfs/dfalib/SDevice.c +++ b/fsck_hfs/dfalib/SDevice.c @@ -205,7 +205,7 @@ OSErr DeviceRead(int device, int drive, void* buffer, SInt64 offset, UInt32 reqB return (5); } - *actBytes = nbytes; + *actBytes = (UInt32)nbytes; return (0); #else @@ -258,7 +258,7 @@ OSErr DeviceWrite(int device, int drive, void* buffer, SInt64 offset, UInt32 req return (5); } - *actBytes = nbytes; + *actBytes = (UInt32)nbytes; return (0); #else OSErr err; diff --git a/fsck_hfs/dfalib/SExtents.c b/fsck_hfs/dfalib/SExtents.c index 1297905..cc06d34 100644 --- a/fsck_hfs/dfalib/SExtents.c +++ b/fsck_hfs/dfalib/SExtents.c @@ -495,7 +495,7 @@ OSErr MapFileBlockC ( if (temp > numberOfBytes) *availableBytes = numberOfBytes; // more there than they asked for, so pin the output else - *availableBytes = temp; + *availableBytes = (UInt32)temp; // LogEndTime(kTraceMapFileBlock, noErr); @@ -787,7 +787,7 @@ OSErr ExtendFileC ( // // Determine the physical EOF in allocation blocks // - eofBlocks = fcb->fcbPhysicalSize / vcb->vcbBlockSize; + eofBlocks = (UInt32)(fcb->fcbPhysicalSize / vcb->vcbBlockSize); // // Make sure the request won't make the file too big (>=2GB). @@ -1346,7 +1346,7 @@ static OSErr SearchExtentFile( UInt32 filePositionBlock; Boolean noMoreExtents = true; - filePositionBlock = sectorOffset / (vcb->vcbBlockSize >> kSectorShift); + filePositionBlock = (UInt32)(sectorOffset / (vcb->vcbBlockSize >> kSectorShift)); // Search the resident FCB first. err = GetFCBExtentRecord(vcb, fcb, foundExtentData); @@ -1603,7 +1603,7 @@ static OSErr MapFileBlockFromFCB( UInt32 index; UInt32 offsetBlocks; - offsetBlocks = sectorOffset / (vcb->vcbBlockSize >> kSectorShift); + offsetBlocks = (UInt32)(sectorOffset / (vcb->vcbBlockSize >> kSectorShift)); if (vcb->vcbSignature == kHFSSigWord) { const HFSExtentDescriptor *extent; diff --git a/fsck_hfs/dfalib/SRebuildBTree.c b/fsck_hfs/dfalib/SRebuildBTree.c index 9951168..c92ad81 100755 --- a/fsck_hfs/dfalib/SRebuildBTree.c +++ b/fsck_hfs/dfalib/SRebuildBTree.c @@ -474,7 +474,7 @@ ExitThisRoutine: SFCB * myFCBPtr, * oldFCBPtr; UInt32 myBytesUsed = 0; UInt32 myMapNodeCount; - UInt64 myNumBlocks; + UInt32 myNumBlocks; FSSize myNewEOF; BTHeaderRec myHeaderRec; @@ -532,7 +532,7 @@ ExitThisRoutine: myErr = BlockFindAll( myBTreeCBPtr->fcbPtr, myNumBlocks); ReturnIfError( myErr ); myBTreeCBPtr->fcbPtr->fcbPhysicalSize = myNewEOF; - myErr = ZeroFileBlocks( myVCBPtr, myBTreeCBPtr->fcbPtr, 0, myNewEOF >> kSectorShift ); + myErr = ZeroFileBlocks( myVCBPtr, myBTreeCBPtr->fcbPtr, 0, (UInt32)(myNewEOF >> kSectorShift) ); ReturnIfError( myErr ); /* now set real values in our BTree Control Block */ @@ -544,7 +544,7 @@ ExitThisRoutine: else if (FileID == kHFSExtentsFileID) myFCBPtr->fcbClumpSize = myVCBPtr->vcbExtentsFile->fcbClumpSize; - myBTreeCBPtr->totalNodes = ( myFCBPtr->fcbPhysicalSize / myBTreeCBPtr->nodeSize ); + myBTreeCBPtr->totalNodes = (UInt32)( myFCBPtr->fcbPhysicalSize / myBTreeCBPtr->nodeSize ); myBTreeCBPtr->freeNodes = myBTreeCBPtr->totalNodes; // Initialize our new BTree (write out header node and an empty leaf node) diff --git a/fsck_hfs/dfalib/SRepair.c b/fsck_hfs/dfalib/SRepair.c index f1d32cd..65cc03a 100644 --- a/fsck_hfs/dfalib/SRepair.c +++ b/fsck_hfs/dfalib/SRepair.c @@ -877,7 +877,7 @@ OSErr FixBadLinkChainFirst(SGlobPtr GPtr, RepairOrderPtr p) (void)snprintf((char*)&attrRec->attrData[0], sizeof(attrdata) - offsetof(HFSPlusAttrData, attrData), "%lu", (unsigned long)(p->correct)); - attrRec->attrSize = 1 + strlen((char*)&attrRec->attrData[0]); + attrRec->attrSize = (u_int32_t)(1 + strlen((char*)&attrRec->attrData[0])); bt_data.bufferAddress = attrRec; recsize = sizeof(HFSPlusAttrData) - 2 + attrRec->attrSize + ((attrRec->attrSize & 1) ? 1 : 0); bt_data.itemSize = recsize; @@ -941,7 +941,7 @@ OSErr FixHardLinkBadDate(SGlobPtr GPtr, RepairOrderPtr p) if (rec.recordType != kHFSPlusFileRecord) { retval = IntError(GPtr, R_IntErr); } else { - rec.hfsPlusFile.createDate = p->correct; + rec.hfsPlusFile.createDate = (u_int32_t)p->correct; retval = ReplaceBTreeRecord(GPtr->calculatedCatalogFCB, &key, kNoHint, &rec, recsize, &hint); } } @@ -1298,7 +1298,7 @@ OSErr UpdFolderCount( SGlobPtr GPtr, RepairOrderPtr p) } #endif - record.hfsPlusFolder.folderCount = p->correct; + record.hfsPlusFolder.folderCount = (u_int32_t)p->correct; result = ReplaceBTreeRecord( GPtr->calculatedCatalogFCB, &foundKey, hint, &record, recSize, &hint); if (result) { @@ -2879,7 +2879,7 @@ static OSErr FixBadExtent(SGlobPtr GPtr, RepairOrderPtr p) Boolean didRepair; fileID = p->parid; - badExtentIndex = p->correct; + badExtentIndex = (UInt32)p->correct; extentStartBlock = p->hint; forkType = p->forkType; @@ -4036,7 +4036,7 @@ Output: <0 if *a < *b int cmpLongs ( const void *a, const void *b ) { - return( *(long*)a - *(long*)b ); + return (int)( *(long*)a - *(long*)b ); } /* Function: FixOverlappingExtents @@ -5142,7 +5142,7 @@ OSErr GetSystemFileName(UInt32 fileID, char *filename, unsigned int *filenamelen break; }; filename[len] = '\0'; - *filenamelen = strlen (filename); + *filenamelen = (unsigned int)strlen (filename); } return err; } @@ -5284,7 +5284,7 @@ OSErr GetFileNamePathByID(SGlobPtr GPtr, UInt32 fileID, char *fullPath, unsigned } /* Do not NULL terminate the string */ - curPtr->namelen = namelen; + curPtr->namelen = (unsigned int)namelen; curPtr->name = malloc(namelen); if (!curPtr->name) { err = memFullErr; @@ -5581,7 +5581,7 @@ FixMissingDirectory( SGlob *GPtr, UInt32 theObjID, UInt32 theParID ) // no way to find the original name and this should make it unique within our // lost+found directory. sprintf( myString, "%ld", (long)theObjID ); - nameLen = strlen( myString ); + nameLen = (int)strlen( myString ); if ( isHFSPlus ) { @@ -5927,7 +5927,7 @@ UInt32 CreateDirByName(SGlob *GPtr , const u_char *dirName, const UInt32 parentI isHFSPlus = VolumeObjectIsHFSPlus( ); fcbPtr = GPtr->calculatedCatalogFCB; - nameLen = strlen( (char *)dirName ); + nameLen = (int)strlen( (char *)dirName ); if ( isHFSPlus ) { diff --git a/fsck_hfs/dfalib/SStubs.c b/fsck_hfs/dfalib/SStubs.c index 23b4ea7..0223f5e 100644 --- a/fsck_hfs/dfalib/SStubs.c +++ b/fsck_hfs/dfalib/SStubs.c @@ -51,7 +51,8 @@ UInt32 GetTimeUTC(void) (void) gettimeofday(&time, &zone); - return time.tv_sec + MAC_GMT_FACTOR; + // Value will be bigger than UIN32_MAX in 2040 + return (UInt32)(time.tv_sec + MAC_GMT_FACTOR); } /* diff --git a/fsck_hfs/dfalib/SUtils.c b/fsck_hfs/dfalib/SUtils.c index 9c66059..9615453 100644 --- a/fsck_hfs/dfalib/SUtils.c +++ b/fsck_hfs/dfalib/SUtils.c @@ -1642,7 +1642,7 @@ DumpData(const void *data, size_t len, char *label) if (*tmp) allzeroes = 0; } - for (i = gap; i >= 0; i--) { + for (i = (int)gap; i >= 0; i--) { fprintf(stderr, " "); if (i % 2 == 1) fprintf(stderr, " "); @@ -2308,17 +2308,17 @@ OSErr FlushVolumeControlBlock( SVCB *vcb ) fcb = vcb->vcbExtentsFile; CopyMemory( fcb->fcbExtents32, volumeHeader->extentsFile.extents, sizeof(HFSPlusExtentRecord) ); volumeHeader->extentsFile.logicalSize = fcb->fcbLogicalSize; - volumeHeader->extentsFile.totalBlocks = fcb->fcbPhysicalSize / vcb->vcbBlockSize; + volumeHeader->extentsFile.totalBlocks = (u_int32_t)(fcb->fcbPhysicalSize / vcb->vcbBlockSize); fcb = vcb->vcbCatalogFile; CopyMemory( fcb->fcbExtents32, volumeHeader->catalogFile.extents, sizeof(HFSPlusExtentRecord) ); volumeHeader->catalogFile.logicalSize = fcb->fcbLogicalSize; - volumeHeader->catalogFile.totalBlocks = fcb->fcbPhysicalSize / vcb->vcbBlockSize; + volumeHeader->catalogFile.totalBlocks = (u_int32_t)(fcb->fcbPhysicalSize / vcb->vcbBlockSize); fcb = vcb->vcbAllocationFile; CopyMemory( fcb->fcbExtents32, volumeHeader->allocationFile.extents, sizeof(HFSPlusExtentRecord) ); volumeHeader->allocationFile.logicalSize = fcb->fcbLogicalSize; - volumeHeader->allocationFile.totalBlocks = fcb->fcbPhysicalSize / vcb->vcbBlockSize; + volumeHeader->allocationFile.totalBlocks = (u_int32_t)(fcb->fcbPhysicalSize / vcb->vcbBlockSize); if (vcb->vcbAttributesFile != NULL) // Only update fields if an attributes file existed and was open { @@ -2326,7 +2326,7 @@ OSErr FlushVolumeControlBlock( SVCB *vcb ) CopyMemory( fcb->fcbExtents32, volumeHeader->attributesFile.extents, sizeof(HFSPlusExtentRecord) ); volumeHeader->attributesFile.logicalSize = fcb->fcbLogicalSize; volumeHeader->attributesFile.clumpSize = fcb->fcbClumpSize; - volumeHeader->attributesFile.totalBlocks = fcb->fcbPhysicalSize / vcb->vcbBlockSize; + volumeHeader->attributesFile.totalBlocks = (u_int32_t)(fcb->fcbPhysicalSize / vcb->vcbBlockSize); } } else diff --git a/fsck_hfs/dfalib/SVerify1.c b/fsck_hfs/dfalib/SVerify1.c index 7ccbafd..cb81689 100644 --- a/fsck_hfs/dfalib/SVerify1.c +++ b/fsck_hfs/dfalib/SVerify1.c @@ -259,7 +259,7 @@ GetJournalInfoBlock(SGlobPtr GPtr, JournalInfoBlock *jibp, UInt32 *bsizep) if (jibp) memcpy(jibp, block, sizeof(JournalInfoBlock)); if (bsizep) - *bsizep = blockSize; + *bsizep = (UInt32)blockSize; result = 0; } else { if (debug) { @@ -602,6 +602,7 @@ OSErr IVChk( SGlobPtr GPtr ) OSErr err; HFSMasterDirectoryBlock * myMDBPtr; HFSPlusVolumeHeader * myVHBPtr; + UInt64 numBlk; UInt32 numABlks; UInt32 minABlkSz; UInt32 maxNumberOfAllocationBlocks; @@ -721,7 +722,7 @@ OSErr IVChk( SGlobPtr GPtr ) // catch the case where the volume allocation block count is greater than // maximum number of device allocation blocks. - bug 2916021 - numABlks = myVOPtr->totalDeviceSectors / ( myVHBPtr->blockSize / Blk_Size ); + numABlks = (UInt32)(myVOPtr->totalDeviceSectors / ( myVHBPtr->blockSize / Blk_Size )); if ( myVHBPtr->totalBlocks > numABlks ) { RcdError( GPtr, E_NABlks ); err = E_NABlks; @@ -753,16 +754,17 @@ OSErr IVChk( SGlobPtr GPtr ) // verify volume allocation info // Note: i is the number of sectors per allocation block - numABlks = totalSectors; + numBlk = totalSectors; minABlkSz = Blk_Size; // init minimum ablock size // loop while #ablocks won't fit - for( i = 2; numABlks > maxNumberOfAllocationBlocks; i++ ) { + for( i = 2; numBlk > maxNumberOfAllocationBlocks; i++ ) { minABlkSz = i * Blk_Size; // jack up minimum - numABlks = totalSectors / i; // recompute #ablocks, assuming this size + numBlk = totalSectors / i; // recompute #ablocks, assuming this size } + numABlks = (UInt32)numBlk; vcb->vcbBlockSize = realAllocationBlockSize; - numABlks = totalSectors / ( realAllocationBlockSize / Blk_Size ); + numABlks = (UInt32)(totalSectors / ( realAllocationBlockSize / Blk_Size )); if ( VolumeObjectIsHFSPlus( ) ) { // HFS Plus allocation block size must be power of 2 if ( (realAllocationBlockSize < minABlkSz) || @@ -794,7 +796,7 @@ OSErr IVChk( SGlobPtr GPtr ) bitMapSizeInSectors = ( numABlks + kBitsPerSector - 1 ) / kBitsPerSector; // VBM size in blocks //¥¥ Calculate the validaty of HFS Allocation blocks, I think realTotalBlocks == numABlks - numABlks = (totalSectors - 3 - bitMapSizeInSectors) / (realAllocationBlockSize / Blk_Size); // actual # of alloc blks + numABlks = (UInt32)((totalSectors - 3 - bitMapSizeInSectors) / (realAllocationBlockSize / Blk_Size)); // actual # of alloc blks if ( realTotalBlocks > numABlks ) { RcdError( GPtr, E_NABlks ); @@ -1075,7 +1077,7 @@ OSErr CreateExtentsBTreeControlBlock( SGlobPtr GPtr ) btcb->lastLeafNode = header.lastLeafNode; btcb->nodeSize = header.nodeSize; - btcb->totalNodes = ( GPtr->calculatedExtentsFCB->fcbPhysicalSize / btcb->nodeSize ); + btcb->totalNodes = (UInt32)( GPtr->calculatedExtentsFCB->fcbPhysicalSize / btcb->nodeSize ); btcb->freeNodes = btcb->totalNodes; // start with everything free // Make sure the header nodes size field is correct by looking at the 1st record offset @@ -1083,7 +1085,7 @@ OSErr CreateExtentsBTreeControlBlock( SGlobPtr GPtr ) if ( (err != noErr) && (btcb->nodeSize != 1024) ) // default HFS+ Extents node size is 1024 { btcb->nodeSize = 1024; - btcb->totalNodes = ( GPtr->calculatedExtentsFCB->fcbPhysicalSize / btcb->nodeSize ); + btcb->totalNodes = (UInt32)( GPtr->calculatedExtentsFCB->fcbPhysicalSize / btcb->nodeSize ); btcb->freeNodes = btcb->totalNodes; // start with everything free err = CheckNodesFirstOffset( GPtr, btcb ); @@ -1136,7 +1138,7 @@ OSErr CreateExtentsBTreeControlBlock( SGlobPtr GPtr ) btcb->lastLeafNode = header.lastLeafNode; btcb->nodeSize = header.nodeSize; - btcb->totalNodes = (GPtr->calculatedExtentsFCB->fcbPhysicalSize / btcb->nodeSize ); + btcb->totalNodes = (UInt32)(GPtr->calculatedExtentsFCB->fcbPhysicalSize / btcb->nodeSize ); btcb->freeNodes = btcb->totalNodes; // start with everything free // Make sure the header nodes size field is correct by looking at the 1st record offset @@ -1429,7 +1431,7 @@ OSErr CreateCatalogBTreeControlBlock( SGlobPtr GPtr ) btcb->keyCompareType = header.keyCompareType; btcb->leafRecords = header.leafRecords; btcb->nodeSize = header.nodeSize; - btcb->totalNodes = ( GPtr->calculatedCatalogFCB->fcbPhysicalSize / btcb->nodeSize ); + btcb->totalNodes = (UInt32)( GPtr->calculatedCatalogFCB->fcbPhysicalSize / btcb->nodeSize ); btcb->freeNodes = btcb->totalNodes; // start with everything free btcb->attributes |=(kBTBigKeysMask + kBTVariableIndexKeysMask); // HFS+ Catalog files have large, variable-sized keys @@ -1444,7 +1446,7 @@ OSErr CreateCatalogBTreeControlBlock( SGlobPtr GPtr ) if ( (err != noErr) && (btcb->nodeSize != 4096) ) // default HFS+ Catalog node size is 4096 { btcb->nodeSize = 4096; - btcb->totalNodes = ( GPtr->calculatedCatalogFCB->fcbPhysicalSize / btcb->nodeSize ); + btcb->totalNodes = (UInt32)( GPtr->calculatedCatalogFCB->fcbPhysicalSize / btcb->nodeSize ); btcb->freeNodes = btcb->totalNodes; // start with everything free err = CheckNodesFirstOffset( GPtr, btcb ); @@ -1489,7 +1491,7 @@ OSErr CreateCatalogBTreeControlBlock( SGlobPtr GPtr ) btcb->keyCompareProc = (void *) CompareCatalogKeys; btcb->leafRecords = header.leafRecords; btcb->nodeSize = header.nodeSize; - btcb->totalNodes = (GPtr->calculatedCatalogFCB->fcbPhysicalSize / btcb->nodeSize ); + btcb->totalNodes = (UInt32)(GPtr->calculatedCatalogFCB->fcbPhysicalSize / btcb->nodeSize ); btcb->freeNodes = btcb->totalNodes; // start with everything free btcb->treeDepth = header.treeDepth; @@ -2129,7 +2131,7 @@ OSErr CreateAttributesBTreeControlBlock( SGlobPtr GPtr ) btcb->keyCompareProc = (void *)CompareAttributeKeys; btcb->leafRecords = header.leafRecords; btcb->nodeSize = header.nodeSize; - btcb->totalNodes = ( GPtr->calculatedAttributesFCB->fcbPhysicalSize / btcb->nodeSize ); + btcb->totalNodes = (UInt32)( GPtr->calculatedAttributesFCB->fcbPhysicalSize / btcb->nodeSize ); btcb->freeNodes = btcb->totalNodes; // start with everything free btcb->attributes |=(kBTBigKeysMask + kBTVariableIndexKeysMask); // HFS+ Attributes files have large, variable-sized keys diff --git a/fsck_hfs/dfalib/VolumeBitmapCheck.c b/fsck_hfs/dfalib/VolumeBitmapCheck.c index 4372336..dde1d92 100644 --- a/fsck_hfs/dfalib/VolumeBitmapCheck.c +++ b/fsck_hfs/dfalib/VolumeBitmapCheck.c @@ -706,7 +706,7 @@ int CheckVolumeBitMap(SGlobPtr g, Boolean repair) * them against the on-disk bitmap. */ for (bit = 0; bit < gTotalBits; bit += kBitsPerSegment) { - (void) GetSegmentBitmap(bit, &buffer, kTestingBits); + (void) GetSegmentBitmap((UInt32)bit, &buffer, kTestingBits); /* * When we cross file block boundries read a new block from disk. diff --git a/fsck_hfs/dfalib/dirhardlink.c b/fsck_hfs/dfalib/dirhardlink.c index ed1b0ed..8b6831a 100644 --- a/fsck_hfs/dfalib/dirhardlink.c +++ b/fsck_hfs/dfalib/dirhardlink.c @@ -464,6 +464,8 @@ int get_first_link_id(SGlobPtr gptr, CatalogRecord *inode_rec, uint32_t inode_id retval = BTSearchRecord(gptr->calculatedAttributesFCB, &iterator, kNoHint, &bt_data, NULL, NULL); if (retval == 0) { + unsigned long link_id; + /* Attribute should be an inline attribute */ if (rec->recordType != kHFSPlusAttrInlineData) { if (fsckGetVerbosity(gptr->context) >= kDebugLog) { @@ -495,7 +497,16 @@ int get_first_link_id(SGlobPtr gptr, CatalogRecord *inode_rec, uint32_t inode_id } } - *first_link_id = strtoul((char *)&rec->attrData[0], NULL, 10); + link_id = strtoul((char *)&rec->attrData[0], NULL, 10); + if (link_id > UINT32_MAX) { + if (fsckGetVerbosity(gptr->context) >= kDebugLog) { + plog ("\tfirst link ID=%lu is > UINT32_MAX for dirinode=%u\n", link_id, inode_id); + } + *first_link_id = 0; + retval = ENOENT; + goto out; + } + *first_link_id = (uint32_t)link_id; if (*first_link_id < kHFSFirstUserCatalogNodeID) { if (fsckGetVerbosity(gptr->context) >= kDebugLog) { plog ("\tfirst link ID=%u is < 16 for dirinode=%u\n", *first_link_id, inode_id); @@ -612,11 +623,21 @@ int inode_check(SGlobPtr gptr, PrimeBuckets *bucket, linkCount = rec->hfsPlusFolder.bsdInfo.special.linkCount; parentid = gptr->dirlink_priv_dir_id; } else { + unsigned long ref_num; + inode_id = rec->hfsPlusFile.fileID; flags = rec->hfsPlusFile.flags; linkCount = rec->hfsPlusFile.bsdInfo.special.linkCount; parentid = gptr->filelink_priv_dir_id; - link_ref_num = strtoul(&found_name[strlen(HFS_INODE_PREFIX)], NULL, 10); + ref_num = strtoul(&found_name[strlen(HFS_INODE_PREFIX)], NULL, 10); + if (ref_num > UINT32_MAX) { + if (fsckGetVerbosity(gptr->context) >= kDebugLog) { + plog ("\tlink reference num=%lu is > UINT32_MAX for inode=%u\n", ref_num, inode_id); + } + retval = 1; + goto out; + } + link_ref_num = (uint32_t)ref_num; } /* inode should only reside in its corresponding private directory */ diff --git a/fsck_hfs/dfalib/fsck_journal.c b/fsck_hfs/dfalib/fsck_journal.c index d144106..8c76d5f 100644 --- a/fsck_hfs/dfalib/fsck_journal.c +++ b/fsck_hfs/dfalib/fsck_journal.c @@ -387,7 +387,7 @@ journal_open(int jfd, uint32_t jBlkSize = 0; if (ioctl(jfd, DKIOCGETBLOCKSIZE, &jBlkSize) == -1) { - jBlkSize = min_fs_blksize; + jBlkSize = (uint32_t)min_fs_blksize; } else { if (jBlkSize < min_fs_blksize) { fplog(stderr, "%s: journal block size %u < min block size %zu for %s\n", __FUNCTION__, jBlkSize, min_fs_blksize, jdev_name); diff --git a/fsck_hfs/dfalib/hfs_endian.c b/fsck_hfs/dfalib/hfs_endian.c index 8fdd66d..38fe64c 100755 --- a/fsck_hfs/dfalib/hfs_endian.c +++ b/fsck_hfs/dfalib/hfs_endian.c @@ -577,7 +577,7 @@ hfs_swap_HFSPlusBTInternalNode ( srcKey->nodeName.length*sizeof(srcKey->nodeName.unicode[0])); if (cur_debug_level & d_dump_record) { plog("Record %u (offset 0x%04X):\n", recordIndex, keyOffset); - HexDump(srcKey, recordSize, FALSE); + HexDump(srcKey, (unsigned)recordSize, FALSE); } } WriteError(fcb->fcbVolume->vcbGPtr, E_KeyLen, fcb->fcbFileID, src->blockNum); diff --git a/fsck_hfs/fsck_hfs.c b/fsck_hfs/fsck_hfs.c index 35d386c..49259b4 100644 --- a/fsck_hfs/fsck_hfs.c +++ b/fsck_hfs/fsck_hfs.c @@ -126,6 +126,7 @@ main(argc, argv) extern int optind; extern char *optarg; char * lastChar; + long mode; if ((progname = strrchr(*argv, '/'))) ++progname; @@ -219,10 +220,11 @@ main(argc, argv) case 'm': modeSetting++; - lostAndFoundMode = strtol( optarg, NULL, 8 ); - if ( lostAndFoundMode == 0 ) + mode = strtol( optarg, NULL, 8 ); + lostAndFoundMode = (int)mode; + if ( lostAndFoundMode == 0 || mode < INT_MIN || mode > INT_MAX) { - (void) fplog(stderr, "%s: invalid mode argument \n", progname); + (void) fplog(stderr, "%s: %ld is invalid mode argument\n", progname, mode); usage(); } break; @@ -705,7 +707,7 @@ setup( char *dev, int *canWritePtr ) err(1, "fsck_hfs: fstat %s", dev); } - error = lseek(fswritefd, 0, SEEK_SET); + error = (int)lseek(fswritefd, 0, SEEK_SET); if (error == -1) { err(1, "fsck_hfs: Could not seek %d for dev: %s, errorno %d", fswritefd, dev, errno); diff --git a/fsck_hfs/utilities.c b/fsck_hfs/utilities.c index e0c31aa..878ad6c 100644 --- a/fsck_hfs/utilities.c +++ b/fsck_hfs/utilities.c @@ -332,7 +332,7 @@ fsck_logging_thread(void *arg) } } - copy_amt = (cur_in_mem_log - in_mem_log); + copy_amt = (int)(cur_in_mem_log - in_mem_log); if (copy_amt == 0) { pthread_mutex_unlock(&mem_buf_lock); continue; @@ -399,7 +399,7 @@ fsck_printing_thread(void *arg) } } - copy_amt = (cur_in_mem_out - in_mem_out); + copy_amt = (int)(cur_in_mem_out - in_mem_out); if (copy_amt == 0) { pthread_mutex_unlock(&mem_buf_lock); continue; diff --git a/hfs.xcodeproj/project.pbxproj b/hfs.xcodeproj/project.pbxproj index ace6a65..f699857 100644 --- a/hfs.xcodeproj/project.pbxproj +++ b/hfs.xcodeproj/project.pbxproj @@ -24,7 +24,6 @@ buildPhases = ( ); dependencies = ( - FBA540011B7BF2DF00899E5B /* PBXTargetDependency */, FBC234C41B4EC6AE0002D849 /* PBXTargetDependency */, 4DBD523F1548A499007AA736 /* PBXTargetDependency */, 4DBD52411548A49A007AA736 /* PBXTargetDependency */, @@ -72,6 +71,8 @@ buildPhases = ( ); dependencies = ( + A6873BA1234287A00045680B /* PBXTargetDependency */, + A6873B9A234280440045680B /* PBXTargetDependency */, 9430FE98211658E7009CC8AF /* PBXTargetDependency */, ); name = hfs_livefiles; @@ -281,7 +282,6 @@ 900BDEFD1FF9246F002F7EC0 /* lf_hfs_logger.h in Headers */ = {isa = PBXBuildFile; fileRef = 900BDEFB1FF9246F002F7EC0 /* lf_hfs_logger.h */; }; 900BDEFE1FF9246F002F7EC0 /* lf_hfs_logger.c in Sources */ = {isa = PBXBuildFile; fileRef = 900BDEFC1FF9246F002F7EC0 /* lf_hfs_logger.c */; }; 9022D170205EC16900D9A2AE /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9022D16F205EC16900D9A2AE /* CoreFoundation.framework */; }; - 9022D171205EC18500D9A2AE /* livefiles_hfs.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 900BDED41FF919C2002F7EC0 /* livefiles_hfs.dylib */; }; 9022D174205FE5FA00D9A2AE /* lf_hfs_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 9022D172205FE5FA00D9A2AE /* lf_hfs_utils.h */; }; 9022D175205FE5FA00D9A2AE /* lf_hfs_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 9022D173205FE5FA00D9A2AE /* lf_hfs_utils.c */; }; 9022D18120600D9E00D9A2AE /* lf_hfs_rangelist.h in Headers */ = {isa = PBXBuildFile; fileRef = 9022D17F20600D9E00D9A2AE /* lf_hfs_rangelist.h */; }; @@ -312,6 +312,22 @@ 90F5EBBB2063CC3A004397B2 /* lf_hfs_btree_node_ops.c in Sources */ = {isa = PBXBuildFile; fileRef = 90F5EBBA2063CC3A004397B2 /* lf_hfs_btree_node_ops.c */; }; 90F5EBBF2063CCE0004397B2 /* lf_hfs_btree_misc_ops.c in Sources */ = {isa = PBXBuildFile; fileRef = 90F5EBBD2063CCE0004397B2 /* lf_hfs_btree_misc_ops.c */; }; 90F5EBC12063CE12004397B2 /* lf_hfs_btree_allocate.c in Sources */ = {isa = PBXBuildFile; fileRef = 90F5EBC02063CE12004397B2 /* lf_hfs_btree_allocate.c */; }; + A64B3BE822E8D388009A2B10 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9022D16F205EC16900D9A2AE /* CoreFoundation.framework */; }; + A64B3BF522E8D4D6009A2B10 /* lf_cs_logging.h in Headers */ = {isa = PBXBuildFile; fileRef = A64B3BF322E8D4D6009A2B10 /* lf_cs_logging.h */; }; + A64B3BF722E8D4D6009A2B10 /* lf_cs_logging.c in Sources */ = {isa = PBXBuildFile; fileRef = A64B3BF422E8D4D6009A2B10 /* lf_cs_logging.c */; }; + A64B3BFB22E8D538009A2B10 /* lf_cs_checksum.h in Headers */ = {isa = PBXBuildFile; fileRef = A64B3BF922E8D538009A2B10 /* lf_cs_checksum.h */; }; + A64B3BFC22E8D538009A2B10 /* lf_cs_checksum.c in Sources */ = {isa = PBXBuildFile; fileRef = A64B3BFA22E8D538009A2B10 /* lf_cs_checksum.c */; }; + A64B3C0122E8D6A7009A2B10 /* livefiles_cs_tester.c in Sources */ = {isa = PBXBuildFile; fileRef = A64B3C0022E8D6A7009A2B10 /* livefiles_cs_tester.c */; }; + A64B3C0622E8D71B009A2B10 /* lf_cs_vfsops.c in Sources */ = {isa = PBXBuildFile; fileRef = A64B3C0422E8D71B009A2B10 /* lf_cs_vfsops.c */; }; + A64B3C0922E8D9D0009A2B10 /* livefiles_hfs.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 900BDED41FF919C2002F7EC0 /* livefiles_hfs.dylib */; }; + A64B3C0A22E8D9D0009A2B10 /* livefiles_hfs.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 900BDED41FF919C2002F7EC0 /* livefiles_hfs.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + A64B3C1522E91B50009A2B10 /* test-lf-cs-plugin.c in Sources */ = {isa = PBXBuildFile; fileRef = A64B3C1322E91AF6009A2B10 /* test-lf-cs-plugin.c */; }; + A64B3C1722EA2C4F009A2B10 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A64B3C1622EA2C4E009A2B10 /* CoreFoundation.framework */; }; + A64B3C1922EA2C5E009A2B10 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A64B3C1822EA2C5E009A2B10 /* IOKit.framework */; }; + A6873B9B234286730045680B /* lf_cs_logging.c in Sources */ = {isa = PBXBuildFile; fileRef = A64B3BF422E8D4D6009A2B10 /* lf_cs_logging.c */; }; + A6873B9C234286780045680B /* lf_cs_checksum.c in Sources */ = {isa = PBXBuildFile; fileRef = A64B3BFA22E8D538009A2B10 /* lf_cs_checksum.c */; }; + A6873B9D2342868D0045680B /* lf_cs_vfsops.c in Sources */ = {isa = PBXBuildFile; fileRef = A64B3C0422E8D71B009A2B10 /* lf_cs_vfsops.c */; }; + A6873B9F234287200045680B /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A6873B9E234287200045680B /* IOKit.framework */; }; A6E6D74020909C72002125B0 /* test-get-volume-create-time.c in Sources */ = {isa = PBXBuildFile; fileRef = A6E6D73F20909C72002125B0 /* test-get-volume-create-time.c */; }; C1B6FA0810CC0A0A00778D48 /* hfsutil_jnl.c in Sources */ = {isa = PBXBuildFile; fileRef = C1B6FA0610CC0A0A00778D48 /* hfsutil_jnl.c */; }; C1B6FA0910CC0A0A00778D48 /* hfsutil_main.c in Sources */ = {isa = PBXBuildFile; fileRef = C1B6FA0710CC0A0A00778D48 /* hfsutil_main.c */; }; @@ -431,7 +447,6 @@ FB48E5121BB3853500523121 /* hfs_fsctl.h in Headers */ = {isa = PBXBuildFile; fileRef = FB20E10C1AE9529400CEBE7B /* hfs_fsctl.h */; settings = {ATTRIBUTES = (Private, ); }; }; FB55AE541B7C271000701D03 /* test-doc-tombstone.c in Sources */ = {isa = PBXBuildFile; fileRef = FB55AE521B7C271000701D03 /* test-doc-tombstone.c */; }; FB55AE591B7CEB0600701D03 /* test-quotas.c in Sources */ = {isa = PBXBuildFile; fileRef = FB55AE581B7CEB0600701D03 /* test-quotas.c */; }; - FB6A57E51B5554DE008AB046 /* hfs_fsctl.h in Headers */ = {isa = PBXBuildFile; fileRef = FB20E10C1AE9529400CEBE7B /* hfs_fsctl.h */; settings = {ATTRIBUTES = (Private, ); }; }; FB75A4061B4AEA20004B5A74 /* hfs_encodings.c in Sources */ = {isa = PBXBuildFile; fileRef = FB20E1051AE9529400CEBE7B /* hfs_encodings.c */; }; FB75A40B1B4AF025004B5A74 /* hfs_encodings.h in Headers */ = {isa = PBXBuildFile; fileRef = FB20E1061AE9529400CEBE7B /* hfs_encodings.h */; settings = {ATTRIBUTES = (Private, ); }; }; FB75A40E1B4AF0BE004B5A74 /* hfs_encodings_kext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FB75A40C1B4AF0BA004B5A74 /* hfs_encodings_kext.cpp */; }; @@ -556,20 +571,34 @@ remoteGlobalIDString = 4DFD94BC15373C2C0039B6BA; remoteInfo = fsck_makestrings; }; - 900BDEE51FF919E7002F7EC0 /* PBXContainerItemProxy */ = { + 9430FE97211658E7009CC8AF /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 900BDED31FF919C2002F7EC0; remoteInfo = livefiles_hfs; }; - 9430FE97211658E7009CC8AF /* PBXContainerItemProxy */ = { + A64B3C0B22E8D9D0009A2B10 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 900BDED31FF919C2002F7EC0; remoteInfo = livefiles_hfs; }; + A6873B99234280440045680B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = A64B3BE122E8D388009A2B10; + remoteInfo = livefiles_cs_tester; + }; + A6873BA0234287A00045680B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = A64B3B9022E8D36F009A2B10; + remoteInfo = livefiles_cs; + }; FB48E4BB1BB30CC400523121 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; @@ -640,13 +669,6 @@ remoteGlobalIDString = 4DE6C75A153504C100C11066; remoteInfo = newfs_hfs; }; - FBA540001B7BF2DF00899E5B /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; - proxyType = 1; - remoteGlobalIDString = FB6A57DD1B55544D008AB046; - remoteInfo = "System Framework Headers"; - }; FBA95AAE1B5045D400887E82 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; @@ -795,6 +817,26 @@ ); runOnlyForDeploymentPostprocessing = 1; }; + A64B3BE922E8D388009A2B10 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + A64B3C0D22E8D9D0009A2B10 /* Embed Libraries */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + A64B3C0A22E8D9D0009A2B10 /* livefiles_hfs.dylib in Embed Libraries */, + ); + name = "Embed Libraries"; + runOnlyForDeploymentPostprocessing = 0; + }; FB76B3D01B7A4BE600FA9F2B /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -1037,6 +1079,23 @@ 9D7AAC861B44874E0001F573 /* mount_hfs.osx.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = mount_hfs.osx.entitlements; sourceTree = ""; }; 9D7AAC871B44880B0001F573 /* hfs_util.osx.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = hfs_util.osx.entitlements; sourceTree = ""; }; 9D9067881B44633C003D2117 /* fsck_hfs.osx.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = fsck_hfs.osx.entitlements; sourceTree = ""; }; + A601423723205BB00030E611 /* gen-custom-dmg.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "gen-custom-dmg.sh"; sourceTree = ""; }; + A601423823205D9D0030E611 /* generate-compressed-image.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "generate-compressed-image.c"; sourceTree = ""; }; + A64B3BE022E8D36F009A2B10 /* livefiles_cs.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = livefiles_cs.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; + A64B3BEE22E8D388009A2B10 /* livefiles_cs_tester */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = livefiles_cs_tester; sourceTree = BUILT_PRODUCTS_DIR; }; + A64B3BF322E8D4D6009A2B10 /* lf_cs_logging.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = lf_cs_logging.h; sourceTree = ""; }; + A64B3BF422E8D4D6009A2B10 /* lf_cs_logging.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = lf_cs_logging.c; sourceTree = ""; }; + A64B3BF922E8D538009A2B10 /* lf_cs_checksum.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = lf_cs_checksum.h; sourceTree = ""; }; + A64B3BFA22E8D538009A2B10 /* lf_cs_checksum.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = lf_cs_checksum.c; sourceTree = ""; }; + A64B3BFE22E8D584009A2B10 /* livefiles_cs_tester.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = livefiles_cs_tester.entitlements; sourceTree = ""; }; + A64B3C0022E8D6A7009A2B10 /* livefiles_cs_tester.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = livefiles_cs_tester.c; sourceTree = ""; }; + A64B3C0222E8D6D9009A2B10 /* lf_cs_disk_format.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = lf_cs_disk_format.h; sourceTree = ""; }; + A64B3C0422E8D71B009A2B10 /* lf_cs_vfsops.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = lf_cs_vfsops.c; sourceTree = ""; }; + A64B3C0822E8D741009A2B10 /* lf_cs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = lf_cs.h; sourceTree = ""; }; + A64B3C1322E91AF6009A2B10 /* test-lf-cs-plugin.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "test-lf-cs-plugin.c"; sourceTree = ""; }; + A64B3C1622EA2C4E009A2B10 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.Internal.sdk/System/Library/Frameworks/CoreFoundation.framework; sourceTree = DEVELOPER_DIR; }; + A64B3C1822EA2C5E009A2B10 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.Internal.sdk/System/Library/Frameworks/IOKit.framework; sourceTree = DEVELOPER_DIR; }; + A6873B9E234287200045680B /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.Internal.sdk/System/Library/Frameworks/IOKit.framework; sourceTree = DEVELOPER_DIR; }; A6E6D73F20909C72002125B0 /* test-get-volume-create-time.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "test-get-volume-create-time.c"; sourceTree = ""; }; C1B6FA0610CC0A0A00778D48 /* hfsutil_jnl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hfsutil_jnl.c; sourceTree = ""; }; C1B6FA0710CC0A0A00778D48 /* hfsutil_main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hfsutil_main.c; sourceTree = ""; }; @@ -1161,7 +1220,6 @@ FB55AE521B7C271000701D03 /* test-doc-tombstone.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "test-doc-tombstone.c"; sourceTree = ""; }; FB55AE581B7CEB0600701D03 /* test-quotas.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "test-quotas.c"; sourceTree = ""; }; FB55AE5D1B7D219700701D03 /* gen-test-plist.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "gen-test-plist.sh"; sourceTree = ""; }; - FB6A57DE1B55544D008AB046 /* hfs-System.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "hfs-System.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; FB75A4021B4AE765004B5A74 /* HFSEncodings.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HFSEncodings.kext; sourceTree = BUILT_PRODUCTS_DIR; }; FB75A4031B4AE765004B5A74 /* HFSEncodings-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "HFSEncodings-Info.plist"; sourceTree = ""; }; FB75A40C1B4AF0BA004B5A74 /* hfs_encodings_kext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = hfs_encodings_kext.cpp; sourceTree = ""; }; @@ -1285,11 +1343,29 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - D7B2DC81233A3F5B00F12230 /* livefiles_hfs.dylib in Frameworks */, + A64B3C0922E8D9D0009A2B10 /* livefiles_hfs.dylib in Frameworks */, 9022D170205EC16900D9A2AE /* CoreFoundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; + A64B3BB422E8D36F009A2B10 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + A64B3C1722EA2C4F009A2B10 /* CoreFoundation.framework in Frameworks */, + A64B3C1922EA2C5E009A2B10 /* IOKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A64B3BE622E8D388009A2B10 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + A6873B9F234287200045680B /* IOKit.framework in Frameworks */, + A64B3BE822E8D388009A2B10 /* CoreFoundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; FB20E0DC1AE950C200CEBE7B /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -1354,6 +1430,7 @@ 08FB7794FE84155DC02AAC07 /* hfs */ = { isa = PBXGroup; children = ( + A64B3B8822E8D2A6009A2B10 /* livefiles_cs_plugin */, 900BDECD1FF91960002F7EC0 /* livefiles_hfs_plugin */, 4DFD953D15377C7D0039B6BA /* hfs.xcconfig */, FDD9FA4614A1343D0043D4A9 /* CopyHFSMeta */, @@ -1599,6 +1676,22 @@ path = livefiles_hfs_plugin; sourceTree = ""; }; + A64B3B8822E8D2A6009A2B10 /* livefiles_cs_plugin */ = { + isa = PBXGroup; + children = ( + A64B3BF322E8D4D6009A2B10 /* lf_cs_logging.h */, + A64B3BF422E8D4D6009A2B10 /* lf_cs_logging.c */, + A64B3BF922E8D538009A2B10 /* lf_cs_checksum.h */, + A64B3BFA22E8D538009A2B10 /* lf_cs_checksum.c */, + A64B3BFE22E8D584009A2B10 /* livefiles_cs_tester.entitlements */, + A64B3C0022E8D6A7009A2B10 /* livefiles_cs_tester.c */, + A64B3C0222E8D6D9009A2B10 /* lf_cs_disk_format.h */, + A64B3C0422E8D71B009A2B10 /* lf_cs_vfsops.c */, + A64B3C0822E8D741009A2B10 /* lf_cs.h */, + ); + path = livefiles_cs_plugin; + sourceTree = ""; + }; C1B6FD2C10CC0DB200778D48 /* Products */ = { isa = PBXGroup; children = ( @@ -1614,7 +1707,6 @@ 86CBF37F183186C300A64A93 /* libhfs_metadata.a */, FB20E0E01AE950C200CEBE7B /* HFS.kext */, FB75A4021B4AE765004B5A74 /* HFSEncodings.kext */, - FB6A57DE1B55544D008AB046 /* hfs-System.framework */, FBAA82451B56F24100EE6863 /* hfs_alloc_test */, FBAA82511B56F26A00EE6863 /* hfs_extents_test */, FBAA825D1B56F28C00EE6863 /* rangelist_test */, @@ -1624,6 +1716,8 @@ FB48E5041BB3798500523121 /* Sim_Headers */, 900BDED41FF919C2002F7EC0 /* livefiles_hfs.dylib */, 900BDEDD1FF919DE002F7EC0 /* livefiles_hfs_tester */, + A64B3BE022E8D36F009A2B10 /* livefiles_cs.dylib */, + A64B3BEE22E8D388009A2B10 /* livefiles_cs_tester */, ); name = Products; sourceTree = ""; @@ -1767,6 +1861,7 @@ FBD69AF81B91309C0022ECAD /* test-dateadded.c */, 09D6B7D61E317ED2003C20DC /* test_disklevel.c */, A6E6D73F20909C72002125B0 /* test-get-volume-create-time.c */, + A64B3C1322E91AF6009A2B10 /* test-lf-cs-plugin.c */, ); path = cases; sourceTree = ""; @@ -1804,6 +1899,8 @@ FB76B3EF1B7BE67400FA9F2B /* systemx.c */, FB76B3F01B7BE67400FA9F2B /* systemx.h */, FBAA826F1B56F32900EE6863 /* test-utils.h */, + A601423723205BB00030E611 /* gen-custom-dmg.sh */, + A601423823205D9D0030E611 /* generate-compressed-image.c */, ); path = tests; sourceTree = ""; @@ -1832,8 +1929,11 @@ FDD9FA4014A133A50043D4A9 /* Frameworks */ = { isa = PBXGroup; children = ( + A64B3C1822EA2C5E009A2B10 /* IOKit.framework */, + A6873B9E234287200045680B /* IOKit.framework */, C1B6FA2210CC0AF400778D48 /* CoreFoundation.framework */, 9022D16F205EC16900D9A2AE /* CoreFoundation.framework */, + A64B3C1622EA2C4E009A2B10 /* CoreFoundation.framework */, 4DE6C7461535012200C11066 /* IOKit.framework */, FDD9FA5B14A135840043D4A9 /* libz.dylib */, 4DE6C74A1535018100C11066 /* libutil.dylib */, @@ -1918,6 +2018,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + A64B3BB522E8D36F009A2B10 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + A64B3BF522E8D4D6009A2B10 /* lf_cs_logging.h in Headers */, + A64B3BFB22E8D538009A2B10 /* lf_cs_checksum.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; FB20E0DD1AE950C200CEBE7B /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -1975,14 +2084,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - FB6A57E41B5554D5008AB046 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - FB6A57E51B5554DE008AB046 /* hfs_fsctl.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; FB75A3DF1B4AE765004B5A74 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -2177,17 +2278,52 @@ 900BDED91FF919DE002F7EC0 /* Sources */, 900BDEDA1FF919DE002F7EC0 /* Frameworks */, 900BDEDB1FF919DE002F7EC0 /* CopyFiles */, + A64B3C0D22E8D9D0009A2B10 /* Embed Libraries */, ); buildRules = ( ); dependencies = ( - 900BDEE61FF919E7002F7EC0 /* PBXTargetDependency */, + A64B3C0C22E8D9D0009A2B10 /* PBXTargetDependency */, ); name = livefiles_hfs_tester; productName = livefiles_hfs_tester; productReference = 900BDEDD1FF919DE002F7EC0 /* livefiles_hfs_tester */; productType = "com.apple.product-type.tool"; }; + A64B3B9022E8D36F009A2B10 /* livefiles_cs */ = { + isa = PBXNativeTarget; + buildConfigurationList = A64B3BDC22E8D36F009A2B10 /* Build configuration list for PBXNativeTarget "livefiles_cs" */; + buildPhases = ( + A64B3B9122E8D36F009A2B10 /* Sources */, + A64B3BB422E8D36F009A2B10 /* Frameworks */, + A64B3BB522E8D36F009A2B10 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = livefiles_cs; + productName = livefiles_hfs; + productReference = A64B3BE022E8D36F009A2B10 /* livefiles_cs.dylib */; + productType = "com.apple.product-type.library.dynamic"; + }; + A64B3BE122E8D388009A2B10 /* livefiles_cs_tester */ = { + isa = PBXNativeTarget; + buildConfigurationList = A64B3BEA22E8D388009A2B10 /* Build configuration list for PBXNativeTarget "livefiles_cs_tester" */; + buildPhases = ( + A64B3BE422E8D388009A2B10 /* Sources */, + A64B3BE622E8D388009A2B10 /* Frameworks */, + A64B3BE922E8D388009A2B10 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = livefiles_cs_tester; + productName = livefiles_cs_tester; + productReference = A64B3BEE22E8D388009A2B10 /* livefiles_cs_tester */; + productType = "com.apple.product-type.tool"; + }; FB20E0DF1AE950C200CEBE7B /* kext */ = { isa = PBXNativeTarget; buildConfigurationList = FB20E0E61AE950C200CEBE7B /* Build configuration list for PBXNativeTarget "kext" */; @@ -2238,22 +2374,6 @@ productReference = FB48E5041BB3798500523121 /* Sim_Headers */; productType = "com.apple.product-type.tool"; }; - FB6A57DD1B55544D008AB046 /* System Framework Headers */ = { - isa = PBXNativeTarget; - buildConfigurationList = FB6A57E11B55544D008AB046 /* Build configuration list for PBXNativeTarget "System Framework Headers" */; - buildPhases = ( - FB6A57E41B5554D5008AB046 /* Headers */, - FB5695F81C0F5ED0004C52F2 /* ShellScript */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "System Framework Headers"; - productName = test; - productReference = FB6A57DE1B55544D008AB046 /* hfs-System.framework */; - productType = "com.apple.product-type.bundle"; - }; FB75A3B11B4AE765004B5A74 /* encodings-kext */ = { isa = PBXNativeTarget; buildConfigurationList = FB75A3FF1B4AE765004B5A74 /* Build configuration list for PBXNativeTarget "encodings-kext" */; @@ -2398,6 +2518,12 @@ CreatedOnToolsVersion = 10.0; ProvisioningStyle = Automatic; }; + A64B3B9022E8D36F009A2B10 = { + ProvisioningStyle = Automatic; + }; + A64B3BE122E8D388009A2B10 = { + ProvisioningStyle = Automatic; + }; DB1AAB7C20472D140036167F = { CreatedOnToolsVersion = 9.3; ProvisioningStyle = Automatic; @@ -2408,9 +2534,6 @@ FB48E5031BB3798500523121 = { CreatedOnToolsVersion = 7.0; }; - FB6A57DD1B55544D008AB046 = { - CreatedOnToolsVersion = 7.0; - }; FB76B3D11B7A4BE600FA9F2B = { CreatedOnToolsVersion = 7.0; }; @@ -2471,7 +2594,6 @@ FBE3F7821AF67748005BB768 /* osx-root */, FBC234B91B4D87A20002D849 /* ios-root */, FBA95AA91B5025E700887E82 /* mk-xnu */, - FB6A57DD1B55544D008AB046 /* System Framework Headers */, FB48E49B1BB3070400523121 /* OSX Kernel Framework Headers */, FBAA82441B56F24100EE6863 /* hfs_alloc_test */, FBAA82501B56F26A00EE6863 /* hfs_extents_test */, @@ -2486,6 +2608,8 @@ 900BDED31FF919C2002F7EC0 /* livefiles_hfs */, 900BDEDC1FF919DE002F7EC0 /* livefiles_hfs_tester */, 9430FE92211658C1009CC8AF /* hfs_livefiles */, + A64B3B9022E8D36F009A2B10 /* livefiles_cs */, + A64B3BE122E8D388009A2B10 /* livefiles_cs_tester */, ); }; /* End PBXProject section */ @@ -2601,19 +2725,6 @@ shellScript = "\"$SCRIPT_INPUT_FILE_0\" \"$SCRIPT_OUTPUT_FILE_0\"\n"; showEnvVarsInLog = 0; }; - FB5695F81C0F5ED0004C52F2 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 8; - files = ( - ); - inputPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 1; - shellPath = /bin/sh; - shellScript = "ditto \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME\" \"$DSTROOT\"/System/Library/Frameworks/System.framework\n"; - }; FB5695FC1C0F98F2004C52F2 /* Create DMG */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -2621,6 +2732,7 @@ ); inputPaths = ( "$(SRCROOT)/tests/gen-dmg.sh", + "$(SRCROOT)/tests/gen-custom-dmg.sh", ); name = "Create DMG"; outputPaths = ( @@ -2628,7 +2740,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "set -e\n\nif [ $PLATFORM_NAME != macosx ] ; then\n \"$SCRIPT_INPUT_FILE_0\" \"$DERIVED_SOURCES_DIR/dmg.dat\"\nfi\ntouch \"$SCRIPT_OUTPUT_FILE_0\"\n"; + shellScript = "set -e\n\nif [ $PLATFORM_NAME != macosx ] ; then\n \"$SCRIPT_INPUT_FILE_0\" \"$DERIVED_SOURCES_DIR/dmg.dat\"\nfi\ntouch \"$SCRIPT_OUTPUT_FILE_0\"\n\nif [ $PLATFORM_NAME != macosx ] ; then\nfor FS in JHFS+ APFS FAT32 EXFAT; do\n \"$SCRIPT_INPUT_FILE_1\" \"$FS\" \"$DERIVED_SOURCES_DIR/$FS-dmg.dat\"\n done\nfi\n\n"; showEnvVarsInLog = 0; }; FB7C14111C2368F4004F8B2C /* ShellScript */ = { @@ -2863,6 +2975,27 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + A64B3B9122E8D36F009A2B10 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + A64B3C0622E8D71B009A2B10 /* lf_cs_vfsops.c in Sources */, + A64B3BFC22E8D538009A2B10 /* lf_cs_checksum.c in Sources */, + A64B3BF722E8D4D6009A2B10 /* lf_cs_logging.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A64B3BE422E8D388009A2B10 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + A64B3C0122E8D6A7009A2B10 /* livefiles_cs_tester.c in Sources */, + A6873B9B234286730045680B /* lf_cs_logging.c in Sources */, + A6873B9D2342868D0045680B /* lf_cs_vfsops.c in Sources */, + A6873B9C234286780045680B /* lf_cs_checksum.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; FB20E0DB1AE950C200CEBE7B /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -2943,6 +3076,7 @@ 2A9399C11BE15F6800FB075B /* test-msync-16k.c in Sources */, 2A9399C21BE15F6800FB075B /* test-readdir.c in Sources */, 2A9399C31BE15F6800FB075B /* test-set-create-time.c in Sources */, + A64B3C1522E91B50009A2B10 /* test-lf-cs-plugin.c in Sources */, 2A9399C41BE15F6800FB075B /* test-set-protection-class.c in Sources */, 2A9399B81BE14AAD00FB075B /* test-scan-range-size.c in Sources */, 2A9399B61BE131A400FB075B /* test-resize.m in Sources */, @@ -3090,15 +3224,25 @@ target = 4DFD94BC15373C2C0039B6BA /* fsck_makestrings */; targetProxy = 4DBD52521548A4D4007AA736 /* PBXContainerItemProxy */; }; - 900BDEE61FF919E7002F7EC0 /* PBXTargetDependency */ = { + 9430FE98211658E7009CC8AF /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 900BDED31FF919C2002F7EC0 /* livefiles_hfs */; - targetProxy = 900BDEE51FF919E7002F7EC0 /* PBXContainerItemProxy */; + targetProxy = 9430FE97211658E7009CC8AF /* PBXContainerItemProxy */; }; - 9430FE98211658E7009CC8AF /* PBXTargetDependency */ = { + A64B3C0C22E8D9D0009A2B10 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 900BDED31FF919C2002F7EC0 /* livefiles_hfs */; - targetProxy = 9430FE97211658E7009CC8AF /* PBXContainerItemProxy */; + targetProxy = A64B3C0B22E8D9D0009A2B10 /* PBXContainerItemProxy */; + }; + A6873B9A234280440045680B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = A64B3BE122E8D388009A2B10 /* livefiles_cs_tester */; + targetProxy = A6873B99234280440045680B /* PBXContainerItemProxy */; + }; + A6873BA1234287A00045680B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = A64B3B9022E8D36F009A2B10 /* livefiles_cs */; + targetProxy = A6873BA0234287A00045680B /* PBXContainerItemProxy */; }; FB48E4BC1BB30CC400523121 /* PBXTargetDependency */ = { isa = PBXTargetDependency; @@ -3150,11 +3294,6 @@ target = 4DE6C75A153504C100C11066 /* newfs_hfs */; targetProxy = FB81AFB91B83E2B8004E8F76 /* PBXContainerItemProxy */; }; - FBA540011B7BF2DF00899E5B /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = FB6A57DD1B55544D008AB046 /* System Framework Headers */; - targetProxy = FBA540001B7BF2DF00899E5B /* PBXContainerItemProxy */; - }; FBA95AAF1B5045D400887E82 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = FBA95AA91B5025E700887E82 /* mk-xnu */; @@ -3816,127 +3955,496 @@ }; name = Coverage; }; - DB1AAB7D20472D140036167F /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - DB1AAB7E20472D140036167F /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - DB1AAB7F20472D140036167F /* Coverage */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Coverage; - }; - FB20E0E71AE950C200CEBE7B /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = FB20E1781AE968BD00CEBE7B /* kext.xcconfig */; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_ASSIGN_ENUM = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CODE_SIGN_IDENTITY = "-"; - COMBINE_HIDPI_IMAGES = YES; - COPY_HEADERS_RUN_UNIFDEF = YES; - COPY_HEADERS_UNIFDEF_FLAGS = "-UKERNEL"; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_SYMBOLS_PRIVATE_EXTERN = YES; - GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; - GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; - GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; - GCC_WARN_ABOUT_MISSING_NEWLINE = YES; - GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; - GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; - GCC_WARN_SHADOW = YES; - GCC_WARN_SIGN_COMPARE = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNKNOWN_PRAGMAS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_LABEL = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - INFOPLIST_FILE = "$(PROJECT_DERIVED_FILE_DIR)/kext-Info.plist"; - INSTALL_MODE_FLAG = "a+rX"; - LLVM_LTO = YES; - MODULE_NAME = "com.apple.file-systems.hfs.kext"; - MODULE_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = com.apple.filesystems.hfs.kext; - PRODUCT_NAME = HFS; - SDKROOT = macosx.internal; - WARNING_CFLAGS = ( - "$(inherited)", - "-Wno-unused-parameter", - "-Wno-shorten-64-to-32", - ); - WRAPPER_EXTENSION = kext; - }; - name = Release; - }; - FB48E4A31BB3070500523121 /* Release */ = { + A64B3BDD22E8D36F009A2B10 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_ANALYZER_OBJC_UNUSED_IVARS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = NO; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COMBINE_HIDPI_IMAGES = YES; - COPY_HEADERS_RUN_UNIFDEF = YES; - COPY_HEADERS_UNIFDEF_FLAGS = "-DKERNEL"; - COPY_PHASE_STRIP = NO; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + DEAD_CODE_STRIPPING = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; + EXECUTABLE_PREFIX = ""; + FRAMEWORK_SEARCH_PATHS = "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks"; + GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = "LF_CS_USE_OSLOG=1"; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_FUNCTION = NO; + GCC_WARN_UNUSED_LABEL = NO; + GCC_WARN_UNUSED_PARAMETER = NO; + GCC_WARN_UNUSED_VALUE = NO; GCC_WARN_UNUSED_VARIABLE = YES; - INSTALL_PATH = /System/Library/Frameworks; - MACOSX_DEPLOYMENT_TARGET = 10.11; + HEADER_SEARCH_PATHS = "livefiles_cs_plugin/**"; + INSTALL_PATH = /System/Library/PrivateFrameworks/UserFS.framework/PlugIns; + MACOSX_DEPLOYMENT_TARGET = 10.13; MTL_ENABLE_DEBUG_INFO = NO; - PRODUCT_NAME = Kernel; - PUBLIC_HEADERS_FOLDER_PATH = Kernel.framework/Versions/A/Headers/hfs; - WRAPPER_EXTENSION = framework; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx.internal; + SUPPORTS_TEXT_BASED_API = NO; }; name = Release; }; - FB48E4A41BB3070500523121 /* Debug */ = { + A64B3BDE22E8D36F009A2B10 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_ANALYZER_OBJC_UNUSED_IVARS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = NO; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + DEAD_CODE_STRIPPING = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + ENABLE_STRICT_OBJC_MSGSEND = YES; + EXECUTABLE_PREFIX = ""; + FRAMEWORK_SEARCH_PATHS = "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks"; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "LF_CS_USE_OSLOG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = NO; + GCC_WARN_UNUSED_LABEL = NO; + GCC_WARN_UNUSED_PARAMETER = NO; + GCC_WARN_UNUSED_VALUE = NO; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = "livefiles_cs_plugin/**"; + INSTALL_PATH = /System/Library/PrivateFrameworks/UserFS.framework/PlugIns; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx.internal; + SUPPORTS_TEXT_BASED_API = NO; + }; + name = Debug; + }; + A64B3BDF22E8D36F009A2B10 /* Coverage */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_ANALYZER_OBJC_UNUSED_IVARS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = NO; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + DEAD_CODE_STRIPPING = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + EXECUTABLE_PREFIX = ""; + FRAMEWORK_SEARCH_PATHS = "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks"; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = "LF_CS_USE_OSLOG=1"; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = NO; + GCC_WARN_UNUSED_LABEL = NO; + GCC_WARN_UNUSED_PARAMETER = NO; + GCC_WARN_UNUSED_VALUE = NO; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = "livefiles_cs_plugin/**"; + INSTALL_PATH = /System/Library/PrivateFrameworks/UserFS.framework/PlugIns; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx.internal; + SUPPORTS_TEXT_BASED_API = NO; + }; + name = Coverage; + }; + A64B3BEB22E8D388009A2B10 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = NO; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_ENTITLEMENTS = livefiles_cs_plugin/livefiles_cs_tester.entitlements; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + FRAMEWORK_SEARCH_PATHS = "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks"; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = livefiles_cs_plugin/; + INSTALL_PATH = /AppleInternal/CoreOS/tests/hfs; + MACOSX_DEPLOYMENT_TARGET = 10.12; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx.internal; + SUPPORTS_TEXT_BASED_API = NO; + }; + name = Release; + }; + A64B3BEC22E8D388009A2B10 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = NO; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_ENTITLEMENTS = livefiles_cs_plugin/livefiles_cs_tester.entitlements; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + FRAMEWORK_SEARCH_PATHS = "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks"; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = livefiles_cs_plugin/; + INSTALL_PATH = /AppleInternal/CoreOS/tests/hfs; + MACOSX_DEPLOYMENT_TARGET = 10.12; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx.internal; + SUPPORTS_TEXT_BASED_API = NO; + }; + name = Debug; + }; + A64B3BED22E8D388009A2B10 /* Coverage */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = NO; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_ENTITLEMENTS = livefiles_cs_plugin/livefiles_cs_tester.entitlements; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + FRAMEWORK_SEARCH_PATHS = "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks"; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = livefiles_cs_plugin/; + INSTALL_PATH = /AppleInternal/CoreOS/tests/hfs; + MACOSX_DEPLOYMENT_TARGET = 10.12; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx.internal; + SUPPORTS_TEXT_BASED_API = NO; + }; + name = Coverage; + }; + DB1AAB7D20472D140036167F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + DB1AAB7E20472D140036167F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + DB1AAB7F20472D140036167F /* Coverage */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Coverage; + }; + FB20E0E71AE950C200CEBE7B /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = FB20E1781AE968BD00CEBE7B /* kext.xcconfig */; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_ASSIGN_ENUM = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_HEADERS_RUN_UNIFDEF = YES; + COPY_HEADERS_UNIFDEF_FLAGS = "-UKERNEL"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_SYMBOLS_PRIVATE_EXTERN = YES; + GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; + GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; + GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; + GCC_WARN_ABOUT_MISSING_NEWLINE = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; + GCC_WARN_SIGN_COMPARE = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNKNOWN_PRAGMAS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_LABEL = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = "$(PROJECT_DERIVED_FILE_DIR)/kext-Info.plist"; + INSTALL_MODE_FLAG = "a+rX"; + LLVM_LTO = YES; + MODULE_NAME = "com.apple.file-systems.hfs.kext"; + MODULE_VERSION = 1.0.0; + PRODUCT_BUNDLE_IDENTIFIER = com.apple.filesystems.hfs.kext; + PRODUCT_NAME = HFS; + SDKROOT = macosx.internal; + WARNING_CFLAGS = ( + "$(inherited)", + "-Wno-unused-parameter", + "-Wno-shorten-64-to-32", + ); + WRAPPER_EXTENSION = kext; + }; + name = Release; + }; + FB48E4A31BB3070500523121 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_HEADERS_RUN_UNIFDEF = YES; + COPY_HEADERS_UNIFDEF_FLAGS = "-DKERNEL"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INSTALL_PATH = /System/Library/Frameworks; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = Kernel; + PUBLIC_HEADERS_FOLDER_PATH = Kernel.framework/Versions/A/Headers/hfs; + WRAPPER_EXTENSION = framework; + }; + name = Release; + }; + FB48E4A41BB3070500523121 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -4086,96 +4594,6 @@ }; name = Debug; }; - FB6A57E21B55544D008AB046 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COMBINE_HIDPI_IMAGES = YES; - COPY_HEADERS_RUN_UNIFDEF = YES; - COPY_HEADERS_UNIFDEF_FLAGS = "-UKERNEL"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; - MTL_ENABLE_DEBUG_INFO = NO; - PRIVATE_HEADERS_FOLDER_PATH = "hfs-System.framework/Versions/B/PrivateHeaders/hfs"; - PRODUCT_NAME = "hfs-System"; - SDKROOT = macosx; - SKIP_INSTALL = YES; - WRAPPER_EXTENSION = framework; - }; - name = Release; - }; - FB6A57E31B55544D008AB046 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COMBINE_HIDPI_IMAGES = YES; - COPY_HEADERS_RUN_UNIFDEF = YES; - COPY_HEADERS_UNIFDEF_FLAGS = "-UKERNEL"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - PRIVATE_HEADERS_FOLDER_PATH = "hfs-System.framework/Versions/B/PrivateHeaders/hfs"; - PRODUCT_NAME = "hfs-System"; - SDKROOT = macosx; - SKIP_INSTALL = YES; - WRAPPER_EXTENSION = framework; - }; - name = Debug; - }; FB75A4001B4AE765004B5A74 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = FB20E1781AE968BD00CEBE7B /* kext.xcconfig */; @@ -5274,54 +5692,6 @@ }; name = Coverage; }; - FBD69B291B94E9990022ECAD /* Coverage */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COMBINE_HIDPI_IMAGES = YES; - COPY_HEADERS_RUN_UNIFDEF = YES; - COPY_HEADERS_UNIFDEF_FLAGS = "-UKERNEL"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - PRIVATE_HEADERS_FOLDER_PATH = "hfs-System.framework/Versions/B/PrivateHeaders/hfs"; - PRODUCT_NAME = "hfs-System"; - SDKROOT = macosx; - SKIP_INSTALL = YES; - WRAPPER_EXTENSION = framework; - }; - name = Coverage; - }; FBD69B2A1B94E9990022ECAD /* Coverage */ = { isa = XCBuildConfiguration; buildSettings = { @@ -5769,6 +6139,26 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + A64B3BDC22E8D36F009A2B10 /* Build configuration list for PBXNativeTarget "livefiles_cs" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + A64B3BDD22E8D36F009A2B10 /* Release */, + A64B3BDE22E8D36F009A2B10 /* Debug */, + A64B3BDF22E8D36F009A2B10 /* Coverage */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + A64B3BEA22E8D388009A2B10 /* Build configuration list for PBXNativeTarget "livefiles_cs_tester" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + A64B3BEB22E8D388009A2B10 /* Release */, + A64B3BEC22E8D388009A2B10 /* Debug */, + A64B3BED22E8D388009A2B10 /* Coverage */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; DB1AAB8020472D140036167F /* Build configuration list for PBXAggregateTarget "Swift_iOS" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -5819,16 +6209,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - FB6A57E11B55544D008AB046 /* Build configuration list for PBXNativeTarget "System Framework Headers" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - FB6A57E21B55544D008AB046 /* Release */, - FB6A57E31B55544D008AB046 /* Debug */, - FBD69B291B94E9990022ECAD /* Coverage */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; FB75A3FF1B4AE765004B5A74 /* Build configuration list for PBXNativeTarget "encodings-kext" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/hfs_util/hfsutil_jnl.c b/hfs_util/hfsutil_jnl.c index 0989d5b..ee379be 100644 --- a/hfs_util/hfsutil_jnl.c +++ b/hfs_util/hfsutil_jnl.c @@ -474,7 +474,7 @@ retry: buf = (char *)calloc(block_size, 1); if (buf) { for(i=0; i < journal_size/block_size; i++) { - ret = write(fd, buf, block_size); + ret = (int)write(fd, buf, block_size); if (ret != block_size) { break; } @@ -502,7 +502,7 @@ retry: free(buf); return 20; } - jstart_block = (start_block / block_size) - (embedded_offset / block_size); + jstart_block = (int32_t)((start_block / block_size) - (embedded_offset / block_size)); memset(&jib, 'Z', sizeof(jib)); jib.flags = kJIJournalInFSMask; @@ -566,7 +566,7 @@ retry: free(buf); return 20; } - jinfo_block = (start_block / block_size) - (embedded_offset / block_size); + jinfo_block = (int32_t)((start_block / block_size) - (embedded_offset / block_size)); // @@ -778,7 +778,7 @@ get_journal_info(char *devname, struct JournalInfoBlock *jib) disksize = (u_int64_t)mdbp->drEmbedExtent.blockCount * (u_int64_t)mdbp->drAlBlkSiz; - mdb_offset = (embeddedOffset / blksize) + HFS_PRI_SECTOR(blksize); + mdb_offset = (daddr_t)((embeddedOffset / blksize) + HFS_PRI_SECTOR(blksize)); if (pread(fd, buff, blksize, mdb_offset * blksize) != blksize) { printf("failed to read the embedded vhp @ offset %d\n", mdb_offset * blksize); ret = -1; @@ -1064,7 +1064,7 @@ restart: disksize = (u_int64_t)SWAP_BE16(mdbp->drEmbedExtent.blockCount) * (u_int64_t)SWAP_BE32(mdbp->drAlBlkSiz); - mdb_offset = (embeddedOffset / blksize) + HFS_PRI_SECTOR(blksize); + mdb_offset = (daddr_t)((embeddedOffset / blksize) + HFS_PRI_SECTOR(blksize)); hdr_offset = mdb_offset * blksize; if (pread(fd, buff, blksize, hdr_offset) != blksize) { fprintf(stderr, "failed to read the embedded vhp @ offset %d\n", mdb_offset * blksize); @@ -1095,7 +1095,7 @@ restart: tmp &= ~kHFSVolumeJournaledMask; vhp->attributes = SWAP_BE32(tmp); - if ((tmp = pwrite(fd, buff, blksize, hdr_offset)) != blksize) { + if ((tmp = (unsigned int)pwrite(fd, buff, blksize, hdr_offset)) != blksize) { fprintf(stderr, "Update of super-block on %s failed! (%d != %d, %s)\n", devname, tmp, blksize, strerror(errno)); } else { @@ -1219,7 +1219,7 @@ SetJournalInFSState(const char *devname, int journal_in_fs) blksize = 512; } - mdb_offset = (embeddedOffset / blksize) + HFS_PRI_SECTOR(blksize); + mdb_offset = (daddr_t)((embeddedOffset / blksize) + HFS_PRI_SECTOR(blksize)); if (pread(fd, buff, blksize, mdb_offset * blksize) != blksize) { printf("failed to read the embedded vhp @ offset %d\n", mdb_offset * blksize); ret = -1; diff --git a/hfs_util/hfsutil_main.c b/hfs_util/hfsutil_main.c index 8d86934..35e848b 100644 --- a/hfs_util/hfsutil_main.c +++ b/hfs_util/hfsutil_main.c @@ -55,6 +55,7 @@ #include #include #include +#include #include #include @@ -280,11 +281,15 @@ static unsigned int __CFStringGetDefaultEncodingForHFSUtil() { if ((fd = open(buffer, O_RDONLY, 0)) > 0) { ssize_t readSize; + long encoding; readSize = read(fd, buffer, MAXPATHLEN); buffer[(readSize < 0 ? 0 : readSize)] = '\0'; close(fd); - return strtol(buffer, NULL, 0); + + encoding = strtol(buffer, NULL, 0); + assert(encoding > -1 && encoding <= UINT_MAX); + return (unsigned int)encoding; } } return 0; // Fallback to smRoman @@ -803,7 +808,7 @@ DoProbe(char *rawDeviceNamePtr, char *blockDeviceNamePtr) /* * Read the HFS Master Directory Block from sector 2 */ - result = readAt(fd, bufPtr, (off_t)(2 * HFS_BLOCK_SIZE), HFS_BLOCK_SIZE); + result = (int)readAt(fd, bufPtr, (off_t)(2 * HFS_BLOCK_SIZE), HFS_BLOCK_SIZE); if (FSUR_IO_FAIL == result) goto Return; @@ -1129,8 +1134,9 @@ ParseArgs(int argc, const char *argv[], const char ** actionPtr, const char ** mountPointPtr, boolean_t * isEjectablePtr, boolean_t * isLockedPtr, boolean_t * isSetuidPtr, boolean_t * isDevPtr) { + size_t deviceLength; int result = FSUR_INVAL; - int deviceLength, doLengthCheck = 1; + int doLengthCheck = 1; int index; int mounting = 0; @@ -1196,7 +1202,10 @@ ParseArgs(int argc, const char *argv[], const char ** actionPtr, doLengthCheck = 0; if (isdigit(argv[2][0])) { char *ptr; - gJournalSize = strtoul(argv[2], &ptr, 0); + unsigned long size = strtoul(argv[2], &ptr, 0); + + assert(size < INT_MAX); + gJournalSize = (int)size; if (ptr) { gJournalSize *= get_multiplier(*ptr); } @@ -1409,7 +1418,7 @@ ReadHeaderBlock(int fd, void *bufPtr, off_t *startOffset, hfs_UUID_t **finderInf * Read the HFS Master Directory Block or Volume Header from sector 2 */ *startOffset = 0; - result = readAt(fd, bufPtr, (off_t)(2 * HFS_BLOCK_SIZE), HFS_BLOCK_SIZE); + result = (int)readAt(fd, bufPtr, (off_t)(2 * HFS_BLOCK_SIZE), HFS_BLOCK_SIZE); if (result != FSUR_IO_SUCCESS) goto Err_Exit; @@ -1422,7 +1431,7 @@ ReadHeaderBlock(int fd, void *bufPtr, off_t *startOffset, hfs_UUID_t **finderInf result = GetEmbeddedHFSPlusVol(mdbPtr, startOffset); if (result != FSUR_IO_SUCCESS) goto Err_Exit; - result = readAt(fd, bufPtr, *startOffset + (off_t)(2*HFS_BLOCK_SIZE), HFS_BLOCK_SIZE); + result = (int)readAt(fd, bufPtr, *startOffset + (off_t)(2*HFS_BLOCK_SIZE), HFS_BLOCK_SIZE); if (result != FSUR_IO_SUCCESS) goto Err_Exit; } @@ -1644,7 +1653,7 @@ SetVolumeUUIDRaw(const char *deviceNamePtr, hfs_UUID_t *volumeUUIDPtr) /* * Write the modified MDB or VHB back to disk */ - result = writeAt(fd, bufPtr, startOffset + (off_t)(2*HFS_BLOCK_SIZE), HFS_BLOCK_SIZE); + result = (int)writeAt(fd, bufPtr, startOffset + (off_t)(2*HFS_BLOCK_SIZE), HFS_BLOCK_SIZE); Err_Exit: if (fd > 0) close(fd); @@ -1976,7 +1985,7 @@ GetNameFromHFSPlusVolumeStartingAt(int fd, off_t hfsPlusVolumeOffset, unsigned c * Read the Volume Header * (This is a little redundant for a pure, unwrapped HFS+ volume) */ - result = readAt( fd, volHdrPtr, hfsPlusVolumeOffset + (off_t)(2*HFS_BLOCK_SIZE), HFS_BLOCK_SIZE ); + result = (int)readAt( fd, volHdrPtr, hfsPlusVolumeOffset + (off_t)(2*HFS_BLOCK_SIZE), HFS_BLOCK_SIZE ); if (result == FSUR_IO_FAIL) { #if TRACE_HFS_UTIL fprintf(stderr, "hfs.util: GetNameFromHFSPlusVolumeStartingAt: readAt failed\n"); @@ -2324,7 +2333,7 @@ static int LogicalToPhysical(off_t offset, ssize_t length, u_int32_t blockSize, u_int32_t blockCount = 0; /* Determine allocation block containing logicalOffset */ - logicalBlock = offset / blockSize; /* This can't overflow for valid volumes */ + logicalBlock = (u_int32_t)(offset / blockSize); /* This can't overflow for valid volumes */ offset %= blockSize; /* Offset from start of allocation block */ /* Find the extent containing logicalBlock */ @@ -2400,7 +2409,7 @@ static int ReadFile(int fd, void *buffer, off_t offset, ssize_t length, if (result != FSUR_IO_SUCCESS) break; - result = readAt(fd, buffer, volOffset+physOffset, physLength); + result = (int)readAt(fd, buffer, volOffset+physOffset, physLength); if (result != FSUR_IO_SUCCESS) break; @@ -2817,7 +2826,7 @@ int ConvertVolumeStatusDB(VolumeStatusDBHandle DBHandle) { * converted it then do nothing. */ lseek(dbstateptr->dbfile, 0, SEEK_SET); - result = read(dbstateptr->dbfile, &entry64, sizeof(entry64)); + result = (int)read(dbstateptr->dbfile, &entry64, sizeof(entry64)); if ((result != sizeof(entry64)) || (entry64.keySeparator != DBKEYSEPARATOR) || (entry64.space != DBBLANKSPACE) || @@ -2825,9 +2834,15 @@ int ConvertVolumeStatusDB(VolumeStatusDBHandle DBHandle) { result = 0; goto ErrExit; } else { + off_t buf_size = dbinfo.st_size; + /* Read in a giant buffer */ if ((result = stat(gVSDBPath, &dbinfo)) != 0) goto ErrExit; - iobuffersize = dbinfo.st_size; + if (buf_size > UINT32_MAX) { + result = EINVAL; + goto ErrExit; + } + iobuffersize = (u_int32_t)buf_size; iobuffer = malloc(iobuffersize); if (iobuffer == NULL) { result = ENOMEM; @@ -2835,7 +2850,7 @@ int ConvertVolumeStatusDB(VolumeStatusDBHandle DBHandle) { }; lseek(dbstateptr->dbfile, 0, SEEK_SET); - result = read(dbstateptr->dbfile, iobuffer, iobuffersize); + result = (int)read(dbstateptr->dbfile, iobuffer, iobuffersize); if (result != iobuffersize) { result = errno; goto ErrExit; @@ -2860,7 +2875,7 @@ int ConvertVolumeStatusDB(VolumeStatusDBHandle DBHandle) { } ConvertHFSUUIDToUUID(entry64.key.uuid, &volumeID); - VolumeStatus = ConvertHexStringToULong(entry64.record.statusFlags, sizeof(entry64.record.statusFlags)); + VolumeStatus = (u_int32_t)ConvertHexStringToULong(entry64.record.statusFlags, sizeof(entry64.record.statusFlags)); FormatDBEntry(&volumeID, VolumeStatus, &dbentry); if ((result = AddVolumeRecord(dbstateptr, &dbentry)) != sizeof(dbentry)) { @@ -3106,13 +3121,13 @@ static int FindVolumeRecordByUUID(VSDBStatePtr dbstateptr, volUUID_t *volumeID, static int AddVolumeRecord(VSDBStatePtr dbstateptr, VSDBEntryUUID_t *dbentry) { lseek(dbstateptr->dbfile, 0, SEEK_END); - return write(dbstateptr->dbfile, dbentry, sizeof(struct VSDBEntryUUID)); + return (int)write(dbstateptr->dbfile, dbentry, sizeof(struct VSDBEntryUUID)); } static int UpdateVolumeRecord(VSDBStatePtr dbstateptr, VSDBEntryUUID_t *dbentry) { lseek(dbstateptr->dbfile, dbstateptr->recordPosition, SEEK_SET); - return write(dbstateptr->dbfile, dbentry, sizeof(*dbentry)); + return (int)write(dbstateptr->dbfile, dbentry, sizeof(*dbentry)); } static int GetVSDBEntry(VSDBStatePtr dbstateptr, VSDBEntryUUID_t *dbentry) { @@ -3120,7 +3135,7 @@ static int GetVSDBEntry(VSDBStatePtr dbstateptr, VSDBEntryUUID_t *dbentry) { int result; dbstateptr->recordPosition = lseek(dbstateptr->dbfile, 0, SEEK_CUR); - result = read(dbstateptr->dbfile, &entry, sizeof(entry)); + result = (int)read(dbstateptr->dbfile, &entry, sizeof(entry)); if ((result != sizeof(entry)) || (entry.keySeparator != DBKEYSEPARATOR) || (entry.space != DBBLANKSPACE) || diff --git a/livefiles_cs_plugin/lf_cs.h b/livefiles_cs_plugin/lf_cs.h new file mode 100644 index 0000000..805cd23 --- /dev/null +++ b/livefiles_cs_plugin/lf_cs.h @@ -0,0 +1,34 @@ +// +// Copyright (c) 2019-2019 Apple Inc. All rights reserved. +// +// lf_cs.h - Defines macros for livefiles Apple_CoreStorage plugin. +// + +#ifndef _LF_CS_H +#define _LF_CS_H + +#include + +// +// Device/Block alignment and rounding. +// +#define CS_HOWMANY(_n, _b) howmany(_n, _b) +#define CS_ALIGN(_n, _b, _up)\ + (((_up) ? CS_HOWMANY(_n, _b) : ((_n) / (_b))) * (_b)) + +#define CS_STATUS(_s) ((_s) & 0x000FFFFF) +#define CS_STATUS_OK 0x00000000 // No error. +#define CS_STATUS_NOTCS 0x00000001 // Not a current CS volume. +#define CS_STATUS_CKSUM 0x00000002 // Cksum mismatch. +#define CS_STATUS_BLKTYPE 0x00000004 // Incorrect block type. +#define CS_STATUS_INVALID 0x00000008 // Invalid field value. +#define CS_STATUS_ADDRESS 0x00000010 // Invalid laddr/vaddr. +#define CS_STATUS_TXG 0x00000020 // Invalid transaction. +#define CS_STATUS_UUID 0x00000040 // Inconsistent UUID. + + +#define CS_INFO(_s) ((_s) & 0xFFF00000) +#define CS_INFO_VERSIONITIS 0x00100000 // Incompatible CS volume format +#define CS_INFO_ZERO_VH 0x02000000 // In-progress CS volume forma + +#endif /* _LF_CS_H */ diff --git a/livefiles_cs_plugin/lf_cs_checksum.c b/livefiles_cs_plugin/lf_cs_checksum.c new file mode 100644 index 0000000..ce52b19 --- /dev/null +++ b/livefiles_cs_plugin/lf_cs_checksum.c @@ -0,0 +1,139 @@ +// +// Copyright (c) 2009-2019 Apple Inc. All rights reserved. +// +// lf_cs_checksum.h - Implements checksum handling for livefiles +// Apple_CoreStorage plugin. +// +// This implementation is copied from CoreStorage project. +// + +#include "lf_cs_checksum.h" + +// +// CRC32-C using polynomial 0x1EDC6F41 +// +static const uint32_t crc32_table[256] = { + 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, + 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb, + 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, + 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, + 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b, + 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384, + 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, + 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b, + 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, + 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, + 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5, + 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa, + 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, + 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a, + 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, + 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, + 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48, + 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957, + 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, + 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198, + 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, + 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, + 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8, + 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7, + 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, + 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789, + 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859, + 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, + 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9, + 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6, + 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, + 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829, + 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, + 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, + 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043, + 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c, + 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, + 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc, + 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c, + 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, + 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652, + 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d, + 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, + 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982, + 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, + 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, + 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2, + 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed, + 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, + 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f, + 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, + 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, + 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f, + 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540, + 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, + 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f, + 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee, + 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, + 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321, + 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e, + 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, + 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e, + 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e, + 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351 +}; + +// +// Initialize 'cksum' buffer for the cksum function for a given +// algorithm 'alg'. Doubles as alg verification for probe/boot. +// +bool +cksum_init(cksum_alg_t alg, uint8_t cksum[MAX_CKSUM_NBYTES]) +{ + switch (alg) { + + case CKSUM_NONE: + memset(cksum, 0, MAX_CKSUM_NBYTES); + break; + + case CKSUM_ALG_CRC_32: + memset(cksum, ~0, MAX_CKSUM_NBYTES); + break; + + default: + return false; + + } + + return true; +} + +// +// cksum - Apply passed checksum algorithm. +// +// Apply checksum algorithm 'alg' to data block 'p' for 'len' bytes and insert +// the result (to max MAX_CKSUM_NBYTES) into 'cksum'. To support incremental +// cksum calculation the caller is responsible for first initialising the +// 'cksum' buffer (using cksum_init). +// +void +cksum(cksum_alg_t alg, const void *p, size_t len, + uint8_t cksum[MAX_CKSUM_NBYTES]) +{ + const uint8_t *data = (const uint8_t *)p; + uint32_t c32; + + switch (alg) { + + case CKSUM_NONE: + break; + + case CKSUM_ALG_CRC_32: + + c32 = *(uint32_t *)cksum; + + while (len-- > 0) { + c32 = crc32_table[(c32 ^ *data++) & 0xff] ^ + (c32 >> 8); + } + + *(uint32_t *)cksum = c32; + break; + } +} diff --git a/livefiles_cs_plugin/lf_cs_checksum.h b/livefiles_cs_plugin/lf_cs_checksum.h new file mode 100644 index 0000000..c51e4d8 --- /dev/null +++ b/livefiles_cs_plugin/lf_cs_checksum.h @@ -0,0 +1,64 @@ +// +// Copyright (c) 2009-2019 Apple Inc. All rights reserved. +// +// lf_cs_checksum.h - Defines for checksum handling for livefiles +// Apple_CoreStorage plugin. +// +// This header is copied from CoreStorage project. +// + +#ifndef _LF_CS_CHECKSUM_H +#define _LF_CS_CHECKSUM_H + +#include +#include +#include +#include + +// +// Checksum Algorithm +// +// Every metadata block has a checksum to check the data integrity. Different +// checksum algorithms can be used by CoreStorage, and [[lvg_checksum_alg]] in +// [[lvg_info_t]] records what checksum algorithm to use. For the first +// prototype, I am copying the CRC algorithm from the UDF project. +// +// The fletcher 2 algorithm used by ZFS has fundamental flaws. And a variation +// of the fletcher 8 algorithm could be used, which is 2 times faster than +// CRC32 and 4 times faster than fletcher. +// +// = +// +#define MAX_CKSUM_NBYTES 8 + +enum cksum_alg { + CKSUM_NONE, + CKSUM_ALG_CRC_32, // CRC-32 algorithm copied from CRC32-C polynomial +}; +typedef enum cksum_alg cksum_alg_t; + + +#define BITS_PER_BYTE 8L +#define META_CKSUM_BITS (MAX_CKSUM_NBYTES * BITS_PER_BYTE) + +// +// Initialize checksum for a certain algorithm +// +bool cksum_init(cksum_alg_t alg, uint8_t cksum[MAX_CKSUM_NBYTES]); + +// +// cksum - Calculate checksum of data for len bytes +// +// Existing value of cksum is also used to calculate the checksum. In order to +// calculate cksums of different memory chunks, this function can be called +// several times: +// +// cksum(alg, data1, len1, cksum); +// cksum(alg, data2, len2, cksum); +// +// and the resultant cksum is calculated on two chunks +// +void cksum(cksum_alg_t alg, const void *data, size_t len, + uint8_t cksum[MAX_CKSUM_NBYTES]); + +#endif /* _LF_CS_CHECKSUM_H */ diff --git a/livefiles_cs_plugin/lf_cs_disk_format.h b/livefiles_cs_plugin/lf_cs_disk_format.h new file mode 100644 index 0000000..e06198d --- /dev/null +++ b/livefiles_cs_plugin/lf_cs_disk_format.h @@ -0,0 +1,452 @@ +// +// Copyright (c) 2009-2019 Apple Inc. All rights reserved. +// +// lf_cs_disk_format.h - Defines on disk format for Apple_CoreStorage physical +// volumes for livefiles Apple_CoreStorage plugin. +// +// This header is copied from CoreStorage project. +// + +#ifndef _LF_CS_DISK_FORMAT_H +#define _LF_CS_DISK_FORMAT_H + +#define MAX_CKSUM_NBYTES 8 +#define CORESTORAGE_FORMAT_VERSION 1 + +// +// The 'dl_lvg.lvg_signature' in a DiskLabel (mimics 'CORESTOR') +// +#define CORE_STORAGE_SIGNATURE 0xC07E5707 + +// +// The 'mh_endianness' used to check endianness (non-palindromic 'CS') +// +#define BYTE_ORDER_MARK 0x5343 + +// +// Metadata block header. +// +struct metadata_header { + + // + // Block cksum. + // + uint8_t mh_cksum[MAX_CKSUM_NBYTES]; + + // + // The on-disk format version of CoreStorage. + // + uint16_t mh_format_version; + + // + // Enum metadata_blk_type (BLK_TYPE_*). + // + uint8_t mh_blk_type; + + // + // Enum metadata_blk_subtype (BLK_SUBTYPE_*), for b-tree/fsck. + // + uint8_t mh_blk_subtype; + + // + // The version of CoreStorage software that wrote this block. + // + uint32_t mh_bundle_version; + + // + // Transaction identification. + // + uint64_t mh_txg_id; + uint64_t mh_vaddr; + uint64_t mh_laddr; + + // + // Records the owner of the block. The owner of any blocks in a B-Tree + // is the root of the tree. The owner of any blocks in a list like + // structure (DSD list, attribute blocks) is the first block in the + // list. This field can be used for crash recovery by fsck_cs. For + // example, if this field has the B-Tree root vaddr that this block + // belongs, fsck_cs could reconstruct the B-Tree based on all leaf + // nodes. + // + uint64_t mh_blk_owner; + + // + // Block size (LVG MLV blksz). + // + uint32_t mh_blk_size; + + // + // Flags (BLK_FLAG_*). + // + uint8_t mh_blk_flags; + + // + // Reserved for future extensions + // make blk header 64 bytes (crypto alignment) + // + uint8_t mh_reserved1; + uint16_t mh_reserved2; + uint64_t mh_reserved8; +}; +typedef struct metadata_header metadata_header_t; + +int check_dk_metadata_header_size[sizeof(metadata_header_t) == 64 ? 1 : -1]; + + +#define NUM_VOL_HEADERS 2 +#define VOL_HEADER_NBYTES 512 +#define MAX_DISK_LABELS 4 +#define MAX_WIPEKEY_NBYTES 64 + +// +// This structure is padded such that it is of correct size. +// +struct dk_vol_header { + union { + struct { + metadata_header_t vh_header; + + // + // PV size in bytes, rounded down to VOL_HEADER_NBYTES + // boundary. + // + uint64_t vh_pv_nbytes; + + // + // If this is not 0, it records a PV resize operation + // + uint64_t vh_pv_resize; + + // + // If this is not 0, it records the old Volume Header + // location before the PV resize started; it is again 0 + // after completion. + // + uint64_t vh_old_pv_nbytes; + + // + // The cpu-platform endian that formatted this LVG. + // + uint16_t vh_endianness; + + // + // Checksum algorithm of VolHdr metadata header. + // + uint16_t vh_cksum_alg; + + // + // Reserved. + // + uint16_t vh_reserved2; + + // + // Number of disk labels. + // + uint16_t vh_num_labels; + + // + // Label address uses this block size. + // + uint32_t vh_blksz; + + // + // Maximum disk label size. + // + uint32_t vh_label_max_nbytes; + + // + // (Physical) Location of the new/old disk labels. + // + uint64_t vh_label_addr[MAX_DISK_LABELS]; + uint64_t vh_move_label_addr[MAX_DISK_LABELS]; + + // + // PV MLV/plist wipe keys ([0] is active, [1] future + // re-key). + // + uint16_t vh_wipe_key_nbytes[2]; + uint16_t vh_wipe_key_alg[2]; + uint8_t vh_wipe_key[2][MAX_WIPEKEY_NBYTES]; + + // + // UUID of this PV and its LVG (for bootstrap/multi-PV) + // + uint8_t vh_pv_uuid[16]; + uint8_t vh_lvg_uuid[16]; + }; + uint8_t vh_padding[VOL_HEADER_NBYTES]; + }; +}; +typedef struct dk_vol_header dk_vol_header_t; +int check_dk_vol_header_size[sizeof(dk_vol_header_t) == VOL_HEADER_NBYTES ? 1 : -1]; + +// +// Existing block types cannot be changed! +// +enum metadata_blk_type { + + // + // The values of the B-Tree types are important. They are the results + // of the bit operations of BTREE_ROOT, BTREE_NODE, and BTREE_LEAF in + // B-Tree code. + // + BLK_TYPE_BTREE_NODE = 2, // A B-Tree node that is not a leaf. + BLK_TYPE_BTREE_ROOT_NODE = 3, // A non-leaf B-Tree node that is also root. + BLK_TYPE_BTREE_LEAF = 4, // A B-Tree leaf node that is not a root. + BLK_TYPE_BTREE_ROOT_LEAF = 5, // A B-Tree leaf node that is also root. + + BLK_TYPE_VOL_HEADER = 16, + + // + // Fixed part of disk label (first MLV block size). + // + BLK_TYPE_DISK_LABEL = 17, + + BLK_TYPE_DISK_LABEL_CONT = 18, // Variable part of disk label. + + // + // LFS related blocks + // + + // + // MLV Partial Segment (PS) header block, first block of the first + // PS in a Group of Partial Segments (GPS). + // + BLK_TYPE_PS_HEADER = 19, + + // + // MLV Continuation Partial Segment block, first block of a Partial + // Segment (PS) in a Group of Partial Segments (GPS), where the PS + // is not the first PS in the GPS. + // + BLK_TYPE_PS_CONT_HDR = 20, + + // + // MLV Partial Segment (PS) Overflow header block, which holds + // information about added or deleted virtual blocks. + // + BLK_TYPE_PS_OVERFLOW_HDR = 21, + + // + // MLV Virtual Address Table (VAT) blocks, which holds VAT information. + // + BLK_TYPE_VAT = 22, + + // + // MLV Segment Usage Table (SUT) blocks, which holds SUT information. + // + BLK_TYPE_SUT = 23, + + // + // Metadata in MLV. + // + // MLV super block, the starting point of all MLV metadata. + // + BLK_TYPE_MLV_SUPERBLOCK = 24, + + // + // Logical Volume Family (LVF) super block. + // + BLK_TYPE_LV_FAMILY_SUPERBLOCK = 25, + + // + // Logical Volume (LV) super block. + // + BLK_TYPE_LV_SUPERBLOCK = 26, + + // + // Hold more LV attributes when they don't fit in the LV superblock. + // + BLK_TYPE_LV_XATTR = 27, + + // + // Holds the Physical Volume (PV) information. + // + BLK_TYPE_PV_TABLE = 28, + + // + // Holds the Physical Volume (PV) Freespace Log (FLOG) table + // information. + // + BLK_TYPE_PV_FLOG_TABLE = 29, + + BLK_TYPE_UNUSED_1 = 30, + BLK_TYPE_UNUSED_2 = 31, + BLK_TYPE_UNUSED_3 = 32, + + // + // Used for space sharing, records the amount of free space not used by + // the file system inside the Logical Volume. + // + BLK_TYPE_LV_FREE_SPACE_SUMMARY_DEPRECATED = 33, + + // + // Used for Physical Volume (PV) free space management, records the + // amount of free space in each chunk of the PV and has pointers to + // the Freespace Log (FLOG). + // + BLK_TYPE_PV_SUMMARY_TABLE = 34, + + BLK_TYPE_UNUSED_4 = 35, + + // + // Hold more LV Family attributes when they don't fit in the + // LVF superblock. + // + BLK_TYPE_LV_FAMILY_XATTR = 36, + + // + // Hold more Delayed Secure Deletion (DSD) list entries when + // they cannot fit in the LVF superblock. + // + BLK_TYPE_DSD_LIST = 37, + + // + // This block type is used to record information about bad sectors + // encountered during background encryption/decryption. + // + BLK_TYPE_BAD_SECTOR_LIST = 38, + + // + // For debugging: block is in dummy tree. + // + BLK_TYPE_DUMMY = 39, + + // + // New types are added here to preserve compatible on-disk format. + // + + NUM_BLK_TYPES, + + BLK_TYPE_UNKNOWN = 255, // Not used for on-disk blocks. +}; + +// +// Existing block subtypes cannot be changed! +// +enum metadata_blk_subtype { + + // + // Metadata in MLV. + // + BLK_SUBTYPE_NO_SUBTYPE = 0, + + BLK_SUBTYPE_LV_FAMILY_TREE, + BLK_SUBTYPE_LV_SNAPSHOT_TREE, + BLK_SUBTYPE_LV_ADDR_MAP_TREE, + BLK_SUBTYPE_PV_REFCOUNT_TREE, + BLK_SUBTYPE_LV_UNUSED_SPACE_TREE, + BLK_SUBTYPE_LVF_REFCOUNT_TREE, + + // + // The b-tree that holds blocks to populate MLV for testing. + // + BLK_SUBTYPE_DUMMY_TREE, + + // + // New types are added here to preserve compatible on-disk format. + // + + NUM_BLK_SUBTYPES, + + BLK_SUBTYPE_UNKNOWN = 255, // Not used for on-disk blocks. +}; +typedef enum metadata_blk_subtype metadata_blk_subtype_t; + + +// +// This block should be in the DSD List. It is not in the DSD list when it +// is first created. But when it is modified or killed, it will be included +// in the DSD list. +// +#define BLK_FLAG_IN_DSD_LIST 0x02 + +// +// On-disk information of LVG. +// +struct lvg_info { + uint32_t lvg_signature; // A signature that CoreStorage recognizes. + + // + // Version numbers can help diagnose problems. + // + + // + // The version of CoreStorage that created the LVG. + // + uint32_t lvg_creator_version; + + // + // The version of CoreStorage that modified the LVG the last time. + // + uint32_t lvg_writer_version; + + // + // The interval to sync MLV metadata in milliseconds. + // + uint16_t lvg_sync_interval_ms; + + // + // Checksum algorithm used for all metadata blocks and data blocks. + // + uint8_t lvg_metadata_cksum_alg; + + // + // Do not punch hole in the LVs on trim, so that the sparse LVs can become + // less and less sparse over time. + // + uint8_t lvg_no_punch_hole_on_trim; + + // + // These fields control our forwards/backwards compatibility. + // Features fall into three categories: compatible, read-only + // compatible, and incompatible. For any given version of the + // file system code, you can mount a file-system with any set + // of compatible features. If the file system encounters bits + // that are set in the read-only compatible features field and + // it does not know about those features then it must only mount + // the file system read-only. If the file system encounters + // any bits set in the incompatible features field that it does + // not know about, then it must not mount or modify the file + // system in any way. + // + // The idea for these compatibility fields is rather shamelessly + // stolen from rocky and ext2. + // + // + uint64_t lvg_compatible_features; + uint64_t lvg_read_only_compatible_features; + uint64_t lvg_incompatible_features; + + // + // When Soft Snapshot is enabled, this is the minimum granularity the + // extents will be updated with new timestamp. This is OK to be 0, so a + // predefined constant will be used. + // + uint64_t lvg_soft_snapshot_granularity_nbytes; + + // + // When LV checksum is enabled, this is the minimum granularity of data + // being checksummed. This is OK to be 0, so a predefined constant will + // be used. + // + uint64_t lvg_checksum_granularity_nbytes; + + // + // The min/max versions of CoreStorage that ever wrote to the LVG. + // + uint32_t lvg_min_writer_version; + uint32_t lvg_max_writer_version; + + // + // The following unused fields are reserved so we don't need to break + // format compatibility too often if we need more per-LVG fields. + // + uint64_t lvg_unused1; + uint64_t lvg_unused2; + uint64_t lvg_unused3; +}; +typedef struct lvg_info lvg_info_t; + +#endif /* _LF_CS_DISK_FORMAT_H */ diff --git a/livefiles_cs_plugin/lf_cs_logging.c b/livefiles_cs_plugin/lf_cs_logging.c new file mode 100644 index 0000000..56513d4 --- /dev/null +++ b/livefiles_cs_plugin/lf_cs_logging.c @@ -0,0 +1,57 @@ +// +// Copyright (c) 2019-2019 Apple Inc. All rights reserved. +// +// lf_cs_logging.c - Implemenents routines for logging info, erros, warnings +// and debug for livefiles Apple_CoreStorage plugin. +// + +#include +#include + +#include "lf_cs_logging.h" + +#if !LF_CS_USE_OSLOG + +#define VPRINTF(fmt, val) vfprintf(stderr, fmt, val) + +void +log_debug(const char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + VPRINTF(fmt, va); + va_end(va); +} + +void +log_info(const char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + VPRINTF(fmt, va); + va_end(va); +} + +void +log_warn(const char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + VPRINTF(fmt, va); + va_end(va); +} + +void +log_err(const char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + VPRINTF(fmt, va); + va_end(va); +} + +#endif /* !LF_CS_USE_OSLOG */ diff --git a/livefiles_cs_plugin/lf_cs_logging.h b/livefiles_cs_plugin/lf_cs_logging.h new file mode 100644 index 0000000..e399283 --- /dev/null +++ b/livefiles_cs_plugin/lf_cs_logging.h @@ -0,0 +1,40 @@ +// +// Copyright (c) 2009-2019 Apple Inc. All rights reserved. +// +// lf_cs_logging.h - Defines for helper methods for logging info, error, +// warning and debug messages for livefiles Apple_CoreStorage +// plugin. +// +#ifndef _LF_CS_LOGGING_H +#define _LF_CS_LOGGING_H + +#if LF_CS_USE_OSLOG +#include + +#define debugmsg(fmt, ...) \ + os_log_debug(OS_LOG_DEFAULT, "%s:%d: " fmt, __func__, __LINE__, ##__VA_ARGS__) +#define infomsg(fmt, ...) \ + os_log_info(OS_LOG_DEFAULT, "%s:%d: " fmt, __func__, __LINE__, ##__VA_ARGS__) +#define warnmsg(fmt, ...) \ + os_log(OS_LOG_DEFAULT, "%s:%d: " fmt, __func__, __LINE__, ##__VA_ARGS__) +#define errmsg(fmt, ...) \ + os_log_error(OS_LOG_DEFAULT, "%s:%d: " fmt, __func__, __LINE__, ##__VA_ARGS__) + +#else /* !LF_CS_USE_OSLOG */ + +void log_debug(const char *fmt, ...) __attribute__((format (printf, 1, 2))); +void log_info(const char *fmt, ...) __attribute__((format (printf, 1, 2))); +void log_warn(const char *fmt, ...) __attribute__((format (printf, 1, 2))); +void log_err(const char *fmt, ...) __attribute__((format (printf, 1, 2))); + +#define debugmsg(fmt, ...) \ + log_debug("%s:%d: " fmt, __func__, __LINE__, ##__VA_ARGS__) +#define infomsg(fmt, ...) \ + log_info("%s:%d: " fmt, __func__, __LINE__, ##__VA_ARGS__) +#define warnmsg(fmt, ...) \ + log_warn("%s:%d: " fmt, __func__, __LINE__, ##__VA_ARGS__) +#define errmsg(fmt, ...) \ + log_err("%s:%d: " fmt, __func__, __LINE__, ##__VA_ARGS__) + +#endif /* LF_CS_USE_OSLOG */ +#endif /* _LF_CS_LOGGING_H */ diff --git a/livefiles_cs_plugin/lf_cs_vfsops.c b/livefiles_cs_plugin/lf_cs_vfsops.c new file mode 100644 index 0000000..976f2e9 --- /dev/null +++ b/livefiles_cs_plugin/lf_cs_vfsops.c @@ -0,0 +1,656 @@ +// +// Copyright (c) 2019-2019 Apple Inc. All rights reserved. +// +// lf_cs_vfsops.c - Implemenents routines for handling VFS operations for +// livefiles Apple_CoreStorage plugin. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "lf_cs_checksum.h" +#include "lf_cs_disk_format.h" +#include "lf_cs_logging.h" +#include "lf_cs.h" + +#define VALUE_UNSPECIFIED ((uint64_t)-1) + +// +// Verify the given data checksum. If no explicit 'chk' area the cksum +// value to match against is assumed to reside at the beginning of the +// provided buffer (typically a 'metadata_header_t') and is excluded from +// the cksum calculation itself. +// +static unsigned +cs_verify_cksum(cksum_alg_t alg, const void *ptr, size_t len, + uint8_t *chk) +{ + uint8_t c[MAX_CKSUM_NBYTES]; + + if (!(alg == CKSUM_NONE) && !(alg == CKSUM_ALG_CRC_32)) { + return CS_STATUS_INVALID; + } + + cksum_init(alg, c); + if (chk == NULL) { + cksum(alg, (chk = (uint8_t *)ptr) + MAX_CKSUM_NBYTES, + len - MAX_CKSUM_NBYTES, c); + } else { + cksum(alg, ptr, len, c); + } + + if (memcmp(c, chk, MAX_CKSUM_NBYTES)) { + return CS_STATUS_CKSUM; + } + + return CS_STATUS_OK; +} + +// +// These block types must belong to the current transaction; all +// other types can be referenced from older transactions. +// +#define CS_CHKPOINT_BLK(_b) \ + ((_b)->mh_blk_type >= BLK_TYPE_VOL_HEADER &&\ + (_b)->mh_blk_type <= BLK_TYPE_SUT) + + +// +// These block types are the only ones with Secure Deletion content (LVF). +// +#define CS_DSDLIST_BLK(_b) \ + ((_b)->mh_blk_type == BLK_TYPE_LV_FAMILY_SUPERBLOCK ||\ + (_b)->mh_blk_type == BLK_TYPE_LV_FAMILY_XATTR) + +// +// cs_verify_blkhdr - Verify standard metadata header fields. +// +// Each block begins with a 'metadata_header_t', which often has known/expected +// values. +// +static unsigned +cs_verify_blkhdr(const metadata_header_t *hdr, uint16_t alg, + uint8_t type, uint8_t subtype, uint64_t vaddr, + uint64_t laddr, uint64_t txg, uint32_t blksz) +{ + unsigned status; + + if (alg != CKSUM_NONE && (status = cs_verify_cksum((cksum_alg_t)alg, + hdr, blksz, NULL)) != CS_STATUS_OK) { + return status; + } + + if (type != BLK_TYPE_UNKNOWN && hdr->mh_blk_type != type) { + return CS_STATUS_BLKTYPE; + } + + if (subtype != BLK_SUBTYPE_UNKNOWN && hdr->mh_blk_subtype != subtype) { + return CS_STATUS_INVALID; + } + + if (vaddr != VALUE_UNSPECIFIED && hdr->mh_vaddr != vaddr) { + return CS_STATUS_ADDRESS; + } + + if (laddr != VALUE_UNSPECIFIED && hdr->mh_laddr != laddr) { + return CS_STATUS_ADDRESS; + } + + if (txg != VALUE_UNSPECIFIED) { + if (CS_CHKPOINT_BLK(hdr) && hdr->mh_txg_id != txg) + return CS_STATUS_TXG; + else if (hdr->mh_txg_id > txg) + return CS_STATUS_TXG; + } + + if (blksz != 0 && hdr->mh_blk_size != blksz) { + return CS_STATUS_INVALID; + } + + if (!CS_DSDLIST_BLK(hdr) && + (hdr->mh_blk_flags & BLK_FLAG_IN_DSD_LIST)) { + return CS_STATUS_INVALID; + } + + return CS_STATUS_OK; +} + +// +// cs_verify_versions - Verify volume header version. +// +static unsigned +cs_verify_versions(const metadata_header_t *hdr) +{ + if (hdr != NULL && hdr->mh_format_version != + CORESTORAGE_FORMAT_VERSION) { + return CS_INFO_VERSIONITIS | CS_STATUS_NOTCS; + } + + if (hdr != NULL && + hdr->mh_blk_type == BLK_TYPE_VOL_HEADER && + ((dk_vol_header_t *)hdr)->vh_endianness != + BYTE_ORDER_MARK) { + return CS_INFO_VERSIONITIS | CS_STATUS_NOTCS; + } + + return CS_STATUS_OK; +} + +// +// cs_verify_vh - Read and verify the Volume Headers (first/last 512-bytes of +// the PV). +// +static unsigned +cs_verify_vh(dk_vol_header_t *hdr, uint32_t blksz) +{ + unsigned status; + + status = cs_verify_blkhdr(&hdr->vh_header, hdr->vh_cksum_alg, + BLK_TYPE_VOL_HEADER, + BLK_SUBTYPE_NO_SUBTYPE, 0, 0, + VALUE_UNSPECIFIED, VOL_HEADER_NBYTES); + if (status != CS_STATUS_OK) { + return status; + } + + status = cs_verify_versions(&hdr->vh_header); + if (status != CS_STATUS_OK) { + return status; + } + + if (!hdr->vh_num_labels || hdr->vh_num_labels > MAX_DISK_LABELS) { + return CS_STATUS_INVALID; + } + + if (hdr->vh_label_max_nbytes % blksz != 0) { + return CS_STATUS_INVALID; + } + + if (hdr->vh_blksz == 0 || hdr->vh_blksz % blksz != 0) { + return CS_STATUS_INVALID; + } + + if (hdr->vh_pv_nbytes % blksz != 0 || + hdr->vh_pv_nbytes < CS_ALIGN(VOL_HEADER_NBYTES, + blksz, true) * NUM_VOL_HEADERS) { + return CS_STATUS_INVALID; + } + + if (hdr->vh_pv_resize != 0 && (hdr->vh_pv_resize % blksz != 0 || + hdr->vh_pv_resize < CS_ALIGN(VOL_HEADER_NBYTES, + blksz, true) * NUM_VOL_HEADERS)) { + return CS_STATUS_INVALID; + } + + if (hdr->vh_old_pv_nbytes != 0 && + (hdr->vh_old_pv_nbytes % blksz != 0 || + hdr->vh_old_pv_nbytes < CS_ALIGN(VOL_HEADER_NBYTES, + blksz, true) * NUM_VOL_HEADERS)) { + return CS_STATUS_INVALID; + } + + return CS_STATUS_OK; +} + +// +// cs_get_content_hint_for_pv - get content hint of the disk from IOReg. We +// read the IOReg to check if the passed disk has +// a Apple_CoreStorage content hint. +// +static bool +cs_get_content_hint_for_pv(struct stat *st) +{ + bool has_cs_hint; + int dev_major, dev_minor; + CFMutableDictionaryRef matching; + + has_cs_hint = false; + if ((matching = IOServiceMatching(kIOMediaClass))) { + CFTypeRef str; + io_service_t service; + + if ((matching = IOServiceMatching(kIOMediaClass))) { + CFNumberRef num_ref; + + dev_major = major(st->st_rdev); + dev_minor = minor(st->st_rdev); + + num_ref = CFNumberCreate(kCFAllocatorDefault, + kCFNumberIntType, &dev_major); + if (num_ref) { + CFDictionarySetValue(matching, + CFSTR(kIOBSDMajorKey), + num_ref); + CFRelease(num_ref); + } + + num_ref = CFNumberCreate(kCFAllocatorDefault, + kCFNumberIntType, &dev_minor); + if (num_ref) { + CFDictionarySetValue(matching, + CFSTR(kIOBSDMinorKey), + num_ref); + CFRelease(num_ref); + } + + service = IOServiceGetMatchingService( + kIOMasterPortDefault, matching); + if (!service) { + goto out; + } + + if ((str = IORegistryEntryCreateCFProperty( service, + CFSTR(kIOMediaContentHintKey), + kCFAllocatorDefault, 0)) != + NULL) { + + has_cs_hint = CFStringCompare((CFStringRef)str, + CFSTR(APPLE_CORESTORAGE_UUID), 0) == + kCFCompareEqualTo; + + CFRelease(str); + IOObjectRelease(service); + } + } + } +out: + return has_cs_hint; +} + +static unsigned +cs_verify_hdrfields(void *block, uint16_t alg, uint8_t type, + uint8_t subtype, uint64_t vaddr, uint64_t laddr, + uint32_t blksz) +{ + unsigned status; + + if (alg != CKSUM_NONE && (status = cs_verify_cksum((cksum_alg_t)alg, + block, blksz, NULL)) != + CS_STATUS_OK) { + return status; + } + + if (type != BLK_TYPE_VOL_HEADER) { + return CS_STATUS_BLKTYPE; + } + + if (subtype != BLK_SUBTYPE_NO_SUBTYPE) { + return CS_STATUS_INVALID; + } + + if (vaddr != 0) { + return CS_STATUS_ADDRESS; + } + + if (laddr != 0) { + return CS_STATUS_ADDRESS; + } + + if (blksz != VOL_HEADER_NBYTES) { + return CS_STATUS_INVALID; + } + + return CS_STATUS_OK; +} + +// +// Verify if a Volume Header error might actually be due to a stale format. +// Some historic block layouts were such that they spuriously fail recent +// validity checks (there was a relocation of some key identifying fields in +// the v9->v10->v11 switch). Thus we follow-up a failure by some rudimentary +// probing (incl cksum) and override error. +// +static unsigned +cs_older_cs_version(dk_vol_header_t *hdr, unsigned status) +{ + uint16_t cksum_alg; + + struct { + uint8_t zeroes[VOL_HEADER_NBYTES]; + } inprogress = {0}; + + struct v11_volhdr { + uint8_t mh_cksum[MAX_CKSUM_NBYTES]; + uint16_t mh_format_version; + uint8_t mh_blk_type; + uint8_t mh_blk_subtype; + uint32_t mh_bundle_version; + uint64_t mh_txg_id; + uint64_t mh_vaddr; + uint64_t mh_laddr; + uint64_t mh_blk_owner; + uint32_t mh_blk_size; + uint8_t mh_blk_flags; + uint8_t mh_reserved1; + uint16_t mh_reserved2; + uint64_t mh_reserved8; + uint64_t vh_pv_nbytes; + uint64_t vh_pv_resize; + uint64_t vh_old_pv_nbytes; + uint16_t vh_endianness; + uint16_t vh_cksum_alg; + uint16_t vh_reserved2; + uint16_t vh_num_labels; + uint32_t vh_blksz; + uint32_t vh_label_max_nbytes; + uint64_t vh_label_addr[MAX_DISK_LABELS]; + uint64_t vh_move_label_addr[MAX_DISK_LABELS]; + uint16_t vh_wipe_key_nbytes[2]; + uint16_t vh_wipe_key_alg[2]; + uint8_t vh_wipe_key[2][MAX_WIPEKEY_NBYTES]; + uint8_t vh_pv_uuid[16]; + uint8_t vh_lvg_uuid[16]; + } *v11; + + + if ((CS_STATUS(status) != CS_STATUS_OK) && + (hdr->vh_header.mh_format_version != + CORESTORAGE_FORMAT_VERSION)) { + + // + // Ensure that the volume header is not totally empty before + // trying to check if this is indeed an older version. + // + if (!memcmp(hdr, &inprogress, VOL_HEADER_NBYTES)) { + return CS_INFO_ZERO_VH | CS_STATUS_NOTCS; + } + + v11 = (struct v11_volhdr *)hdr; + if (v11->mh_format_version == 11) { + + cksum_alg = v11->vh_cksum_alg; + if (cs_verify_hdrfields(v11, cksum_alg, + v11->mh_blk_type, + v11->mh_blk_subtype, + v11->mh_vaddr, + v11->mh_laddr, + v11->mh_blk_size) == + CS_STATUS_OK) { + + return CS_INFO_VERSIONITIS | CS_STATUS_NOTCS; + } + } + } + + return status; +} + +// +// cs_fd_is_corestorage_pv - taste if the disk is Apple_CoreStorage PV. +// +static int +cs_fd_is_corestorage_pv(int disk_fd, bool *is_cs_pv) +{ + struct stat st; + bool pv_has_csuuid_hint; + int vh_idx, error; + uint32_t pv_blksz; + uint64_t pv_nblks; + uint64_t offset[NUM_VOL_HEADERS + 1]; + unsigned status[NUM_VOL_HEADERS + 1]; + + dk_vol_header_t hdr[NUM_VOL_HEADERS + 1]; + + error = 0; + pv_blksz = 0; + pv_nblks = 0; + *is_cs_pv = false; + pv_has_csuuid_hint = false; + + infomsg("Tasting Apple_CoreStorage plugin, fd: %d\n", disk_fd); + + // + // Userfs corestorage plugin only supports block device. Thus, we + // ensure that the passed device is block device before proceeding + // further. + // + fstat(disk_fd, &st); + if (!S_ISBLK(st.st_mode)) { + errmsg("Apple_CoreStorage plugin only supports block " + "device. Aborting taste.\n"); + return ENOTSUP; + } + + // + // Each PV has two volume headers, each has size 512 bytes, and resides + // on the first and last 512 bytes of the PV. Each volume header has a + // common block header with txg id and checksum, and only the volume + // header with the right checksum and largest txg id is used when + // mounting the LVG. Thus, to read the last volume header we need to + // know the block-size and the number of blocks in the block device. + // + if (ioctl(disk_fd, DKIOCGETBLOCKSIZE, &pv_blksz) == -1) { + error = errno; + } + + if (!error && ioctl(disk_fd, DKIOCGETBLOCKCOUNT, &pv_nblks) == -1) { + error = errno; + } + + // + // If we fail to determine the block size and block count, we bail out. + // + if (!error && (!pv_blksz || !pv_nblks)) { + error = ENOTBLK; + } + + if (error) { + errmsg("Failed to get blocksize and block count " + "for the device. Aborting taste.\n"); + return error; + } + + // + // Check if the device is tagged as being Apple_CoreStorage (Content + // Hint). If not we bail-out now. + // + pv_has_csuuid_hint = cs_get_content_hint_for_pv(&st); + if (!pv_has_csuuid_hint) { + *is_cs_pv = false; + return 0; + } + + // + // We go through the two volume headers at offset 0 and at offset + // (pv_nblks * pv_blksz - VOL_HEADER_NBYTES) and try to verify if + // the volume headers are valid core storage physical volume volume + // headers. + // + offset[0] = 0; + offset[1] = pv_nblks * pv_blksz - VOL_HEADER_NBYTES; + + // + // Initialize status as invalid. + // + for (vh_idx = 0; vh_idx < NUM_VOL_HEADERS; ++vh_idx ) { + status[vh_idx] = CS_STATUS_INVALID; + } + + for (vh_idx = 0; vh_idx < NUM_VOL_HEADERS; ++vh_idx) { + ssize_t bytes_read; + + // + // Read the PV volume header and cache it inside `hdr[vh_idx]`. + // + bytes_read = pread(disk_fd, &hdr[vh_idx], VOL_HEADER_NBYTES, + offset[vh_idx]); + + if (bytes_read == -1) { + error = errno; + } + + if (!error && bytes_read != VOL_HEADER_NBYTES) { + error = EIO; + } + + if (error) { + errmsg("Failed to read volume-hearder at offset %llu " + "for disk with fd %d, Aborting taste.\n", + offset[vh_idx], disk_fd); + break; + } + + // + // Verify read volume-header. + // + status[vh_idx] = cs_verify_vh(&hdr[vh_idx], pv_blksz); + if (CS_STATUS(status[vh_idx]) != CS_STATUS_OK) { + + // + // Check if this physical volume has an older version + // of header. + // + status[vh_idx] = cs_older_cs_version(&hdr[vh_idx], + status[vh_idx]); + if (CS_INFO(status[vh_idx]) & CS_INFO_VERSIONITIS) { + + infomsg("Disk with fd %u has older physical " + "volume header format.\n", + disk_fd); + status[vh_idx] = CS_STATUS_OK; + } + } + + if (status[vh_idx] != CS_STATUS_OK) { + break; + } + } + + if (error) { + return error; + } + + // + // If there was no error and both the volume headers passed + // verification that means this is a core storage physical volume. + // + for (vh_idx = 0; vh_idx < NUM_VOL_HEADERS; ++vh_idx ) { + if (status[vh_idx] != CS_STATUS_OK) { + break; + } + *is_cs_pv = true; + } + + return 0; +} + +// +// cs_uvfsop_taste - taste if a given disk is Apple_CoreStorage PV. +// +// disk_fd: file descriptor of the disk to taste. +// +// Returns: +// +// i) 0 if the passed disk is indeed an Apple_CoreStorage PV. +// +// Or +// +// ii) ENOTSUP if the passed disk is not an Apple_CoreStorage PV. +// +// Or +// +// iii) errno if there was some error attempting to taste the disk. +// +static int +cs_uvfsop_taste(int disk_fd) +{ + int error; + bool is_cs_pv; + + // + // Each PV has two volume headers, each has size 512 bytes, and resides + // on the first and last 512 bytes of the PV. Each volume header has a + // common block header with transaction-id and checksum, and only the + // volume header with the right checksum and largest transaction-id is + // used when mounting the LVG(logical volume group). To verify that + // the disk with file descriptor is indeed a Apple_CoreStorage PV + // (physical volume), we: + // + // i) Read IOReg to verify that it has `APPLE_CORESTORAGE_UUID` hint. + // + // and + // + // ii) Verify the PV volume headers at the start and end of the disk. + // + // Please NOTE: This taste function is defensive (strict). We do a + // strict match so that we ensure that we don't falsely match some + // other volume format. + // + error = cs_fd_is_corestorage_pv(disk_fd, &is_cs_pv); + if (error) { + errmsg("Encountered error while tasting disk with file " + "descriptor %d for Apple_CoreStorage " + "plugin (error %d).\n", disk_fd, error); + return error; + + } + + // + // This is not an Apple_CoreStorage PV. + // + if (!is_cs_pv) { + errmsg("Disk with file descriptor %d is not an corestorage " + "physical volume.\n", disk_fd); + return ENOTSUP; + } + + // + // We have found an Apple_CoreStorage PV, return success. + // + infomsg("Disk with file descriptor %d is corestorage physical " + "volume.\n", disk_fd); + + return 0; +} + +// +// Plugin lifecycle functions. +// +static int +cs_uvfsop_init(void) +{ + infomsg("Initializing CS UserFS plugin...\n"); + return 0; +} + +static void +cs_uvfsop_fini(void) +{ + infomsg("Cleaning up CS UserFS plugin...\n"); +} + +// +// Plugin function registration. +// +UVFSFSOps cs_fsops = { + .fsops_version = UVFS_FSOPS_VERSION_CURRENT, + .fsops_init = cs_uvfsop_init, + .fsops_fini = cs_uvfsop_fini, + .fsops_taste = cs_uvfsop_taste, +}; + +__attribute__((visibility("default"))) +void +livefiles_plugin_init(UVFSFSOps **ops) +{ + if (ops) { + *ops = &cs_fsops; + } +} diff --git a/livefiles_cs_plugin/livefiles_cs_tester.c b/livefiles_cs_plugin/livefiles_cs_tester.c new file mode 100644 index 0000000..4261bdc --- /dev/null +++ b/livefiles_cs_plugin/livefiles_cs_tester.c @@ -0,0 +1,157 @@ +// +// Copyright (c) 2019 Apple Inc. All rights reserved. +// +// @APPLE_LICENSE_HEADER_START@ +// +// This file contains Original Code and/or Modifications of Original Code +// as defined in and that are subject to the Apple Public Source License +// Version 2.0 (the 'License'). You may not use this file except in +// compliance with the License. Please obtain a copy of the License at +// http://www.opensource.apple.com/apsl/ and read it before using this +// file. +// +// The Original Code and all software distributed under the License are +// distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +// EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +// INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +// Please see the License for the specific language governing rights and +// limitations under the License. +// +// @APPLE_LICENSE_HEADER_END@ +// +// livefiles_cs_tester.c - Implements unit tests for livefiles +// Apple_CoreStorage plugin. +// + +#include +#include +#include +#include +#include +#include + +#include + +extern UVFSFSOps cs_fsops; + +// +// Enums describing file-system formats. +// +typedef enum { + JHFS = 1, + APFS, + FAT32, + EXFAT, + APPLE_CS, + + INVALID_FS_TYPE = INT8_MAX, +} lf_cspt_fstype_t; + +// +// Array describing file-system name and analogous types. +// +const struct { + const char *const fs_name; + lf_cspt_fstype_t fs_type; +} lf_cspt_fstype_arr_t[] = { + + {"JHFS", JHFS}, + {"APFS", APFS}, + {"EXFAT",EXFAT}, + {"FAT32",FAT32}, + {"APPLE_CS", APPLE_CS}, + + {NULL, INVALID_FS_TYPE} +}; + +// +// Validate file-system types that is supported by this program. +// +static bool +is_fstype_valid(const char *fs_name, lf_cspt_fstype_t *fs_type) +{ + int idx; + + for (idx = 0; lf_cspt_fstype_arr_t[idx].fs_name != NULL; idx++) { + if (strcmp(fs_name, lf_cspt_fstype_arr_t[idx].fs_name) == 0) { + *fs_type = lf_cspt_fstype_arr_t[idx].fs_type; + return true; + } + } + + return false; +} + +// +// Usage string returned to user. +// +static int +usage(const char *prog_name) +{ + fprintf(stderr, "Usage: %s filesystem-format device-path\n", + prog_name); + return EINVAL; +} + +int +main(int argc, char *argv[]) +{ + int fd, error; + lf_cspt_fstype_t fs_type; + + if (argc != 3) { + return usage(argv[0]); + } + + if (!is_fstype_valid(argv[1], &fs_type)) { + fprintf(stderr, "Unknown file-system type %s\n", argv[1]); + return EINVAL; + } + + fd = open(argv[2], O_RDWR); + if (fd < 0) { + fprintf(stderr, "Failed to open device [%s]: %d\n", + argv[2], errno); + return EBADF; + } + + error = cs_fsops.fsops_init(); + printf("Init for fs_type %s returned [%d]\n", argv[1], error); + if (error) { + goto test_end; + } + + error = cs_fsops.fsops_taste(fd); + switch(fs_type) { + case JHFS: + case APFS: + case EXFAT: + case FAT32: + + // + // Taste with these disk-image is expected to retrun + // ENOTSUP. Thus supress the error here. + // + if (error == ENOTSUP) { + error = 0; + } + break; + + case APPLE_CS: + break; + + // + // Control should not come here. + // + default: + fprintf(stderr, "Bug in test.\n"); + } + printf("Taste for fs_type %s returned [%d]\n", argv[1], error); + cs_fsops.fsops_fini(); + +test_end: + printf("Test result [%d]\n", error); + close(fd); + return EXIT_SUCCESS; +} diff --git a/livefiles_cs_plugin/livefiles_cs_tester.entitlements b/livefiles_cs_plugin/livefiles_cs_tester.entitlements new file mode 100644 index 0000000..4396b7d --- /dev/null +++ b/livefiles_cs_plugin/livefiles_cs_tester.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.rootless.restricted-block-devices + + com.apple.private.security.disk-device-access + + + diff --git a/livefiles_hfs_plugin/lf_hfs.h b/livefiles_hfs_plugin/lf_hfs.h index 8ddb76e..56b3345 100644 --- a/livefiles_hfs_plugin/lf_hfs.h +++ b/livefiles_hfs_plugin/lf_hfs.h @@ -279,8 +279,8 @@ typedef struct hfsmount { uuid_t hfs_full_uuid; /* Per mount cnode hash variables: */ - pthread_mutex_t hfs_chash_mutex; /* protects access to cnode hash table */ - u_long hfs_cnodehash; /* size of cnode hash table - 1 */ + pthread_mutex_t hfs_chash_mutex; /* protects access to cnode hash table */ + u_long hfs_cnodehash; /* size of cnode hash table - 1 */ LIST_HEAD(cnodehashhead, cnode) *hfs_cnodehashtbl; /* base of cnode hash */ /* Per mount fileid hash variables (protected by catalog lock!) */ diff --git a/livefiles_hfs_plugin/lf_hfs_catalog.c b/livefiles_hfs_plugin/lf_hfs_catalog.c index 2c274ce..165e089 100644 --- a/livefiles_hfs_plugin/lf_hfs_catalog.c +++ b/livefiles_hfs_plugin/lf_hfs_catalog.c @@ -3207,12 +3207,12 @@ cat_check_link_ancestry(struct hfsmount *hfsmp, cnid_t cnid, cnid_t pointed_at_c break; } if ((result = getkey(hfsmp, cnid, (CatalogKey *)keyp))) { - LFHFS_LOG(LEVEL_ERROR, "cat_check_link_ancestry: getkey failed id=%u, vol=%s\n", cnid, hfsmp->vcbVN); + LFHFS_LOG(LEVEL_ERROR, "cat_check_link_ancestry: getkey failed [%d] id=%u, vol=%s\n", result, cnid, hfsmp->vcbVN); invalid = 1; /* On errors, assume an invalid parent */ break; } if ((result = BTSearchRecord(fcb, ip, &btdata, NULL, NULL))) { - LFHFS_LOG(LEVEL_ERROR, "cat_check_link_ancestry: cannot find id=%u, vol=%s\n", cnid, hfsmp->vcbVN); + LFHFS_LOG(LEVEL_ERROR, "cat_check_link_ancestry: cannot find id=%u, vol=%s, [%d]\n", cnid, hfsmp->vcbVN, result); invalid = 1; /* On errors, assume an invalid parent */ break; } diff --git a/livefiles_hfs_plugin/lf_hfs_chash.c b/livefiles_hfs_plugin/lf_hfs_chash.c index 60f4fd5..1eb9ce8 100644 --- a/livefiles_hfs_plugin/lf_hfs_chash.c +++ b/livefiles_hfs_plugin/lf_hfs_chash.c @@ -23,13 +23,22 @@ hfs_chash_wait(struct hfsmount *hfsmp, struct cnode *cp) pthread_cond_wait(&cp->c_cacsh_cond, &hfsmp->hfs_chash_mutex); } -void +static void hfs_chash_broadcast_and_unlock(struct hfsmount *hfsmp, struct cnode *cp) { - pthread_cond_signal(&cp->c_cacsh_cond); + if (cp) + pthread_cond_signal(&cp->c_cacsh_cond); hfs_chash_unlock(hfsmp); } +static void +hfs_chash_wait_and_unlock(struct hfsmount *hfsmp, struct cnode *cp) +{ + SET(cp->c_hflag, H_WAITING); + pthread_cond_wait(&cp->c_cacsh_cond, &hfsmp->hfs_chash_mutex); + hfs_chash_broadcast_and_unlock(hfsmp, cp); +} + void hfs_chash_raise_OpenLookupCounter(struct cnode *cp) { @@ -175,7 +184,7 @@ loop_with_lock: if (hfs_lock(cp, HFS_TRY_EXCLUSIVE_LOCK, HFS_LOCK_ALLOW_NOEXISTS)) { SET(cp->c_hflag, H_WAITING); - hfs_chash_broadcast_and_unlock(hfsmp,cp); + hfs_chash_broadcast_and_unlock(hfsmp, cp); usleep(100); goto loop; } @@ -216,6 +225,7 @@ loop_with_lock: *hflags &= ~H_ATTACH; } + pthread_cond_signal(&cp->c_cacsh_cond); vp = NULL; cp = NULL; if (renamed) @@ -224,8 +234,12 @@ loop_with_lock: } } - if (cp) hfs_chash_raise_OpenLookupCounter(cp); - hfs_chash_broadcast_and_unlock(hfsmp,cp); + if (cp) { + hfs_chash_raise_OpenLookupCounter(cp); + } + + hfs_chash_broadcast_and_unlock(hfsmp, cp); + *vpp = vp; return (cp); } @@ -242,7 +256,6 @@ loop_with_lock: if (ncp == NULL) { hfs_chash_unlock(hfsmp); - ncp = hfs_mallocz(sizeof(struct cnode)); if (ncp == NULL) { @@ -267,7 +280,7 @@ loop_with_lock: lf_lck_rw_init(&ncp->c_rwlock); lf_cond_init(&ncp->c_cacsh_cond); - + if (!skiplock) { (void) hfs_lock(ncp, HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT); @@ -290,10 +303,9 @@ hfs_chashwakeup(struct hfsmount *hfsmp, struct cnode *cp, int hflags) if (ISSET(cp->c_hflag, H_WAITING)) { CLR(cp->c_hflag, H_WAITING); - pthread_cond_broadcast(&cp->c_cacsh_cond); } - hfs_chash_unlock(hfsmp); + hfs_chash_broadcast_and_unlock(hfsmp, cp); } /* @@ -312,9 +324,8 @@ hfs_chash_abort(struct hfsmount *hfsmp, struct cnode *cp) if (ISSET(cp->c_hflag, H_WAITING)) { CLR(cp->c_hflag, H_WAITING); - pthread_cond_broadcast(&cp->c_cacsh_cond); } - hfs_chash_unlock(hfsmp); + hfs_chash_broadcast_and_unlock(hfsmp, cp); } /* @@ -342,8 +353,7 @@ loop: /* Wait if cnode is being created or reclaimed. */ if (ISSET(cp->c_hflag, H_ALLOC | H_TRANSIT | H_ATTACH)) { SET(cp->c_hflag, H_WAITING); - hfs_chash_broadcast_and_unlock(hfsmp,cp); - usleep(100); + hfs_chash_wait_and_unlock(hfsmp,cp); goto loop; } /* Obtain the desired vnode. */ @@ -358,7 +368,7 @@ loop: if (hfs_lock(cp, HFS_TRY_EXCLUSIVE_LOCK, HFS_LOCK_ALLOW_NOEXISTS)) { SET(cp->c_hflag, H_WAITING); - hfs_chash_broadcast_and_unlock(hfsmp,cp); + hfs_chash_broadcast_and_unlock(hfsmp, cp); usleep(100); goto loop; } @@ -380,9 +390,10 @@ loop: } hfs_chash_raise_OpenLookupCounter(cp); - hfs_chash_broadcast_and_unlock(hfsmp,cp); + hfs_chash_broadcast_and_unlock(hfsmp, cp); return (vp); } + exit: hfs_chash_unlock(hfsmp); return (NULL); @@ -494,7 +505,7 @@ hfs_chash_set_childlinkbit(struct hfsmount *hfsmp, cnid_t cnid) retval = 1; } } - hfs_chash_unlock(hfsmp); + hfs_chash_broadcast_and_unlock(hfsmp, cp); return retval; } @@ -510,7 +521,7 @@ hfs_chashremove(struct hfsmount *hfsmp, struct cnode *cp) /* Check if a vnode is getting attached */ if (ISSET(cp->c_hflag, H_ATTACH)) { - hfs_chash_unlock(hfsmp); + hfs_chash_broadcast_and_unlock(hfsmp, cp); return (EBUSY); } if (cp->c_hash.le_next || cp->c_hash.le_prev) { @@ -519,7 +530,7 @@ hfs_chashremove(struct hfsmount *hfsmp, struct cnode *cp) cp->c_hash.le_prev = NULL; } - hfs_chash_unlock(hfsmp); + hfs_chash_broadcast_and_unlock(hfsmp, cp); return (0); } @@ -534,5 +545,5 @@ hfs_chash_mark_in_transit(struct hfsmount *hfsmp, struct cnode *cp) SET(cp->c_hflag, H_TRANSIT); - hfs_chash_unlock(hfsmp); + hfs_chash_broadcast_and_unlock(hfsmp, cp); } diff --git a/livefiles_hfs_plugin/lf_hfs_cnode.c b/livefiles_hfs_plugin/lf_hfs_cnode.c index 2e15868..1431f98 100644 --- a/livefiles_hfs_plugin/lf_hfs_cnode.c +++ b/livefiles_hfs_plugin/lf_hfs_cnode.c @@ -94,7 +94,6 @@ hfs_getnewvnode(struct hfsmount *hfsmp, struct vnode *dvp, struct componentname struct mount *mp = HFSTOVFS(hfsmp); struct vnode *vp = NULL; struct vnode **cvpp; - struct vnode *tvp = NULL; struct cnode *cp = NULL; struct filefork *fp = NULL; struct vnode *provided_vp = NULL; @@ -439,7 +438,7 @@ hfs_getnewvnode(struct hfsmount *hfsmp, struct vnode *dvp, struct componentname } cp->c_rsrcfork = fp; cvpp = &cp->c_rsrc_vp; - if ( (tvp = cp->c_vp) != NULL ) + if (cp->c_vp != NULL ) { cp->c_flag |= C_NEED_DVNODE_PUT; } @@ -459,7 +458,7 @@ hfs_getnewvnode(struct hfsmount *hfsmp, struct vnode *dvp, struct componentname cp->c_datafork = fp; cvpp = &cp->c_vp; - if ( (tvp = cp->c_rsrc_vp) != NULL) + if (cp->c_rsrc_vp != NULL) { cp->c_flag |= C_NEED_RVNODE_PUT; } @@ -489,7 +488,7 @@ hfs_getnewvnode(struct hfsmount *hfsmp, struct vnode *dvp, struct componentname retval = ENOMEM; goto gnv_exit; } - + bzero(vfsp.vnfs_cnp, sizeof(struct componentname)); memcpy((void*) vfsp.vnfs_cnp, (void*)cnp, sizeof(struct componentname)); vfsp.vnfs_cnp->cn_nameptr = lf_hfs_utils_allocate_and_copy_string( (char*) cnp->cn_nameptr, cnp->cn_namelen ); @@ -1871,9 +1870,12 @@ hfs_fork_release(struct cnode* cp, struct vnode *vp, bool bIsRsc, int* piErr) if (vp->sFSParams.vnfs_cnp) { - if (vp->sFSParams.vnfs_cnp->cn_nameptr) + if (vp->sFSParams.vnfs_cnp->cn_nameptr) { hfs_free(vp->sFSParams.vnfs_cnp->cn_nameptr); + vp->sFSParams.vnfs_cnp->cn_nameptr = NULL; + } hfs_free(vp->sFSParams.vnfs_cnp); + vp->sFSParams.vnfs_cnp = NULL; } @@ -1931,6 +1933,8 @@ hfs_fork_release(struct cnode* cp, struct vnode *vp, bool bIsRsc, int* piErr) int hfs_vnop_reclaim(struct vnode *vp) { + if (!vp) return EINVAL; + struct cnode* cp = VTOC(vp); struct hfsmount *hfsmp = VTOHFS(vp); struct vnode *altvp = NULL; diff --git a/livefiles_hfs_plugin/lf_hfs_fsops_handler.c b/livefiles_hfs_plugin/lf_hfs_fsops_handler.c index b4bb873..09bb5ac 100644 --- a/livefiles_hfs_plugin/lf_hfs_fsops_handler.c +++ b/livefiles_hfs_plugin/lf_hfs_fsops_handler.c @@ -491,8 +491,11 @@ LFHFS_GetFSAttr ( UVFSFileNode psNode, const char *pcAttr, UVFSFSAttributeValue return E2BIG; } // A string representing the type of file system - strcpy(psAttrVal->fsa_string, "HFS"); - *(psAttrVal->fsa_string+3) = 0; // Must be null terminated + size_t n = strlcpy(psAttrVal->fsa_string, "HFS", *puRetLen); + if (n >= *puRetLen) + { + *(psAttrVal->fsa_string + (*puRetLen - 1)) = '\0'; // Must be null terminated + } goto end; } @@ -523,7 +526,7 @@ LFHFS_GetFSAttr ( UVFSFileNode psNode, const char *pcAttr, UVFSFSAttributeValue return E2BIG; } - strcpy( psAttrVal->fsa_string, pcFSSubType ); + strlcpy( psAttrVal->fsa_string, pcFSSubType, *puRetLen); goto end; } @@ -534,7 +537,7 @@ LFHFS_GetFSAttr ( UVFSFileNode psNode, const char *pcAttr, UVFSFSAttributeValue { return E2BIG; } - strcpy(psAttrVal->fsa_string, (char *)psMount->vcbVN); + strlcpy(psAttrVal->fsa_string, (char *)psMount->vcbVN, *puRetLen); goto end; } diff --git a/livefiles_hfs_plugin/lf_hfs_journal.c b/livefiles_hfs_plugin/lf_hfs_journal.c index 471868d..cc3522d 100644 --- a/livefiles_hfs_plugin/lf_hfs_journal.c +++ b/livefiles_hfs_plugin/lf_hfs_journal.c @@ -2914,11 +2914,11 @@ static int end_transaction(transaction *tr, int force_it, errno_t (*callback)(vo lock_oldstart(jnl); /* - * Because old_start is locked above, we can cast away the volatile qualifier before passing it to memcpy. + * Because old_start is locked above, we can cast away the volatile qualifier before passing it to memmove. * slide everyone else down and put our latest guy in the last * entry in the old_start array */ - memcpy(__CAST_AWAY_QUALIFIER(&jnl->old_start[0], volatile, void *), __CAST_AWAY_QUALIFIER(&jnl->old_start[1], volatile, void *), sizeof(jnl->old_start)-sizeof(jnl->old_start[0])); + memmove(__CAST_AWAY_QUALIFIER(&jnl->old_start[0], volatile, void *), __CAST_AWAY_QUALIFIER(&jnl->old_start[1], volatile, void *), sizeof(jnl->old_start)-sizeof(jnl->old_start[0])); jnl->old_start[sizeof(jnl->old_start)/sizeof(jnl->old_start[0]) - 1] = tr->journal_start | 0x8000000000000000LL; unlock_oldstart(jnl); diff --git a/livefiles_hfs_plugin/lf_hfs_link.c b/livefiles_hfs_plugin/lf_hfs_link.c index f765476..2797881 100644 --- a/livefiles_hfs_plugin/lf_hfs_link.c +++ b/livefiles_hfs_plugin/lf_hfs_link.c @@ -558,7 +558,7 @@ hfs_privatedir_init(struct hfsmount * hfsmp, enum privdirtype type) /* Get the CNID for use */ cnid_t new_id; - if ((error = cat_acquire_cnid(hfsmp, &new_id))) { + if (cat_acquire_cnid(hfsmp, &new_id)) { hfs_systemfile_unlock (hfsmp, lockflags); goto exit; } diff --git a/livefiles_hfs_plugin/lf_hfs_vfsops.c b/livefiles_hfs_plugin/lf_hfs_vfsops.c index 4689cad..3b1c3cc 100644 --- a/livefiles_hfs_plugin/lf_hfs_vfsops.c +++ b/livefiles_hfs_plugin/lf_hfs_vfsops.c @@ -324,6 +324,7 @@ static int hfs_InitialMount(struct vnode *devvp, struct mount *mp, struct hfs_mo mntwrapper = 0; minblksize = kHFSBlockSize; + *hfsmp = NULL; /* Get the logical block size (treated as physical block size everywhere) */ if (ioctl(devvp->psFSRecord->iFD, DKIOCGETBLOCKSIZE, &log_blksize)) @@ -361,6 +362,16 @@ static int hfs_InitialMount(struct vnode *devvp, struct mount *mp, struct hfs_mo goto error_exit; } + /* Don't let phys_blksize be smaller than the logical */ + if (phys_blksize < log_blksize) { + /* + * In the off chance that the phys_blksize is SMALLER than the logical + * then don't let that happen. Pretend that the PHYSICALBLOCKSIZE + * ioctl was not supported. + */ + phys_blksize = log_blksize; + } + /* Get the number of physical blocks. */ if (ioctl(devvp->psFSRecord->iFD, DKIOCGETBLOCKCOUNT, &log_blkcnt)) { @@ -1601,180 +1612,6 @@ void hfs_scan_blocks (struct hfsmount *hfsmp) hfs_systemfile_unlock(hfsmp, flags); } -int -hfs_GetInfoByID(struct hfsmount *hfsmp, cnid_t cnid, UVFSFileAttributes *file_attrs, char pcName[MAX_UTF8_NAME_LENGTH]) -{ - u_int32_t linkref = 0; - struct vnode *psVnode = NULL; - struct cat_desc cndesc; - struct cat_attr cnattr; - struct cat_fork cnfork; - int error = 0; - - /* Check for cnids that should't be exported. */ - if ((cnid < kHFSFirstUserCatalogNodeID) && - (cnid != kHFSRootFolderID && cnid != kHFSRootParentID)) { - return (ENOENT); - } - /* Don't export our private directories. */ - if (cnid == hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid || - cnid == hfsmp->hfs_private_desc[DIR_HARDLINKS].cd_cnid) { - return (ENOENT); - } - /* - * Check the hash first - */ - psVnode = hfs_chash_getvnode(hfsmp, cnid, 0, 0, 0); - if (psVnode) { - goto getAttrAndDone; - } - - bzero(&cndesc, sizeof(cndesc)); - bzero(&cnattr, sizeof(cnattr)); - bzero(&cnfork, sizeof(cnfork)); - - /* - * Not in hash, lookup in catalog - */ - if (cnid == kHFSRootParentID) { - static char hfs_rootname[] = "/"; - - cndesc.cd_nameptr = (const u_int8_t *)&hfs_rootname[0]; - cndesc.cd_namelen = 1; - cndesc.cd_parentcnid = kHFSRootParentID; - cndesc.cd_cnid = kHFSRootFolderID; - cndesc.cd_flags = CD_ISDIR; - - cnattr.ca_fileid = kHFSRootFolderID; - cnattr.ca_linkcount = 1; - cnattr.ca_entries = 1; - cnattr.ca_dircount = 1; - cnattr.ca_mode = (S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO); - } else { - int lockflags; - cnid_t pid; - const char *nameptr; - - lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK); - error = cat_idlookup(hfsmp, cnid, 0, 0, &cndesc, &cnattr, &cnfork); - hfs_systemfile_unlock(hfsmp, lockflags); - - if (error) { - return (error); - } - - /* - * Check for a raw hardlink inode and save its linkref. - */ - pid = cndesc.cd_parentcnid; - nameptr = (const char *)cndesc.cd_nameptr; - if ((pid == hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid) && - cndesc.cd_namelen > HFS_INODE_PREFIX_LEN && - (bcmp(nameptr, HFS_INODE_PREFIX, HFS_INODE_PREFIX_LEN) == 0)) { - linkref = (uint32_t) strtoul(&nameptr[HFS_INODE_PREFIX_LEN], NULL, 10); - - } else if ((pid == hfsmp->hfs_private_desc[DIR_HARDLINKS].cd_cnid) && - cndesc.cd_namelen > HFS_DIRINODE_PREFIX_LEN && - (bcmp(nameptr, HFS_DIRINODE_PREFIX, HFS_DIRINODE_PREFIX_LEN) == 0)) { - linkref = (uint32_t) strtoul(&nameptr[HFS_DIRINODE_PREFIX_LEN], NULL, 10); - - } else if ((pid == hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid) && - cndesc.cd_namelen > HFS_DELETE_PREFIX_LEN && - (bcmp(nameptr, HFS_DELETE_PREFIX, HFS_DELETE_PREFIX_LEN) == 0)) { - cat_releasedesc(&cndesc); - return (ENOENT); /* open unlinked file */ - } - } - - /* - * Finish initializing cnode descriptor for hardlinks. - * - * We need a valid name and parent for reverse lookups. - */ - if (linkref) { - cnid_t lastid; - struct cat_desc linkdesc; - int linkerr = 0; - - cnattr.ca_linkref = linkref; - bzero (&linkdesc, sizeof (linkdesc)); - - /* - * If the caller supplied the raw inode value, then we don't know exactly - * which hardlink they wanted. It's likely that they acquired the raw inode - * value BEFORE the item became a hardlink, in which case, they probably - * want the oldest link. So request the oldest link from the catalog. - * - * Unfortunately, this requires that we iterate through all N hardlinks. On the plus - * side, since we know that we want the last linkID, we can also have this one - * call give us back the name of the last ID, since it's going to have it in-hand... - */ - linkerr = hfs_lookup_lastlink (hfsmp, linkref, &lastid, &linkdesc); - if ((linkerr == 0) && (lastid != 0)) { - /* - * Release any lingering buffers attached to our local descriptor. - * Then copy the name and other business into the cndesc - */ - cat_releasedesc (&cndesc); - bcopy (&linkdesc, &cndesc, sizeof(linkdesc)); - } - /* If it failed, the linkref code will just use whatever it had in-hand below. */ - - int newvnode_flags = 0; - error = hfs_getnewvnode(hfsmp, NULL, NULL, &cndesc, 0, &cnattr, &cnfork, &psVnode, &newvnode_flags); - if (error == 0) { - VTOC(psVnode)->c_flag |= C_HARDLINK; - } - } - else - { - int newvnode_flags = 0; - - void *buf = hfs_malloc(MAX_UTF8_NAME_LENGTH); - if (buf == NULL) { - return (ENOMEM); - } - - /* Supply hfs_getnewvnode with a component name. */ - struct componentname cn = { - .cn_nameiop = LOOKUP, - .cn_flags = ISLASTCN, - .cn_pnlen = MAXPATHLEN, - .cn_namelen = cndesc.cd_namelen, - .cn_pnbuf = buf, - .cn_nameptr = buf - }; - - bcopy(cndesc.cd_nameptr, cn.cn_nameptr, cndesc.cd_namelen + 1); - error = hfs_getnewvnode(hfsmp, NULL, &cn, &cndesc, 0, &cnattr, &cnfork, &psVnode, &newvnode_flags); - if (error == 0 && (VTOC(psVnode)->c_flag & C_HARDLINK)) { - hfs_savelinkorigin(VTOC(psVnode), cndesc.cd_parentcnid); - } - - hfs_free(buf); - } - cat_releasedesc(&cndesc); - -getAttrAndDone: - if (!error) vnode_GetAttrInternal (psVnode, file_attrs); - if (psVnode != NULL) hfs_unlock(VTOC(psVnode)); - - if (error || psVnode == NULL || psVnode->sFSParams.vnfs_cnp->cn_nameptr == NULL){ - hfs_vnop_reclaim(psVnode); - return EFAULT; - } - - if (cnid == kHFSRootFolderID) - pcName[0] = 0; - else { - strlcpy(pcName, (char*) psVnode->sFSParams.vnfs_cnp->cn_nameptr, MAX_UTF8_NAME_LENGTH); - } - - error = hfs_vnop_reclaim(psVnode); - - return (error); -} - /* * Look up an HFS object by ID. * @@ -1952,6 +1789,34 @@ hfs_vget(struct hfsmount *hfsmp, cnid_t cnid, struct vnode **vpp, int skiplock, return (error); } +int +hfs_GetInfoByID(struct hfsmount *hfsmp, cnid_t cnid, UVFSFileAttributes *file_attrs, char pcName[MAX_UTF8_NAME_LENGTH]) +{ + struct vnode *psVnode = NULL; + int error = hfs_vget(hfsmp, cnid, &psVnode, 0, 0); + if (error || psVnode == NULL) { + if (psVnode != NULL) hfs_unlock(VTOC(psVnode)); + hfs_vnop_reclaim(psVnode); + return EFAULT; + } else { + vnode_GetAttrInternal (psVnode, file_attrs); + hfs_unlock(VTOC(psVnode)); + } + + if (cnid == kHFSRootFolderID) + pcName[0] = 0; + else { + //Make sure we actually have the name in the vnode + if (psVnode->sFSParams.vnfs_cnp && psVnode->sFSParams.vnfs_cnp->cn_nameptr) + strlcpy(pcName, (char*) psVnode->sFSParams.vnfs_cnp->cn_nameptr, MAX_UTF8_NAME_LENGTH); + else + return EINVAL; + } + + error = hfs_vnop_reclaim(psVnode); + return (error); +} + /* * Return the root of a filesystem. */ diff --git a/livefiles_hfs_plugin/lf_hfs_vnode.c b/livefiles_hfs_plugin/lf_hfs_vnode.c index 0bc73b6..f8b27ed 100644 --- a/livefiles_hfs_plugin/lf_hfs_vnode.c +++ b/livefiles_hfs_plugin/lf_hfs_vnode.c @@ -125,10 +125,12 @@ void vnode_update_identity(vnode_t vp, vnode_t dvp, const char *name, int name_l LFHFS_LOG(LEVEL_ERROR, "vnode_update_identity: failed to malloc vnfs_cnp\n"); assert(0); } + bzero(vp->sFSParams.vnfs_cnp, sizeof(struct componentname)); } vp->sFSParams.vnfs_cnp->cn_namelen = name_len; if (vp->sFSParams.vnfs_cnp->cn_nameptr) { hfs_free(vp->sFSParams.vnfs_cnp->cn_nameptr); + vp->sFSParams.vnfs_cnp->cn_nameptr = NULL; } vp->sFSParams.vnfs_cnp->cn_nameptr = lf_hfs_utils_allocate_and_copy_string( (char*) name, name_len ); vp->sFSParams.vnfs_cnp->cn_hash = name_hashval; diff --git a/livefiles_hfs_plugin/lf_hfs_xattr.c b/livefiles_hfs_plugin/lf_hfs_xattr.c index e15edaa..17b3f62 100644 --- a/livefiles_hfs_plugin/lf_hfs_xattr.c +++ b/livefiles_hfs_plugin/lf_hfs_xattr.c @@ -168,7 +168,6 @@ hfs_vnop_getxattr(vnode_t vp, const char *attr_name, void *buf, size_t bufsize, BTreeIterator * iterator = NULL; size_t attrsize = 0; HFSPlusAttrRecord *recp = NULL; - size_t recp_size = 0; FSBufferDescriptor btdata; int lockflags = 0; u_int16_t datasize = 0; @@ -196,7 +195,7 @@ hfs_vnop_getxattr(vnode_t vp, const char *attr_name, void *buf, size_t bufsize, * big enough to read in all types of attribute records. It is not big * enough to read inline attribute data which is read in later. */ - recp = hfs_malloc(recp_size = sizeof(HFSPlusAttrRecord)); + recp = hfs_malloc(sizeof(HFSPlusAttrRecord)); btdata.bufferAddress = recp; btdata.itemSize = sizeof(HFSPlusAttrRecord); btdata.itemCount = 1; @@ -250,7 +249,7 @@ hfs_vnop_getxattr(vnode_t vp, const char *attr_name, void *buf, size_t bufsize, */ attrsize = sizeof(HFSPlusAttrData) - 2 + recp->attrData.attrSize; hfs_free(recp); - recp = hfs_malloc(recp_size = attrsize); + recp = hfs_malloc(attrsize); btdata.bufferAddress = recp; btdata.itemSize = attrsize; @@ -558,7 +557,6 @@ hfs_vnop_setxattr(vnode_t vp, const char *attr_name, const void *buf, size_t buf FSBufferDescriptor btdata; HFSPlusAttrRecord attrdata; /* 90 bytes */ HFSPlusAttrRecord *recp = NULL; - size_t recp_size = 0; HFSPlusExtentDescriptor *extentptr = NULL; size_t extentbufsize = 0; int lockflags = 0; @@ -674,7 +672,7 @@ hfs_vnop_setxattr(vnode_t vp, const char *attr_name, const void *buf, size_t buf } } /* Create attribute fork data record. */ - recp = hfs_malloc(recp_size = sizeof(HFSPlusAttrRecord)); + recp = hfs_malloc(sizeof(HFSPlusAttrRecord)); btdata.bufferAddress = recp; btdata.itemCount = 1; @@ -731,7 +729,7 @@ hfs_vnop_setxattr(vnode_t vp, const char *attr_name, const void *buf, size_t buf /* Calculate size of record rounded up to multiple of 2 bytes. */ btdata.itemSize = sizeof(HFSPlusAttrData) - 2 + attrsize + ((attrsize & 1) ? 1 : 0); - recp = hfs_malloc(recp_size = btdata.itemSize); + recp = hfs_malloc(btdata.itemSize); recp->recordType = kHFSPlusAttrInlineData; recp->attrData.reserved[0] = 0; diff --git a/mount_hfs/mount_hfs.c b/mount_hfs/mount_hfs.c index 9e8fcff..60e7162 100644 --- a/mount_hfs/mount_hfs.c +++ b/mount_hfs/mount_hfs.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -370,7 +371,7 @@ void syncCreateDate(const char *mntpt, u_int32_t localCreateTime) if (result) return; gmtCreateTime = attrReturnBuffer.creationTime.tv_sec; - gmtOffset = gmtCreateTime - (int64_t) localCreateTime + 900; + gmtOffset = (int32_t)(gmtCreateTime - (int64_t) localCreateTime + 900); if (gmtOffset > 0) { gmtOffset = 1800 * (gmtOffset / 1800); } else { @@ -747,8 +748,12 @@ a_mask(s) done = 0; rv = -1; if (*s >= '0' && *s <= '7') { + long mask; + done = 1; - rv = strtol(optarg, &ep, 8); + mask = strtol(optarg, &ep, 8); + if (mask >= 0 && mask <= INT_MAX) + rv = (int)mask; } if (!done || rv < 0 || *ep) errx(1, "invalid file mode: %s", s); @@ -878,11 +883,14 @@ get_default_encoding() if ((fd = open(buffer, O_RDONLY, 0)) > 0) { ssize_t readSize; + long encoding; readSize = read(fd, buffer, MAXPATHLEN); buffer[(readSize < 0 ? 0 : readSize)] = '\0'; close(fd); - return strtol(buffer, NULL, 0); + encoding = strtol(buffer, NULL, 0); + assert(encoding > -1 && encoding <= UINT_MAX); + return (unsigned int)encoding; } } return (0); /* Fallback to smRoman */ diff --git a/newfs_hfs/makehfs.c b/newfs_hfs/makehfs.c index 724a43d..3b05d25 100644 --- a/newfs_hfs/makehfs.c +++ b/newfs_hfs/makehfs.c @@ -279,7 +279,7 @@ createExtents(HFSPlusForkData *file, */ if ((blockStep * numExtents) < blocksLeft) { // Need to adjust the first one. - firstAdjust = blocksLeft - (blockStep * numExtents); + firstAdjust = (int)(blocksLeft - (blockStep * numExtents)); if ((firstAdjust % minBlocks) != 0) firstAdjust = ROUNDUP(firstAdjust, minBlocks); } @@ -657,7 +657,7 @@ InitVH(hfsparams_t *defaults, UInt64 sectors, HFSPlusVolumeHeader *hp) bzero(hp, kBytesPerSector); blockSize = defaults->blockSize; - blockCount = sectors / (blockSize >> kLog2SectorSize); + blockCount = (UInt32)(sectors / (blockSize >> kLog2SectorSize)); /* * HFSPlusVolumeHeader is located at sector 2, so we may need @@ -984,7 +984,7 @@ MarkExtentUsed(const DriveInfo *driveInfo, memset(buf, 0, sizeof(buf)); secNum = curBlock / (bufSize * kBitsPerByte); blockOffset = curBlock % (bufSize * kBitsPerByte); - numBlocks = MIN((bufSize * kBitsPerByte) - blockOffset, blocksLeft); + numBlocks = (uint32_t)MIN((bufSize * kBitsPerByte) - blockOffset, blocksLeft); /* * Okay, now we've got the block number to read, @@ -1895,7 +1895,7 @@ WriteBuffer(const DriveInfo *driveInfo, UInt64 startingSector, UInt64 byteCount, /* try a buffer size for optimal IO, __UP TO 4MB__. if that fails, then try with the minimum allowed buffer size, which is equal to physSectorSize */ - tempbufSizeInPhysSectors = MIN ( (byteCount - 1 + physSectorSize) / physSectorSize, + tempbufSizeInPhysSectors = (UInt32)MIN ( (byteCount - 1 + physSectorSize) / physSectorSize, driveInfo->physSectorsPerIO ); /* limit at 4MB */ tempbufSizeInPhysSectors = MIN ( tempbufSizeInPhysSectors, (4 * 1024 * 1024) / physSectorSize ); @@ -1922,9 +1922,9 @@ WriteBuffer(const DriveInfo *driveInfo, UInt64 startingSector, UInt64 byteCount, byteOffsetInPhysSector = (sector % sectorSizeRatio) * kBytesPerSector; while (byteCount > 0) { - numPhysSectorsToIO = MIN ( (byteCount - 1 + physSectorSize) / physSectorSize, + numPhysSectorsToIO = (UInt32)MIN ( (byteCount - 1 + physSectorSize) / physSectorSize, tempbufSizeInPhysSectors ); - numBytesToIO = MIN(byteCount, (unsigned)((numPhysSectorsToIO * physSectorSize) - byteOffsetInPhysSector)); + numBytesToIO = (UInt32)MIN(byteCount, (unsigned)((numPhysSectorsToIO * physSectorSize) - byteOffsetInPhysSector)); /* if IO does not align with physical sector boundaries */ if ((0 != byteOffsetInPhysSector) || ((numBytesToIO % physSectorSize) != 0)) { diff --git a/newfs_hfs/newfs_hfs.c b/newfs_hfs/newfs_hfs.c index 466fdc1..7b27182 100644 --- a/newfs_hfs/newfs_hfs.c +++ b/newfs_hfs/newfs_hfs.c @@ -299,7 +299,7 @@ main(argc, argv) fatal("%s: bad allocation block size (too small)", optarg); if (tempBlockSize > HFSMAXBSIZE) fatal("%s: bad allocation block size (too large)", optarg); - gBlockSize = tempBlockSize; + gBlockSize = (uint32_t)tempBlockSize; break; } @@ -564,6 +564,8 @@ static void getstartopts(char* optlist) char *ndarg; char *p; unsigned long startat = 0; + int pos; + UInt32 upos; startat = strtoul(optlist, &strp, 0); if (startat == ULONG_MAX && errno != 0) { @@ -575,7 +577,7 @@ static void getstartopts(char* optlist) if (strp && *strp == ',') strp++; - gFSStartBlock = startat; + gFSStartBlock = (UInt32)startat; while((ndarg = strsep(&strp, ",")) != NULL && *ndarg != '\0') { @@ -584,29 +586,33 @@ static void getstartopts(char* optlist) if (p == NULL) usage(); - startat = atoi(p+1); - + pos = atoi(p+1); + if (pos < 0 || pos > UINT32_MAX) { + errx(1, "pos=%d is invalid", pos); + } + upos = (UInt32)pos; + switch (*ndarg) { case 'a': - attrExtStart = startat; + attrExtStart = upos; break; case 'b': - blkallocExtStart = startat; + blkallocExtStart = upos; break; case 'c': - catExtStart = startat; + catExtStart = upos; break; case 'e': - extExtStart = startat; + extExtStart = upos; break; case 'j': - jibStart = startat; + jibStart = upos; break; case 'J': - jnlStart = startat; + jnlStart = upos; break; case 'N': - allocStart = startat; + allocStart = upos; break; default: usage(); @@ -656,7 +662,8 @@ a_uid(char *s) static mode_t a_mask(char *s) { - int done, rv; + int done; + long rv; char *ep; done = 0; @@ -665,9 +672,9 @@ a_mask(char *s) done = 1; rv = strtol(s, &ep, 8); } - if (!done || rv < 0 || *ep) + if (!done || rv < 0 || rv > INT_MAX || *ep) errx(1, "invalid access mask: %s", s); - return (rv); + return ((int)rv); } /* @@ -812,7 +819,7 @@ static void validate_hfsplus_block_size(UInt64 sectorCount, UInt32 sectorSize) * value. At 2TB, we grow to the 8K block size. */ if ((bit_index >= 0) && (bit_index < 22)) { - gBlockSize = alloc_blocksize[bit_index]; + gBlockSize = (uint32_t)alloc_blocksize[bit_index]; } if (bit_index >= 22) { @@ -836,7 +843,7 @@ static void validate_hfsplus_block_size(UInt64 sectorCount, UInt32 sectorSize) if (gFSStartBlock) { u_int64_t fs_size = sectorCount * sectorSize; - u_int32_t totalBlocks = fs_size/gBlockSize; + u_int32_t totalBlocks = (u_int32_t)(fs_size/gBlockSize); if (gFSStartBlock >= totalBlocks) { warnx("Warning: %u is invalid file system start allocation block number, must be less than total allocation blocks (%u)", (unsigned int)gFSStartBlock, (unsigned int)totalBlocks); @@ -1013,7 +1020,8 @@ static void hfsplus_params (const DriveInfo* dip, hfsparams_t *defaults) defaults->blockSize = gBlockSize; defaults->fsStartBlock = gFSStartBlock; defaults->nextFreeFileID = gNextCNID; - defaults->createDate = createtime + MAC_GMT_FACTOR; /* Mac OS GMT time */ + // Value will be bigger than UIN32_MAX in 2040 + defaults->createDate = (uint32_t)(createtime + MAC_GMT_FACTOR); /* Mac OS GMT time */ defaults->hfsAlignment = 0; defaults->journaledHFS = gJournaled; defaults->journalDevice = gJournalDevice; @@ -1079,7 +1087,7 @@ static void hfsplus_params (const DriveInfo* dip, hfsparams_t *defaults) } /* defaults->journalSize will get reset below if it is 0 */ - defaults->journalSize = gJournalSize; + defaults->journalSize = (uint32_t)gJournalSize; } if ((gJournalSize == 0) || (defaults->journalSize == 0)) { @@ -1271,7 +1279,7 @@ static void hfsplus_params (const DriveInfo* dip, hfsparams_t *defaults) * Note: this minimum value may be too large when it counts the * space used by the wrapper */ - totalBlocks = sectorCount / (gBlockSize / sectorSize); + totalBlocks = (uint32_t)(sectorCount / (gBlockSize / sectorSize)); minClumpSize = totalBlocks >> 3; /* convert bits to bytes by dividing by 8 */ if (totalBlocks & 7) @@ -1454,7 +1462,7 @@ CalcHFSPlusBTreeClumpSize(UInt32 blockSize, UInt32 nodeSize, UInt64 sectors, int * it must also be a multiple of the node and block size. */ if (sectors < 0x200000) { - clumpSize = sectors << 2; /* 0.8 % */ + clumpSize = (UInt32)(sectors << 2); /* 0.8 % */ if (clumpSize < (8 * nodeSize)) clumpSize = 8 * nodeSize; } else { diff --git a/tests/cases/test-external-jnl.c b/tests/cases/test-external-jnl.c index 6b86236..c5542b2 100644 --- a/tests/cases/test-external-jnl.c +++ b/tests/cases/test-external-jnl.c @@ -23,41 +23,45 @@ #include "../core/hfs_format.h" #include "test-utils.h" -#define DISK_IMAGE_1 "/tmp/external-jnl1.sparseimage" -#define DISK_IMAGE_2 "/tmp/external-jnl2.sparseimage" +#define HOST_IMAGE "/tmp/external-jnl1.sparseimage" +#define EXTERNAL_IMAGE "/tmp/external-jnl2.sparseimage" TEST(external_jnl) int run_external_jnl(__unused test_ctx_t *ctx) { - unlink(DISK_IMAGE_1); - unlink(DISK_IMAGE_2); - - disk_image_t *di1 = disk_image_create(DISK_IMAGE_1, - &(disk_image_opts_t){ - .size = 64 * 1024 * 1024 - }); - disk_image_t *di2 - = disk_image_create(DISK_IMAGE_2, + unlink(HOST_IMAGE); + unlink(EXTERNAL_IMAGE); + + /* Since disk image cleanup occurs on a stack, create the external + * journal partition first so that the cleanup of the host image + * prevents a resource busy error during the journal partition ejection. + */ + disk_image_t *di_ext = disk_image_create(EXTERNAL_IMAGE, &(disk_image_opts_t){ .partition_type = EXTJNL_CONTENT_TYPE_UUID, .size = 8 * 1024 * 1024 }); - unmount(di1->mount_point, 0); + disk_image_t *di_host = disk_image_create(HOST_IMAGE, + &(disk_image_opts_t){ + .size = 64 * 1024 * 1024 + }); + + unmount(di_host->mount_point, 0); - assert(!systemx("/sbin/newfs_hfs", SYSTEMX_QUIET, "-J", "-D", di2->disk, di1->disk, NULL)); + assert(!systemx("/sbin/newfs_hfs", SYSTEMX_QUIET, "-J", "-D", di_ext->disk, di_host->disk, NULL)); - assert(!systemx("/usr/sbin/diskutil", SYSTEMX_QUIET, "mount", di1->disk, NULL)); + assert(!systemx("/usr/sbin/diskutil", SYSTEMX_QUIET, "mount", di_host->disk, NULL)); - free((char *)di1->mount_point); - di1->mount_point = NULL; + free((char *)di_host->mount_point); + di_host->mount_point = NULL; struct statfs *mntbuf; int i, n = getmntinfo(&mntbuf, 0); for (i = 0; i < n; ++i) { - if (!strcmp(mntbuf[i].f_mntfromname, di1->disk)) { - di1->mount_point = strdup(mntbuf[i].f_mntonname); + if (!strcmp(mntbuf[i].f_mntfromname, di_host->disk)) { + di_host->mount_point = strdup(mntbuf[i].f_mntonname); break; } } @@ -65,7 +69,7 @@ int run_external_jnl(__unused test_ctx_t *ctx) assert(i < n); char *path; - asprintf(&path, "%s/test", di1->mount_point); + asprintf(&path, "%s/test", di_host->mount_point); int fd = open(path, O_RDWR | O_CREAT, 0666); assert_with_errno(fd >= 0); assert_no_err(close(fd)); diff --git a/tests/cases/test-key-roll.c b/tests/cases/test-key-roll.c index 74dedda..42f60cb 100644 --- a/tests/cases/test-key-roll.c +++ b/tests/cases/test-key-roll.c @@ -112,7 +112,7 @@ void *append_to_file(void *param) assert_no_err(msync(p + total - round, todo + round, MS_ASYNC | MS_INVALIDATE)); - CC_MD5_Update(&md5_ctx, buf1, todo); + CC_MD5_Update(&md5_ctx, buf1, (CC_LONG)todo); total += todo; } @@ -192,10 +192,10 @@ static void fill_disk(int *fd, uint64_t *size) struct statfs sfs; assert_no_err(fstatfs(*fd, &sfs)); - uint32_t blocks = sfs.f_bfree; + uint64_t blocks = sfs.f_bfree; for (;;) { - uint64_t size = (uint64_t)blocks * sfs.f_bsize; + uint64_t size = blocks * sfs.f_bsize; if (!fcntl(*fd, F_SETSIZE, &size)) break; @@ -206,15 +206,15 @@ static void fill_disk(int *fd, uint64_t *size) } // Now increase the size until we hit no space - uint32_t upper = sfs.f_bfree + 128; + uint64_t upper = sfs.f_bfree + 128; for (;;) { - uint32_t try = (upper + blocks) / 2; + uint64_t try = (upper + blocks) / 2; if (try <= blocks) try = blocks + 1; - uint64_t size = (uint64_t)try * sfs.f_bsize; + uint64_t size = try * sfs.f_bsize; if (!fcntl(*fd, F_SETSIZE, &size)) { blocks = try; if (try >= upper) { @@ -231,7 +231,7 @@ static void fill_disk(int *fd, uint64_t *size) } } - *size = (uint64_t)blocks * sfs.f_bsize; + *size = blocks * sfs.f_bsize; } volatile int32_t threads_running; diff --git a/tests/cases/test-lf-cs-plugin.c b/tests/cases/test-lf-cs-plugin.c new file mode 100644 index 0000000..c436d31 --- /dev/null +++ b/tests/cases/test-lf-cs-plugin.c @@ -0,0 +1,350 @@ +// +// Copyright (c) 2019-2019 Apple Inc. All rights reserved. +// +// test-lf-cs-plugin.c - Implements unit test for livefiles Apple_CoreStorage +// plugin. +// + +#include "hfs-tests.h" +#include "test-utils.h" +#include "systemx.h" + +#include +#include +#include +#include +#include +#include + +// +// Enable this test on iOS and no other iOS-style platforms. +// +#if TARGET_OS_IOS + +// +// Headers generated at build time. Containes compressed disk images for the +// corresponding file-system formats. +// +#include "JHFS+-dmg.dat" +#include "APFS-dmg.dat" +#include "EXFAT-dmg.dat" +#include "FAT32-dmg.dat" + +TEST(lf_cs_plugin, .run_as_root = true) + +#define LF_CS_PLUGIN_TEST_DMG "/tmp/lf_cs_plugin_test.sparseimage" +#define LF_CS_PLUGIN_PATH_TO_HDIK "/usr/sbin/hdik" +#define LF_CS_PLUGIN_INSTALL_PATH "/AppleInternal/CoreOS/tests/hfs/" + +// +// The output of hdik gets truncated, so just search for the leading part of +// the UUID and partition scheme names. +// +#define LF_CSP_HFS_UUID "48465300-0000-11AA-AA11" +#define LF_CSP_APFS_UUID "7C3457EF-0000-11AA-AA11" +#define LF_CSP_EXFAT_PART_SCHEME "Windows_NTFS" +#define LF_CSP_FAT32_PART_SCHEME "DOS_FAT_32" + +// +// Enums describing file-system formats. +// +typedef enum { + JHFS = 1, + APFS, + FAT32, + EXFAT, +} lf_csp_fstype_t; + +// +// Local struct describing the disk image on disk. +// +typedef struct { + char *path; // Path to disk-image on disk. + char *disk; // Path to dev node after disk-image is attached. + char *slice; // Path to dev node slice after disk-image is attached. +} lf_csp_disk_image_t; + +// +// lf_csp_disk_image_cleanup - disattach disk image from the DiskImages driver +// and unlink the disk image file on disk. +// +static bool +lf_csp_disk_image_cleanup(lf_csp_disk_image_t *di) +{ + pid_t pid; + posix_spawn_file_actions_t facts; + + struct stat sb; + int ret, status; + bool result; + char *detach_args[] = { "hdik", "-e", (char *)di->disk, NULL }; + + result = false; + ret = posix_spawn_file_actions_init(&facts); + + if (!ret) { + (void)posix_spawn_file_actions_addopen(&facts, STDOUT_FILENO, + "/dev/null", O_APPEND, 0); + (void)posix_spawn_file_actions_addopen(&facts, STDERR_FILENO, + "/dev/null", O_APPEND, 0); + } + + assert_no_err(posix_spawn(&pid, LF_CS_PLUGIN_PATH_TO_HDIK, &facts, + NULL, detach_args, NULL)); + + if (ret) { + posix_spawn_file_actions_destroy(&facts); + } + + assert_with_errno(ignore_eintr(waitpid(pid, &status, 0), -1) == pid); + errno = 0; + if (WIFEXITED(status) && + !WEXITSTATUS(status) && + (stat(di->disk, &sb) == -1) && + (errno == ENOENT)) { + + unlink(di->path); + free(di->path); + free(di->disk); + free(di->slice); + free(di); + result = true; + } + + return result; +} + +// +// lf_csp_disk_image_create - create a new disk image file on disk and attach +// disk images directly to the DiskImages driver. +// +// This routine reads the compressed file system image (generated during build) +// based on the passed file-system type parameter. The compressed image is +// decompressd and written to disk and then attached to directly to the +// DiskImages driver. +// +// Please NOTE: The created image is hooked up to the test cleanup list thus +// gets cleaned up automatically after the test, even on failures. Explicit +// cleanup is not needed. +// +static lf_csp_disk_image_t * +lf_csp_disk_image_create(const char *path, lf_csp_fstype_t fs_type) +{ + pid_t pid; + uid_t uid_old; + lf_csp_disk_image_t *di; + z_stream u_stream; + posix_spawn_file_actions_t actions; + + FILE *fp; + size_t lnsz; + int ret, fd, fds[2], status; + void *uncompressed_out_buf; + const size_t chunk_size = (1ULL << 20); + char *attach_args[4], *line, *part_scheme, *uuid_or_partid_str; + + // + // We need to ensure that we are root. + // + if ((uid_old = geteuid()) != 0) { + assert_no_err(seteuid(0)); + } + + di = calloc(1, sizeof(lf_csp_disk_image_t)); + assert(di); + + // + // We need to extract the compressed image into the passed image + // file path, thus we open it for writing. + // + fd = open(path, O_RDWR | O_TRUNC | O_CREAT, 0666); + assert_with_errno(fd != -1); + + u_stream = (z_stream) { + .zalloc = Z_NULL, + .zfree = Z_NULL, + .opaque = Z_NULL, + }; + + ret = inflateInit(&u_stream); + if (ret != Z_OK) { + assert_fail("inflateInit failed\n"); + } + + uncompressed_out_buf = malloc(chunk_size); + assert(uncompressed_out_buf); + + uuid_or_partid_str = NULL; + part_scheme = NULL; + switch(fs_type) { + case JHFS: + u_stream.next_in = JHFS_data; + u_stream.avail_in = sizeof(JHFS_data); + uuid_or_partid_str = LF_CSP_HFS_UUID; + part_scheme = "GUID"; + break; + + case APFS: + u_stream.next_in = APFS_data; + u_stream.avail_in = sizeof(APFS_data); + uuid_or_partid_str = LF_CSP_APFS_UUID; + part_scheme = "GUID"; + break; + + case FAT32: + u_stream.next_in = FAT32_data; + u_stream.avail_in = sizeof(FAT32_data); + uuid_or_partid_str = LF_CSP_FAT32_PART_SCHEME; + part_scheme = "FDisk"; + break; + + case EXFAT: + u_stream.next_in = EXFAT_data; + u_stream.avail_in = sizeof(EXFAT_data); + uuid_or_partid_str = LF_CSP_EXFAT_PART_SCHEME; + part_scheme = "FDisk"; + break; + + default: + assert_fail("passed unkown file-system type\n"); + } + + do { + ssize_t bytes_to_write; + + u_stream.next_out = uncompressed_out_buf; + u_stream.avail_out = chunk_size; + + ret = inflate(&u_stream, Z_NO_FLUSH); + assert(ret != Z_STREAM_ERROR); + + bytes_to_write = chunk_size - u_stream.avail_out; + assert(write(fd, uncompressed_out_buf, bytes_to_write) == + (ssize_t)bytes_to_write); + } while (ret == Z_OK); + assert(ret == Z_STREAM_END); + (void)inflateEnd(&u_stream); + + // + // Update the disk image path. + // + di->path = strdup(path); + + // + // Attach the created disk image directly to the DiskImage driver. + // + attach_args[0] = "hdik"; + attach_args[1] = "-nomount"; + attach_args[2] = (char *)di->path; + attach_args[3] = NULL; + + assert_no_err(pipe(fds)); + ret = posix_spawn_file_actions_init(&actions); + if (ret) { + assert_fail("Failed to init file actions, error %d\n", ret); + } + + ret = posix_spawn_file_actions_adddup2(&actions, fds[1], + STDOUT_FILENO); + if (ret) { + assert_fail("Failed to adddup file action, error %d\n", + ret); + } + + assert_no_err(posix_spawn(&pid, LF_CS_PLUGIN_PATH_TO_HDIK, &actions, + NULL, attach_args, NULL)); + + (void)posix_spawn_file_actions_destroy(&actions); + (void)close(fds[1]); + + // + // Read the output from `hdik` and populate the disk image's dev node + // after it is attached to DiskImage driver. + // + di->slice = NULL; + di->disk = NULL; + line = NULL; + lnsz = 64; + line = malloc(lnsz); + assert(line); + fp = fdopen(fds[0], "r"); + while (getline(&line, &lnsz, fp) != -1) { + char *disk_path, *uuid_or_partid; + + disk_path = strtok(line, " "); + assert(disk_path); + + uuid_or_partid = strtok(NULL, " "); + assert(uuid_or_partid); + + if (strstr(uuid_or_partid, part_scheme)) + di->disk = strdup(disk_path); + else if (strstr(uuid_or_partid, uuid_or_partid_str)) + di->slice = strdup(disk_path); + } + + assert_with_errno(ignore_eintr(waitpid(pid, &status, 0), -1) == pid); + assert(WIFEXITED(status) && !WEXITSTATUS(status)); + + assert(di->disk && di->slice); + free(line); + fclose(fp); + + // + // Place this attached image in the cleanup list so that it can be + // disattached after the test is run. + // + test_cleanup(^ bool { return lf_csp_disk_image_cleanup(di); }); + + // + // Restore back the old uid. + // + assert_no_err(seteuid(uid_old)); + return di; +} + +int +run_lf_cs_plugin(__unused test_ctx_t *ctx) +{ + lf_csp_disk_image_t *di; + char *tester_path; + + assert(asprintf(&tester_path, "%s/livefiles_cs_tester", + LF_CS_PLUGIN_INSTALL_PATH) > 0); + + // + // Call livefiles Apple_CoreStorage plugin with all our file-system + // disk-images. + // + // Kindly NOTE: We don't explicitly free the disk-images after use + // because preparing the disk image with lf_csp_disk_image_create() we + // place the image in a cleanup list and they get cleaned up after + // test, regardless of the test failures. + // + // Test livefiles Apple_CoreStorage plugin with AFPS disk image. + // + di = lf_csp_disk_image_create(LF_CS_PLUGIN_TEST_DMG, APFS); + assert(!systemx(tester_path, "APFS", di->slice, NULL)); + + // + // Test livefiles Apple_CoreStorage plugin with HFS+ disk image. + // + di = lf_csp_disk_image_create(LF_CS_PLUGIN_TEST_DMG, JHFS); + assert(!systemx(tester_path, "JHFS", di->slice, NULL)); + + // + // Test livefiles Apple_CoreStorage plugin with EXFAT disk image. + // + di = lf_csp_disk_image_create(LF_CS_PLUGIN_TEST_DMG, EXFAT); + assert(!systemx(tester_path, "EXFAT", di->slice, NULL)); + + // + // Test livefiles Apple_CoreStorage plugin with FAT32 disk image. + // + di = lf_csp_disk_image_create(LF_CS_PLUGIN_TEST_DMG, FAT32); + assert(!systemx(tester_path, "FAT32", di->slice, NULL)); + + free(tester_path); + return 0; +} +#endif /* TARGET_OS_IOS */ diff --git a/tests/disk-image.m b/tests/disk-image.m index 7a37064..c0bc434 100644 --- a/tests/disk-image.m +++ b/tests/disk-image.m @@ -23,6 +23,8 @@ #include "test-utils.h" #include "systemx.h" +#define RETRY_MAX 3 + #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) #include "dmg.dat" @@ -31,6 +33,8 @@ bool disk_image_cleanup(disk_image_t *di) { pid_t pid; bool result = false; + int eject_retry; + int status; // We need to be root assert(seteuid(0) == 0); @@ -40,27 +44,32 @@ bool disk_image_cleanup(disk_image_t *di) assert_no_err(posix_spawn(&pid, "/sbin/umount", NULL, NULL, umount_args, NULL)); - int status; waitpid(pid, &status, 0); char *detach_args[] = { "hdik", "-e", (char *)di->disk, NULL }; - + posix_spawn_file_actions_t facts; posix_spawn_file_actions_init(&facts); posix_spawn_file_actions_addopen(&facts, STDOUT_FILENO, "/dev/null", O_APPEND, 0); posix_spawn_file_actions_addopen(&facts, STDERR_FILENO, "/dev/null", O_APPEND, 0); - assert_no_err(posix_spawn(&pid, "/usr/sbin/hdik", &facts, NULL, detach_args, NULL)); + for (eject_retry = 0; eject_retry < RETRY_MAX; ++eject_retry) { + if (!posix_spawn(&pid, "/usr/sbin/hdik", &facts, NULL, detach_args, NULL)) { + waitpid(pid, &status, 0); + if (WIFEXITED(status) && !WEXITSTATUS(status)) + break; + } + sleep(1); + } posix_spawn_file_actions_destroy(&facts); - waitpid(pid, &status, 0); + assert(eject_retry != RETRY_MAX); struct stat sb; - if (WIFEXITED(status) && !WEXITSTATUS(status) - && stat(di->disk, &sb) == -1 && errno == ENOENT) { + if (stat(di->disk, &sb) == -1 && errno == ENOENT) { unlink(di->path); result = true; // We are the last user of di, so free it. @@ -117,7 +126,7 @@ disk_image_t *disk_image_create(const char *path, disk_image_opts_t *opts) do { zs.next_out = out_buf; - zs.avail_out = buf_size; + zs.avail_out = (uInt)buf_size; ret = inflate(&zs, 0); @@ -255,23 +264,31 @@ bool disk_image_cleanup(disk_image_t *di) pid_t pid; bool result = false; + int eject_retry; + int status; posix_spawn_file_actions_t facts; posix_spawn_file_actions_init(&facts); posix_spawn_file_actions_addopen(&facts, STDOUT_FILENO, "/dev/null", O_APPEND, 0); posix_spawn_file_actions_addopen(&facts, STDERR_FILENO, "/dev/null", O_APPEND, 0); - assert_no_err(posix_spawn(&pid, "/usr/bin/hdiutil", &facts, NULL, detach_args, NULL)); + for (eject_retry = 0; eject_retry < RETRY_MAX; ++eject_retry) { + if (!posix_spawn(&pid, "/usr/bin/hdiutil", &facts, NULL, detach_args, NULL)) { + waitpid(pid, &status, 0); + if (WIFEXITED(status) && !WEXITSTATUS(status)) { + break; + } + } + sleep(1); + } posix_spawn_file_actions_destroy(&facts); - int status; - waitpid(pid, &status, 0); + assert(eject_retry != RETRY_MAX); struct stat sb; - if (WIFEXITED(status) && !WEXITSTATUS(status) - && stat(di->disk, &sb) == -1 && errno == ENOENT) { + if (stat(di->disk, &sb) == -1 && errno == ENOENT) { if (unlink(di->path) && errno == EACCES && !seteuid(0)) unlink(di->path); result = true; diff --git a/tests/gen-custom-dmg.sh b/tests/gen-custom-dmg.sh new file mode 100755 index 0000000..892192f --- /dev/null +++ b/tests/gen-custom-dmg.sh @@ -0,0 +1,9 @@ +#!/bin/sh +set -e + +mkdir -p "$DERIVED_FILE_DIR" +env -i xcrun -sdk macosx.internal clang "$SRCROOT"/tests/generate-compressed-image.c -lz -o "$DERIVED_FILE_DIR"/generate-compressed-image + +"$DERIVED_FILE_DIR"/generate-compressed-image -size 1g -type SPARSE -fs "$1" -uid 501 -gid 501 >"$2" + +echo "Created $2 of type $1" diff --git a/tests/gen-test-plist.sh b/tests/gen-test-plist.sh index b65f3a7..fd20b25 100755 --- a/tests/gen-test-plist.sh +++ b/tests/gen-test-plist.sh @@ -28,6 +28,10 @@ EOF set -e set -o pipefail +for FS in JHFS+ APFS FAT32 EXFAT; do + touch "$DERIVED_SOURCES_DIR/$FS-dmg.dat" +done + # The following change is taken directly from the XCBuild changes made for APFS in # the commit cf61eef74b8 if [ "$CURRENT_ARCH" = undefined_arch ]; then @@ -44,7 +48,7 @@ fi # filter out any that aren't applicable to the targeted # platform). Finally grep for the TEST macro again grep -l -E '^TEST\(' *.[cm] | xargs xcrun clang -E -D TEST=TEST \ - -arch "$CURRENT_ARCH" -I.. -F"$SDKROOT""$SYSTEM_LIBRARY_DIR"/PrivateFrameworks | \ + -arch "$CURRENT_ARCH" -I"$DERIVED_SOURCES_DIR" -I.. -F"$SDKROOT""$SYSTEM_LIBRARY_DIR"/PrivateFrameworks | \ grep -h -E 'TEST\(' >>"$DERIVED_FILE_DIR"/list-tests.c # Build an executable for the host platform diff --git a/tests/generate-compressed-image.c b/tests/generate-compressed-image.c new file mode 100644 index 0000000..c7f13c2 --- /dev/null +++ b/tests/generate-compressed-image.c @@ -0,0 +1,303 @@ +// +// Copyright (c) 2019-2019 Apple Inc. All rights reserved. +// +// generate-compressed-image.c - Generates compressed disk images for +// file-system type passed as argument. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Rationale: We don't have `hdiutil` in iOS runtime and thus cannot generate +// disk-images for test inside iOS. We assume that the build enviornment has +// `hdiutil` and thus generate custom file-system images (passed as argument) +// during build, compress it using deflate and finally use the compressed byte +// stream to generate files which can then be be used from iOS runtime. +// + +// +// Name template for the temporary directory where we create the file-system +// image before we can compress it. +// +#define GEN_COM_IMAGE_TMP_DIR "/tmp/generate_compressed_image.XXXXXXXX" + +// +// Name of the temporary file-system image. +// +#define GEN_COM_IMAGE_TMP_FILENAME "img.sparseimage" + +// +// Path to hdiutil utility inside build enviornment. +// +#define GEN_COM_IMAGE_HDIUTIL_PATH "/usr/bin/hdiutil" + +enum { + + // + // Count of fixed number of argumets needed to call hdiutil, additional + // options are passed by the caller. + // + FIXED_NR_ARGUMENTS = 4, + ADDITIONAL_NR_ARGUMENTS = 10, + BYTES_PER_LINE_MASK = 0xF, +}; + +// +// Valid file-system types that is supported by this program. +// +static bool +is_fstype_valid(const char *fs_type) +{ + int idx; + + const char *const VALID_FSTYPES[] = { + "JHFS+", + "APFS", + "EXFAT", + "FAT32", + + NULL + }; + + for (idx = 0; VALID_FSTYPES[idx] != NULL; idx++) { + if (strcmp(fs_type, VALID_FSTYPES[idx]) == 0) { + return true; + } + } + return false; +} + +int +main(int argc, char *argv[]) +{ + pid_t pid, child_state_changed; + z_stream c_stream; + int fd, idx, ret, status, flush, offset; + char *tmp_dir, *tmp_disk_image_path, *fs_type; + unsigned char *compressed_out_buf, *uncompressed_in_buf; + const size_t chunk_size = (1ULL << 20); + char *args[argc + FIXED_NR_ARGUMENTS]; + char tmp_dir_name_template[] = GEN_COM_IMAGE_TMP_DIR; + const char *progname = (progname = strrchr(argv[0], '/')) ? + progname+=1 : (progname = argv[0]); + + // + // Disable stdout buffering. + // + setvbuf(stdout, NULL, _IONBF, 0); + + // + // Validate that we have correct number of arguments passed (minimal, + // this is only called from inside build internally). + // + if (argc != (ADDITIONAL_NR_ARGUMENTS + 1)) { + +err_usage: + fprintf(stderr, "Usage: %s -size [size-arg] -type " + "[type-arg] -fs [APFS|JHFS+|EXFAT|FAT32] " + "-uid [uid-arg] -gid [gid-arg]\n", progname); + return EXIT_FAILURE; + } + + // + // Just to simplify this program and to avoid parsing input aruments + // we assume that the arguments are passed in order and 7th argument + // has the file-system type. We confirm this now. + // + if (!is_fstype_valid(argv[6])) { + fprintf(stderr, "Unknown file-system type %s\n", argv[6]); + goto err_usage; + } + fs_type = argv[6]; + if (!strcmp(argv[6], "JHFS+")) { + fs_type = "JHFS"; + } + + // + // First we create a temporary directory to host our newly created + // disk image in the build environment. + // + tmp_dir = mkdtemp(tmp_dir_name_template); + if (!tmp_dir) + err(EX_NOINPUT, "mkdtemp failed"); + + // + // Path where we want to keep our temporary disk image. + // + asprintf(&tmp_disk_image_path, "%s/"GEN_COM_IMAGE_TMP_FILENAME, + tmp_dir); + + // + // Set up the fixed command line parameters to be passed to the hdiutil + // child process. + // + // - program name. + // - create a new disk-image. + // - path of disk-image file to create. + // - silent mode. + // + args[0] = "hdiutil"; + args[1] = "create"; + args[2] = tmp_disk_image_path; + args[3] = "-quiet"; + + // + // Copy the additional arguments passed by the caller needed for + // hdiutil. + // + for (idx = 1; idx < argc; ++idx) { + args[idx + FIXED_NR_ARGUMENTS - 1] = argv[idx]; + } + args[idx + FIXED_NR_ARGUMENTS - 1] = NULL; + + // + // Spawn the hdiutil as a child process and wait for its completion. + // + ret = posix_spawn(&pid, GEN_COM_IMAGE_HDIUTIL_PATH, NULL, NULL, + args, NULL); + if (ret) { + errno = ret; + err(EX_OSERR, "posix_spawn failed"); + } + + // + // Wait for the child process to finish. + // + do { + errno = 0; + child_state_changed = waitpid(pid, &status, 0); + } while (child_state_changed == -1 && errno == EINTR); + + if (child_state_changed == -1) { + err(EX_OSERR, "waitpid failed"); + } + if (!WIFEXITED(status) || WEXITSTATUS(status)) { + fprintf(stderr, "hdiutil failed, status %d", status); + exit(EXIT_FAILURE); + } + + // + // We have successfully create the disk image, now we have to + // open this disk image, read and finally write out a compess + // stream of this disk image to a data file. + // + fd = open(tmp_disk_image_path, O_RDONLY); + if (fd == -1) { + err(EX_NOINPUT, "open failed for file %s", + tmp_disk_image_path); + } + + // + // Initialize the compressed stream of bytes we will write out. + // + c_stream = (z_stream) { + .zalloc = Z_NULL, + .zfree = Z_NULL, + .opaque = Z_NULL, + }; + + ret = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); + if (ret != Z_OK) { + err(EX_SOFTWARE, "deflateInit faile, ret %d", ret); + } + + compressed_out_buf = malloc(chunk_size); + if (!compressed_out_buf) { + err(EX_OSERR, "malloc faliled for compressed_out_buf"); + } + + uncompressed_in_buf = malloc(chunk_size); + if (!uncompressed_in_buf) { + err(EX_OSERR, "malloc faliled for uncompressed_in_buf"); + } + + fprintf(stdout, "unsigned char %s_data[] = {", fs_type); + + offset = 0; + flush = Z_NO_FLUSH; + do { + ssize_t bytes_read; + + bytes_read = read(fd, uncompressed_in_buf, chunk_size); + if (bytes_read == -1) { + (void)deflateEnd(&c_stream); + err(EX_OSERR, "read failed for file %s\n", + tmp_disk_image_path); + } + + // + // Set the stream's input buffer and number of input bytes + // available to be compressed. + // + c_stream.next_in = uncompressed_in_buf; + c_stream.avail_in = bytes_read; + + // + // If we have reached the end of the file, we have to flush the + // compressed stream. + // + if (!bytes_read) { + flush = Z_FINISH; + } + + // + // Run deflate() on input until output buffer is not full, + // finish compression if all of source has been read in. + // + do { + unsigned written; + + c_stream.avail_out = chunk_size; + c_stream.next_out = compressed_out_buf; + + ret = deflate(&c_stream, flush); + assert(ret != Z_STREAM_ERROR); + + written = chunk_size - c_stream.avail_out; + for (idx = 0; idx < written; ++idx) { + if (!(offset & BYTES_PER_LINE_MASK)) + fprintf(stdout, "\n "); + fprintf(stdout, "0x%02x, ", + compressed_out_buf[idx]); + ++offset; + } + + } while (c_stream.avail_out == 0); + + // + // All input should be used. + // + assert(c_stream.avail_in == 0); + + } while (flush != Z_FINISH); + + // + // Stream will be complete. + // + assert(ret == Z_STREAM_END); + (void)close(fd); + + // + // stdout is line buffered by default and this should flush it. + // + fprintf(stdout, "\n};\n"); + + // + // Clean up + // + (void)deflateEnd(&c_stream); + unlink(tmp_disk_image_path); + free(tmp_disk_image_path); + rmdir(tmp_dir); +} diff --git a/tests/hfs-tests.entitlements b/tests/hfs-tests.entitlements index 994efb8..fc0325f 100644 --- a/tests/hfs-tests.entitlements +++ b/tests/hfs-tests.entitlements @@ -2,6 +2,8 @@ + com.apple.private.vfs.setsize + com.apple.rootless.internal-installer-equivalent com.apple.private.security.disk-device-access -- 2.45.2