2 * Copyright (c) 2008 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 1999-2002, Apple, Inc. All rights reserved.
25 Responsibility: Christopher Kane
28 #include "CFInternal.h"
35 #include <crt_externs.h>
36 #include <mach-o/dyld.h>
38 #if DEPLOYMENT_TARGET_MACOSX
39 #define kCFPlatformInterfaceStringEncoding kCFStringEncodingUTF8
41 #define kCFPlatformInterfaceStringEncoding CFStringGetSystemEncoding()
44 static CFStringRef
_CFUserName(void);
46 #if DEPLOYMENT_TARGET_MACOSX
47 // CoreGraphics and LaunchServices are only projects (1 Dec 2006) that use these
48 char **_CFArgv(void) { return *_NSGetArgv(); }
49 int _CFArgc(void) { return *_NSGetArgc(); }
53 __private_extern__ Boolean
_CFGetCurrentDirectory(char *path
, int maxlen
) {
55 DWORD len
= GetCurrentDirectoryA(maxlen
, path
);
56 return ((0 != len
) && (maxlen
> 0) && (len
+ 1 <= (DWORD
)maxlen
));
58 return getcwd(path
, maxlen
) != NULL
;
62 static Boolean __CFIsCFM
= false;
64 // If called super early, we just return false
65 __private_extern__ Boolean
_CFIsCFM(void) {
75 #if !defined(__WIN32__)
76 #define PATH_LIST_SEP ':'
78 static char *_CFSearchForNameInPath(const char *name
, char *path
) {
80 char nname
[strlen(name
) + strlen(path
) + 2];
81 int no_hang_fd
= open("/dev/autofs_nowait", 0);
83 char *p
= (char *)strchr(path
, PATH_LIST_SEP
);
88 strlcat(nname
, path
, sizeof(nname
));
89 strlcat(nname
, "/", sizeof(nname
));
90 strlcat(nname
, name
, sizeof(nname
));
91 // Could also do access(us, X_OK) == 0 in next condition,
92 // for executable-only searching
93 if (0 == stat(nname
, &statbuf
) && (statbuf
.st_mode
& S_IFMT
) == S_IFREG
) {
112 static const char *__CFProcessPath
= NULL
;
113 static const char *__CFprogname
= NULL
;
115 const char **_CFGetProgname(void) {
117 _CFProcessPath(); // sets up __CFprogname as a side-effect
118 return &__CFprogname
;
121 const char **_CFGetProcessPath(void) {
122 if (!__CFProcessPath
)
123 _CFProcessPath(); // sets up __CFProcessPath as a side-effect
124 return &__CFProcessPath
;
127 const char *_CFProcessPath(void) {
128 if (__CFProcessPath
) return __CFProcessPath
;
130 char *thePath
= NULL
;
131 #if DEPLOYMENT_TARGET_MACOSX
133 thePath
= getenv("CFProcessPath");
135 int len
= strlen(thePath
);
136 __CFProcessPath
= (const char *)CFAllocatorAllocate(kCFAllocatorSystemDefault
, len
+1, 0);
137 if (__CFOASafe
) __CFSetLastAllocationEventName((void *)__CFProcessPath
, "CFUtilities (process-path)");
138 memmove((char *)__CFProcessPath
, thePath
, len
+ 1);
142 #if DEPLOYMENT_TARGET_MACOSX
146 if (!__CFProcessPath
&& NULL
!= (*_NSGetArgv())[execIndex
]) {
147 int no_hang_fd
= open("/dev/autofs_nowait", 0);
148 char buf
[CFMaxPathSize
] = {0};
150 const char *arg0
= (*_NSGetArgv())[execIndex
];
151 if (arg0
[0] == '/') {
152 // We've got an absolute path; look no further;
153 thePath
= (char *)arg0
;
155 char *theList
= getenv("PATH");
156 if (NULL
!= theList
&& NULL
== strrchr(arg0
, '/')) {
157 thePath
= _CFSearchForNameInPath(arg0
, theList
);
159 // User could have "." or "../bin" or other relative path in $PATH
160 if (('/' != thePath
[0]) && _CFGetCurrentDirectory(buf
, CFMaxPathSize
)) {
161 strlcat(buf
, "/", sizeof(buf
));
162 strlcat(buf
, thePath
, sizeof(buf
));
163 if (0 == stat(buf
, &statbuf
)) {
168 if (thePath
!= buf
) {
169 strlcpy(buf
, thePath
, sizeof(buf
));
170 free((void *)thePath
);
177 // After attempting a search through $PATH, if existant,
178 // try prepending the current directory to argv[0].
179 if (!thePath
&& _CFGetCurrentDirectory(buf
, CFMaxPathSize
)) {
180 if (buf
[strlen(buf
)-1] != '/') {
181 strlcat(buf
, "/", sizeof(buf
));
183 strlcat(buf
, arg0
, CFMaxPathSize
);
184 if (0 == stat(buf
, &statbuf
)) {
190 // We are going to process the buffer replacing all "/./" and "//" with "/"
191 CFIndex srcIndex
= 0, dstIndex
= 0;
192 CFIndex len
= strlen(thePath
);
193 for (srcIndex
=0; srcIndex
<len
; srcIndex
++) {
194 thePath
[dstIndex
] = thePath
[srcIndex
];
196 while (srcIndex
< len
-1 && thePath
[srcIndex
] == '/' && (thePath
[srcIndex
+1] == '/' || (thePath
[srcIndex
+1] == '.' && srcIndex
< len
-2 && thePath
[srcIndex
+2] == '/'))) srcIndex
+= (thePath
[srcIndex
+1] == '/' ? 1 : 2);
198 thePath
[dstIndex
] = 0;
201 thePath
= (*_NSGetArgv())[execIndex
];
205 int len
= strlen(thePath
);
206 __CFProcessPath
= (const char *)CFAllocatorAllocate(kCFAllocatorSystemDefault
, len
+ 1, 0);
207 if (__CFOASafe
) __CFSetLastAllocationEventName((void *)__CFProcessPath
, "CFUtilities (process-path)");
208 memmove((char *)__CFProcessPath
, thePath
, len
+ 1);
210 if (__CFProcessPath
) {
214 for (i
= 0; __CFProcessPath
[i
] != 0; i
++){
215 if (__CFProcessPath
[i
] == PATH_SEP
)
216 p
= __CFProcessPath
+ i
;
219 __CFprogname
= p
+ 1;
221 __CFprogname
= __CFProcessPath
;
226 if (!__CFProcessPath
) {
227 __CFProcessPath
= "";
228 __CFprogname
= __CFProcessPath
;
232 for (i
= 0; __CFProcessPath
[i
] != 0; i
++){
233 if (__CFProcessPath
[i
] == PATH_SEP
)
234 p
= __CFProcessPath
+ i
;
237 __CFprogname
= p
+ 1;
239 __CFprogname
= __CFProcessPath
;
241 return __CFProcessPath
;
244 __private_extern__ CFStringRef
_CFProcessNameString(void) {
245 static CFStringRef __CFProcessNameString
= NULL
;
246 if (!__CFProcessNameString
) {
247 const char *processName
= *_CFGetProgname();
248 if (!processName
) processName
= "";
249 __CFProcessNameString
= CFStringCreateWithCString(__CFGetDefaultAllocator(), processName
, kCFPlatformInterfaceStringEncoding
);
251 return __CFProcessNameString
;
254 static CFStringRef __CFUserName
= NULL
;
256 #if (DEPLOYMENT_TARGET_MACOSX) || defined(__svr4__) || defined(__hpux__) || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
257 static CFURLRef __CFHomeDirectory
= NULL
;
258 static uint32_t __CFEUID
= -1;
259 static uint32_t __CFUID
= -1;
261 static CFURLRef
_CFCopyHomeDirURLForUser(struct passwd
*upwd
) {
262 CFURLRef home
= NULL
;
264 const char *path
= getenv("CFFIXED_USER_HOME");
266 home
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault
, (uint8_t *)path
, strlen(path
), true);
270 if (upwd
&& upwd
->pw_dir
) {
271 home
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault
, (uint8_t *)upwd
->pw_dir
, strlen(upwd
->pw_dir
), true);
277 static void _CFUpdateUserInfo(void) {
280 __CFEUID
= geteuid();
282 if (__CFHomeDirectory
) CFRelease(__CFHomeDirectory
);
283 __CFHomeDirectory
= NULL
;
284 if (__CFUserName
) CFRelease(__CFUserName
);
287 upwd
= getpwuid(__CFEUID
? __CFEUID
: __CFUID
);
288 __CFHomeDirectory
= _CFCopyHomeDirURLForUser(upwd
);
289 if (!__CFHomeDirectory
) {
290 const char *cpath
= getenv("HOME");
292 __CFHomeDirectory
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault
, (uint8_t *)cpath
, strlen(cpath
), true);
296 // This implies that UserManager stores directory info in CString
297 // rather than FileSystemRep. Perhaps this is wrong & we should
298 // expect NeXTSTEP encodings. A great test of our localized system would
299 // be to have a user "O-umlat z e r". XXX
300 if (upwd
&& upwd
->pw_name
) {
301 __CFUserName
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, upwd
->pw_name
, kCFPlatformInterfaceStringEncoding
);
303 const char *cuser
= getenv("USER");
305 __CFUserName
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, cuser
, kCFPlatformInterfaceStringEncoding
);
310 static CFURLRef
_CFCreateHomeDirectoryURLForUser(CFStringRef uName
) {
311 #if (DEPLOYMENT_TARGET_MACOSX) || defined(__svr4__) || defined(__hpux__) || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
313 if (geteuid() != __CFEUID
|| getuid() != __CFUID
|| !__CFHomeDirectory
)
315 if (__CFHomeDirectory
) CFRetain(__CFHomeDirectory
);
316 return __CFHomeDirectory
;
318 struct passwd
*upwd
= NULL
;
319 char buf
[128], *user
;
320 SInt32 len
= CFStringGetLength(uName
), size
= CFStringGetMaximumSizeForEncoding(len
, kCFPlatformInterfaceStringEncoding
);
325 user
= CFAllocatorAllocate(kCFAllocatorSystemDefault
, size
+1, 0);
326 if (__CFOASafe
) __CFSetLastAllocationEventName(user
, "CFUtilities (temp)");
328 if (CFStringGetBytes(uName
, CFRangeMake(0, len
), kCFPlatformInterfaceStringEncoding
, 0, true, (uint8_t *)user
, size
, &usedSize
) == len
) {
329 user
[usedSize
] = '\0';
330 upwd
= getpwnam(user
);
333 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, user
);
335 return _CFCopyHomeDirURLForUser(upwd
);
337 #elif defined(__WIN32__)
338 CFStringRef user
= !uName
? _CFUserName() : uName
;
339 CFURLRef home
= NULL
;
341 if (!uName
|| CFEqual(user
, _CFUserName())) {
342 const char *cpath
= getenv("HOMEPATH");
343 const char *cdrive
= getenv("HOMEDRIVE");
344 if (cdrive
&& cpath
) {
345 char fullPath
[CFMaxPathSize
];
347 strlcpy(fullPath
, cdrive
, sizeof(fullPath
));
348 strlcat(fullPath
, cpath
, sizeof(fullPath
));
349 str
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, fullPath
, kCFPlatformInterfaceStringEncoding
);
350 home
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, str
, kCFURLWindowsPathStyle
, true);
355 UniChar pathChars
[MAX_PATH
];
356 if (S_OK
== SHGetFolderPath(NULL
, CSIDL_PROFILE
, NULL
, SHGFP_TYPE_CURRENT
, (LPWSTR
) pathChars
)) {
357 UniChar
* p
= pathChars
;
362 str
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, pathChars
, len
);
363 home
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, str
, kCFURLWindowsPathStyle
, true);
366 // We have to get "some" directory location, so fall-back to the
367 // processes current directory.
368 UniChar currDir
[MAX_PATH
];
369 DWORD dwChars
= GetCurrentDirectory(MAX_PATH
+ 1, (LPWSTR
)currDir
);
371 UniChar
* p
= currDir
;
376 str
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, currDir
, len
);
377 home
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, str
, kCFURLWindowsPathStyle
, true);
381 // We could do more here (as in KB Article Q101507). If that article is to
382 // be believed, we should only run into this case on Win95, or through
385 CFStringRef str
= CFURLCopyFileSystemPath(home
, kCFURLWindowsPathStyle
);
386 if (str
&& CFStringGetLength(str
) == 0) {
390 if (str
) CFRelease(str
);
394 #error Dont know how to compute users home directories on this platform
398 static CFStringRef
_CFUserName(void) {
399 #if (DEPLOYMENT_TARGET_MACOSX) || defined(__svr4__) || defined(__hpux__) || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
400 if (geteuid() != __CFEUID
|| getuid() != __CFUID
)
402 #elif defined(__WIN32__)
407 if (GetUserNameA(username
, &size
)) {
408 __CFUserName
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, username
, kCFPlatformInterfaceStringEncoding
);
410 const char *cname
= getenv("USERNAME");
412 __CFUserName
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, cname
, kCFPlatformInterfaceStringEncoding
);
416 #error Dont know how to compute user name on this platform
419 __CFUserName
= (CFStringRef
)CFRetain(CFSTR(""));
423 __private_extern__ CFStringRef
_CFGetUserName(void) {
424 return CFStringCreateCopy(kCFAllocatorSystemDefault
, _CFUserName());
427 #define CFMaxHostNameLength 256
428 #define CFMaxHostNameSize (CFMaxHostNameLength+1)
430 __private_extern__ CFStringRef
_CFStringCreateHostName(void) {
431 char myName
[CFMaxHostNameSize
];
433 // return @"" instead of nil a la CFUserName() and Ali Ozer
434 if (0 != gethostname(myName
, CFMaxHostNameSize
)) myName
[0] = '\0';
435 return CFStringCreateWithCString(kCFAllocatorSystemDefault
, myName
, kCFPlatformInterfaceStringEncoding
);
438 /* These are sanitized versions of the above functions. We might want to eliminate the above ones someday.
439 These can return NULL.
441 CF_EXPORT CFStringRef
CFGetUserName(void) {
442 return _CFUserName();
445 CF_EXPORT CFURLRef
CFCopyHomeDirectoryURLForUser(CFStringRef uName
) {
446 return _CFCreateHomeDirectoryURLForUser(uName
);
449 #undef CFMaxHostNameLength
450 #undef CFMaxHostNameSize