#include "CFInternal.h"
#include <CoreFoundation/CFPriv.h>
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <pwd.h>
#include <crt_externs.h>
#include <mach-o/dyld.h>
#include <pthread/tsd_private.h>
#endif
#if DEPLOYMENT_TARGET_WINDOWS
#include <shellapi.h>
#include <shlobj.h>
#include <WinIoCtl.h>
#define getcwd _NS_getcwd
#endif
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS
#define kCFPlatformInterfaceStringEncoding kCFStringEncodingUTF8
#else
#define kCFPlatformInterfaceStringEncoding CFStringGetSystemEncoding()
#endif
extern void __CFGetUGIDs(uid_t *euid, gid_t *egid);
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
char **_CFArgv(void) { return *_NSGetArgv(); }
int _CFArgc(void) { return *_NSGetArgc(); }
#endif
CF_PRIVATE Boolean _CFGetCurrentDirectory(char *path, int maxlen) {
return getcwd(path, maxlen) != NULL;
}
#if DEPLOYMENT_TARGET_WINDOWS
bool bDllPathCached = false;
CF_PRIVATE const wchar_t *_CFDLLPath(void) {
static wchar_t cachedPath[MAX_PATH+1];
if (!bDllPathCached) {
#ifdef _DEBUG
wchar_t *DLLFileName = L"CoreFoundation_debug.dll";
#else
wchar_t *DLLFileName = L"CoreFoundation.dll";
#endif
HMODULE ourModule = GetModuleHandleW(DLLFileName);
CFAssert(ourModule, __kCFLogAssertion, "GetModuleHandle failed");
DWORD wResult = GetModuleFileNameW(ourModule, cachedPath, MAX_PATH+1);
CFAssert1(wResult > 0, __kCFLogAssertion, "GetModuleFileName failed: %d", GetLastError());
CFAssert1(wResult < MAX_PATH+1, __kCFLogAssertion, "GetModuleFileName result truncated: %s", cachedPath);
CFIndex idx;
for (idx = wResult - 1; idx; idx--) {
if ('\\' == cachedPath[idx]) {
cachedPath[idx] = '\0';
break;
}
}
bDllPathCached = true;
}
return cachedPath;
}
#endif
static const char *__CFProcessPath = NULL;
static const char *__CFprogname = NULL;
const char **_CFGetProgname(void) {
if (!__CFprogname)
_CFProcessPath(); return &__CFprogname;
}
const char **_CFGetProcessPath(void) {
if (!__CFProcessPath)
_CFProcessPath(); return &__CFProcessPath;
}
#if DEPLOYMENT_TARGET_WINDOWS
const char *_CFProcessPath(void) {
if (__CFProcessPath) return __CFProcessPath;
wchar_t buf[CFMaxPathSize] = {0};
DWORD rlen = GetModuleFileNameW(NULL, buf, sizeof(buf) / sizeof(buf[0]));
if (0 < rlen) {
char asciiBuf[CFMaxPathSize] = {0};
int res = WideCharToMultiByte(CP_UTF8, 0, buf, rlen, asciiBuf, sizeof(asciiBuf) / sizeof(asciiBuf[0]), NULL, NULL);
if (0 < res) {
__CFProcessPath = strdup(asciiBuf);
__CFprogname = strrchr(__CFProcessPath, PATH_SEP);
__CFprogname = (__CFprogname ? __CFprogname + 1 : __CFProcessPath);
}
}
if (!__CFProcessPath) {
__CFProcessPath = "";
__CFprogname = __CFProcessPath;
}
return __CFProcessPath;
}
#endif
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
const char *_CFProcessPath(void) {
if (__CFProcessPath) return __CFProcessPath;
#if DEPLOYMENT_TARGET_MACOSX
if (!issetugid()) {
const char *path = (char *)__CFgetenv("CFProcessPath");
if (path) {
__CFProcessPath = strdup(path);
__CFprogname = strrchr(__CFProcessPath, PATH_SEP);
__CFprogname = (__CFprogname ? __CFprogname + 1 : __CFProcessPath);
return __CFProcessPath;
}
}
#endif
uint32_t size = CFMaxPathSize;
char buffer[size];
if (0 == _NSGetExecutablePath(buffer, &size)) {
__CFProcessPath = strdup(buffer);
__CFprogname = strrchr(__CFProcessPath, PATH_SEP);
__CFprogname = (__CFprogname ? __CFprogname + 1 : __CFProcessPath);
}
if (!__CFProcessPath) {
__CFProcessPath = "";
__CFprogname = __CFProcessPath;
}
return __CFProcessPath;
}
#endif
#if DEPLOYMENT_TARGET_LINUX
#include <unistd.h>
const char *_CFProcessPath(void) {
if (__CFProcessPath) return __CFProcessPath;
char buf[CFMaxPathSize + 1];
ssize_t res = readlink("/proc/self/exe", buf, CFMaxPathSize);
if (res > 0) {
buf[res] = 0;
__CFProcessPath = strdup(buf);
__CFprogname = strrchr(__CFProcessPath, PATH_SEP);
__CFprogname = (__CFprogname ? __CFprogname + 1 : __CFProcessPath);
} else {
__CFProcessPath = "";
__CFprogname = __CFProcessPath;
}
return __CFProcessPath;
}
#endif
CF_PRIVATE CFStringRef _CFProcessNameString(void) {
static CFStringRef __CFProcessNameString = NULL;
if (!__CFProcessNameString) {
const char *processName = *_CFGetProgname();
if (!processName) processName = "";
CFStringRef newStr = CFStringCreateWithCString(kCFAllocatorSystemDefault, processName, kCFPlatformInterfaceStringEncoding);
if (!OSAtomicCompareAndSwapPtrBarrier(NULL, (void *) newStr, (void * volatile *)& __CFProcessNameString)) {
CFRelease(newStr); }
}
return __CFProcessNameString;
}
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
#include <pwd.h>
#include <sys/param.h>
static CFURLRef _CFCopyHomeDirURLForUser(struct passwd *upwd, bool fallBackToHome) {
const char *fixedHomePath = issetugid() ? NULL : __CFgetenv("CFFIXED_USER_HOME");
const char *homePath = NULL;
CFURLRef home = NULL;
if (!issetugid() && fixedHomePath) home = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, (uint8_t *)fixedHomePath, strlen(fixedHomePath), true);
if (!home && upwd && upwd->pw_dir) home = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, (uint8_t *)upwd->pw_dir, strlen(upwd->pw_dir), true);
if (fallBackToHome && !home) homePath = __CFgetenv("HOME");
if (fallBackToHome && !home && homePath) home = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, (uint8_t *)homePath, strlen(homePath), true);
return home;
}
#endif
#define CFMaxHostNameLength 256
#define CFMaxHostNameSize (CFMaxHostNameLength+1)
CF_PRIVATE CFStringRef _CFStringCreateHostName(void) {
char myName[CFMaxHostNameSize];
if (0 != gethostname(myName, CFMaxHostNameSize)) myName[0] = '\0';
return CFStringCreateWithCString(kCFAllocatorSystemDefault, myName, kCFPlatformInterfaceStringEncoding);
}
CF_EXPORT CFStringRef CFGetUserName(void) {
return CFCopyUserName();
}
CF_EXPORT CFStringRef CFCopyUserName(void) {
CFStringRef result = NULL;
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
uid_t euid;
__CFGetUGIDs(&euid, NULL);
struct passwd *upwd = getpwuid(euid ? euid : getuid());
if (upwd && upwd->pw_name) {
result = CFStringCreateWithCString(kCFAllocatorSystemDefault, upwd->pw_name, kCFPlatformInterfaceStringEncoding);
} else {
const char *cuser = __CFgetenv("USER");
if (cuser) {
result = CFStringCreateWithCString(kCFAllocatorSystemDefault, cuser, kCFPlatformInterfaceStringEncoding);
}
}
#elif DEPLOYMENT_TARGET_WINDOWS
wchar_t username[1040];
DWORD size = 1040;
username[0] = 0;
if (GetUserNameW(username, &size)) {
result = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)username, size - 1);
} else {
const char *cname = __CFgetenv("USERNAME");
if (cname) {
result = CFStringCreateWithCString(kCFAllocatorSystemDefault, cname, kCFPlatformInterfaceStringEncoding);
}
}
#else
#error Dont know how to compute user name on this platform
#endif
if (!result)
result = (CFStringRef)CFRetain(CFSTR(""));
return result;
}
CFURLRef CFCopyHomeDirectoryURL(void) {
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
uid_t euid;
__CFGetUGIDs(&euid, NULL);
struct passwd *upwd = getpwuid(euid ? euid : getuid());
return _CFCopyHomeDirURLForUser(upwd, true);
#elif DEPLOYMENT_TARGET_WINDOWS
CFURLRef retVal = NULL;
CFIndex len = 0;
CFStringRef str = NULL;
UniChar pathChars[MAX_PATH];
if (S_OK == SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, (wchar_t *)pathChars)) {
len = (CFIndex)wcslen((wchar_t *)pathChars);
str = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, pathChars, len);
retVal = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str, kCFURLWindowsPathStyle, true);
CFRelease(str);
}
if (!retVal) {
const char *cpath = __CFgetenv("HOMEPATH");
const char *cdrive = __CFgetenv("HOMEDRIVE");
if (cdrive && cpath) {
char fullPath[CFMaxPathSize];
strlcpy(fullPath, cdrive, sizeof(fullPath));
strlcat(fullPath, cpath, sizeof(fullPath));
str = CFStringCreateWithCString(kCFAllocatorSystemDefault, fullPath, kCFPlatformInterfaceStringEncoding);
retVal = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str, kCFURLWindowsPathStyle, true);
CFRelease(str);
}
}
if (!retVal) {
UniChar currDir[MAX_PATH];
DWORD dwChars = GetCurrentDirectoryW(MAX_PATH + 1, (wchar_t *)currDir);
if (dwChars > 0) {
len = (CFIndex)wcslen((wchar_t *)currDir);
str = CFStringCreateWithCharacters(kCFAllocatorDefault, currDir, len);
retVal = CFURLCreateWithFileSystemPath(NULL, str, kCFURLWindowsPathStyle, true);
CFRelease(str);
}
}
CFStringRef testPath = CFURLCopyFileSystemPath(retVal, kCFURLWindowsPathStyle);
if (CFStringGetLength(testPath) == 0) {
CFRelease(retVal);
retVal = NULL;
}
if (testPath) CFRelease(testPath);
return retVal;
#else
#error Dont know how to compute users home directories on this platform
#endif
}
CF_EXPORT CFURLRef CFCopyHomeDirectoryURLForUser(CFStringRef uName) {
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
if (!uName) {
uid_t euid;
__CFGetUGIDs(&euid, NULL);
struct passwd *upwd = getpwuid(euid ? euid : getuid());
return _CFCopyHomeDirURLForUser(upwd, true);
} else {
struct passwd *upwd = NULL;
char buf[128], *user;
SInt32 len = CFStringGetLength(uName), size = CFStringGetMaximumSizeForEncoding(len, kCFPlatformInterfaceStringEncoding);
CFIndex usedSize;
if (size < 127) {
user = buf;
} else {
user = CFAllocatorAllocate(kCFAllocatorSystemDefault, size+1, 0);
}
if (CFStringGetBytes(uName, CFRangeMake(0, len), kCFPlatformInterfaceStringEncoding, 0, true, (uint8_t *)user, size, &usedSize) == len) {
user[usedSize] = '\0';
upwd = getpwnam(user);
}
if (buf != user) {
CFAllocatorDeallocate(kCFAllocatorSystemDefault, user);
}
return _CFCopyHomeDirURLForUser(upwd, false);
}
#elif DEPLOYMENT_TARGET_WINDOWS
CFStringRef userName = uName ? CFCopyUserName() : NULL;
if (uName && !CFEqual(uName, userName)) {
CFLog(kCFLogLevelError, CFSTR("CFCopyHomeDirectoryURLForUser(): Unable to get home directory for other user"));
if (userName) CFRelease(userName);
return NULL;
}
if (userName) CFRelease(userName);
return CFCopyHomeDirectoryURL();
#else
#error Dont know how to compute users home directories on this platform
#endif
}
#undef CFMaxHostNameLength
#undef CFMaxHostNameSize
#if DEPLOYMENT_TARGET_WINDOWS
CF_INLINE CFIndex strlen_UniChar(const UniChar* p) {
CFIndex result = 0;
while ((*p++) != 0)
++result;
return result;
}
CF_EXPORT CFMutableStringRef _CFCreateApplicationRepositoryPath(CFAllocatorRef alloc, int nFolder) {
CFMutableStringRef result = NULL;
UniChar szPath[MAX_PATH];
if (S_OK == SHGetFolderPathW(NULL, nFolder, NULL, 0, (wchar_t *) szPath)) {
CFStringRef directoryPath;
directoryPath = CFStringCreateWithCharacters(alloc, szPath, strlen_UniChar(szPath));
if (directoryPath) {
CFBundleRef bundle;
CFStringRef bundleName;
CFStringRef completePath;
bundle = CFBundleGetMainBundle();
if (bundle) {
bundleName = (CFStringRef)CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleNameKey);
}
else {
bundleName = NULL;
}
if (bundleName) {
completePath = CFStringCreateWithFormat(alloc, NULL, CFSTR("%@\\Apple Computer\\%@\\"), directoryPath, bundleName);
}
else {
completePath = CFStringCreateWithFormat(alloc, NULL, CFSTR("%@\\Apple Computer\\"), directoryPath);
}
CFRelease(directoryPath);
if (completePath) {
result = CFStringCreateMutableCopy(alloc, 0, completePath);
CFRelease(completePath);
}
}
}
return ( result );
}
#endif
#pragma mark -
#pragma mark Thread Functions
#if DEPLOYMENT_TARGET_WINDOWS
const DWORD MS_VC_EXCEPTION=0x406D1388;
#pragma pack(push,8)
typedef struct tagTHREADNAME_INFO
{
DWORD dwType; LPCSTR szName; DWORD dwThreadID; DWORD dwFlags; } THREADNAME_INFO;
#pragma pack(pop)
CF_EXPORT void _NS_pthread_setname_np(const char *name) {
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = name;
info.dwThreadID = GetCurrentThreadId();
info.dwFlags = 0;
__try
{
RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
}
static pthread_t __initialPthread = { NULL, 0 };
CF_EXPORT int _NS_pthread_main_np() {
pthread_t me = pthread_self();
if (NULL == __initialPthread.p) {
__initialPthread.p = me.p;
__initialPthread.x = me.x;
}
return (pthread_equal(__initialPthread, me));
}
#endif
#pragma mark -
#pragma mark Thread Local Data
#define CF_TSD_MAX_SLOTS 70
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
static const unsigned long CF_TSD_KEY = __PTK_FRAMEWORK_COREFOUNDATION_KEY5;
#endif
#define CF_TSD_BAD_PTR ((void *)0x1000)
typedef void (*tsdDestructor)(void *);
typedef struct __CFTSDTable {
uint32_t destructorCount;
uintptr_t data[CF_TSD_MAX_SLOTS];
tsdDestructor destructors[CF_TSD_MAX_SLOTS];
} __CFTSDTable;
static void __CFTSDFinalize(void *arg);
#if DEPLOYMENT_TARGET_WINDOWS
static DWORD __CFTSDIndexKey = 0xFFFFFFFF;
CF_PRIVATE void __CFTSDWindowsInitialize() {
__CFTSDIndexKey = TlsAlloc();
}
CF_PRIVATE void __CFTSDWindowsCleanup() {
TlsFree(__CFTSDIndexKey);
}
CF_PRIVATE void __CFFinalizeWindowsThreadData() {
__CFTSDFinalize(TlsGetValue(__CFTSDIndexKey));
}
#endif
#if DEPLOYMENT_TARGET_LINUX
static pthread_key_t __CFTSDIndexKey;
CF_PRIVATE void __CFTSDLinuxInitialize() {
(void)pthread_key_create(&__CFTSDIndexKey, __CFTSDFinalize);
}
#endif
static void __CFTSDSetSpecific(void *arg) {
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
_pthread_setspecific_direct(CF_TSD_KEY, arg);
#elif DEPLOYMENT_TARGET_LINUX
pthread_setspecific(__CFTSDIndexKey, arg);
#elif DEPLOYMENT_TARGET_WINDOWS
TlsSetValue(__CFTSDIndexKey, arg);
#endif
}
static void *__CFTSDGetSpecific() {
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
return _pthread_getspecific_direct(CF_TSD_KEY);
#elif DEPLOYMENT_TARGET_LINUX
return pthread_getspecific(__CFTSDIndexKey);
#elif DEPLOYMENT_TARGET_WINDOWS
return TlsGetValue(__CFTSDIndexKey);
#endif
}
static void __CFTSDFinalize(void *arg) {
__CFTSDSetSpecific(arg);
if (!arg || arg == CF_TSD_BAD_PTR) {
return;
}
__CFTSDTable *table = (__CFTSDTable *)arg;
table->destructorCount++;
for (int32_t i = 0; i < CF_TSD_MAX_SLOTS; i++) {
if (table->data[i] && table->destructors[i]) {
uintptr_t old = table->data[i];
table->data[i] = (uintptr_t)NULL;
table->destructors[i]((void *)(old));
}
}
if (table->destructorCount == PTHREAD_DESTRUCTOR_ITERATIONS - 1) { free(table);
__CFTSDSetSpecific(CF_TSD_BAD_PTR);
return;
}
}
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
extern int pthread_key_init_np(int, void (*)(void *));
#endif
static __CFTSDTable *__CFTSDGetTable() {
__CFTSDTable *table = (__CFTSDTable *)__CFTSDGetSpecific();
if (table == CF_TSD_BAD_PTR) {
return NULL;
}
if (!table) {
table = (__CFTSDTable *)calloc(1, sizeof(__CFTSDTable));
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
pthread_key_init_np(CF_TSD_KEY, __CFTSDFinalize);
#endif
__CFTSDSetSpecific(table);
}
return table;
}
CF_EXPORT void *_CFGetTSD(uint32_t slot) {
if (slot > CF_TSD_MAX_SLOTS) {
_CFLogSimple(kCFLogLevelError, "Error: TSD slot %d out of range (get)", slot);
HALT;
}
__CFTSDTable *table = __CFTSDGetTable();
if (!table) {
_CFLogSimple(kCFLogLevelWarning, "Warning: TSD slot %d retrieved but the thread data has already been torn down.", slot);
return NULL;
}
uintptr_t *slots = (uintptr_t *)(table->data);
return (void *)slots[slot];
}
CF_EXPORT void *_CFSetTSD(uint32_t slot, void *newVal, tsdDestructor destructor) {
if (slot > CF_TSD_MAX_SLOTS) {
_CFLogSimple(kCFLogLevelError, "Error: TSD slot %d out of range (set)", slot);
HALT;
}
__CFTSDTable *table = __CFTSDGetTable();
if (!table) {
_CFLogSimple(kCFLogLevelWarning, "Warning: TSD slot %d set but the thread data has already been torn down.", slot);
return NULL;
}
void *oldVal = (void *)table->data[slot];
table->data[slot] = (uintptr_t)newVal;
table->destructors[slot] = destructor;
return oldVal;
}
#pragma mark -
#pragma mark Windows Wide to UTF8 and UTF8 to Wide
#if DEPLOYMENT_TARGET_WINDOWS
#include <sys/stat.h>
#include <share.h>
static wchar_t *createWideFileSystemRepresentation(const char *str, CFIndex *resultLen) {
CFStringRef cfStr = CFStringCreateWithCString(kCFAllocatorSystemDefault, str, kCFStringEncodingUTF8);
CFIndex strLen = CFStringGetLength(cfStr);
wchar_t *wideBuf = (wchar_t *)malloc((strLen + 1) * sizeof(wchar_t));
CFStringGetCharacters(cfStr, CFRangeMake(0, strLen), (UniChar *)wideBuf);
wideBuf[strLen] = 0;
CFRelease(cfStr);
if (resultLen) *resultLen = strLen;
return wideBuf;
}
static void copyToNarrowFileSystemRepresentation(const wchar_t *wide, CFIndex dstBufSize, char *dstbuf) {
CFStringRef cfStr = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)wide, wcslen(wide));
CFIndex strLen = CFStringGetLength(cfStr);
CFIndex bytesUsed;
CFStringGetBytes(cfStr, CFRangeMake(0, strLen), kCFStringEncodingUTF8, 0, false, (uint8_t *)dstbuf, dstBufSize, &bytesUsed);
dstbuf[bytesUsed] = 0;
CFRelease(cfStr);
}
CF_EXPORT int _NS_stat(const char *name, struct _stat *st) {
wchar_t *wide = createWideFileSystemRepresentation(name, NULL);
int res = _wstat(wide, st);
free(wide);
return res;
}
CF_EXPORT int _NS_mkdir(const char *name) {
wchar_t *wide = createWideFileSystemRepresentation(name, NULL);
int res = _wmkdir(wide);
free(wide);
return res;
}
CF_EXPORT int _NS_rmdir(const char *name) {
wchar_t *wide = createWideFileSystemRepresentation(name, NULL);
int res = _wrmdir(wide);
free(wide);
return res;
}
CF_EXPORT int _NS_chmod(const char *name, int mode) {
wchar_t *wide = createWideFileSystemRepresentation(name, NULL);
int newMode = 0;
if (mode | 0400) newMode |= _S_IREAD;
if (mode | 0200) newMode |= _S_IWRITE;
if (mode | 0100) newMode |= _S_IEXEC;
int res = _wchmod(wide, newMode);
free(wide);
return res;
}
CF_EXPORT int _NS_unlink(const char *name) {
wchar_t *wide = createWideFileSystemRepresentation(name, NULL);
int res = _wunlink(wide);
free(wide);
return res;
}
CF_EXPORT char *_NS_getcwd(char *dstbuf, size_t size) {
if (!dstbuf) {
CFLog(kCFLogLevelWarning, CFSTR("CFPlatform: getcwd called with null buffer"));
return 0;
}
wchar_t *buf = _wgetcwd(NULL, 0);
if (!buf) {
return NULL;
}
copyToNarrowFileSystemRepresentation(buf, (CFIndex)size, dstbuf);
free(buf);
return dstbuf;
}
CF_EXPORT char *_NS_getenv(const char *name) {
return getenv(name);
}
CF_EXPORT int _NS_rename(const char *oldName, const char *newName) {
wchar_t *oldWide = createWideFileSystemRepresentation(oldName, NULL);
wchar_t *newWide = createWideFileSystemRepresentation(newName, NULL);
BOOL winRes = MoveFileExW(oldWide, newWide, MOVEFILE_REPLACE_EXISTING);
DWORD error = GetLastError();
if (!winRes) {
switch (error) {
case ERROR_SUCCESS:
errno = 0;
break;
case ERROR_FILE_NOT_FOUND:
case ERROR_PATH_NOT_FOUND:
case ERROR_OPEN_FAILED:
errno = ENOENT;
break;
case ERROR_ACCESS_DENIED:
errno = EACCES;
break;
default:
errno = error;
}
}
free(oldWide);
free(newWide);
return (winRes ? 0 : -1);
}
CF_EXPORT int _NS_open(const char *name, int oflag, int pmode) {
wchar_t *wide = createWideFileSystemRepresentation(name, NULL);
int fd;
_wsopen_s(&fd, wide, oflag, _SH_DENYNO, _S_IREAD | _S_IWRITE);
free(wide);
return fd;
}
CF_EXPORT int _NS_chdir(const char *name) {
wchar_t *wide = createWideFileSystemRepresentation(name, NULL);
int res = _wchdir(wide);
free(wide);
return res;
}
CF_EXPORT int _NS_access(const char *name, int amode) {
if (amode == 1) return 0;
wchar_t *wide = createWideFileSystemRepresentation(name, NULL);
int res = _waccess(wide, amode & 06);
free(wide);
return res;
}
CF_EXPORT int _NS_mkstemp(char *name, int bufSize) {
CFIndex nameLen;
wchar_t *wide = createWideFileSystemRepresentation(name, &nameLen);
wchar_t *lastSlash = wcsrchr(wide, '\\');
if (!lastSlash) {
free(wide);
return -1;
}
*lastSlash = 0;
struct _stat dirInfo;
int res = _wstat(wide, &dirInfo);
if (res < 0) {
if (errno == ENOENT) {
errno = ENOTDIR;
}
free(wide);
return -1;
}
*lastSlash = '\\';
errno_t err = _wmktemp_s(wide, nameLen + 1);
if (err != 0) {
free(wide);
return 0;
}
int fd;
_wsopen_s(&fd, wide, _O_RDWR | _O_CREAT | CF_OPENFLGS, _SH_DENYNO, _S_IREAD | _S_IWRITE);
copyToNarrowFileSystemRepresentation(wide, bufSize, name);
free(wide);
return fd;
}
Boolean _isAFloppy(char driveLetter)
{
HANDLE h;
TCHAR tsz[8];
Boolean retval = false;
int iDrive;
if (driveLetter >= 'a' && driveLetter <= 'z') {
driveLetter = driveLetter - 'a' + 'A';
}
if ((driveLetter < 'A') || (driveLetter > 'Z')) {
return false;
}
iDrive = driveLetter - 'A' + 1;
wsprintf(tsz, TEXT("\\\\.\\%c:"), TEXT('@') + iDrive);
h = CreateFile(tsz, 0, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
if (h != INVALID_HANDLE_VALUE)
{
DISK_GEOMETRY Geom[20];
DWORD cb;
if (DeviceIoControl (h, IOCTL_DISK_GET_MEDIA_TYPES, 0, 0,
Geom, sizeof(Geom), &cb, 0)
&& cb > 0)
{
switch (Geom[0].MediaType)
{
case F5_1Pt2_512: case F5_360_512: case F5_320_512: case F5_320_1024: case F5_180_512: case F5_160_512: case F3_1Pt44_512: case F3_2Pt88_512: case F3_20Pt8_512: case F3_720_512: retval = true;
break;
}
}
CloseHandle(h);
}
return retval;
}
extern CFStringRef CFCreateWindowsDrivePathFromVolumeName(CFStringRef volNameStr) {
if (!volNameStr) return NULL;
CFIndex strLen = CFStringGetLength(volNameStr);
if (strLen == 0) {
return NULL;
}
long length, result;
wchar_t *driveNames = NULL;
length = GetLogicalDriveStringsW(0, 0);
if (!length) {
return NULL;
}
driveNames = (wchar_t *)malloc((length + 1) * sizeof(wchar_t));
result = GetLogicalDriveStringsW(length, driveNames);
if (!result || result > length) {
free(driveNames);
return NULL;
}
wchar_t *theVolumeName = (wchar_t *)malloc((strLen + 1) * sizeof(wchar_t));
CFStringGetCharacters(volNameStr, CFRangeMake(0, strLen), (UniChar *)theVolumeName);
theVolumeName[strLen] = 0;
_wcslwr(theVolumeName);
wchar_t *drivePtr = driveNames;
CFStringRef drivePathResult = NULL;
while (*drivePtr) {
_wcslwr(drivePtr);
if (!_isAFloppy((char)*drivePtr)) {
UINT oldErrorMode;
DWORD whoCares1, whoCares2;
BOOL getVolInfoSucceeded;
UniChar thisVolumeName[MAX_PATH];
oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
getVolInfoSucceeded = GetVolumeInformationW(drivePtr, (LPWSTR)thisVolumeName, sizeof(thisVolumeName), NULL, &whoCares1, &whoCares2, NULL, 0);
SetErrorMode(oldErrorMode);
if (getVolInfoSucceeded) {
_wcslwr((wchar_t *)thisVolumeName);
if (!wcscmp((const wchar_t *)thisVolumeName, theVolumeName) ||
(*thisVolumeName == 0x00 && (CFStringCompare(volNameStr, CFSTR("NONAME"), 0) == kCFCompareEqualTo))) {
drivePathResult = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)drivePtr, wcslen(drivePtr));
break;
}
}
}
drivePtr += wcslen(drivePtr) + 1;
}
free(driveNames);
free(theVolumeName);
return drivePathResult;
}
struct timezone {
int tz_minuteswest;
int tz_dsttime;
};
CF_PRIVATE int _NS_gettimeofday(struct timeval *tv, struct timezone *tz) {
if (tv) {
FILETIME ft;
GetSystemTimeAsFileTime(&ft);
unsigned __int64 t = 0;
t |= ft.dwHighDateTime;
t <<= 32;
t |= ft.dwLowDateTime;
t /= 10;
t -= 11644473600000000Ui64;
tv->tv_sec = (long)(t / 1000000UL);
tv->tv_usec = (long)(t % 1000000UL);
}
return 0;
}
#endif // DEPLOYMENT_TARGET_WINDOWS
#pragma mark -
#pragma mark Linux OSAtomic
#if DEPLOYMENT_TARGET_LINUX
bool OSAtomicCompareAndSwapPtr(void *oldp, void *newp, void *volatile *dst)
{
return __sync_bool_compare_and_swap(dst, oldp, newp);
}
bool OSAtomicCompareAndSwapLong(long oldl, long newl, long volatile *dst)
{
return __sync_val_compare_and_swap(dst, oldl, newl);
}
bool OSAtomicCompareAndSwapPtrBarrier(void *oldp, void *newp, void *volatile *dst)
{
return __sync_bool_compare_and_swap(dst, oldp, newp);
}
int32_t OSAtomicAdd32Barrier( int32_t theAmount, volatile int32_t *theValue ) {
return __sync_fetch_and_add(theValue, theAmount) + theAmount;
}
bool OSAtomicCompareAndSwap32Barrier(int32_t oldValue, int32_t newValue, volatile int32_t *theValue) {
return __sync_bool_compare_and_swap(theValue, oldValue, newValue);
}
bool OSAtomicCompareAndSwap64Barrier(int64_t oldValue, int64_t newValue, volatile int64_t *theValue) {
return __sync_bool_compare_and_swap(theValue, oldValue, newValue);
}
int32_t OSAtomicDecrement32Barrier(volatile int32_t *dst)
{
return OSAtomicAdd32Barrier(-1, dst);
}
int32_t OSAtomicIncrement32Barrier(volatile int32_t *dst)
{
return OSAtomicAdd32Barrier(1, dst);
}
int32_t OSAtomicAdd32( int32_t theAmount, volatile int32_t *theValue ) {
return OSAtomicAdd32Barrier(theAmount, theValue);
}
int32_t OSAtomicIncrement32(volatile int32_t *theValue) {
return OSAtomicIncrement32Barrier(theValue);
}
int32_t OSAtomicDecrement32(volatile int32_t *theValue) {
return OSAtomicDecrement32Barrier(theValue);
}
void OSMemoryBarrier() {
__sync_synchronize();
}
#include <Block_private.h>
void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) {
struct Block_layout *layout = (struct Block_layout *)block;
pthread_once(predicate, (void (*)(void))layout->invoke);
}
#endif // DEPLOYMENT_TARGET_LINUX
#pragma mark -
#pragma mark Windows and Linux Helpers
#if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
#include <stdio.h>
CF_PRIVATE int asprintf(char **ret, const char *format, ...) {
va_list args;
size_t sz = 1024;
*ret = (char *) malloc(sz * sizeof(char));
if (!*ret) return -1;
va_start(args, format);
int cnt = vsnprintf(*ret, sz, format, args);
va_end(args);
if (cnt < sz - 1) return cnt;
sz = cnt + 8;
char *oldret = *ret;
*ret = (char *) realloc(*ret, sz * sizeof(char));
if (!*ret && oldret) free(oldret);
if (!*ret) return -1;
va_start(args, format);
cnt = vsnprintf(*ret, sz, format, args);
va_end(args);
if (cnt < sz - 1) return cnt;
free(*ret);
*ret = NULL;
return -1;
}
#endif