2 * Copyright (c) 2005 Apple Computer, 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 1999-2002, Apple, Inc. All rights reserved.
25 Responsibility: Christopher Kane
28 #include "CFInternal.h"
30 #if defined(__WIN32__)
40 #include <crt_externs.h>
43 extern char *getenv(const char *name
);
46 #define kCFPlatformInterfaceStringEncoding kCFStringEncodingUTF8
48 #define kCFPlatformInterfaceStringEncoding CFStringGetSystemEncoding()
52 char **_CFArgv(void) {
62 __private_extern__ Boolean
_CFGetCurrentDirectory(char *path
, int maxlen
) {
63 #if defined(__WIN32__)
64 DWORD len
= GetCurrentDirectoryA(maxlen
, path
);
65 return (0 != len
&& len
+ 1 <= maxlen
);
67 return getcwd(path
, maxlen
) != NULL
;
71 static Boolean __CFIsCFM
= false;
73 // If called super early, we just return false
74 __private_extern__ Boolean
_CFIsCFM(void) {
78 #if defined(__WIN32__)
84 #if !defined(__WIN32__)
85 #define PATH_LIST_SEP ':'
87 static char *_CFSearchForNameInPath(CFAllocatorRef alloc
, const char *name
, char *path
) {
89 char *nname
= CFAllocatorAllocate(alloc
, strlen(name
) + strlen(path
) + 2, 0);
90 if (__CFOASafe
) __CFSetLastAllocationEventName(nname
, "CFUtilities (temp)");
92 char *p
= (char *)strchr(path
, PATH_LIST_SEP
);
100 // Could also do access(us, X_OK) == 0 in next condition,
101 // for executable-only searching
102 if (0 == stat(nname
, &statbuf
) && (statbuf
.st_mode
& S_IFMT
) == S_IFREG
) {
114 CFAllocatorDeallocate(alloc
, nname
);
121 #if defined(__WIN32__)
122 // Returns the path to the CF DLL, which we can then use to find resources like char sets
124 __private_extern__
const char *_CFDLLPath(void) {
125 static TCHAR cachedPath
[MAX_PATH
+1] = "";
127 if ('\0' == cachedPath
[0]) {
129 char *DLLFileName
= "CoreFoundation_debug";
130 #elif defined(PROFILE)
131 char *DLLFileName
= "CoreFoundation_profile";
133 char *DLLFileName
= "CoreFoundation";
135 HMODULE ourModule
= GetModuleHandle(DLLFileName
);
136 CFAssert(ourModule
, __kCFLogAssertion
, "GetModuleHandle failed");
138 DWORD wResult
= GetModuleFileName(ourModule
, cachedPath
, MAX_PATH
+1);
139 CFAssert1(wResult
> 0, __kCFLogAssertion
, "GetModuleFileName failed: %d", GetLastError());
140 CFAssert1(wResult
< MAX_PATH
+1, __kCFLogAssertion
, "GetModuleFileName result truncated: %s", cachedPath
);
142 // strip off last component, the DLL name
144 for (idx
= wResult
- 1; idx
; idx
--) {
145 if ('\\' == cachedPath
[idx
]) {
146 cachedPath
[idx
] = '\0';
155 static const char *__CFProcessPath
= NULL
;
156 static const char *__CFprogname
= NULL
;
158 const char **_CFGetProgname(void) {
160 _CFProcessPath(); // sets up __CFprogname as a side-effect
161 return &__CFprogname
;
164 const char **_CFGetProcessPath(void) {
165 if (!__CFProcessPath
)
166 _CFProcessPath(); // sets up __CFProcessPath as a side-effect
167 return &__CFProcessPath
;
170 const char *_CFProcessPath(void) {
171 CFAllocatorRef alloc
= NULL
;
172 char *thePath
= NULL
;
174 if (__CFProcessPath
) return __CFProcessPath
;
175 if (!__CFProcessPath
) {
176 thePath
= getenv("CFProcessPath");
178 alloc
= CFRetain(__CFGetDefaultAllocator());
181 int len
= strlen(thePath
);
182 __CFProcessPath
= CFAllocatorAllocate(alloc
, len
+1, 0);
183 if (__CFOASafe
) __CFSetLastAllocationEventName((void *)__CFProcessPath
, "CFUtilities (process-path)");
184 memmove((char *)__CFProcessPath
, thePath
, len
+ 1);
188 #if defined(__MACH__)
191 struct stat exec
, lcfm
;
192 uint32_t size
= CFMaxPathSize
;
193 char buffer
[CFMaxPathSize
];
194 if (0 == _NSGetExecutablePath(buffer
, &size
) &&
195 strcasestr(buffer
, "LaunchCFMApp") != NULL
&&
196 0 == stat("/System/Library/Frameworks/Carbon.framework/Versions/Current/Support/LaunchCFMApp", &lcfm
) &&
197 0 == stat(buffer
, &exec
) &&
198 (lcfm
.st_dev
== exec
.st_dev
) &&
199 (lcfm
.st_ino
== exec
.st_ino
)) {
200 // Executable is LaunchCFMApp, take special action
207 #if defined(__WIN32__)
208 if (!__CFProcessPath
) {
209 char buf
[CFMaxPathSize
] = {0};
210 DWORD rlen
= GetModuleFileName(NULL
, buf
, 1028);
211 thePath
= rlen
? buf
: NULL
;
213 if (!__CFProcessPath
&& NULL
!= (*_NSGetArgv())[execIndex
]) {
214 char buf
[CFMaxPathSize
] = {0};
216 const char *arg0
= (*_NSGetArgv())[execIndex
];
217 if (arg0
[0] == '/') {
218 // We've got an absolute path; look no further;
219 thePath
= (char *)arg0
;
221 char *theList
= getenv("PATH");
222 if (NULL
!= theList
&& NULL
== strrchr(arg0
, '/')) {
223 thePath
= _CFSearchForNameInPath(alloc
, arg0
, theList
);
225 // User could have "." or "../bin" or other relative path in $PATH
226 if (('/' != thePath
[0]) && _CFGetCurrentDirectory(buf
, CFMaxPathSize
)) {
227 strlcat(buf
, "/", CFMaxPathSize
);
228 strlcat(buf
, thePath
, CFMaxPathSize
);
229 if (0 == stat(buf
, &statbuf
)) {
230 CFAllocatorDeallocate(alloc
, (void *)thePath
);
234 if (thePath
!= buf
) {
235 strlcpy(buf
, thePath
, CFMaxPathSize
);
236 CFAllocatorDeallocate(alloc
, (void *)thePath
);
243 // After attempting a search through $PATH, if existant,
244 // try prepending the current directory to argv[0].
245 if (!thePath
&& _CFGetCurrentDirectory(buf
, CFMaxPathSize
)) {
246 if (buf
[strlen(buf
)-1] != '/') {
247 strlcat(buf
, "/", CFMaxPathSize
);
249 strlcat(buf
, arg0
, CFMaxPathSize
);
250 if (0 == stat(buf
, &statbuf
)) {
256 // We are going to process the buffer replacing all "/./" and "//" with "/"
257 CFIndex srcIndex
= 0, dstIndex
= 0;
258 CFIndex len
= strlen(thePath
);
259 for (srcIndex
=0; srcIndex
<len
; srcIndex
++) {
260 thePath
[dstIndex
] = thePath
[srcIndex
];
262 while (srcIndex
< len
-1 && thePath
[srcIndex
] == '/' && (thePath
[srcIndex
+1] == '/' || (thePath
[srcIndex
+1] == '.' && srcIndex
< len
-2 && thePath
[srcIndex
+2] == '/'))) srcIndex
+= (thePath
[srcIndex
+1] == '/' ? 1 : 2);
264 thePath
[dstIndex
] = 0;
267 thePath
= (*_NSGetArgv())[execIndex
];
271 int len
= strlen(thePath
);
272 __CFProcessPath
= CFAllocatorAllocate(alloc
, len
+ 1, 0);
273 if (__CFOASafe
) __CFSetLastAllocationEventName((void *)__CFProcessPath
, "CFUtilities (process-path)");
274 memmove((char *)__CFProcessPath
, thePath
, len
+ 1);
276 if (__CFProcessPath
) {
280 for (i
= 0; __CFProcessPath
[i
] != 0; i
++){
281 if (__CFProcessPath
[i
] == PATH_SEP
)
282 p
= __CFProcessPath
+ i
;
285 __CFprogname
= p
+ 1;
287 __CFprogname
= __CFProcessPath
;
290 if (!__CFProcessPath
) {
291 __CFProcessPath
= "";
292 __CFprogname
= __CFProcessPath
;
296 for (i
= 0; __CFProcessPath
[i
] != 0; i
++){
297 if (__CFProcessPath
[i
] == PATH_SEP
)
298 p
= __CFProcessPath
+ i
;
301 __CFprogname
= p
+ 1;
303 __CFprogname
= __CFProcessPath
;
305 return __CFProcessPath
;
308 __private_extern__ CFStringRef
_CFProcessNameString(void) {
309 static CFStringRef __CFProcessNameString
= NULL
;
310 if (!__CFProcessNameString
) {
311 const char *processName
= *_CFGetProgname();
312 if (!processName
) processName
= "";
313 __CFProcessNameString
= CFStringCreateWithCString(__CFGetDefaultAllocator(), processName
, kCFPlatformInterfaceStringEncoding
);
315 return __CFProcessNameString
;
318 static CFStringRef __CFUserName
= NULL
;
320 #if defined(__MACH__) || defined(__svr4__) || defined(__hpux__) || defined(__LINUX__) || defined(__FREEBSD__)
321 static CFURLRef __CFHomeDirectory
= NULL
;
322 static uint32_t __CFEUID
= -1;
323 static uint32_t __CFUID
= -1;
325 static CFURLRef
_CFCopyHomeDirURLForUser(struct passwd
*upwd
) {
326 CFURLRef home
= NULL
;
327 if (upwd
&& upwd
->pw_dir
) {
328 home
= CFURLCreateFromFileSystemRepresentation(NULL
, upwd
->pw_dir
, strlen(upwd
->pw_dir
), true);
333 static void _CFUpdateUserInfo(void) {
336 __CFEUID
= geteuid();
338 if (__CFHomeDirectory
) CFRelease(__CFHomeDirectory
);
339 __CFHomeDirectory
= NULL
;
340 if (__CFUserName
) CFRelease(__CFUserName
);
343 upwd
= getpwuid(__CFEUID
? __CFEUID
: __CFUID
);
344 __CFHomeDirectory
= _CFCopyHomeDirURLForUser(upwd
);
345 if (!__CFHomeDirectory
) {
346 const char *cpath
= getenv("HOME");
348 __CFHomeDirectory
= CFURLCreateFromFileSystemRepresentation(NULL
, cpath
, strlen(cpath
), true);
352 // This implies that UserManager stores directory info in CString
353 // rather than FileSystemRep. Perhaps this is wrong & we should
354 // expect NeXTSTEP encodings. A great test of our localized system would
355 // be to have a user "O-umlat z e r". XXX
356 if (upwd
&& upwd
->pw_name
) {
357 __CFUserName
= CFStringCreateWithCString(NULL
, upwd
->pw_name
, kCFPlatformInterfaceStringEncoding
);
359 const char *cuser
= getenv("USER");
361 __CFUserName
= CFStringCreateWithCString(NULL
, cuser
, kCFPlatformInterfaceStringEncoding
);
366 static CFURLRef
_CFCreateHomeDirectoryURLForUser(CFStringRef uName
) {
367 #if defined(__MACH__) || defined(__svr4__) || defined(__hpux__) || defined(__LINUX__) || defined(__FREEBSD__)
369 if (geteuid() != __CFEUID
|| getuid() != __CFUID
|| !__CFHomeDirectory
)
371 if (__CFHomeDirectory
) CFRetain(__CFHomeDirectory
);
372 return __CFHomeDirectory
;
374 struct passwd
*upwd
= NULL
;
375 char buf
[128], *user
;
376 SInt32 len
= CFStringGetLength(uName
), size
= CFStringGetMaximumSizeForEncoding(len
, kCFPlatformInterfaceStringEncoding
);
381 user
= CFAllocatorAllocate(kCFAllocatorDefault
, size
+1, 0);
382 if (__CFOASafe
) __CFSetLastAllocationEventName(user
, "CFUtilities (temp)");
384 if (CFStringGetBytes(uName
, CFRangeMake(0, len
), kCFPlatformInterfaceStringEncoding
, 0, true, user
, size
, &usedSize
) == len
) {
385 user
[usedSize
] = '\0';
386 upwd
= getpwnam(user
);
389 CFAllocatorDeallocate(kCFAllocatorDefault
, user
);
391 return _CFCopyHomeDirURLForUser(upwd
);
393 #elif defined(__WIN32__)
394 #warning CF: Windows home directory goop disabled
397 CFString
*user
= !uName
? CFUserName() : uName
;
399 if (!uName
|| CFEqual(user
, CFUserName())) {
400 const char *cpath
= getenv("HOMEPATH");
401 const char *cdrive
= getenv("HOMEDRIVE");
402 if (cdrive
&& cpath
) {
403 char fullPath
[CFMaxPathSize
];
405 strcpy(fullPath
, cdrive
);
406 strncat(fullPath
, cpath
, CFMaxPathSize
-strlen(cdrive
)-1);
407 str
= CFStringCreateWithCString(NULL
, fullPath
, kCFPlatformInterfaceStringEncoding
);
408 home
= CFURLCreateWithFileSystemPath(NULL
, str
, kCFURLWindowsPathStyle
, true);
413 struct _USER_INFO_2
*userInfo
;
414 HINSTANCE hinstDll
= GetModuleHandleA("NETAPI32");
416 hinstDll
= LoadLibraryEx("NETAPI32", NULL
, 0);
418 FARPROC lpfn
= GetProcAddress(hinstDll
, "NetUserGetInfo");
420 unsigned namelen
= CFStringGetLength(user
);
422 username
= CFAllocatorAllocate(kCFAllocatorDefault
, sizeof(UniChar
) * (namelen
+ 1), 0);
423 if (__CFOASafe
) __CFSetLastAllocationEventName(username
, "CFUtilities (temp)");
424 CFStringGetCharacters(user
, CFRangeMake(0, namelen
), username
);
425 if (!(*lpfn
)(NULL
, (LPWSTR
)username
, 2, (LPBYTE
*)&userInfo
)) {
427 CFMutableStringRef str
;
428 while (userInfo
->usri2_home_dir
[len
] != 0) len
++;
429 str
= CFStringCreateMutable(NULL
, len
+1);
430 CFStringAppendCharacters(str
, userInfo
->usri2_home_dir
, len
);
431 home
= CFURLCreateWithFileSystemPath(NULL
, str
, kCFURLWindowsPathStyle
, true);
434 CFAllocatorDeallocate(kCFAllocatorDefault
, username
);
439 // We could do more here (as in KB Article Q101507). If that article is to
440 // be believed, we should only run into this case on Win95, or through
442 if (CFStringGetLength(CFURLGetPath(home
)) == 0) {
449 #error Dont know how to compute users home directories on this platform
453 static CFStringRef
_CFUserName(void) {
454 #if defined(__MACH__) || defined(__svr4__) || defined(__hpux__) || defined(__LINUX__) || defined(__FREEBSD__)
455 if (geteuid() != __CFEUID
|| getuid() != __CFUID
)
457 #elif defined(__WIN32__)
462 if (GetUserNameA(username
, &size
)) {
463 __CFUserName
= CFStringCreateWithCString(NULL
, username
, kCFPlatformInterfaceStringEncoding
);
465 const char *cname
= getenv("USERNAME");
467 __CFUserName
= CFStringCreateWithCString(NULL
, cname
, kCFPlatformInterfaceStringEncoding
);
471 #error Dont know how to compute user name on this platform
474 __CFUserName
= CFRetain(CFSTR(""));
478 __private_extern__ CFStringRef
_CFGetUserName(void) {
479 return CFStringCreateCopy(NULL
, _CFUserName());
482 #define CFMaxHostNameLength 256
483 #define CFMaxHostNameSize (CFMaxHostNameLength+1)
485 __private_extern__ CFStringRef
_CFStringCreateHostName(void) {
486 char myName
[CFMaxHostNameSize
];
488 // return @"" instead of nil a la CFUserName() and Ali Ozer
489 if (0 != gethostname(myName
, CFMaxHostNameSize
)) myName
[0] = '\0';
490 return CFStringCreateWithCString(NULL
, myName
, kCFPlatformInterfaceStringEncoding
);
493 /* These are sanitized versions of the above functions. We might want to eliminate the above ones someday.
494 These can return NULL.
496 CF_EXPORT CFStringRef
CFGetUserName(void) {
497 return _CFUserName();
500 CF_EXPORT CFURLRef
CFCopyHomeDirectoryURLForUser(CFStringRef uName
) {
501 return _CFCreateHomeDirectoryURLForUser(uName
);
504 #undef CFMaxHostNameLength
505 #undef CFMaxHostNameSize