2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 Copyright 1999-2002, Apple, Inc. All rights reserved.
27 Responsibility: Christopher Kane
30 #include "CFInternal.h"
32 #if defined(__WIN32__)
44 #include <mach-o/dyld.h>
45 #include <crt_externs.h>
48 extern char *getenv(const char *name
);
51 #define kCFPlatformInterfaceStringEncoding kCFStringEncodingUTF8
53 #define kCFPlatformInterfaceStringEncoding CFStringGetSystemEncoding()
56 char **_CFArgv(void) {
73 __private_extern__ Boolean
_CFGetCurrentDirectory(char *path
, int maxlen
) {
74 #if defined(__WIN32__)
75 DWORD len
= GetCurrentDirectoryA(maxlen
, path
);
76 return (0 != len
&& len
+ 1 <= maxlen
);
78 return getcwd(path
, maxlen
) != NULL
;
82 static Boolean __CFIsCFM
= false;
84 // If called super early, we just return false
85 __private_extern__ Boolean
_CFIsCFM(void) {
90 #if defined(__WIN32__)
91 #define PATH_LIST_SEP ';'
93 #define PATH_LIST_SEP ':'
96 static char *_CFSearchForNameInPath(CFAllocatorRef alloc
, const char *name
, char *path
) {
98 char *nname
= CFAllocatorAllocate(alloc
, strlen(name
) + strlen(path
) + 2, 0);
99 if (__CFOASafe
) __CFSetLastAllocationEventName(nname
, "CFUtilities (temp)");
101 char *p
= (char *)strchr(path
, PATH_LIST_SEP
);
109 // Could also do access(us, X_OK) == 0 in next condition,
110 // for executable-only searching
111 if (0 == stat(nname
, &statbuf
) && (statbuf
.st_mode
& S_IFMT
) == S_IFREG
) {
123 CFAllocatorDeallocate(alloc
, nname
);
129 static const char *__CFProcessPath
= NULL
;
130 static const char *__CFprogname
= "";
132 const char **_CFGetProgname(void) { // This is a hack around the broken _NSGetPrognam(), for now; will be removed
133 return &__CFprogname
;
136 const char *_CFProcessPath(void) {
137 CFAllocatorRef alloc
= NULL
;
138 char *thePath
= NULL
;
141 if (__CFProcessPath
) return __CFProcessPath
;
142 if (!__CFProcessPath
) {
143 thePath
= getenv("CFProcessPath");
145 alloc
= CFRetain(__CFGetDefaultAllocator());
148 int len
= strlen(thePath
);
149 __CFProcessPath
= CFAllocatorAllocate(alloc
, len
+1, 0);
150 if (__CFOASafe
) __CFSetLastAllocationEventName((void *)__CFProcessPath
, "CFUtilities (process-path)");
151 memmove((char *)__CFProcessPath
, thePath
, len
+ 1);
155 #if defined(__MACH__)
157 struct stat exec
, lcfm
;
158 unsigned long size
= CFMaxPathSize
;
159 char buffer
[CFMaxPathSize
];
160 if (0 == _NSGetExecutablePath(buffer
, &size
) &&
161 strcasestr(buffer
, "LaunchCFMApp") != NULL
&&
162 0 == stat("/System/Library/Frameworks/Carbon.framework/Versions/Current/Support/LaunchCFMApp", &lcfm
) &&
163 0 == stat(buffer
, &exec
) &&
164 (lcfm
.st_dev
== exec
.st_dev
) &&
165 (lcfm
.st_ino
== exec
.st_ino
)) {
166 // Executable is LaunchCFMApp, take special action
173 if (!__CFProcessPath
&& NULL
!= (*_NSGetArgv())[execIndex
]) {
174 char buf
[CFMaxPathSize
] = {0};
175 #if defined(__WIN32__)
176 HINSTANCE hinst
= GetModuleHandle(NULL
);
177 DWORD rlen
= hinst
? GetModuleFileName(hinst
, buf
, 1028) : 0;
178 thePath
= rlen
? buf
: NULL
;
181 const char *arg0
= (*_NSGetArgv())[execIndex
];
182 if (arg0
[0] == '/') {
183 // We've got an absolute path; look no further;
184 thePath
= (char *)arg0
;
186 char *theList
= getenv("PATH");
187 if (NULL
!= theList
&& NULL
== strrchr(arg0
, '/')) {
188 thePath
= _CFSearchForNameInPath(alloc
, arg0
, theList
);
190 // User could have "." or "../bin" or other relative path in $PATH
191 if (('/' != thePath
[0]) && _CFGetCurrentDirectory(buf
, CFMaxPathSize
)) {
193 strcat(buf
, thePath
);
194 if (0 == stat(buf
, &statbuf
)) {
195 CFAllocatorDeallocate(alloc
, (void *)thePath
);
199 if (thePath
!= buf
) {
200 strcpy(buf
, thePath
);
201 CFAllocatorDeallocate(alloc
, (void *)thePath
);
208 // After attempting a search through $PATH, if existant,
209 // try prepending the current directory to argv[0].
210 if (!thePath
&& _CFGetCurrentDirectory(buf
, CFMaxPathSize
)) {
211 if (buf
[strlen(buf
)-1] != '/') {
215 if (0 == stat(buf
, &statbuf
)) {
221 // We are going to process the buffer replacing all "/./" with "/"
222 CFIndex srcIndex
= 0, dstIndex
= 0;
223 CFIndex len
= strlen(thePath
);
224 for (srcIndex
=0; srcIndex
<len
; srcIndex
++) {
225 thePath
[dstIndex
] = thePath
[srcIndex
];
227 if ((srcIndex
< len
-2) && (thePath
[srcIndex
] == '/') && (thePath
[srcIndex
+1] == '.') && (thePath
[srcIndex
+2] == '/')) {
228 // We are at the first slash of a "/./" Skip the "./"
232 thePath
[dstIndex
] = 0;
236 thePath
= (*_NSGetArgv())[execIndex
];
239 int len
= strlen(thePath
);
240 __CFProcessPath
= CFAllocatorAllocate(alloc
, len
+ 1, 0);
241 if (__CFOASafe
) __CFSetLastAllocationEventName((void *)__CFProcessPath
, "CFUtilities (process-path)");
242 memmove((char *)__CFProcessPath
, thePath
, len
+ 1);
244 if (__CFProcessPath
) {
247 for (i
= 0; __CFProcessPath
[i
] != 0; i
++){
248 if (__CFProcessPath
[i
] == '/')
249 p
= __CFProcessPath
+ i
;
252 __CFprogname
= p
+ 1;
254 __CFprogname
= __CFProcessPath
;
257 if (!__CFProcessPath
) {
258 __CFProcessPath
= "";
260 return __CFProcessPath
;
263 __private_extern__ CFStringRef
_CFProcessNameString(void) {
264 static CFStringRef __CFProcessNameString
= NULL
;
265 if (!__CFProcessNameString
) {
266 const char *processName
= *_CFGetProgname();
267 if (!processName
) processName
= "";
268 __CFProcessNameString
= CFStringCreateWithCString(__CFGetDefaultAllocator(), processName
, kCFPlatformInterfaceStringEncoding
);
270 return __CFProcessNameString
;
273 static CFURLRef __CFHomeDirectory
= NULL
;
274 static CFStringRef __CFUserName
= NULL
;
275 static uint32_t __CFEUID
= -1;
276 static uint32_t __CFUID
= -1;
278 #if defined(__MACH__) || defined(__svr4__) || defined(__hpux__) || defined(__LINUX__) || defined(__FREEBSD__)
279 static CFURLRef
_CFCopyHomeDirURLForUser(struct passwd
*upwd
) {
280 CFURLRef home
= NULL
;
281 if (upwd
&& upwd
->pw_dir
) {
282 home
= CFURLCreateFromFileSystemRepresentation(NULL
, upwd
->pw_dir
, strlen(upwd
->pw_dir
), true);
287 static void _CFUpdateUserInfo(void) {
290 __CFEUID
= geteuid();
292 if (__CFHomeDirectory
) CFRelease(__CFHomeDirectory
);
293 __CFHomeDirectory
= NULL
;
294 if (__CFUserName
) CFRelease(__CFUserName
);
297 upwd
= getpwuid(__CFEUID
? __CFEUID
: __CFUID
);
298 __CFHomeDirectory
= _CFCopyHomeDirURLForUser(upwd
);
299 if (!__CFHomeDirectory
) {
300 const char *cpath
= getenv("HOME");
302 __CFHomeDirectory
= CFURLCreateFromFileSystemRepresentation(NULL
, cpath
, strlen(cpath
), true);
306 // This implies that UserManager stores directory info in CString
307 // rather than FileSystemRep. Perhaps this is wrong & we should
308 // expect NeXTSTEP encodings. A great test of our localized system would
309 // be to have a user "O-umlat z e r". XXX
310 if (upwd
&& upwd
->pw_name
) {
311 __CFUserName
= CFStringCreateWithCString(NULL
, upwd
->pw_name
, kCFPlatformInterfaceStringEncoding
);
313 const char *cuser
= getenv("USER");
315 __CFUserName
= CFStringCreateWithCString(NULL
, cuser
, kCFPlatformInterfaceStringEncoding
);
320 static CFURLRef
_CFCreateHomeDirectoryURLForUser(CFStringRef uName
) {
321 #if defined(__MACH__) || defined(__svr4__) || defined(__hpux__) || defined(__LINUX__) || defined(__FREEBSD__)
323 if (geteuid() != __CFEUID
|| getuid() != __CFUID
|| !__CFHomeDirectory
)
325 if (__CFHomeDirectory
) CFRetain(__CFHomeDirectory
);
326 return __CFHomeDirectory
;
328 struct passwd
*upwd
= NULL
;
329 char buf
[128], *user
;
330 SInt32 len
= CFStringGetLength(uName
), size
= CFStringGetMaximumSizeForEncoding(len
, kCFPlatformInterfaceStringEncoding
);
335 user
= CFAllocatorAllocate(kCFAllocatorDefault
, size
+1, 0);
336 if (__CFOASafe
) __CFSetLastAllocationEventName(user
, "CFUtilities (temp)");
338 if (CFStringGetBytes(uName
, CFRangeMake(0, len
), kCFPlatformInterfaceStringEncoding
, 0, true, user
, size
, &usedSize
) == len
) {
339 user
[usedSize
] = '\0';
340 upwd
= getpwnam(user
);
343 CFAllocatorDeallocate(kCFAllocatorDefault
, user
);
345 return _CFCopyHomeDirURLForUser(upwd
);
347 #elif defined(__WIN32__)
348 #warning CF: Windows home directory goop disabled
351 CFString
*user
= !uName
? CFUserName() : uName
;
353 if (!uName
|| CFEqual(user
, CFUserName())) {
354 const char *cpath
= getenv("HOMEPATH");
355 const char *cdrive
= getenv("HOMEDRIVE");
356 if (cdrive
&& cpath
) {
357 char fullPath
[CFMaxPathSize
];
359 strcpy(fullPath
, cdrive
);
360 strncat(fullPath
, cpath
, CFMaxPathSize
-strlen(cdrive
)-1);
361 str
= CFStringCreateWithCString(NULL
, fullPath
, kCFPlatformInterfaceStringEncoding
);
362 home
= CFURLCreateWithFileSystemPath(NULL
, str
, kCFURLWindowsPathStyle
, true);
367 struct _USER_INFO_2
*userInfo
;
368 HINSTANCE hinstDll
= GetModuleHandleA("NETAPI32");
370 hinstDll
= LoadLibraryEx("NETAPI32", NULL
, 0);
372 FARPROC lpfn
= GetProcAddress(hinstDll
, "NetUserGetInfo");
374 unsigned namelen
= CFStringGetLength(user
);
376 username
= CFAllocatorAllocate(kCFAllocatorDefault
, sizeof(UniChar
) * (namelen
+ 1), 0);
377 if (__CFOASafe
) __CFSetLastAllocationEventName(username
, "CFUtilities (temp)");
378 CFStringGetCharacters(user
, CFRangeMake(0, namelen
), username
);
379 if (!(*lpfn
)(NULL
, (LPWSTR
)username
, 2, (LPBYTE
*)&userInfo
)) {
381 CFMutableStringRef str
;
382 while (userInfo
->usri2_home_dir
[len
] != 0) len
++;
383 str
= CFStringCreateMutable(NULL
, len
+1);
384 CFStringAppendCharacters(str
, userInfo
->usri2_home_dir
, len
);
385 home
= CFURLCreateWithFileSystemPath(NULL
, str
, kCFURLWindowsPathStyle
, true);
388 CFAllocatorDeallocate(kCFAllocatorDefault
, username
);
393 // We could do more here (as in KB Article Q101507). If that article is to
394 // be believed, we should only run into this case on Win95, or through
396 if (CFStringGetLength(CFURLGetPath(home
)) == 0) {
403 #error Dont know how to compute users home directories on this platform
407 static CFStringRef
_CFUserName(void) {
408 #if defined(__MACH__) || defined(__svr4__) || defined(__hpux__) || defined(__LINUX__) || defined(__FREEBSD__)
409 if (geteuid() != __CFEUID
|| getuid() != __CFUID
)
411 #elif defined(__WIN32__)
416 if (GetUserNameA(username
, &size
)) {
417 __CFUserName
= CFStringCreateWithCString(NULL
, username
, kCFPlatformInterfaceStringEncoding
);
419 const char *cname
= getenv("USERNAME");
421 __CFUserName
= CFStringCreateWithCString(NULL
, cname
, kCFPlatformInterfaceStringEncoding
);
425 #error Dont know how to compute user name on this platform
428 __CFUserName
= CFRetain(CFSTR(""));
432 __private_extern__ CFStringRef
_CFGetUserName(void) {
433 return CFStringCreateCopy(NULL
, _CFUserName());
436 #define CFMaxHostNameLength 256
437 #define CFMaxHostNameSize (CFMaxHostNameLength+1)
439 __private_extern__ CFStringRef
_CFStringCreateHostName(void) {
440 char myName
[CFMaxHostNameSize
];
442 // return @"" instead of nil a la CFUserName() and Ali Ozer
443 if (0 != gethostname(myName
, CFMaxHostNameSize
)) myName
[0] = '\0';
444 return CFStringCreateWithCString(NULL
, myName
, kCFPlatformInterfaceStringEncoding
);
447 /* These are sanitized versions of the above functions. We might want to eliminate the above ones someday.
448 These can return NULL.
450 CF_EXPORT CFStringRef
CFGetUserName(void) {
451 return _CFUserName();
454 CF_EXPORT CFURLRef
CFCopyHomeDirectoryURLForUser(CFStringRef uName
) {
455 return _CFCreateHomeDirectoryURLForUser(uName
);
459 #undef CFMaxHostNameLength
460 #undef CFMaxHostNameSize