2 * Copyright (c) 2010 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 Copyright (c) 1999-2009, Apple Inc. All rights reserved.
26 Responsibility: Christopher Kane
29 #include "CFInternal.h"
30 #include <CoreFoundation/CFPriv.h>
31 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
38 #include <crt_externs.h>
39 #include <mach-o/dyld.h>
42 #if DEPLOYMENT_TARGET_WINDOWS
46 #define getcwd _NS_getcwd
50 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC
51 #define kCFPlatformInterfaceStringEncoding kCFStringEncodingUTF8
53 #define kCFPlatformInterfaceStringEncoding CFStringGetSystemEncoding()
56 static CFStringRef
_CFUserName(void);
58 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
59 // CoreGraphics and LaunchServices are only projects (1 Dec 2006) that use these
60 char **_CFArgv(void) { return *_NSGetArgv(); }
61 int _CFArgc(void) { return *_NSGetArgc(); }
65 __private_extern__ Boolean
_CFGetCurrentDirectory(char *path
, int maxlen
) {
66 return getcwd(path
, maxlen
) != NULL
;
69 static Boolean __CFIsCFM
= false;
71 // If called super early, we just return false
72 __private_extern__ Boolean
_CFIsCFM(void) {
76 #if DEPLOYMENT_TARGET_WINDOWS
83 #if DEPLOYMENT_TARGET_WINDOWS
84 // Returns the path to the CF DLL, which we can then use to find resources like char sets
85 bool bDllPathCached
= false;
86 __private_extern__
const wchar_t *_CFDLLPath(void) {
87 static wchar_t cachedPath
[MAX_PATH
+1];
89 if (!bDllPathCached
) {
91 // might be nice to get this from the project file at some point
92 wchar_t *DLLFileName
= L
"CoreFoundation_debug.dll";
94 wchar_t *DLLFileName
= L
"CoreFoundation.dll";
96 HMODULE ourModule
= GetModuleHandleW(DLLFileName
);
98 CFAssert(ourModule
, __kCFLogAssertion
, "GetModuleHandle failed");
100 DWORD wResult
= GetModuleFileNameW(ourModule
, cachedPath
, MAX_PATH
+1);
101 CFAssert1(wResult
> 0, __kCFLogAssertion
, "GetModuleFileName failed: %d", GetLastError());
102 CFAssert1(wResult
< MAX_PATH
+1, __kCFLogAssertion
, "GetModuleFileName result truncated: %s", cachedPath
);
104 // strip off last component, the DLL name
106 for (idx
= wResult
- 1; idx
; idx
--) {
107 if ('\\' == cachedPath
[idx
]) {
108 cachedPath
[idx
] = '\0';
112 bDllPathCached
= true;
118 static const char *__CFProcessPath
= NULL
;
119 static const char *__CFprogname
= NULL
;
121 const char **_CFGetProgname(void) {
123 _CFProcessPath(); // sets up __CFprogname as a side-effect
124 return &__CFprogname
;
127 const char **_CFGetProcessPath(void) {
128 if (!__CFProcessPath
)
129 _CFProcessPath(); // sets up __CFProcessPath as a side-effect
130 return &__CFProcessPath
;
133 #if DEPLOYMENT_TARGET_WINDOWS
134 const char *_CFProcessPath(void) {
135 if (__CFProcessPath
) return __CFProcessPath
;
136 wchar_t buf
[CFMaxPathSize
] = {0};
137 DWORD rlen
= GetModuleFileNameW(NULL
, buf
, sizeof(buf
) / sizeof(buf
[0]));
139 char asciiBuf
[CFMaxPathSize
] = {0};
140 int res
= WideCharToMultiByte(CP_UTF8
, 0, buf
, rlen
, asciiBuf
, sizeof(asciiBuf
) / sizeof(asciiBuf
[0]), NULL
, NULL
);
142 __CFProcessPath
= strdup(asciiBuf
);
143 __CFprogname
= strrchr(__CFProcessPath
, PATH_SEP
);
144 __CFprogname
= (__CFprogname
? __CFprogname
+ 1 : __CFProcessPath
);
147 if (!__CFProcessPath
) {
148 __CFProcessPath
= "";
149 __CFprogname
= __CFProcessPath
;
151 return __CFProcessPath
;
155 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
156 const char *_CFProcessPath(void) {
157 if (__CFProcessPath
) return __CFProcessPath
;
158 #if DEPLOYMENT_TARGET_MACOSX
160 const char *path
= (char *)__CFgetenv("CFProcessPath");
162 __CFProcessPath
= strdup(path
);
163 __CFprogname
= strrchr(__CFProcessPath
, PATH_SEP
);
164 __CFprogname
= (__CFprogname
? __CFprogname
+ 1 : __CFProcessPath
);
165 return __CFProcessPath
;
169 uint32_t size
= CFMaxPathSize
;
171 if (0 == _NSGetExecutablePath(buffer
, &size
)) {
172 #if DEPLOYMENT_TARGET_MACOSX && defined(__ppc__)
173 size_t len
= strlen(buffer
);
174 if (12 <= len
&& 0 == strcmp("LaunchCFMApp", buffer
+ len
- 12)) {
175 struct stat exec
, lcfm
;
176 const char *launchcfm
= "/System/Library/Frameworks/Carbon.framework/Versions/Current/Support/LaunchCFMApp";
177 if (0 == stat(launchcfm
, &lcfm
) && 0 == stat(buffer
, &exec
) && (lcfm
.st_dev
== exec
.st_dev
) && (lcfm
.st_ino
== exec
.st_ino
)) {
178 // Executable is LaunchCFMApp, take special action
180 if ((*_NSGetArgv())[1] && '/' == *((*_NSGetArgv())[1])) {
181 strlcpy(buffer
, (*_NSGetArgv())[1], sizeof(buffer
));
186 __CFProcessPath
= strdup(buffer
);
187 __CFprogname
= strrchr(__CFProcessPath
, PATH_SEP
);
188 __CFprogname
= (__CFprogname
? __CFprogname
+ 1 : __CFProcessPath
);
190 if (!__CFProcessPath
) {
191 __CFProcessPath
= "";
192 __CFprogname
= __CFProcessPath
;
194 return __CFProcessPath
;
198 __private_extern__ CFStringRef
_CFProcessNameString(void) {
199 static CFStringRef __CFProcessNameString
= NULL
;
200 if (!__CFProcessNameString
) {
201 const char *processName
= *_CFGetProgname();
202 if (!processName
) processName
= "";
203 CFStringRef newStr
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, processName
, kCFPlatformInterfaceStringEncoding
);
204 if (!OSAtomicCompareAndSwapPtrBarrier(NULL
, (void *) newStr
, (void * volatile *)& __CFProcessNameString
)) {
205 CFRelease(newStr
); // someone else made the assignment, so just release the extra string.
208 return __CFProcessNameString
;
211 static CFStringRef __CFUserName
= NULL
;
213 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
214 static CFURLRef __CFHomeDirectory
= NULL
;
215 static uint32_t __CFEUID
= -1;
216 static uint32_t __CFUID
= -1;
218 static CFURLRef
_CFCopyHomeDirURLForUser(struct passwd
*upwd
) {
219 CFURLRef home
= NULL
;
221 const char *path
= __CFgetenv("CFFIXED_USER_HOME");
223 home
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault
, (uint8_t *)path
, strlen(path
), true);
227 if (upwd
&& upwd
->pw_dir
) {
228 home
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault
, (uint8_t *)upwd
->pw_dir
, strlen(upwd
->pw_dir
), true);
234 static void _CFUpdateUserInfo(void) {
237 __CFEUID
= geteuid();
239 if (__CFHomeDirectory
) CFRelease(__CFHomeDirectory
);
240 __CFHomeDirectory
= NULL
;
241 if (__CFUserName
) CFRelease(__CFUserName
);
244 upwd
= getpwuid(__CFEUID
? __CFEUID
: __CFUID
);
245 __CFHomeDirectory
= _CFCopyHomeDirURLForUser(upwd
);
246 if (!__CFHomeDirectory
) {
247 const char *cpath
= __CFgetenv("HOME");
249 __CFHomeDirectory
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault
, (uint8_t *)cpath
, strlen(cpath
), true);
253 // This implies that UserManager stores directory info in CString
254 // rather than FileSystemRep. Perhaps this is wrong & we should
255 // expect NeXTSTEP encodings. A great test of our localized system would
256 // be to have a user "O-umlat z e r". XXX
257 if (upwd
&& upwd
->pw_name
) {
258 __CFUserName
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, upwd
->pw_name
, kCFPlatformInterfaceStringEncoding
);
260 const char *cuser
= __CFgetenv("USER");
262 __CFUserName
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, cuser
, kCFPlatformInterfaceStringEncoding
);
267 #if DEPLOYMENT_TARGET_WINDOWS
268 typedef DWORD (*NetUserGetInfoCall
)(wchar_t *, wchar_t *, DWORD
, char* *);
271 static CFURLRef
_CFCreateHomeDirectoryURLForUser(CFStringRef uName
) {
272 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
274 if (geteuid() != __CFEUID
|| getuid() != __CFUID
|| !__CFHomeDirectory
)
276 if (__CFHomeDirectory
) CFRetain(__CFHomeDirectory
);
277 return __CFHomeDirectory
;
279 struct passwd
*upwd
= NULL
;
280 char buf
[128], *user
;
281 SInt32 len
= CFStringGetLength(uName
), size
= CFStringGetMaximumSizeForEncoding(len
, kCFPlatformInterfaceStringEncoding
);
286 user
= CFAllocatorAllocate(kCFAllocatorSystemDefault
, size
+1, 0);
287 if (__CFOASafe
) __CFSetLastAllocationEventName(user
, "CFUtilities (temp)");
289 if (CFStringGetBytes(uName
, CFRangeMake(0, len
), kCFPlatformInterfaceStringEncoding
, 0, true, (uint8_t *)user
, size
, &usedSize
) == len
) {
290 user
[usedSize
] = '\0';
291 upwd
= getpwnam(user
);
294 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, user
);
296 return _CFCopyHomeDirURLForUser(upwd
);
298 #elif DEPLOYMENT_TARGET_WINDOWS
299 CFStringRef user
= !uName
? _CFUserName() : uName
;
300 CFURLRef retVal
= NULL
;
302 CFStringRef str
= NULL
;
304 if (!uName
|| CFEqual(user
, _CFUserName())) {
305 const char *cpath
= __CFgetenv("HOMEPATH");
306 const char *cdrive
= __CFgetenv("HOMEDRIVE");
307 if (cdrive
&& cpath
) {
308 char fullPath
[CFMaxPathSize
];
309 strlcpy(fullPath
, cdrive
, sizeof(fullPath
));
310 strlcat(fullPath
, cpath
, sizeof(fullPath
));
311 str
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, fullPath
, kCFPlatformInterfaceStringEncoding
);
312 retVal
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, str
, kCFURLWindowsPathStyle
, true);
316 if (retVal
== NULL
) {
317 UniChar pathChars
[MAX_PATH
];
318 if (S_OK
== SHGetFolderPathW(NULL
, CSIDL_PROFILE
, NULL
, SHGFP_TYPE_CURRENT
, (wchar_t *) pathChars
)) {
319 UniChar
* p
= pathChars
;
322 str
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, pathChars
, len
);
323 retVal
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, str
, kCFURLWindowsPathStyle
, true);
325 // We have to get "some" directory location, so fall-back to the
326 // processes current directory.
327 UniChar currDir
[MAX_PATH
];
328 DWORD dwChars
= GetCurrentDirectoryW(MAX_PATH
+ 1, (wchar_t *)currDir
);
330 UniChar
* p
= currDir
;
333 str
= CFStringCreateWithCharacters(kCFAllocatorDefault
, currDir
, len
);
334 retVal
= CFURLCreateWithFileSystemPath(NULL
, str
, kCFURLWindowsPathStyle
, true);
340 char fullPath
[CFMaxPathSize
];
341 HRESULT hr
= SHGetFolderPathA(NULL
, CSIDL_PROFILE
, NULL
, 0 /* SHGFP_TYPE_CURRENT */, fullPath
);
343 CFStringRef str
= CFStringCreateWithCString(NULL
, fullPath
, kCFPlatformInterfaceStringEncoding
);
344 retVal
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, str
, kCFURLWindowsPathStyle
, true);
349 struct _USER_INFO_2
*userInfo
;
350 HINSTANCE hinstDll
= GetModuleHandleA("NETAPI32");
352 hinstDll
= LoadLibraryExA("NETAPI32", NULL
, 0);
354 NetUserGetInfoCall lpfn
= (NetUserGetInfoCall
)GetProcAddress(hinstDll
, "NetUserGetInfo");
356 unsigned namelen
= CFStringGetLength(user
);
358 username
= (UniChar
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(UniChar
) * (namelen
+ 1), 0);
359 CFStringGetCharacters(user
, CFRangeMake(0, namelen
), username
);
360 if (!(*lpfn
)(NULL
, (wchar_t *)username
, 2, (char * *)&userInfo
)) {
362 CFMutableStringRef str
;
363 while (userInfo
->usri2_home_dir
[len
] != 0) len
++;
364 str
= CFStringCreateMutable(kCFAllocatorSystemDefault
, len
+1);
365 CFStringAppendCharacters(str
, (const UniChar
*)userInfo
->usri2_home_dir
, len
);
366 retVal
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, str
, kCFURLWindowsPathStyle
, true);
369 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, username
);
376 // We could do more here (as in KB Article Q101507). If that article is to
377 // be believed, we should only run into this case on Win95, or through
379 #if DEPLOYMENT_TARGET_WINDOWS_SAFARI
381 CFStringRef str
= CFURLCopyFileSystemPath(retVal
, kCFURLWindowsPathStyle
);
382 if (str
&& CFStringGetLength(str
) == 0) {
386 if (str
) CFRelease(str
);
389 CFStringRef testPath
= CFURLCopyPath(retVal
);
390 if (CFStringGetLength(testPath
) == 0) {
401 #error Dont know how to compute users home directories on this platform
405 static CFStringRef
_CFUserName(void) {
406 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
407 if (geteuid() != __CFEUID
|| getuid() != __CFUID
)
409 #elif DEPLOYMENT_TARGET_WINDOWS
411 wchar_t username
[1040];
414 if (GetUserNameW(username
, &size
)) {
415 // discount the extra NULL by decrementing the size
416 __CFUserName
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (const UniChar
*)username
, size
- 1);
418 const char *cname
= __CFgetenv("USERNAME");
420 __CFUserName
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, cname
, kCFPlatformInterfaceStringEncoding
);
424 #error Dont know how to compute user name on this platform
427 __CFUserName
= (CFStringRef
)CFRetain(CFSTR(""));
431 __private_extern__ CFStringRef
_CFGetUserName(void) {
432 return CFStringCreateCopy(kCFAllocatorSystemDefault
, _CFUserName());
435 #define CFMaxHostNameLength 256
436 #define CFMaxHostNameSize (CFMaxHostNameLength+1)
438 __private_extern__ CFStringRef
_CFStringCreateHostName(void) {
439 char myName
[CFMaxHostNameSize
];
441 // return @"" instead of nil a la CFUserName() and Ali Ozer
442 if (0 != gethostname(myName
, CFMaxHostNameSize
)) myName
[0] = '\0';
443 return CFStringCreateWithCString(kCFAllocatorSystemDefault
, myName
, kCFPlatformInterfaceStringEncoding
);
446 /* These are sanitized versions of the above functions. We might want to eliminate the above ones someday.
447 These can return NULL.
449 CF_EXPORT CFStringRef
CFGetUserName(void) {
450 return _CFUserName();
453 CF_EXPORT CFURLRef
CFCopyHomeDirectoryURLForUser(CFStringRef uName
) {
454 return _CFCreateHomeDirectoryURLForUser(uName
);
457 #undef CFMaxHostNameLength
458 #undef CFMaxHostNameSize
460 #if DEPLOYMENT_TARGET_WINDOWS
461 CF_INLINE CFIndex
strlen_UniChar(const UniChar
* p
) {
468 //#include <shfolder.h>
470 * _CFCreateApplicationRepositoryPath returns the path to the application's
471 * repository in a CFMutableStringRef. The path returned will be:
472 * <nFolder_path>\Apple Computer\<bundle_name>\
473 * or if the bundle name cannot be obtained:
474 * <nFolder_path>\Apple Computer\
475 * where nFolder_path is obtained by calling SHGetFolderPath with nFolder
476 * (for example, with CSIDL_APPDATA or CSIDL_LOCAL_APPDATA).
478 * The CFMutableStringRef result must be released by the caller.
480 * If anything fails along the way, the result will be NULL.
482 CF_EXPORT CFMutableStringRef
_CFCreateApplicationRepositoryPath(CFAllocatorRef alloc
, int nFolder
) {
483 CFMutableStringRef result
= NULL
;
484 UniChar szPath
[MAX_PATH
];
486 // get the current path to the data repository: CSIDL_APPDATA (roaming) or CSIDL_LOCAL_APPDATA (nonroaming)
487 if (S_OK
== SHGetFolderPathW(NULL
, nFolder
, NULL
, 0, (wchar_t *) szPath
)) {
488 CFStringRef directoryPath
;
490 // make it a CFString
491 directoryPath
= CFStringCreateWithCharacters(alloc
, szPath
, strlen_UniChar(szPath
));
494 CFStringRef bundleName
;
495 CFStringRef completePath
;
497 // attempt to get the bundle name
498 bundle
= CFBundleGetMainBundle();
500 bundleName
= (CFStringRef
)CFBundleGetValueForInfoDictionaryKey(bundle
, kCFBundleNameKey
);
507 // the path will be "<directoryPath>\Apple Computer\<bundleName>\" if there is a bundle name
508 completePath
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%@\\Apple Computer\\%@\\"), directoryPath
, bundleName
);
511 // or "<directoryPath>\Apple Computer\" if there is no bundle name.
512 completePath
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%@\\Apple Computer\\"), directoryPath
);
515 CFRelease(directoryPath
);
517 // make a mutable copy to return
519 result
= CFStringCreateMutableCopy(alloc
, 0, completePath
);
520 CFRelease(completePath
);
529 #if DEPLOYMENT_TARGET_WINDOWS
530 /* On Windows, we want to use UTF-16LE for path names to get full unicode support. Internally, however, everything remains in UTF-8 representation. These helper functions stand between CF and the Microsoft CRT to ensure that we are using the right representation on both sides. */
532 #include <sys/stat.h>
535 // Creates a buffer of wchar_t to hold a UTF16LE version of the UTF8 str passed in. Caller must free the buffer when done. If resultLen is non-NULL, it is filled out with the number of characters in the string.
536 static wchar_t *createWideFileSystemRepresentation(const char *str
, CFIndex
*resultLen
) {
537 // Get the real length of the string in UTF16 characters
538 CFStringRef cfStr
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, str
, kCFStringEncodingUTF8
);
539 CFIndex strLen
= CFStringGetLength(cfStr
);
541 // Allocate a wide buffer to hold the converted string, including space for a NULL terminator
542 wchar_t *wideBuf
= (wchar_t *)malloc((strLen
+ 1) * sizeof(wchar_t));
544 // Copy the string into the buffer and terminate
545 CFStringGetCharacters(cfStr
, CFRangeMake(0, strLen
), (UniChar
*)wideBuf
);
549 if (resultLen
) *resultLen
= strLen
;
553 // Copies a UTF16 buffer into a supplied UTF8 buffer.
554 static void copyToNarrowFileSystemRepresentation(const wchar_t *wide
, CFIndex dstBufSize
, char *dstbuf
) {
555 // Get the real length of the wide string in UTF8 characters
556 CFStringRef cfStr
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (const UniChar
*)wide
, wcslen(wide
));
557 CFIndex strLen
= CFStringGetLength(cfStr
);
560 // Copy the wide string into the buffer and terminate
561 CFStringGetBytes(cfStr
, CFRangeMake(0, strLen
), kCFStringEncodingUTF8
, 0, false, (uint8_t *)dstbuf
, dstBufSize
, &bytesUsed
);
562 dstbuf
[bytesUsed
] = 0;
567 CF_EXPORT
int _NS_stat(const char *name
, struct _stat
*st
) {
568 wchar_t *wide
= createWideFileSystemRepresentation(name
, NULL
);
569 int res
= _wstat(wide
, st
);
574 CF_EXPORT
int _NS_mkdir(const char *name
) {
575 wchar_t *wide
= createWideFileSystemRepresentation(name
, NULL
);
576 int res
= _wmkdir(wide
);
581 CF_EXPORT
int _NS_rmdir(const char *name
) {
582 wchar_t *wide
= createWideFileSystemRepresentation(name
, NULL
);
583 int res
= _wrmdir(wide
);
588 CF_EXPORT
int _NS_chmod(const char *name
, int mode
) {
589 wchar_t *wide
= createWideFileSystemRepresentation(name
, NULL
);
590 int res
= _wchmod(wide
, mode
);
595 CF_EXPORT
int _NS_unlink(const char *name
) {
596 wchar_t *wide
= createWideFileSystemRepresentation(name
, NULL
);
597 int res
= _wunlink(wide
);
602 // Warning: this doesn't support dstbuf as null even though 'getcwd' does
603 CF_EXPORT
char *_NS_getcwd(char *dstbuf
, size_t size
) {
605 CFLog(kCFLogLevelWarning
, CFSTR("CFPlatform: getcwd called with null buffer"));
609 wchar_t *buf
= _wgetcwd(NULL
, 0);
614 // Convert result to UTF8
615 copyToNarrowFileSystemRepresentation(buf
, (CFIndex
)size
, dstbuf
);
620 CF_EXPORT
char *_NS_getenv(const char *name
) {
621 // todo: wide env variables
625 CF_EXPORT
int _NS_rename(const char *oldName
, const char *newName
) {
626 wchar_t *oldWide
= createWideFileSystemRepresentation(oldName
, NULL
);
627 wchar_t *newWide
= createWideFileSystemRepresentation(newName
, NULL
);
628 // _wrename on Windows does not behave exactly as rename() on Mac OS -- if the file exists, the Windows one will fail whereas the Mac OS version will replace
629 // To simulate the Mac OS behavior, we use the Win32 API then fill out errno if something goes wrong
630 BOOL winRes
= MoveFileExW(oldWide
, newWide
, MOVEFILE_REPLACE_EXISTING
);
631 DWORD error
= GetLastError();
637 case ERROR_FILE_NOT_FOUND
:
638 case ERROR_PATH_NOT_FOUND
:
639 case ERROR_OPEN_FAILED
:
642 case ERROR_ACCESS_DENIED
:
651 return (winRes
? 0 : -1);
654 CF_EXPORT
int _NS_open(const char *name
, int oflag
, int pmode
) {
655 wchar_t *wide
= createWideFileSystemRepresentation(name
, NULL
);
657 _wsopen_s(&fd
, wide
, oflag
, _SH_DENYNO
, _S_IREAD
| _S_IWRITE
);
662 CF_EXPORT
int _NS_chdir(const char *name
) {
663 wchar_t *wide
= createWideFileSystemRepresentation(name
, NULL
);
664 int res
= _wchdir(wide
);
669 CF_EXPORT
int _NS_access(const char *name
, int amode
) {
670 // execute is always true
671 if (amode
== 1) return 0;
673 wchar_t *wide
= createWideFileSystemRepresentation(name
, NULL
);
674 // we only care about the read-only (04) and write-only (02) bits, so mask octal 06
675 int res
= _waccess(wide
, amode
& 06);
680 // This is a bit different than the standard 'mkstemp', because the size parameter is needed so we know the size of the UTF8 buffer
681 // Also, we don't avoid the race between creating a temporary file name and opening it on Windows like we do on Mac
682 CF_EXPORT
int _NS_mkstemp(char *name
, int bufSize
) {
684 wchar_t *wide
= createWideFileSystemRepresentation(name
, &nameLen
);
686 // First check to see if the directory that this new temporary file will be created in exists. If not, set errno to ENOTDIR. This mimics the behavior of mkstemp on MacOS more closely.
687 // Look for the last '\' in the path
688 wchar_t *lastSlash
= wcsrchr(wide
, '\\');
694 // Set the last slash to NULL temporarily and use it for _wstat
696 struct _stat dirInfo
;
697 int res
= _wstat(wide
, &dirInfo
);
699 if (errno
== ENOENT
) {
705 // Restore the last slash
708 errno_t err
= _wmktemp_s(wide
, nameLen
+ 1);
715 _wsopen_s(&fd
, wide
, _O_RDWR
| _O_CREAT
| CF_OPENFLGS
, _SH_DENYNO
, _S_IREAD
| _S_IWRITE
);
717 // Convert the wide name back into the UTF8 buffer the caller supplied
718 copyToNarrowFileSystemRepresentation(wide
, bufSize
, name
);