2 * Copyright (c) 2009 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@
24 Copyright (c) 1999-2009, Apple Inc. All rights reserved.
25 Responsibility: Christopher Kane
28 #include "CFInternal.h"
29 #include <CoreFoundation/CFPriv.h>
30 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
37 #include <crt_externs.h>
38 #include <mach-o/dyld.h>
41 #if DEPLOYMENT_TARGET_WINDOWS
45 #define getcwd _NS_getcwd
49 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC
50 #define kCFPlatformInterfaceStringEncoding kCFStringEncodingUTF8
52 #define kCFPlatformInterfaceStringEncoding CFStringGetSystemEncoding()
55 static CFStringRef
_CFUserName(void);
57 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
58 // CoreGraphics and LaunchServices are only projects (1 Dec 2006) that use these
59 char **_CFArgv(void) { return *_NSGetArgv(); }
60 int _CFArgc(void) { return *_NSGetArgc(); }
64 __private_extern__ Boolean
_CFGetCurrentDirectory(char *path
, int maxlen
) {
65 return getcwd(path
, maxlen
) != NULL
;
68 static Boolean __CFIsCFM
= false;
70 // If called super early, we just return false
71 __private_extern__ Boolean
_CFIsCFM(void) {
75 #if DEPLOYMENT_TARGET_WINDOWS
82 #if DEPLOYMENT_TARGET_WINDOWS
83 // Returns the path to the CF DLL, which we can then use to find resources like char sets
84 bool bDllPathCached
= false;
85 __private_extern__
const wchar_t *_CFDLLPath(void) {
86 static wchar_t cachedPath
[MAX_PATH
+1];
88 if (!bDllPathCached
) {
90 // might be nice to get this from the project file at some point
91 wchar_t *DLLFileName
= L
"CoreFoundation_debug.dll";
93 wchar_t *DLLFileName
= L
"CoreFoundation.dll";
95 HMODULE ourModule
= GetModuleHandleW(DLLFileName
);
97 CFAssert(ourModule
, __kCFLogAssertion
, "GetModuleHandle failed");
99 DWORD wResult
= GetModuleFileNameW(ourModule
, cachedPath
, MAX_PATH
+1);
100 CFAssert1(wResult
> 0, __kCFLogAssertion
, "GetModuleFileName failed: %d", GetLastError());
101 CFAssert1(wResult
< MAX_PATH
+1, __kCFLogAssertion
, "GetModuleFileName result truncated: %s", cachedPath
);
103 // strip off last component, the DLL name
105 for (idx
= wResult
- 1; idx
; idx
--) {
106 if ('\\' == cachedPath
[idx
]) {
107 cachedPath
[idx
] = '\0';
111 bDllPathCached
= true;
117 static const char *__CFProcessPath
= NULL
;
118 static const char *__CFprogname
= NULL
;
120 const char **_CFGetProgname(void) {
122 _CFProcessPath(); // sets up __CFprogname as a side-effect
123 return &__CFprogname
;
126 const char **_CFGetProcessPath(void) {
127 if (!__CFProcessPath
)
128 _CFProcessPath(); // sets up __CFProcessPath as a side-effect
129 return &__CFProcessPath
;
132 #if DEPLOYMENT_TARGET_WINDOWS
133 const char *_CFProcessPath(void) {
134 if (__CFProcessPath
) return __CFProcessPath
;
135 wchar_t buf
[CFMaxPathSize
] = {0};
136 DWORD rlen
= GetModuleFileNameW(NULL
, buf
, sizeof(buf
) / sizeof(buf
[0]));
138 char asciiBuf
[CFMaxPathSize
] = {0};
139 int res
= WideCharToMultiByte(CP_UTF8
, 0, buf
, rlen
, asciiBuf
, sizeof(asciiBuf
) / sizeof(asciiBuf
[0]), NULL
, NULL
);
141 __CFProcessPath
= strdup(asciiBuf
);
142 __CFprogname
= strrchr(__CFProcessPath
, PATH_SEP
);
143 __CFprogname
= (__CFprogname
? __CFprogname
+ 1 : __CFProcessPath
);
146 if (!__CFProcessPath
) {
147 __CFProcessPath
= "";
148 __CFprogname
= __CFProcessPath
;
150 return __CFProcessPath
;
154 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
155 const char *_CFProcessPath(void) {
156 if (__CFProcessPath
) return __CFProcessPath
;
157 #if DEPLOYMENT_TARGET_MACOSX
159 const char *path
= (char *)__CFgetenv("CFProcessPath");
161 __CFProcessPath
= strdup(path
);
162 __CFprogname
= strrchr(__CFProcessPath
, PATH_SEP
);
163 __CFprogname
= (__CFprogname
? __CFprogname
+ 1 : __CFProcessPath
);
164 return __CFProcessPath
;
168 uint32_t size
= CFMaxPathSize
;
170 if (0 == _NSGetExecutablePath(buffer
, &size
)) {
171 #if DEPLOYMENT_TARGET_MACOSX && defined(__ppc__)
172 size_t len
= strlen(buffer
);
173 if (12 <= len
&& 0 == strcmp("LaunchCFMApp", buffer
+ len
- 12)) {
174 struct stat exec
, lcfm
;
175 const char *launchcfm
= "/System/Library/Frameworks/Carbon.framework/Versions/Current/Support/LaunchCFMApp";
176 if (0 == stat(launchcfm
, &lcfm
) && 0 == stat(buffer
, &exec
) && (lcfm
.st_dev
== exec
.st_dev
) && (lcfm
.st_ino
== exec
.st_ino
)) {
177 // Executable is LaunchCFMApp, take special action
179 if ((*_NSGetArgv())[1] && '/' == *((*_NSGetArgv())[1])) {
180 strlcpy(buffer
, (*_NSGetArgv())[1], sizeof(buffer
));
185 __CFProcessPath
= strdup(buffer
);
186 __CFprogname
= strrchr(__CFProcessPath
, PATH_SEP
);
187 __CFprogname
= (__CFprogname
? __CFprogname
+ 1 : __CFProcessPath
);
189 if (!__CFProcessPath
) {
190 __CFProcessPath
= "";
191 __CFprogname
= __CFProcessPath
;
193 return __CFProcessPath
;
197 __private_extern__ CFStringRef
_CFProcessNameString(void) {
198 static CFStringRef __CFProcessNameString
= NULL
;
199 if (!__CFProcessNameString
) {
200 const char *processName
= *_CFGetProgname();
201 if (!processName
) processName
= "";
202 CFStringRef newStr
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, processName
, kCFPlatformInterfaceStringEncoding
);
203 if (!OSAtomicCompareAndSwapPtrBarrier(NULL
, (void *) newStr
, (void * volatile *)& __CFProcessNameString
)) {
204 CFRelease(newStr
); // someone else made the assignment, so just release the extra string.
207 return __CFProcessNameString
;
210 static CFStringRef __CFUserName
= NULL
;
212 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
213 static CFURLRef __CFHomeDirectory
= NULL
;
214 static uint32_t __CFEUID
= -1;
215 static uint32_t __CFUID
= -1;
217 static CFURLRef
_CFCopyHomeDirURLForUser(struct passwd
*upwd
) {
218 CFURLRef home
= NULL
;
220 const char *path
= __CFgetenv("CFFIXED_USER_HOME");
222 home
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault
, (uint8_t *)path
, strlen(path
), true);
226 if (upwd
&& upwd
->pw_dir
) {
227 home
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault
, (uint8_t *)upwd
->pw_dir
, strlen(upwd
->pw_dir
), true);
233 static void _CFUpdateUserInfo(void) {
236 __CFEUID
= geteuid();
238 if (__CFHomeDirectory
) CFRelease(__CFHomeDirectory
);
239 __CFHomeDirectory
= NULL
;
240 if (__CFUserName
) CFRelease(__CFUserName
);
243 upwd
= getpwuid(__CFEUID
? __CFEUID
: __CFUID
);
244 __CFHomeDirectory
= _CFCopyHomeDirURLForUser(upwd
);
245 if (!__CFHomeDirectory
) {
246 const char *cpath
= __CFgetenv("HOME");
248 __CFHomeDirectory
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault
, (uint8_t *)cpath
, strlen(cpath
), true);
252 // This implies that UserManager stores directory info in CString
253 // rather than FileSystemRep. Perhaps this is wrong & we should
254 // expect NeXTSTEP encodings. A great test of our localized system would
255 // be to have a user "O-umlat z e r". XXX
256 if (upwd
&& upwd
->pw_name
) {
257 __CFUserName
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, upwd
->pw_name
, kCFPlatformInterfaceStringEncoding
);
259 const char *cuser
= __CFgetenv("USER");
261 __CFUserName
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, cuser
, kCFPlatformInterfaceStringEncoding
);
266 #if DEPLOYMENT_TARGET_WINDOWS
267 typedef DWORD (*NetUserGetInfoCall
)(wchar_t *, wchar_t *, DWORD
, char* *);
270 static CFURLRef
_CFCreateHomeDirectoryURLForUser(CFStringRef uName
) {
271 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
273 if (geteuid() != __CFEUID
|| getuid() != __CFUID
|| !__CFHomeDirectory
)
275 if (__CFHomeDirectory
) CFRetain(__CFHomeDirectory
);
276 return __CFHomeDirectory
;
278 struct passwd
*upwd
= NULL
;
279 char buf
[128], *user
;
280 SInt32 len
= CFStringGetLength(uName
), size
= CFStringGetMaximumSizeForEncoding(len
, kCFPlatformInterfaceStringEncoding
);
285 user
= CFAllocatorAllocate(kCFAllocatorSystemDefault
, size
+1, 0);
286 if (__CFOASafe
) __CFSetLastAllocationEventName(user
, "CFUtilities (temp)");
288 if (CFStringGetBytes(uName
, CFRangeMake(0, len
), kCFPlatformInterfaceStringEncoding
, 0, true, (uint8_t *)user
, size
, &usedSize
) == len
) {
289 user
[usedSize
] = '\0';
290 upwd
= getpwnam(user
);
293 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, user
);
295 return _CFCopyHomeDirURLForUser(upwd
);
297 #elif DEPLOYMENT_TARGET_WINDOWS
298 CFStringRef user
= !uName
? _CFUserName() : uName
;
299 CFURLRef retVal
= NULL
;
301 CFStringRef str
= NULL
;
303 if (!uName
|| CFEqual(user
, _CFUserName())) {
304 const char *cpath
= __CFgetenv("HOMEPATH");
305 const char *cdrive
= __CFgetenv("HOMEDRIVE");
306 if (cdrive
&& cpath
) {
307 char fullPath
[CFMaxPathSize
];
308 strlcpy(fullPath
, cdrive
, sizeof(fullPath
));
309 strlcat(fullPath
, cpath
, sizeof(fullPath
));
310 str
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, fullPath
, kCFPlatformInterfaceStringEncoding
);
311 retVal
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, str
, kCFURLWindowsPathStyle
, true);
315 if (retVal
== NULL
) {
316 UniChar pathChars
[MAX_PATH
];
317 if (S_OK
== SHGetFolderPathW(NULL
, CSIDL_PROFILE
, NULL
, SHGFP_TYPE_CURRENT
, (wchar_t *) pathChars
)) {
318 UniChar
* p
= pathChars
;
321 str
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, pathChars
, len
);
322 retVal
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, str
, kCFURLWindowsPathStyle
, true);
324 // We have to get "some" directory location, so fall-back to the
325 // processes current directory.
326 UniChar currDir
[MAX_PATH
];
327 DWORD dwChars
= GetCurrentDirectoryW(MAX_PATH
+ 1, (wchar_t *)currDir
);
329 UniChar
* p
= currDir
;
332 str
= CFStringCreateWithCharacters(kCFAllocatorDefault
, currDir
, len
);
333 retVal
= CFURLCreateWithFileSystemPath(NULL
, str
, kCFURLWindowsPathStyle
, true);
339 char fullPath
[CFMaxPathSize
];
340 HRESULT hr
= SHGetFolderPathA(NULL
, CSIDL_PROFILE
, NULL
, 0 /* SHGFP_TYPE_CURRENT */, fullPath
);
342 CFStringRef str
= CFStringCreateWithCString(NULL
, fullPath
, kCFPlatformInterfaceStringEncoding
);
343 retVal
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, str
, kCFURLWindowsPathStyle
, true);
348 struct _USER_INFO_2
*userInfo
;
349 HINSTANCE hinstDll
= GetModuleHandleA("NETAPI32");
351 hinstDll
= LoadLibraryExA("NETAPI32", NULL
, 0);
353 NetUserGetInfoCall lpfn
= (NetUserGetInfoCall
)GetProcAddress(hinstDll
, "NetUserGetInfo");
355 unsigned namelen
= CFStringGetLength(user
);
357 username
= (UniChar
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(UniChar
) * (namelen
+ 1), 0);
358 CFStringGetCharacters(user
, CFRangeMake(0, namelen
), username
);
359 if (!(*lpfn
)(NULL
, (wchar_t *)username
, 2, (char * *)&userInfo
)) {
361 CFMutableStringRef str
;
362 while (userInfo
->usri2_home_dir
[len
] != 0) len
++;
363 str
= CFStringCreateMutable(kCFAllocatorSystemDefault
, len
+1);
364 CFStringAppendCharacters(str
, (const UniChar
*)userInfo
->usri2_home_dir
, len
);
365 retVal
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, str
, kCFURLWindowsPathStyle
, true);
368 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, username
);
375 // We could do more here (as in KB Article Q101507). If that article is to
376 // be believed, we should only run into this case on Win95, or through
378 #if DEPLOYMENT_TARGET_WINDOWS_SAFARI
380 CFStringRef str
= CFURLCopyFileSystemPath(retVal
, kCFURLWindowsPathStyle
);
381 if (str
&& CFStringGetLength(str
) == 0) {
385 if (str
) CFRelease(str
);
388 CFStringRef testPath
= CFURLCopyPath(retVal
);
389 if (CFStringGetLength(testPath
) == 0) {
400 #error Dont know how to compute users home directories on this platform
404 static CFStringRef
_CFUserName(void) {
405 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
406 if (geteuid() != __CFEUID
|| getuid() != __CFUID
)
408 #elif DEPLOYMENT_TARGET_WINDOWS
410 wchar_t username
[1040];
413 if (GetUserNameW(username
, &size
)) {
414 // discount the extra NULL by decrementing the size
415 __CFUserName
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (const UniChar
*)username
, size
- 1);
417 const char *cname
= __CFgetenv("USERNAME");
419 __CFUserName
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, cname
, kCFPlatformInterfaceStringEncoding
);
423 #error Dont know how to compute user name on this platform
426 __CFUserName
= (CFStringRef
)CFRetain(CFSTR(""));
430 __private_extern__ CFStringRef
_CFGetUserName(void) {
431 return CFStringCreateCopy(kCFAllocatorSystemDefault
, _CFUserName());
434 #define CFMaxHostNameLength 256
435 #define CFMaxHostNameSize (CFMaxHostNameLength+1)
437 __private_extern__ CFStringRef
_CFStringCreateHostName(void) {
438 char myName
[CFMaxHostNameSize
];
440 // return @"" instead of nil a la CFUserName() and Ali Ozer
441 if (0 != gethostname(myName
, CFMaxHostNameSize
)) myName
[0] = '\0';
442 return CFStringCreateWithCString(kCFAllocatorSystemDefault
, myName
, kCFPlatformInterfaceStringEncoding
);
445 /* These are sanitized versions of the above functions. We might want to eliminate the above ones someday.
446 These can return NULL.
448 CF_EXPORT CFStringRef
CFGetUserName(void) {
449 return _CFUserName();
452 CF_EXPORT CFURLRef
CFCopyHomeDirectoryURLForUser(CFStringRef uName
) {
453 return _CFCreateHomeDirectoryURLForUser(uName
);
456 #undef CFMaxHostNameLength
457 #undef CFMaxHostNameSize
459 #if DEPLOYMENT_TARGET_WINDOWS
460 CF_INLINE CFIndex
strlen_UniChar(const UniChar
* p
) {
467 //#include <shfolder.h>
469 * _CFCreateApplicationRepositoryPath returns the path to the application's
470 * repository in a CFMutableStringRef. The path returned will be:
471 * <nFolder_path>\Apple Computer\<bundle_name>\
472 * or if the bundle name cannot be obtained:
473 * <nFolder_path>\Apple Computer\
474 * where nFolder_path is obtained by calling SHGetFolderPath with nFolder
475 * (for example, with CSIDL_APPDATA or CSIDL_LOCAL_APPDATA).
477 * The CFMutableStringRef result must be released by the caller.
479 * If anything fails along the way, the result will be NULL.
481 CF_EXPORT CFMutableStringRef
_CFCreateApplicationRepositoryPath(CFAllocatorRef alloc
, int nFolder
) {
482 CFMutableStringRef result
= NULL
;
483 UniChar szPath
[MAX_PATH
];
485 // get the current path to the data repository: CSIDL_APPDATA (roaming) or CSIDL_LOCAL_APPDATA (nonroaming)
486 if (S_OK
== SHGetFolderPathW(NULL
, nFolder
, NULL
, 0, (wchar_t *) szPath
)) {
487 CFStringRef directoryPath
;
489 // make it a CFString
490 directoryPath
= CFStringCreateWithCharacters(alloc
, szPath
, strlen_UniChar(szPath
));
493 CFStringRef bundleName
;
494 CFStringRef completePath
;
496 // attempt to get the bundle name
497 bundle
= CFBundleGetMainBundle();
499 bundleName
= (CFStringRef
)CFBundleGetValueForInfoDictionaryKey(bundle
, kCFBundleNameKey
);
506 // the path will be "<directoryPath>\Apple Computer\<bundleName>\" if there is a bundle name
507 completePath
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%@\\Apple Computer\\%@\\"), directoryPath
, bundleName
);
510 // or "<directoryPath>\Apple Computer\" if there is no bundle name.
511 completePath
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%@\\Apple Computer\\"), directoryPath
);
514 CFRelease(directoryPath
);
516 // make a mutable copy to return
518 result
= CFStringCreateMutableCopy(alloc
, 0, completePath
);
519 CFRelease(completePath
);
528 #if DEPLOYMENT_TARGET_WINDOWS
529 /* 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. */
531 #include <sys/stat.h>
534 // 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.
535 static wchar_t *createWideFileSystemRepresentation(const char *str
, CFIndex
*resultLen
) {
536 // Get the real length of the string in UTF16 characters
537 CFStringRef cfStr
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, str
, kCFStringEncodingUTF8
);
538 CFIndex strLen
= CFStringGetLength(cfStr
);
540 // Allocate a wide buffer to hold the converted string, including space for a NULL terminator
541 wchar_t *wideBuf
= (wchar_t *)malloc((strLen
+ 1) * sizeof(wchar_t));
543 // Copy the string into the buffer and terminate
544 CFStringGetCharacters(cfStr
, CFRangeMake(0, strLen
), (UniChar
*)wideBuf
);
548 if (resultLen
) *resultLen
= strLen
;
552 // Copies a UTF16 buffer into a supplied UTF8 buffer.
553 static void copyToNarrowFileSystemRepresentation(const wchar_t *wide
, CFIndex dstBufSize
, char *dstbuf
) {
554 // Get the real length of the wide string in UTF8 characters
555 CFStringRef cfStr
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (const UniChar
*)wide
, wcslen(wide
));
556 CFIndex strLen
= CFStringGetLength(cfStr
);
559 // Copy the wide string into the buffer and terminate
560 CFStringGetBytes(cfStr
, CFRangeMake(0, strLen
), kCFStringEncodingUTF8
, 0, false, (uint8_t *)dstbuf
, dstBufSize
, &bytesUsed
);
561 dstbuf
[bytesUsed
] = 0;
566 CF_EXPORT
int _NS_stat(const char *name
, struct _stat
*st
) {
567 wchar_t *wide
= createWideFileSystemRepresentation(name
, NULL
);
568 int res
= _wstat(wide
, st
);
573 CF_EXPORT
int _NS_mkdir(const char *name
) {
574 wchar_t *wide
= createWideFileSystemRepresentation(name
, NULL
);
575 int res
= _wmkdir(wide
);
580 CF_EXPORT
int _NS_rmdir(const char *name
) {
581 wchar_t *wide
= createWideFileSystemRepresentation(name
, NULL
);
582 int res
= _wrmdir(wide
);
587 CF_EXPORT
int _NS_chmod(const char *name
, int mode
) {
588 wchar_t *wide
= createWideFileSystemRepresentation(name
, NULL
);
589 int res
= _wchmod(wide
, mode
);
594 CF_EXPORT
int _NS_unlink(const char *name
) {
595 wchar_t *wide
= createWideFileSystemRepresentation(name
, NULL
);
596 int res
= _wunlink(wide
);
601 // Warning: this doesn't support dstbuf as null even though 'getcwd' does
602 CF_EXPORT
char *_NS_getcwd(char *dstbuf
, size_t size
) {
604 CFLog(kCFLogLevelWarning
, CFSTR("CFPlatform: getcwd called with null buffer"));
608 wchar_t *buf
= _wgetcwd(NULL
, 0);
613 // Convert result to UTF8
614 copyToNarrowFileSystemRepresentation(buf
, (CFIndex
)size
, dstbuf
);
619 CF_EXPORT
char *_NS_getenv(const char *name
) {
620 // todo: wide env variables
624 CF_EXPORT
int _NS_rename(const char *oldName
, const char *newName
) {
625 wchar_t *oldWide
= createWideFileSystemRepresentation(oldName
, NULL
);
626 wchar_t *newWide
= createWideFileSystemRepresentation(newName
, NULL
);
627 // _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
628 // To simulate the Mac OS behavior, we use the Win32 API then fill out errno if something goes wrong
629 BOOL winRes
= MoveFileExW(oldWide
, newWide
, MOVEFILE_REPLACE_EXISTING
);
630 DWORD error
= GetLastError();
636 case ERROR_FILE_NOT_FOUND
:
637 case ERROR_PATH_NOT_FOUND
:
638 case ERROR_OPEN_FAILED
:
641 case ERROR_ACCESS_DENIED
:
650 return (winRes
? 0 : -1);
653 CF_EXPORT
int _NS_open(const char *name
, int oflag
, int pmode
) {
654 wchar_t *wide
= createWideFileSystemRepresentation(name
, NULL
);
656 _wsopen_s(&fd
, wide
, oflag
, _SH_DENYNO
, _S_IREAD
| _S_IWRITE
);
661 CF_EXPORT
int _NS_chdir(const char *name
) {
662 wchar_t *wide
= createWideFileSystemRepresentation(name
, NULL
);
663 int res
= _wchdir(wide
);
668 CF_EXPORT
int _NS_access(const char *name
, int amode
) {
669 // execute is always true
670 if (amode
== 1) return 0;
672 wchar_t *wide
= createWideFileSystemRepresentation(name
, NULL
);
673 // we only care about the read-only (04) and write-only (02) bits, so mask octal 06
674 int res
= _waccess(wide
, amode
& 06);
679 // This is a bit different than the standard 'mkstemp', because the size parameter is needed so we know the size of the UTF8 buffer
680 // Also, we don't avoid the race between creating a temporary file name and opening it on Windows like we do on Mac
681 CF_EXPORT
int _NS_mkstemp(char *name
, int bufSize
) {
683 wchar_t *wide
= createWideFileSystemRepresentation(name
, &nameLen
);
685 // 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.
686 // Look for the last '\' in the path
687 wchar_t *lastSlash
= wcsrchr(wide
, '\\');
693 // Set the last slash to NULL temporarily and use it for _wstat
695 struct _stat dirInfo
;
696 int res
= _wstat(wide
, &dirInfo
);
698 if (errno
== ENOENT
) {
704 // Restore the last slash
707 errno_t err
= _wmktemp_s(wide
, nameLen
+ 1);
714 _wsopen_s(&fd
, wide
, _O_RDWR
| _O_CREAT
| CF_OPENFLGS
, _SH_DENYNO
, _S_IREAD
| _S_IWRITE
);
716 // Convert the wide name back into the UTF8 buffer the caller supplied
717 copyToNarrowFileSystemRepresentation(wide
, bufSize
, name
);