#include <CoreFoundation/CFPriv.h>
#include "CFInternal.h"
#include "CFLocaleInternal.h"
#include <CoreFoundation/CFPriv.h>
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
#include <CoreFoundation/CFBundle.h>
#endif
#include <CoreFoundation/CFURLAccess.h>
#include <CoreFoundation/CFPropertyList.h>
#include <CoreFoundation/CFTimeZone.h>
#include <CoreFoundation/CFCalendar.h>
#if DEPLOYMENT_TARGET_WINDOWS
#include <process.h>
#endif
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
#include <asl.h>
#else
#define ASL_LEVEL_EMERG 0
#define ASL_LEVEL_DEBUG 7
#endif
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
#include <unistd.h>
#include <sys/uio.h>
#include <mach/mach.h>
#include <pthread.h>
#include <mach-o/loader.h>
#include <mach-o/dyld.h>
#include <crt_externs.h>
#include <dlfcn.h>
#include <vproc.h>
#include <vproc_priv.h>
#include <sys/sysctl.h>
#include <sys/stat.h>
#include <mach/mach.h>
#include <mach/mach_vm.h>
#include <sys/mman.h>
#include <stdio.h>
#include <sys/errno.h>
#include <mach/mach_time.h>
#include <Block.h>
#endif
#if DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
#include <string.h>
#include <pthread.h>
#endif
__private_extern__ CFIndex CFBSearch(const void *element, CFIndex elementSize, const void *list, CFIndex count, CFComparatorFunction comparator, void *context) {
const char *ptr = (const char *)list;
while (0 < count) {
CFIndex half = count / 2;
const char *probe = ptr + elementSize * half;
CFComparisonResult cr = comparator(element, probe, context);
if (0 == cr) return (probe - (const char *)list) / elementSize;
ptr = (cr < 0) ? ptr : probe + elementSize;
count = (cr < 0) ? half : (half + (count & 1) - 1);
}
return (ptr - (const char *)list) / elementSize;
}
#define ELF_STEP(B) T1 = (H << 4) + B; T2 = T1 & 0xF0000000; if (T2) T1 ^= (T2 >> 24); T1 &= (~T2); H = T1;
CFHashCode CFHashBytes(uint8_t *bytes, CFIndex length) {
UInt32 H = 0, T1, T2;
SInt32 rem = length;
while (3 < rem) {
ELF_STEP(bytes[length - rem]);
ELF_STEP(bytes[length - rem + 1]);
ELF_STEP(bytes[length - rem + 2]);
ELF_STEP(bytes[length - rem + 3]);
rem -= 4;
}
switch (rem) {
case 3: ELF_STEP(bytes[length - 3]);
case 2: ELF_STEP(bytes[length - 2]);
case 1: ELF_STEP(bytes[length - 1]);
case 0: ;
}
return H;
}
#undef ELF_STEP
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
__private_extern__ uintptr_t __CFFindPointer(uintptr_t ptr, uintptr_t start) {
vm_map_t task = mach_task_self();
mach_vm_address_t address = start;
for (;;) {
mach_vm_size_t size = 0;
vm_region_basic_info_data_64_t info;
mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64;
mach_port_t object_name;
kern_return_t ret = mach_vm_region(task, &address, &size, VM_REGION_BASIC_INFO_64, (vm_region_info_t)&info, &count, &object_name);
if (KERN_SUCCESS != ret) break;
boolean_t scan = (info.protection & VM_PROT_WRITE) ? 1 : 0;
if (scan) {
uintptr_t *addr = (uintptr_t *)((uintptr_t)address);
uintptr_t *end = (uintptr_t *)((uintptr_t)address + (uintptr_t)size);
while (addr < end) {
if ((uintptr_t *)start <= addr && *addr == ptr) {
return (uintptr_t)addr;
}
addr++;
}
}
address += size;
}
return 0;
}
__private_extern__ void __CFDumpAllPointerLocations(uintptr_t ptr) {
uintptr_t addr = 0;
do {
addr = __CFFindPointer(ptr, sizeof(void *) + addr);
printf("%p\n", (void *)addr);
} while (addr != 0);
}
#endif
#if DEPLOYMENT_TARGET_WINDOWS
struct _args {
void *func;
void *arg;
HANDLE handle;
};
static unsigned __stdcall __CFWinThreadFunc(void *arg) {
struct _args *args = (struct _args*)arg;
((void (*)(void *))args->func)(args->arg);
CloseHandle(args->handle);
CFAllocatorDeallocate(kCFAllocatorSystemDefault, arg);
_endthreadex(0);
return 0;
}
#endif
__private_extern__ void *__CFStartSimpleThread(void *func, void *arg) {
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
pthread_attr_t attr;
pthread_t tid = 0;
pthread_attr_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_attr_setstacksize(&attr, 60 * 1024); OSMemoryBarrier(); pthread_create(&tid, &attr, func, arg);
pthread_attr_destroy(&attr);
return (void *)tid;
#elif DEPLOYMENT_TARGET_WINDOWS
unsigned tid;
struct _args *args = (struct _args*)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(struct _args), 0);
if (__CFOASafe) __CFSetLastAllocationEventName(args, "CFUtilities (thread-args)");
HANDLE handle;
args->func = func;
args->arg = arg;
args->handle = (HANDLE)_beginthreadex(NULL, 0, __CFWinThreadFunc, args, CREATE_SUSPENDED, &tid);
handle = args->handle;
ResumeThread(handle);
return handle;
#endif
}
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
static CFStringRef _CFCopyLocalizedVersionKey(CFBundleRef *bundlePtr, CFStringRef nonLocalized) {
CFStringRef localized = NULL;
CFBundleRef locBundle = bundlePtr ? *bundlePtr : NULL;
if (!locBundle) {
CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, CFSTR("/System/Library/CoreServices/SystemVersion.bundle"), kCFURLPOSIXPathStyle, false);
if (url) {
locBundle = CFBundleCreate(kCFAllocatorSystemDefault, url);
CFRelease(url);
}
}
if (locBundle) {
localized = CFBundleCopyLocalizedString(locBundle, nonLocalized, nonLocalized, CFSTR("SystemVersion"));
if (bundlePtr) *bundlePtr = locBundle; else CFRelease(locBundle);
}
return localized ? localized : (CFStringRef)CFRetain(nonLocalized);
}
#endif
static CFDictionaryRef _CFCopyVersionDictionary(CFStringRef path) {
CFPropertyListRef plist = NULL;
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
CFDataRef data;
CFURLRef url;
url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, path, kCFURLPOSIXPathStyle, false);
if (url && CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault, url, &data, NULL, NULL, NULL)) {
plist = CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, data, kCFPropertyListMutableContainers, NULL);
CFRelease(data);
}
if (url) CFRelease(url);
if (plist) {
CFBundleRef locBundle = NULL;
CFStringRef fullVersion, vers, versExtra, build;
CFStringRef versionString = _CFCopyLocalizedVersionKey(&locBundle, _kCFSystemVersionProductVersionStringKey);
CFStringRef buildString = _CFCopyLocalizedVersionKey(&locBundle, _kCFSystemVersionBuildStringKey);
CFStringRef fullVersionString = _CFCopyLocalizedVersionKey(&locBundle, CFSTR("FullVersionString"));
if (locBundle) CFRelease(locBundle);
if (CFEqual(fullVersionString, CFSTR("FullVersionString"))) {
CFRelease(fullVersionString);
fullVersionString = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@ %%@ (%@ %%@)"), versionString, buildString);
}
vers = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)plist, _kCFSystemVersionProductVersionKey);
versExtra = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)plist, _kCFSystemVersionProductVersionExtraKey);
if (vers && versExtra) vers = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@ %@"), vers, versExtra);
build = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)plist, _kCFSystemVersionBuildVersionKey);
fullVersion = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, fullVersionString, (vers ? vers : CFSTR("?")), build ? build : CFSTR("?"));
if (vers && versExtra) CFRelease(vers);
CFDictionarySetValue((CFMutableDictionaryRef)plist, _kCFSystemVersionProductVersionStringKey, versionString);
CFDictionarySetValue((CFMutableDictionaryRef)plist, _kCFSystemVersionBuildStringKey, buildString);
CFDictionarySetValue((CFMutableDictionaryRef)plist, CFSTR("FullVersionString"), fullVersion);
CFRelease(versionString);
CFRelease(buildString);
CFRelease(fullVersionString);
CFRelease(fullVersion);
}
#elif DEPLOYMENT_TARGET_WINDOWS
OSVERSIONINFOEX osvi;
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
BOOL result = GetVersionEx((OSVERSIONINFO *)&osvi);
if (!result) return NULL;
plist = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 10, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFStringRef versionString = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%ld.%ld(%ld,%ld)"), osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.wServicePackMajor, osvi.wServicePackMinor);
CFStringRef buildString = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%ld"), osvi.dwBuildNumber);
CFDictionarySetValue((CFMutableDictionaryRef)plist, _kCFSystemVersionProductVersionKey, versionString);
CFDictionarySetValue((CFMutableDictionaryRef)plist, _kCFSystemVersionBuildVersionKey, buildString);
CFDictionarySetValue((CFMutableDictionaryRef)plist, _kCFSystemVersionProductNameKey, CFSTR("Windows"));
CFRelease(versionString);
CFRelease(buildString);
#endif
return (CFDictionaryRef)plist;
}
CFStringRef CFCopySystemVersionString(void) {
CFStringRef versionString;
CFDictionaryRef dict = _CFCopyServerVersionDictionary();
if (!dict) dict = _CFCopySystemVersionDictionary();
if (!dict) return NULL;
versionString = (CFStringRef)CFDictionaryGetValue(dict, CFSTR("FullVersionString"));
if (versionString) CFRetain(versionString);
CFRelease(dict);
return versionString;
}
CFDictionaryRef _CFCopySystemVersionDictionary(void) {
CFPropertyListRef plist = NULL;
plist = _CFCopyVersionDictionary(CFSTR("/System/Library/CoreServices/SystemVersion.plist"));
return (CFDictionaryRef)plist;
}
CFDictionaryRef _CFCopyServerVersionDictionary(void) {
CFPropertyListRef plist = NULL;
plist = _CFCopyVersionDictionary(CFSTR("/System/Library/CoreServices/ServerVersion.plist"));
return (CFDictionaryRef)plist;
}
CONST_STRING_DECL(_kCFSystemVersionProductNameKey, "ProductName")
CONST_STRING_DECL(_kCFSystemVersionProductCopyrightKey, "ProductCopyright")
CONST_STRING_DECL(_kCFSystemVersionProductVersionKey, "ProductVersion")
CONST_STRING_DECL(_kCFSystemVersionProductVersionExtraKey, "ProductVersionExtra")
CONST_STRING_DECL(_kCFSystemVersionProductUserVisibleVersionKey, "ProductUserVisibleVersion")
CONST_STRING_DECL(_kCFSystemVersionBuildVersionKey, "ProductBuildVersion")
CONST_STRING_DECL(_kCFSystemVersionProductVersionStringKey, "Version")
CONST_STRING_DECL(_kCFSystemVersionBuildStringKey, "Build")
CF_EXPORT Boolean _CFExecutableLinkedOnOrAfter(CFSystemVersion version) {
return true;
}
#if DEPLOYMENT_TARGET_MACOSX
__private_extern__ void *__CFLookupCarbonCoreFunction(const char *name) {
static void *image = NULL;
if (NULL == image) {
image = dlopen("/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore", RTLD_LAZY | RTLD_LOCAL);
}
void *dyfunc = NULL;
if (image) {
dyfunc = dlsym(image, name);
}
return dyfunc;
}
#endif
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
__private_extern__ void *__CFLookupCoreServicesInternalFunction(const char *name) {
static void *image = NULL;
if (NULL == image) {
image = dlopen("/System/Library/PrivateFrameworks/CoreServicesInternal.framework/CoreServicesInternal", RTLD_LAZY | RTLD_LOCAL);
}
void *dyfunc = NULL;
if (image) {
dyfunc = dlsym(image, name);
}
return dyfunc;
}
__private_extern__ void *__CFLookupCFNetworkFunction(const char *name) {
static void *image = NULL;
if (NULL == image) {
const char *path = NULL;
if (!issetugid()) {
path = __CFgetenv("CFNETWORK_LIBRARY_PATH");
}
if (!path) {
path = "/System/Library/Frameworks/CFNetwork.framework/CFNetwork";
}
image = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
}
void *dyfunc = NULL;
if (image) {
dyfunc = dlsym(image, name);
}
return dyfunc;
}
#endif
#ifndef __CFGetSessionID_defined
__private_extern__ uint32_t __CFGetSessionID(void) {
return 0;
}
#endif
__private_extern__ CFIndex __CFActiveProcessorCount() {
int32_t pcnt;
#if DEPLOYMENT_TARGET_WINDOWS
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
DWORD_PTR activeProcessorMask = sysInfo.dwActiveProcessorMask;
uint64_t v = activeProcessorMask;
v = v - ((v >> 1) & 0x5555555555555555ULL);
v = (v & 0x3333333333333333ULL) + ((v >> 2) & 0x3333333333333333ULL);
v = (v + (v >> 4)) & 0xf0f0f0f0f0f0f0fULL;
pcnt = (v * 0x0101010101010101ULL) >> ((sizeof(v) - 1) * 8);
#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
int32_t mib[] = {CTL_HW, HW_AVAILCPU};
size_t len = sizeof(pcnt);
int32_t result = sysctl(mib, sizeof(mib) / sizeof(int32_t), &pcnt, &len, NULL, 0);
if (result != 0) {
pcnt = 0;
}
#else
pcnt = 1;
#endif
return pcnt;
}
__private_extern__ void __CFGetUGIDs(uid_t *euid, gid_t *egid) {
#if 1 && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI)
uid_t uid;
gid_t gid;
if (0 == pthread_getugid_np(&uid, &gid)) {
if (euid) *euid = uid;
if (egid) *egid = gid;
} else
#endif
{
if (euid) *euid = geteuid();
if (egid) *egid = getegid();
}
}
const char *_CFPrintForDebugger(const void *obj) {
static char *result = NULL;
CFStringRef str;
CFIndex cnt = 0;
free(result); result = NULL;
if (obj) {
if (CFGetTypeID(obj) == CFStringGetTypeID()) {
str = __CFCopyFormattingDescription(obj, NULL);
if (!str) str = CFCopyDescription(obj);
} else {
str = CFCopyDescription(obj);
}
} else {
str = (CFStringRef)CFRetain(CFSTR("(null)"));
}
if (str != NULL) {
CFStringGetBytes(str, CFRangeMake(0, CFStringGetLength(str)), kCFStringEncodingUTF8, 0, FALSE, NULL, 0, &cnt);
}
result = (char *) malloc(cnt + 2); if (str != NULL) {
CFStringGetBytes(str, CFRangeMake(0, CFStringGetLength(str)), kCFStringEncodingUTF8, 0, FALSE, (UInt8 *) result, cnt, &cnt);
}
result[cnt] = '\0';
if (str) CFRelease(str);
return result;
}
static void _CFShowToFile(FILE *file, Boolean flush, const void *obj) {
CFStringRef str;
CFIndex idx, cnt;
CFStringInlineBuffer buffer;
bool lastNL = false;
if (obj) {
if (CFGetTypeID(obj) == CFStringGetTypeID()) {
str = __CFCopyFormattingDescription(obj, NULL);
if (!str) str = CFCopyDescription(obj);
} else {
str = CFCopyDescription(obj);
}
} else {
str = (CFStringRef)CFRetain(CFSTR("(null)"));
}
cnt = CFStringGetLength(str);
#if DEPLOYMENT_TARGET_WINDOWS
UniChar *ptr = (UniChar *)CFStringGetCharactersPtr(str);
BOOL freePtr = false;
if (!ptr) {
CFIndex strLen = CFStringGetLength(str);
CFIndex bufSize = sizeof(UniChar *) * (CFStringGetMaximumSizeForEncoding(strLen, kCFStringEncodingUnicode) + 2);
CFIndex bytesUsed = 0;
ptr = (UniChar *)malloc(bufSize);
CFStringGetCharacters(str, CFRangeMake(0, strLen), ptr);
ptr[strLen] = L'\n';
ptr[strLen+1] = 0;
freePtr = true;
}
OutputDebugStringW((wchar_t *)ptr);
if (freePtr) free(ptr);
#else
CFStringInitInlineBuffer(str, &buffer, CFRangeMake(0, cnt));
for (idx = 0; idx < cnt; idx++) {
UniChar ch = __CFStringGetCharacterFromInlineBufferQuick(&buffer, idx);
if (ch < 128) {
fprintf_l(file, NULL, "%c", ch);
lastNL = (ch == '\n');
} else {
fprintf_l(file, NULL, "\\u%04x", ch);
}
}
if (!lastNL) {
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
fprintf_l(file, NULL, "\n");
#else
fprintf(file, NULL, "\n");
#endif
if (flush) fflush(file);
}
#endif
if (str) CFRelease(str);
}
void CFShow(const void *obj) {
_CFShowToFile(stderr, true, obj);
}
typedef void (*CFLogFunc)(int32_t lev, const char *message, size_t length, char withBanner);
static Boolean also_do_stderr() {
#if DEPLOYMENT_TARGET_EMBEDDED_MINI
return true;
#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
if (!issetugid() && __CFgetenv("CFLOG_FORCE_STDERR")) {
return true;
}
struct stat sb;
int ret = fstat(STDERR_FILENO, &sb);
if (ret < 0) return false;
mode_t m = sb.st_mode & S_IFMT;
if (S_IFREG == m || S_IFSOCK == m) return true;
if (!(S_IFIFO == m || S_IFCHR == m)) return false; int64_t val = 0;
vproc_swap_integer(NULL, VPROC_GSK_IS_MANAGED, NULL, &val);
if (val) return false;
#endif
return true;
}
extern char *__CFBundleMainID;
static void __CFLogCString(int32_t lev, const char *message, size_t length, char withBanner) {
char *banner = NULL;
char *time = NULL;
char *thread = NULL;
char *uid = NULL;
#if DEPLOYMENT_TARGET_WINDOWS
int bannerLen = 0;
#endif
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
if (withBanner) {
CFAbsoluteTime at = CFAbsoluteTimeGetCurrent();
CFCalendarRef calendar = CFCalendarCreateWithIdentifier(kCFAllocatorSystemDefault, kCFCalendarIdentifierGregorian);
if (!calendar) goto after_banner;
CFTimeZoneRef tz = CFTimeZoneCopySystem();
if (!tz) {
CFRelease(calendar);
goto after_banner;
}
CFCalendarSetTimeZone(calendar, tz);
CFRelease(tz);
int32_t year, month, day, hour, minute, second;
Boolean dec = CFCalendarDecomposeAbsoluteTime(calendar, at, "yMdHms", &year, &month, &day, &hour, &minute, &second);
CFRelease(calendar);
if (!dec) goto after_banner;
double atf;
int32_t ms = (int32_t)floor(1000.0 * modf(at, &atf));
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
asprintf(&banner, "%04d-%02d-%02d %02d:%02d:%02d.%03d %s[%d:%x] ", year, month, day, hour, minute, second, ms, *_CFGetProgname(), getpid(), pthread_mach_thread_np(pthread_self()));
asprintf(&thread, "%x", pthread_mach_thread_np(pthread_self()));
#elif DEPLOYMENT_TARGET_WINDOWS
bannerLen = asprintf(&banner, "%04d-%02d-%02d %02d:%02d:%02d.%03d %s[%d:%x] ", year, month, day, hour, minute, second, ms, *_CFGetProgname(), getpid(), GetCurrentThreadId());
asprintf(&thread, "%x", GetCurrentThreadId());
#else
bannerLen = asprintf(&banner, "%04d-%02d-%02d %02d:%02d:%02d.%03d %s[%d:%x] ", year, month, day, hour, minute, second, ms, *_CFGetProgname(), getpid(), (unsigned int)pthread_self());
asprintf(&thread, "%x", pthread_self());
#endif
asprintf(&time, "%04d-%02d-%02d %02d:%02d:%02d.%03d", year, month, day, hour, minute, second, ms);
}
after_banner:;
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
uid_t euid;
__CFGetUGIDs(&euid, NULL);
asprintf(&uid, "%d", euid);
aslclient asl = asl_open(NULL, __CFBundleMainID[0] ? __CFBundleMainID : "com.apple.console", ASL_OPT_NO_DELAY);
aslmsg msg = asl_new(ASL_TYPE_MSG);
asl_set(msg, "CFLog Local Time", time); asl_set(msg, "CFLog Thread", thread); asl_set(msg, "ReadUID", uid);
static const char *levstr[] = {"0", "1", "2", "3", "4", "5", "6", "7"};
asl_set(msg, ASL_KEY_LEVEL, levstr[lev]);
asl_set(msg, ASL_KEY_MSG, message);
asl_send(asl, msg);
asl_free(msg);
asl_close(asl);
#endif
#endif // DEPLOYMENT_TARGET
if (also_do_stderr()) {
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
struct iovec v[3];
v[0].iov_base = banner;
v[0].iov_len = banner ? strlen(banner) : 0;
v[1].iov_base = (char *)message;
v[1].iov_len = length;
v[2].iov_base = "\n";
v[2].iov_len = (message[length - 1] != '\n') ? 1 : 0;
int nv = (v[0].iov_base ? 1 : 0) + 1 + (v[2].iov_len ? 1 : 0);
static CFSpinLock_t lock = CFSpinLockInit;
__CFSpinLock(&lock);
writev(STDERR_FILENO, v[0].iov_base ? v : v + 1, nv);
__CFSpinUnlock(&lock);
#elif DEPLOYMENT_TARGET_WINDOWS
size_t bufLen = bannerLen + length + 1;
char *buf = (char *)malloc(sizeof(char) * bufLen);
if (banner) {
memmove_s(buf, bufLen, banner, bannerLen);
strcpy_s(buf + bannerLen, bufLen - bannerLen, message);
} else {
strcpy_s(buf, bufLen, message);
}
buf[bufLen - 1] = '\0';
fprintf_s(stderr, "%s\n", buf);
free(buf);
#else
size_t bufLen = bannerLen + length + 1;
char *buf = (char *)malloc(sizeof(char) * bufLen);
if (banner) {
memmove(buf, banner, bannerLen);
strncpy(buf + bannerLen, message, bufLen - bannerLen);
} else {
strncpy(buf, message, bufLen);
}
buf[bufLen - 1] = '\0';
fprintf(stderr, "%s\n", buf);
free(buf);
#endif
}
if (thread) free(thread);
if (time) free(time);
if (banner) free(banner);
if (uid) free(uid);
}
CF_EXPORT void _CFLogvEx(CFLogFunc logit, CFStringRef (*copyDescFunc)(void *, const void *), CFDictionaryRef formatOptions, int32_t lev, CFStringRef format, va_list args) {
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
uintptr_t val = (uintptr_t)_CFGetTSD(__CFTSDKeyIsInCFLog);
if (3 < val) return; _CFSetTSD(__CFTSDKeyIsInCFLog, (void *)(val + 1), NULL);
#endif
CFStringRef str = format ? _CFStringCreateWithFormatAndArgumentsAux(kCFAllocatorSystemDefault, copyDescFunc, formatOptions, (CFStringRef)format, args) : 0;
CFIndex blen = str ? CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8) + 1 : 0;
char *buf = str ? (char *)malloc(blen) : 0;
if (str && buf) {
Boolean converted = CFStringGetCString(str, buf, blen, kCFStringEncodingUTF8);
size_t len = strlen(buf);
if (converted && !(len <= 0 || (1 << 24) < len) && !(lev < ASL_LEVEL_EMERG || ASL_LEVEL_DEBUG < lev)) {
(logit ? logit : __CFLogCString)(lev, buf, len, 1);
}
}
if (buf) free(buf);
if (str) CFRelease(str);
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
_CFSetTSD(__CFTSDKeyIsInCFLog, (void *)val, NULL);
#endif
}
__private_extern__ void _CFLogSimple(int32_t lev, char *format, ...) {
va_list args;
va_start(args, format);
char formattedMessage[1024];
int length = vsnprintf(formattedMessage, 1024, format, args);
if (length > 0) {
__CFLogCString(lev, formattedMessage, length, 0);
}
va_end(args);
}
void CFLog(int32_t lev, CFStringRef format, ...) {
va_list args;
va_start(args, format);
_CFLogvEx(NULL, NULL, NULL, lev, format, args);
va_end(args);
}
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
kern_return_t _CFDiscorporateMemoryAllocate(CFDiscorporateMemory *hm, size_t size, bool purgeable) {
kern_return_t ret = KERN_SUCCESS;
size = round_page(size);
if (0 == size) size = vm_page_size;
memset(hm, 0, sizeof(CFDiscorporateMemory));
void *addr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, VM_MAKE_TAG(0) | (purgeable ? VM_FLAGS_PURGABLE : 0), 0);
if ((uintptr_t)addr == -1) {
ret = KERN_NO_SPACE;
}
if (KERN_SUCCESS == ret) {
hm->address = (mach_vm_address_t)(uintptr_t)addr;
hm->size = (mach_vm_size_t)size;
hm->port = MACH_PORT_NULL;
hm->corporeal = true;
hm->purgeable = purgeable;
}
if (KERN_SUCCESS == ret) ret = mach_make_memory_entry_64(mach_task_self(), &hm->size, hm->address, VM_PROT_DEFAULT, &hm->port, MACH_PORT_NULL);
if (KERN_SUCCESS == ret) hm->corporeal = true;
return ret;
}
kern_return_t _CFDiscorporateMemoryDeallocate(CFDiscorporateMemory *hm) {
kern_return_t ret1 = KERN_SUCCESS, ret2 = KERN_SUCCESS;
if (hm->corporeal) ret1 = mach_vm_deallocate(mach_task_self(), hm->address, hm->size);
hm->address = MACH_VM_MIN_ADDRESS;
hm->corporeal = false;
ret2 = mach_port_deallocate(mach_task_self(), hm->port);
hm->port = MACH_PORT_NULL;
return ret1 != KERN_SUCCESS ? ret1 : ret2;
}
kern_return_t _CFDiscorporateMemoryDematerialize(CFDiscorporateMemory *hm) {
kern_return_t ret = KERN_SUCCESS;
if (!hm->corporeal) ret = KERN_INVALID_MEMORY_CONTROL;
int state = VM_PURGABLE_VOLATILE;
if (KERN_SUCCESS == ret) vm_purgable_control(mach_task_self(), (vm_address_t)hm->address, VM_PURGABLE_SET_STATE, &state);
if (KERN_SUCCESS == ret) ret = mach_vm_deallocate(mach_task_self(), hm->address, hm->size);
if (KERN_SUCCESS == ret) hm->address = MACH_VM_MIN_ADDRESS;
if (KERN_SUCCESS == ret) hm->corporeal = false;
return ret;
}
kern_return_t _CFDiscorporateMemoryMaterialize(CFDiscorporateMemory *hm) {
kern_return_t ret = KERN_SUCCESS;
if (hm->corporeal) ret = KERN_INVALID_MEMORY_CONTROL;
if (KERN_SUCCESS == ret) ret = mach_vm_map(mach_task_self(), &hm->address, hm->size, 0, VM_FLAGS_ANYWHERE, hm->port, 0, FALSE, VM_PROT_DEFAULT, VM_PROT_DEFAULT, VM_INHERIT_DEFAULT);
if (KERN_SUCCESS == ret) hm->corporeal = true;
int state = VM_PURGABLE_NONVOLATILE;
if (KERN_SUCCESS == ret) ret = vm_purgable_control(mach_task_self(), (vm_address_t)hm->address, VM_PURGABLE_SET_STATE, &state);
if (KERN_SUCCESS == ret) if (VM_PURGABLE_EMPTY == state) ret = KERN_PROTECTION_FAILURE; return ret;
}
#endif
#if DEPLOYMENT_TARGET_MACOSX
#define SUDDEN_TERMINATION_ENABLE_VPROC 1
#if SUDDEN_TERMINATION_ENABLE_VPROC
static CFSpinLock_t __CFProcessKillingLock = CFSpinLockInit;
static CFIndex __CFProcessKillingDisablingCount = 1;
static Boolean __CFProcessKillingWasTurnedOn = false;
void _CFSuddenTerminationDisable(void) {
__CFSpinLock(&__CFProcessKillingLock);
__CFProcessKillingDisablingCount++;
_vproc_transaction_begin();
__CFSpinUnlock(&__CFProcessKillingLock);
}
void _CFSuddenTerminationEnable(void) {
__CFSpinLock(&__CFProcessKillingLock);
__CFProcessKillingDisablingCount--;
if (__CFProcessKillingDisablingCount==0 && !__CFProcessKillingWasTurnedOn) {
_vproc_transactions_enable();
__CFProcessKillingWasTurnedOn = true;
} else {
if (__CFProcessKillingDisablingCount>=0) {
_vproc_transaction_end();
} else {
CFLog(kCFLogLevelError, CFSTR("-[NSProcessInfo enableSuddenTermination] has been invoked more times than necessary to balance invocations of -[NSProcessInfo disableSuddenTermination]. Ignoring."));
}
}
__CFSpinUnlock(&__CFProcessKillingLock);
}
void _CFSuddenTerminationExitIfTerminationEnabled(int exitStatus) {
__CFSpinLock(&__CFProcessKillingLock);
if (_vproc_transaction_count()==0 && __CFProcessKillingWasTurnedOn) {
_exit(exitStatus);
}
__CFSpinUnlock(&__CFProcessKillingLock);
}
void _CFSuddenTerminationExitWhenTerminationEnabled(int exitStatus) {
__CFSpinLock(&__CFProcessKillingLock);
if (__CFProcessKillingWasTurnedOn) {
_vproc_transaction_try_exit(exitStatus);
}
__CFSpinUnlock(&__CFProcessKillingLock);
}
size_t _CFSuddenTerminationDisablingCount(void) {
return _vproc_transaction_count() + (__CFProcessKillingWasTurnedOn ? 0 : 1);
}
#else
#warning Building with vproc sudden termination API disabled.
static CFSpinLock_t __CFProcessKillingLock = CFSpinLockInit;
static size_t __CFProcessKillingDisablingCount = 1;
static Boolean __CFProcessExitNextTimeKillingIsEnabled = false;
static int32_t __CFProcessExitStatus = 0;
static int __CFProcessIsKillableNotifyToken;
static Boolean __CFProcessIsKillableNotifyTokenIsFigured = false;
__private_extern__ void _CFSetSuddenTerminationEnabled(Boolean isEnabled) {
if (!__CFProcessIsKillableNotifyTokenIsFigured) {
char *notificationName = NULL;
asprintf(¬ificationName, "com.apple.isKillable.%i", getpid());
uint32_t notifyResult = notify_register_check(notificationName, &__CFProcessIsKillableNotifyToken);
if (notifyResult != NOTIFY_STATUS_OK) {
CFLog(kCFLogLevelError, CFSTR("%s: notify_register_check() returned %i."), __PRETTY_FUNCTION__, notifyResult);
}
free(notificationName);
__CFProcessIsKillableNotifyTokenIsFigured = true;
}
uint32_t notifyResult = notify_set_state(__CFProcessIsKillableNotifyToken, isEnabled);
if (notifyResult != NOTIFY_STATUS_OK) {
CFLog(kCFLogLevelError, CFSTR("%s: notify_set_state() returned %i"), __PRETTY_FUNCTION__, notifyResult);
}
}
void _CFSuddenTerminationDisable(void) {
__CFSpinLock(&__CFProcessKillingLock);
if (__CFProcessKillingDisablingCount == 0) {
_CFSetSuddenTerminationEnabled(false);
}
__CFProcessKillingDisablingCount++;
__CFSpinUnlock(&__CFProcessKillingLock);
}
void _CFSuddenTerminationEnable(void) {
__CFSpinLock(&__CFProcessKillingLock);
__CFProcessKillingDisablingCount--;
if (__CFProcessKillingDisablingCount == 0) {
if (__CFProcessExitNextTimeKillingIsEnabled) {
_exit(__CFProcessExitStatus);
} else {
_CFSetSuddenTerminationEnabled(true);
}
}
__CFSpinUnlock(&__CFProcessKillingLock);
}
void _CFSuddenTerminationExitIfTerminationEnabled(int exitStatus) {
__CFSpinLock(&__CFProcessKillingLock);
if (__CFProcessKillingDisablingCount == 0) {
_exit(exitStatus);
}
__CFSpinUnlock(&__CFProcessKillingLock);
}
void _CFSuddenTerminationExitWhenTerminationEnabled(int exitStatus) {
__CFSpinLock(&__CFProcessKillingLock);
if (__CFProcessKillingDisablingCount == 0) {
_exit(exitStatus);
} else {
__CFProcessExitNextTimeKillingIsEnabled = YES;
__CFProcessExitStatus = exitStatus;
}
__CFSpinUnlock(&__CFProcessKillingLock);
}
size_t _CFSuddenTerminationDisablingCount(void) {
return __CFProcessKillingDisablingCount;
}
#endif
#endif
#if 0
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
typedef void (^ThrottleTypeA)(void); typedef void (^ThrottleTypeB)(uint64_t amt);
__private_extern__ ThrottleTypeA __CFCreateThrottleTypeA(uint16_t calls, uint64_t nanoseconds) {
struct mach_timebase_info info;
mach_timebase_info(&info);
uint64_t period = nanoseconds / info.numer * info.denom;
if (0 == calls || 0 == period) return NULL;
__block OSSpinLock b_lock = OS_SPINLOCK_INIT;
__block uint64_t b_values[calls];
__block uint64_t *b_oldest = b_values;
memset(b_values, 0, sizeof(b_values));
return Block_copy(^{
uint64_t curr_time = mach_absolute_time();
OSSpinLockLock(&b_lock);
uint64_t next_time = *b_oldest + period;
*b_oldest = (curr_time < next_time) ? next_time : curr_time;
b_oldest++;
if (b_values + calls <= b_oldest) b_oldest = b_values;
OSSpinLockUnlock(&b_lock);
if (curr_time < next_time) {
mach_wait_until(next_time);
}
});
}
__private_extern__ ThrottleTypeB __CFCreateThrottleTypeB(uint64_t amount, uint64_t nanoseconds) {
struct mach_timebase_info info;
mach_timebase_info(&info);
uint64_t period = nanoseconds / info.numer * info.denom;
if (0 == amount || 0 == period) return NULL;
__block OSSpinLock b_lock = OS_SPINLOCK_INIT;
__block uint64_t b_sum = 0ULL;
__block uint16_t b_num_values = 8;
__block uint64_t *b_values = calloc(b_num_values, 2 * sizeof(uint64_t));
__block uint64_t *b_oldest = b_values;
return Block_copy(^(uint64_t amt){
OSSpinLockLock(&b_lock);
OSSpinLockUnlock(&b_lock);
});
}
#endif
#endif
#pragma mark File Reading
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#if DEPLOYMENT_TARGET_WINDOWS
#include <io.h>
#include <direct.h>
#define close _close
#define write _write
#define read _read
#define open _NS_open
#define stat _NS_stat
#define fstat _fstat
#define statinfo _stat
#define mach_task_self() 0
#else
#define statinfo stat
#endif
static CFErrorRef _CFErrorWithFilePathCodeDomain(CFStringRef domain, CFIndex code, CFStringRef path) {
CFStringRef key = CFSTR("NSFilePath");
CFDictionaryRef userInfo = CFDictionaryCreate(kCFAllocatorSystemDefault, (const void **)&key, (const void **)&path, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFErrorRef result = CFErrorCreate(kCFAllocatorSystemDefault, domain, code, userInfo);
CFRelease(userInfo);
return result;
}
__private_extern__ Boolean _CFReadMappedFromFile(CFStringRef path, Boolean map, Boolean uncached, void **outBytes, CFIndex *outLength, CFErrorRef *errorPtr) {
void *bytes = NULL;
unsigned long length;
char cpath[CFMaxPathSize];
if (!CFStringGetFileSystemRepresentation(path, cpath, CFMaxPathSize)) {
if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainCocoa, -1, path);
return false;
}
struct statinfo statBuf;
int32_t fd = -1;
fd = open(cpath, O_RDONLY|CF_OPENFLGS, 0666);
if (fd < 0) {
if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainPOSIX, errno, path);
return false;
}
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
if (uncached) (void)fcntl(fd, F_NOCACHE, 1); #endif
if (fstat(fd, &statBuf) < 0) {
int32_t savederrno = errno;
close(fd);
if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainPOSIX, savederrno, path);
return false;
}
if ((statBuf.st_mode & S_IFMT) != S_IFREG) {
close(fd);
if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainPOSIX, EACCES, path);
return false;
}
if (statBuf.st_size < 0LL) { close(fd);
if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainPOSIX, ENOMEM, path);
return false;
}
#if __LP64__
#else
if (statBuf.st_size > (1LL << 31)) { close(fd);
if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainPOSIX, EFBIG, path);
return false;
}
#endif
if (0LL == statBuf.st_size) {
bytes = malloc(8); length = 0;
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
} else if (map) {
if((void *)-1 == (bytes = mmap(0, (size_t)statBuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0))) {
int32_t savederrno = errno;
close(fd);
if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainPOSIX, savederrno, path);
return false;
}
length = (unsigned long)statBuf.st_size;
} else {
bytes = malloc(statBuf.st_size);
if (bytes == NULL) {
close(fd);
if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainPOSIX, ENOMEM, path);
return false;
}
size_t numBytesRemaining = (size_t)statBuf.st_size;
void *readLocation = bytes;
while (numBytesRemaining > 0) {
size_t numBytesRequested = (numBytesRemaining < (1LL << 31)) ? numBytesRemaining : ((1LL << 31) - 1); ssize_t numBytesRead = read(fd, readLocation, numBytesRequested);
if (numBytesRead <= 0) {
if (numBytesRead < 0) {
int32_t savederrno = errno;
free(bytes);
close(fd);
if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainPOSIX, savederrno, path);
bytes = NULL;
return false;
} else {
break;
}
} else {
readLocation += numBytesRead;
numBytesRemaining -= numBytesRead;
}
}
length = (unsigned long)statBuf.st_size - numBytesRemaining;
}
#else
} else {
bytes = malloc(statBuf.st_size);
DWORD numBytesRead;
if (!ReadFile((HANDLE)_get_osfhandle(fd), bytes, statBuf.st_size, &numBytesRead, NULL)) {
DWORD lastError = GetLastError();
if (errorPtr) *errorPtr = _CFErrorWithFilePathCodeDomain(kCFErrorDomainPOSIX, lastError, path);
free(bytes);
close(fd);
errno = lastError;
bytes = NULL;
return false;
}
length = numBytesRead;
}
#endif
close(fd);
*outBytes = bytes;
*outLength = length;
return true;
}