mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-25 01:31:08 +00:00
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@13627 72102866-910b-0410-8b05-ffd578937521
1069 lines
28 KiB
Objective-C
1069 lines
28 KiB
Objective-C
/** Implementation of login-related functions for GNUstep
|
|
Copyright (C) 1996 Free Software Foundation, Inc.
|
|
|
|
Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
|
|
Created: May 1996
|
|
|
|
This file is part of the GNUstep Base Library.
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
License along with this library; if not, write to the Free
|
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
|
|
|
<title>NSUser class reference</title>
|
|
$Date$ $Revision$
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <base/preface.h>
|
|
#include <Foundation/NSObjCRuntime.h>
|
|
#include <Foundation/NSString.h>
|
|
#include <Foundation/NSPathUtilities.h>
|
|
#include <Foundation/NSException.h>
|
|
#include <Foundation/NSArray.h>
|
|
#include <Foundation/NSDictionary.h>
|
|
#include <Foundation/NSFileManager.h>
|
|
#include <Foundation/NSProcessInfo.h>
|
|
#include <Foundation/NSString.h>
|
|
#include <Foundation/NSValue.h>
|
|
#include <Foundation/NSLock.h>
|
|
#include <Foundation/NSUserDefaults.h>
|
|
|
|
#include "GSPrivate.h"
|
|
|
|
#include <stdlib.h> // for getenv()
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h> // for getlogin()
|
|
#endif
|
|
#ifdef HAVE_PWD_H
|
|
#include <pwd.h> // for getpwnam()
|
|
#endif
|
|
#include <sys/types.h>
|
|
#include <stdio.h>
|
|
|
|
#define lowlevelstringify(X) #X
|
|
#define stringify(X) lowlevelstringify(X)
|
|
|
|
static NSString *theUserName = nil;
|
|
/* We read these four only once */
|
|
static NSString *gnustep_user_root = nil; /* GNUSTEP_USER_ROOT */
|
|
static NSString *gnustep_local_root = nil; /* GNUSTEP_LOCAL_ROOT */
|
|
static NSString *gnustep_network_root = nil; /* GNUSTEP_NETWORK_ROOT */
|
|
static NSString *gnustep_system_root = nil; /* GNUSTEP_SYSTEM_ROOT */
|
|
|
|
static void setupPathNames();
|
|
static NSString *userDirectory(NSString *name, BOOL defaults);
|
|
|
|
static NSString*
|
|
ImportPath(NSString *s, const char *c)
|
|
{
|
|
static NSFileManager *mgr = nil;
|
|
const char *ptr = c;
|
|
unsigned len;
|
|
|
|
if (mgr == nil)
|
|
{
|
|
mgr = [NSFileManager defaultManager];
|
|
RETAIN(mgr);
|
|
}
|
|
if (ptr == 0)
|
|
{
|
|
if (s == nil)
|
|
{
|
|
return nil;
|
|
}
|
|
ptr = [s cString];
|
|
}
|
|
len = strlen(ptr);
|
|
return [mgr stringWithFileSystemRepresentation: ptr length: len];
|
|
}
|
|
|
|
/**
|
|
* Sets the user name for this process. This method is supplied to enable
|
|
* setuid programs to run properly as the user indicated by their effective
|
|
* user Id.<br />
|
|
* This function calls [NSUserDefaults+resetStandardUserDefaults] as well
|
|
* as changing the value returned by NSUserName() and modifying the user
|
|
* root directory for the process.
|
|
*/
|
|
void
|
|
GSSetUserName(NSString* name)
|
|
{
|
|
if (theUserName == nil)
|
|
{
|
|
NSUserName(); // Ensure we know the old user name.
|
|
}
|
|
if ([theUserName isEqualToString: name] == NO)
|
|
{
|
|
/*
|
|
* We can destroy the cached user path so that next time
|
|
* anything wants it, it will be regenerated.
|
|
*/
|
|
DESTROY(gnustep_user_root);
|
|
/*
|
|
* Next we can set up the new user name, and reset the user defaults
|
|
* system so that standard user defaults will be those of the new
|
|
* user.
|
|
*/
|
|
ASSIGN(theUserName, name);
|
|
[NSUserDefaults resetStandardUserDefaults];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return the caller's login name as an NSString object.
|
|
* The 'LOGNAME' environment variable is our primary source, but we use
|
|
* other system-dependent sources if LOGNAME is not set. This function
|
|
* is intended to return the name under which the user logged in rather
|
|
* than the name associated with their numeric user ID (though the two
|
|
* are usually the same). If you have a setuid program and want to
|
|
* change the user to reflect the uid, use GSSetUserName()
|
|
*/
|
|
/* NOTE FOR DEVELOPERS.
|
|
* If you change the behavior of this method you must also change
|
|
* user_home.c in the makefiles package to match.
|
|
*/
|
|
NSString *
|
|
NSUserName(void)
|
|
{
|
|
if (theUserName == nil)
|
|
{
|
|
const char *loginName = 0;
|
|
#if defined(__WIN32__)
|
|
/* The GetUserName function returns the current user name */
|
|
char buf[1024];
|
|
DWORD n = 1024;
|
|
|
|
if (GetEnvironmentVariable("LOGNAME", buf, 1024) != 0 && buf[0] != '\0')
|
|
loginName = buf;
|
|
else if (GetUserName(buf, &n) != 0 && buf[0] != '\0')
|
|
loginName = buf;
|
|
#else
|
|
loginName = getenv("LOGNAME");
|
|
#ifdef HAVE_GETPWNAM
|
|
/*
|
|
* Check that LOGNAME contained legal name.
|
|
*/
|
|
if (loginName != 0 && getpwnam(loginName) == 0)
|
|
{
|
|
loginName = 0;
|
|
}
|
|
#endif /* HAVE_GETPWNAM */
|
|
#ifdef HAVE_GETLOGIN
|
|
/*
|
|
* Try getlogin() if LOGNAME environmentm variable didn't work.
|
|
*/
|
|
if (loginName == 0)
|
|
{
|
|
loginName = getlogin();
|
|
}
|
|
#endif /* HAVE_GETLOGIN */
|
|
#ifdef HAVE_GETPWUID
|
|
/*
|
|
* Try getting the name of the effective user as a last resort.
|
|
*/
|
|
if (loginName == 0)
|
|
{
|
|
#ifdef HAVE_GETEUID
|
|
int uid = geteuid();
|
|
#else
|
|
int uid = getuid();
|
|
#endif /* HAVE_GETEUID */
|
|
struct passwd *pwent = getpwuid (uid);
|
|
loginName = pwent->pw_name;
|
|
}
|
|
#endif /* HAVE_GETPWUID */
|
|
#endif
|
|
if (loginName)
|
|
theUserName = [[NSString alloc] initWithCString: loginName];
|
|
else
|
|
[NSException raise: NSInternalInconsistencyException
|
|
format: @"Unable to determine current user name"];
|
|
}
|
|
return theUserName;
|
|
}
|
|
|
|
/**
|
|
* Return the caller's home directory as an NSString object.
|
|
* Calls NSHomeDirectoryForUser() to do this.
|
|
*/
|
|
NSString *
|
|
NSHomeDirectory(void)
|
|
{
|
|
return NSHomeDirectoryForUser (NSUserName ());
|
|
}
|
|
|
|
#if defined(__MINGW__)
|
|
NSString *
|
|
GSStringFromWin32EnvironmentVariable(const char * envVar)
|
|
{
|
|
char buf[1024], *nb;
|
|
DWORD n;
|
|
NSString *s = nil;
|
|
|
|
[gnustep_global_lock lock];
|
|
n = GetEnvironmentVariable(envVar, buf, 1024);
|
|
if (n > 1024)
|
|
{
|
|
/* Buffer not big enough, so dynamically allocate it */
|
|
nb = (char *)NSZoneMalloc(NSDefaultMallocZone(), sizeof(char)*(n+1));
|
|
n = GetEnvironmentVariable(envVar, nb, n+1);
|
|
nb[n] = '\0';
|
|
s = [NSString stringWithCString: nb];
|
|
NSZoneFree(NSDefaultMallocZone(), nb);
|
|
}
|
|
else if (n > 0)
|
|
{
|
|
/* null terminate it and return the string */
|
|
buf[n] = '\0';
|
|
s = [NSString stringWithCString: buf];
|
|
}
|
|
[gnustep_global_lock unlock];
|
|
return s;
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* Returns loginName's home directory as an NSString object.
|
|
*/
|
|
/* NOTE FOR DEVELOPERS.
|
|
* If you change the behavior of this method you must also change
|
|
* user_home.c in the makefiles package to match.
|
|
*/
|
|
NSString *
|
|
NSHomeDirectoryForUser(NSString *loginName)
|
|
{
|
|
NSString *s = nil;
|
|
#if !defined(__MINGW__)
|
|
struct passwd *pw;
|
|
|
|
[gnustep_global_lock lock];
|
|
pw = getpwnam ([loginName cString]);
|
|
if (pw != 0)
|
|
{
|
|
s = [NSString stringWithCString: pw->pw_dir];
|
|
}
|
|
[gnustep_global_lock unlock];
|
|
#else
|
|
if ([loginName isEqual: NSUserName()] == YES)
|
|
{
|
|
/* Then environment variable HOMEPATH holds the home directory
|
|
for the user on Windows NT; Win95 has no concept of home. */
|
|
[gnustep_global_lock lock];
|
|
s = GSStringFromWin32EnvironmentVariable("HOMEPATH");
|
|
if (s != nil)
|
|
{
|
|
s = [GSStringFromWin32EnvironmentVariable("HOMEDRIVE")
|
|
stringByAppendingString: s];
|
|
}
|
|
[gnustep_global_lock unlock];
|
|
}
|
|
if ([s length] == 0 && [loginName length] != 1)
|
|
{
|
|
s = nil;
|
|
NSLog(@"NSHomeDirectoryForUser(%@) failed", loginName);
|
|
}
|
|
#endif
|
|
s = ImportPath(s, 0);
|
|
// NSLog(@"Home for %@ is %@", loginName, s);
|
|
return s;
|
|
}
|
|
|
|
/**
|
|
* Returns the full username of the current user.
|
|
* If unable to determine this, returns the standard user name.
|
|
*/
|
|
NSString *
|
|
NSFullUserName(void)
|
|
{
|
|
#ifdef HAVE_PWD_H
|
|
struct passwd *pw;
|
|
|
|
pw = getpwnam([NSUserName() cString]);
|
|
return [NSString stringWithCString: pw->pw_gecos];
|
|
#else
|
|
NSLog(@"Warning: NSFullUserName not implemented\n");
|
|
return NSUserName();
|
|
#endif
|
|
}
|
|
|
|
static BOOL
|
|
setupSystemRoot(NSDictionary *env)
|
|
{
|
|
BOOL warned = NO;
|
|
|
|
if (gnustep_system_root == nil)
|
|
{
|
|
/* Any of the following might be nil */
|
|
gnustep_system_root = [env objectForKey: @"GNUSTEP_SYSTEM_ROOT"];
|
|
gnustep_system_root = ImportPath(gnustep_system_root, 0);
|
|
TEST_RETAIN (gnustep_system_root);
|
|
if (gnustep_system_root == nil)
|
|
{
|
|
/*
|
|
* This is pretty important as we need it to load
|
|
* character sets, language settings and similar
|
|
* resources. Use fprintf to avoid recursive calls.
|
|
*/
|
|
warned = YES;
|
|
gnustep_system_root
|
|
= ImportPath(nil, stringify(GNUSTEP_INSTALL_PREFIX));
|
|
RETAIN(gnustep_system_root);
|
|
fprintf (stderr,
|
|
"Warning - GNUSTEP_SYSTEM_ROOT is not set "
|
|
"- using %s\n", [gnustep_system_root lossyCString]);
|
|
}
|
|
}
|
|
return warned;
|
|
}
|
|
|
|
static BOOL
|
|
setupLocalRoot(NSDictionary *env, BOOL warned)
|
|
{
|
|
if (gnustep_local_root == nil)
|
|
{
|
|
gnustep_local_root = [env objectForKey: @"GNUSTEP_LOCAL_ROOT"];
|
|
gnustep_local_root = ImportPath(gnustep_local_root, 0);
|
|
TEST_RETAIN (gnustep_local_root);
|
|
if (gnustep_local_root == nil)
|
|
{
|
|
gnustep_local_root
|
|
= ImportPath(nil, stringify(GNUSTEP_LOCAL_ROOT));
|
|
if ([gnustep_local_root length] == 0)
|
|
{
|
|
gnustep_local_root = nil;
|
|
}
|
|
else
|
|
{
|
|
RETAIN(gnustep_local_root);
|
|
}
|
|
}
|
|
if (gnustep_local_root == nil)
|
|
{
|
|
if ([[gnustep_system_root lastPathComponent] isEqual:
|
|
@"System"] == YES)
|
|
{
|
|
gnustep_local_root = [[gnustep_system_root
|
|
stringByDeletingLastPathComponent]
|
|
stringByAppendingPathComponent: @"Local"];
|
|
TEST_RETAIN (gnustep_local_root);
|
|
}
|
|
else
|
|
{
|
|
gnustep_local_root = @"/usr/GNUstep/Local";
|
|
}
|
|
#ifndef NDEBUG
|
|
if (warned == NO)
|
|
{
|
|
warned = YES;
|
|
fprintf (stderr,
|
|
"Warning - GNUSTEP_LOCAL_ROOT is not set "
|
|
"- using %s\n", [gnustep_local_root lossyCString]);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
return warned;
|
|
}
|
|
|
|
static BOOL
|
|
setupNetworkRoot(NSDictionary *env, BOOL warned)
|
|
{
|
|
if (gnustep_network_root == nil)
|
|
{
|
|
gnustep_network_root = [env objectForKey: @"GNUSTEP_NETWORK_ROOT"];
|
|
gnustep_network_root = ImportPath(gnustep_network_root, 0);
|
|
TEST_RETAIN (gnustep_network_root);
|
|
if (gnustep_network_root == nil)
|
|
{
|
|
gnustep_network_root
|
|
= ImportPath(nil, stringify(GNUSTEP_NETWORK_ROOT));
|
|
if ([gnustep_network_root length] == 0)
|
|
{
|
|
gnustep_network_root = nil;
|
|
}
|
|
else
|
|
{
|
|
RETAIN(gnustep_network_root);
|
|
}
|
|
}
|
|
if (gnustep_network_root == nil)
|
|
{
|
|
if ([[gnustep_system_root lastPathComponent] isEqual:
|
|
@"System"] == YES)
|
|
{
|
|
gnustep_network_root = [[gnustep_system_root
|
|
stringByDeletingLastPathComponent]
|
|
stringByAppendingPathComponent: @"Network"];
|
|
TEST_RETAIN (gnustep_network_root);
|
|
}
|
|
else
|
|
{
|
|
gnustep_network_root = @"/usr/GNUstep/Network";
|
|
}
|
|
#ifndef NDEBUG
|
|
if (warned == NO)
|
|
{
|
|
warned = YES;
|
|
fprintf (stderr,
|
|
"Warning - GNUSTEP_NETWORK_ROOT is not set "
|
|
"- using %s\n", [gnustep_network_root lossyCString]);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
return warned;
|
|
}
|
|
|
|
|
|
static void
|
|
setupPathNames()
|
|
{
|
|
if (gnustep_user_root == nil)
|
|
{
|
|
NS_DURING
|
|
{
|
|
BOOL warned = NO;
|
|
NSDictionary *env = [[NSProcessInfo processInfo] environment];
|
|
|
|
[gnustep_global_lock lock];
|
|
|
|
warned = setupSystemRoot(env);
|
|
warned = setupLocalRoot(env, warned);
|
|
warned = setupNetworkRoot(env, warned);
|
|
if (gnustep_user_root == nil)
|
|
{
|
|
gnustep_user_root = [userDirectory(NSUserName(), NO) copy];
|
|
}
|
|
|
|
[gnustep_global_lock unlock];
|
|
}
|
|
NS_HANDLER
|
|
{
|
|
// unlock then re-raise the exception
|
|
[gnustep_global_lock unlock];
|
|
[localException raise];
|
|
}
|
|
NS_ENDHANDLER
|
|
}
|
|
}
|
|
|
|
/** Returns a string containing the path to the GNUstep system
|
|
installation directory. This function is guarenteed to return a non-nil
|
|
answer (unless something is seriously wrong, in which case the application
|
|
will probably crash anyway) */
|
|
NSString *
|
|
GSSystemRootDirectory(void)
|
|
{
|
|
if (gnustep_system_root == nil)
|
|
{
|
|
setupPathNames();
|
|
}
|
|
return gnustep_system_root;
|
|
}
|
|
|
|
/**
|
|
* Return the path of the defaults directory for name.<br />
|
|
* This examines the .GNUsteprc file in the home directory of the
|
|
* user for the GNUSTEP_DEFAULTS_ROOT or the GNUSTEP_USER_ROOT
|
|
* directory definitions.
|
|
*/
|
|
NSString*
|
|
GSDefaultsRootForUser(NSString *userName)
|
|
{
|
|
return userDirectory(userName, YES);
|
|
}
|
|
|
|
static NSString *
|
|
userDirectory(NSString *name, BOOL defaults)
|
|
{
|
|
NSFileManager *manager;
|
|
NSString *home;
|
|
NSString *path = nil;
|
|
NSString *file;
|
|
NSString *user = nil;
|
|
NSString *defs = nil;
|
|
BOOL forceD = NO;
|
|
BOOL forceU = NO;
|
|
NSDictionary *attributes;
|
|
|
|
NSCAssert([name length] > 0, NSInvalidArgumentException);
|
|
|
|
home = NSHomeDirectoryForUser(name);
|
|
manager = [NSFileManager defaultManager];
|
|
|
|
if (gnustep_system_root == nil)
|
|
{
|
|
NSDictionary *env = [[NSProcessInfo processInfo] environment];
|
|
|
|
[gnustep_global_lock lock];
|
|
setupSystemRoot(env);
|
|
[gnustep_global_lock unlock];
|
|
}
|
|
file = [gnustep_system_root stringByAppendingPathComponent: @".GNUsteprc"];
|
|
attributes = [manager fileAttributesAtPath: file traverseLink: YES];
|
|
if (([attributes filePosixPermissions] & 022) != 0)
|
|
{
|
|
fprintf(stderr, "The file '%s' is writable by someone other than"
|
|
" its owner.\nIgnoring it.\n", [file fileSystemRepresentation]);
|
|
}
|
|
else if ([manager isReadableFileAtPath: file] == YES)
|
|
{
|
|
NSArray *lines;
|
|
unsigned count;
|
|
|
|
file = [NSString stringWithContentsOfFile: file];
|
|
lines = [file componentsSeparatedByString: @"\n"];
|
|
count = [lines count];
|
|
while (count-- > 0)
|
|
{
|
|
NSRange r;
|
|
NSString *line;
|
|
NSString *key;
|
|
NSString *val;
|
|
|
|
line = [[lines objectAtIndex: count] stringByTrimmingSpaces];
|
|
r = [line rangeOfString: @"="];
|
|
if (r.length == 1)
|
|
{
|
|
key = [line substringToIndex: r.location];
|
|
val = [line substringFromIndex: NSMaxRange(r)];
|
|
|
|
key = [key stringByTrimmingSpaces];
|
|
val = [val stringByTrimmingSpaces];
|
|
}
|
|
else
|
|
{
|
|
key = [line stringByTrimmingSpaces];
|
|
val = nil;
|
|
}
|
|
|
|
if ([key isEqualToString: @"GNUSTEP_USER_ROOT"] == YES)
|
|
{
|
|
if ([val length] > 0 && [val characterAtIndex: 0] == '~')
|
|
{
|
|
val = [home stringByAppendingString:
|
|
[val substringFromIndex: 1]];
|
|
}
|
|
user = val;
|
|
}
|
|
else if ([key isEqualToString: @"GNUSTEP_DEFAULTS_ROOT"] == YES)
|
|
{
|
|
if ([val length] > 0 && [val characterAtIndex: 0] == '~')
|
|
{
|
|
val = [home stringByAppendingString:
|
|
[val substringFromIndex: 1]];
|
|
}
|
|
defs = val;
|
|
}
|
|
else if ([key isEqualToString: @"FORCE_USER_ROOT"] == YES)
|
|
{
|
|
forceU = YES;
|
|
}
|
|
else if ([key isEqualToString: @"FORCE_DEFAULTS_ROOT"] == YES)
|
|
{
|
|
forceD = YES;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (forceD == NO || defs == nil || forceU == NO || user == nil)
|
|
{
|
|
file = [home stringByAppendingPathComponent: @".GNUsteprc"];
|
|
|
|
attributes = [manager fileAttributesAtPath: file traverseLink: YES];
|
|
if (([attributes filePosixPermissions] & 022) != 0)
|
|
{
|
|
fprintf(stderr, "The file '%s' is writable by someone other than"
|
|
" its owner.\nIgnoring it.\n", [file fileSystemRepresentation]);
|
|
}
|
|
#ifndef __MINGW__
|
|
/* FIXME ... need to get mingw working */
|
|
else if (attributes != nil
|
|
&& [[attributes fileOwnerAccountName] isEqual: NSUserName()] == NO)
|
|
{
|
|
fprintf(stderr, "The file '%s' is not owned by the current user."
|
|
"\nIgnoring it.\n", [file fileSystemRepresentation]);
|
|
}
|
|
#endif
|
|
else if ([manager isReadableFileAtPath: file] == YES)
|
|
{
|
|
NSArray *lines;
|
|
unsigned count;
|
|
|
|
file = [NSString stringWithContentsOfFile: file];
|
|
lines = [file componentsSeparatedByString: @"\n"];
|
|
count = [lines count];
|
|
while (count-- > 0)
|
|
{
|
|
NSRange r;
|
|
NSString *line;
|
|
|
|
line = [[lines objectAtIndex: count] stringByTrimmingSpaces];
|
|
r = [line rangeOfString: @"="];
|
|
if (r.length == 1)
|
|
{
|
|
NSString *key = [line substringToIndex: r.location];
|
|
NSString *val = [line substringFromIndex: NSMaxRange(r)];
|
|
|
|
key = [key stringByTrimmingSpaces];
|
|
val = [val stringByTrimmingSpaces];
|
|
if ([key isEqualToString: @"GNUSTEP_USER_ROOT"] == YES)
|
|
{
|
|
if ([val length] > 0 && [val characterAtIndex: 0] == '~')
|
|
{
|
|
val = [home stringByAppendingString:
|
|
[val substringFromIndex: 1]];
|
|
}
|
|
if (user == nil || forceU == NO)
|
|
{
|
|
user = val;
|
|
}
|
|
}
|
|
else if ([key isEqualToString: @"GNUSTEP_DEFAULTS_ROOT"])
|
|
{
|
|
if ([val length] > 0 && [val characterAtIndex: 0] == '~')
|
|
{
|
|
val = [home stringByAppendingString:
|
|
[val substringFromIndex: 1]];
|
|
}
|
|
if (defs == nil || forceD == NO)
|
|
{
|
|
defs = val;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (defaults == YES)
|
|
{
|
|
path = defs;
|
|
/*
|
|
* defaults root may default to user root
|
|
*/
|
|
if (path == nil)
|
|
{
|
|
path = user;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
path = user;
|
|
}
|
|
|
|
/*
|
|
* If not specified in file, default to standard location.
|
|
*/
|
|
if (path == nil)
|
|
{
|
|
path = [home stringByAppendingPathComponent: @"GNUstep"];
|
|
}
|
|
|
|
return ImportPath(path, 0);
|
|
}
|
|
|
|
/** Returns an array of strings which contain paths that should be in
|
|
the standard search order for resources, etc. If the environment
|
|
variable GNUSTEP_PATHPREFIX_LIST is set. It returns the list of
|
|
paths set in that variable. Otherwise, it returns the user, local,
|
|
network, and system paths, in that order. This function is
|
|
guarenteed to return a non-nil answer (unless something is
|
|
seriously wrong, in which case the application will probably crash
|
|
anyway) */
|
|
NSArray *
|
|
GSStandardPathPrefixes(void)
|
|
{
|
|
NSDictionary *env;
|
|
NSString *prefixes;
|
|
NSArray *prefixArray;
|
|
|
|
env = [[NSProcessInfo processInfo] environment];
|
|
prefixes = [env objectForKey: @"GNUSTEP_PATHPREFIX_LIST"];
|
|
if (prefixes != nil)
|
|
{
|
|
unsigned c;
|
|
|
|
#if defined(__WIN32__)
|
|
prefixArray = [prefixes componentsSeparatedByString: @";"];
|
|
#else
|
|
prefixArray = [prefixes componentsSeparatedByString: @":"];
|
|
#endif
|
|
if ((c = [prefixArray count]) <= 1)
|
|
{
|
|
/* This probably means there was some parsing error, but who
|
|
knows. Play it safe though... */
|
|
prefixArray = nil;
|
|
}
|
|
else
|
|
{
|
|
NSString *a[c];
|
|
unsigned i;
|
|
|
|
[prefixArray getObjects: a];
|
|
for (i = 0; i < c; i++)
|
|
{
|
|
a[c] = ImportPath(a[c], 0);
|
|
}
|
|
prefixArray = [NSArray arrayWithObjects: a count: c];
|
|
}
|
|
}
|
|
if (prefixes == nil)
|
|
{
|
|
NSString *strings[4];
|
|
NSString *str;
|
|
unsigned count = 0;
|
|
|
|
if (gnustep_user_root == nil)
|
|
{
|
|
setupPathNames();
|
|
}
|
|
str = gnustep_user_root;
|
|
if (str != nil)
|
|
strings[count++] = str;
|
|
|
|
str = gnustep_local_root;
|
|
if (str != nil)
|
|
strings[count++] = str;
|
|
|
|
str = gnustep_network_root;
|
|
if (str != nil)
|
|
strings[count++] = str;
|
|
|
|
str = gnustep_system_root;
|
|
if (str != nil)
|
|
strings[count++] = str;
|
|
|
|
if (count)
|
|
prefixArray = [NSArray arrayWithObjects: strings count: count];
|
|
else
|
|
prefixArray = [NSArray array];
|
|
}
|
|
return prefixArray;
|
|
}
|
|
|
|
/**
|
|
* Returns the standard paths in which applications are stored and
|
|
* should be searched for. Calls NSSearchPathForDirectoriesInDomains()
|
|
*/
|
|
NSArray *
|
|
NSStandardApplicationPaths(void)
|
|
{
|
|
return NSSearchPathForDirectoriesInDomains(NSAllApplicationsDirectory,
|
|
NSAllDomainsMask, YES);
|
|
}
|
|
|
|
/**
|
|
* Returns the standard paths in which libraries are stored and
|
|
* should be searched for. Calls NSSearchPathForDirectoriesInDomains()
|
|
*/
|
|
NSArray *
|
|
NSStandardLibraryPaths(void)
|
|
{
|
|
return NSSearchPathForDirectoriesInDomains(NSAllLibrariesDirectory,
|
|
NSAllDomainsMask, YES);
|
|
}
|
|
|
|
/**
|
|
* Returns the name of a directory in which temporary files can be stored.
|
|
* Under GNUstep this is a location which is not readable by other users.
|
|
*/
|
|
NSString *
|
|
NSTemporaryDirectory(void)
|
|
{
|
|
NSFileManager *manager;
|
|
NSString *tempDirName;
|
|
NSString *baseTempDirName = nil;
|
|
NSDictionary *attr;
|
|
int perm;
|
|
BOOL flag;
|
|
#if defined(__WIN32__)
|
|
char buffer[1024];
|
|
|
|
if (GetTempPath(1024, buffer))
|
|
{
|
|
baseTempDirName = ImportPath(nil, buffer);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* If the user has supplied a directory name in the TEMP or TMP
|
|
* environment variable, attempt to use that unless we already
|
|
* have a tem porary directory specified.
|
|
*/
|
|
if (baseTempDirName == nil)
|
|
{
|
|
NSDictionary *env = [[NSProcessInfo processInfo] environment];
|
|
|
|
baseTempDirName = [env objectForKey: @"TEMP"];
|
|
if (baseTempDirName == nil)
|
|
{
|
|
baseTempDirName = [env objectForKey: @"TMP"];
|
|
if (baseTempDirName == nil)
|
|
{
|
|
#if defined(__MINGW__)
|
|
#ifdef __CYGWIN__
|
|
baseTempDirName = @"/cygdrive/c/";
|
|
#else
|
|
baseTempDirName = @"/c/";
|
|
#endif
|
|
#else
|
|
baseTempDirName = @"/tmp";
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check that the base directory exists ... if it doesn't we can't
|
|
* go any further.
|
|
*/
|
|
tempDirName = baseTempDirName;
|
|
manager = [NSFileManager defaultManager];
|
|
if ([manager fileExistsAtPath: tempDirName isDirectory: &flag] == NO
|
|
|| flag == NO)
|
|
{
|
|
NSLog(@"Temporary directory (%@) does not seem to exist", tempDirName);
|
|
return nil;
|
|
}
|
|
|
|
/*
|
|
* Check that the directory owner (presumably us) has access to it,
|
|
* and nobody else. If other people have access, try to create a
|
|
* secure subdirectory.
|
|
*/
|
|
attr = [manager fileAttributesAtPath: tempDirName traverseLink: YES];
|
|
perm = [[attr objectForKey: NSFilePosixPermissions] intValue];
|
|
perm = perm & 0777;
|
|
if (perm != 0700 && perm != 0600)
|
|
{
|
|
/*
|
|
NSLog(@"Temporary directory (%@) may be insecure ... attempting to "
|
|
@"add secure subdirectory", tempDirName);
|
|
*/
|
|
|
|
tempDirName
|
|
= [baseTempDirName stringByAppendingPathComponent: NSUserName()];
|
|
if ([manager fileExistsAtPath: tempDirName] == NO)
|
|
{
|
|
NSNumber *p = [NSNumber numberWithInt: 0700];
|
|
|
|
attr = [NSDictionary dictionaryWithObject: p
|
|
forKey: NSFilePosixPermissions];
|
|
if ([manager createDirectoryAtPath: tempDirName
|
|
attributes: attr] == NO)
|
|
{
|
|
tempDirName = baseTempDirName;
|
|
NSLog(@"Temporary directory (%@) may be insecure", tempDirName);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ([manager isWritableFileAtPath: tempDirName] == NO)
|
|
{
|
|
NSLog(@"Temporary directory (%@) is not writable", tempDirName);
|
|
return nil;
|
|
}
|
|
return tempDirName;
|
|
}
|
|
|
|
/**
|
|
* Returns the root directory for the OpenStep (GNUstep) installation.
|
|
* This si determined by the GNUSTEP_ROOT environment variable if available.
|
|
*/
|
|
NSString *
|
|
NSOpenStepRootDirectory(void)
|
|
{
|
|
NSString *root;
|
|
|
|
root = [[[NSProcessInfo processInfo] environment]
|
|
objectForKey: @"GNUSTEP_ROOT"];
|
|
if (root == nil)
|
|
{
|
|
#if defined(__MINGW__)
|
|
#ifdef __CYGWIN__
|
|
root = @"/cygdrive/c/";
|
|
#else
|
|
root = @"/c/";
|
|
#endif
|
|
#else
|
|
root = @"/";
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
root = ImportPath(root, 0);
|
|
}
|
|
return root;
|
|
}
|
|
|
|
/**
|
|
* Returns an array of search paths to look at for resources.
|
|
*/
|
|
NSArray *
|
|
NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory directoryKey,
|
|
NSSearchPathDomainMask domainMask, BOOL expandTilde)
|
|
{
|
|
NSFileManager *fm;
|
|
NSString *adminDir = @"Administrator";
|
|
NSString *appsDir = @"Applications";
|
|
NSString *demosDir = @"Demos";
|
|
NSString *devDir = @"Developer";
|
|
NSString *libraryDir = @"Library";
|
|
NSString *libsDir = @"Libraries";
|
|
NSString *toolsDir = @"Tools";
|
|
NSString *docDir = @"Documentation";
|
|
NSMutableArray *paths = [NSMutableArray new];
|
|
NSString *path;
|
|
unsigned i;
|
|
unsigned count;
|
|
|
|
if (gnustep_user_root == nil)
|
|
{
|
|
setupPathNames();
|
|
}
|
|
|
|
/*
|
|
* The order in which we return paths is important - user must come
|
|
* first, followed by local, followed by network, followed by system.
|
|
* The calling code can then loop on the returned paths, and stop as
|
|
* soon as it finds something. So things in user automatically
|
|
* override things in system etc.
|
|
*/
|
|
|
|
/*
|
|
* FIXME - The following code will not respect this order for
|
|
* NSAllApplicationsDirectory. This should be fixed I think.
|
|
*/
|
|
|
|
#define ADD_PATH(mask, base_dir, add_dir) \
|
|
if (domainMask & mask) \
|
|
{ \
|
|
path = [base_dir stringByAppendingPathComponent: add_dir]; \
|
|
if (path != nil) \
|
|
[paths addObject: path]; \
|
|
}
|
|
|
|
if (directoryKey == NSApplicationDirectory
|
|
|| directoryKey == NSAllApplicationsDirectory)
|
|
{
|
|
ADD_PATH (NSUserDomainMask, gnustep_user_root, appsDir);
|
|
ADD_PATH (NSLocalDomainMask, gnustep_local_root, appsDir);
|
|
ADD_PATH (NSNetworkDomainMask, gnustep_network_root, appsDir);
|
|
ADD_PATH (NSSystemDomainMask, gnustep_system_root, appsDir);
|
|
}
|
|
if (directoryKey == NSDemoApplicationDirectory
|
|
|| directoryKey == NSAllApplicationsDirectory);
|
|
{
|
|
NSString *devDemosDir = [devDir stringByAppendingPathComponent: demosDir];
|
|
ADD_PATH (NSSystemDomainMask, gnustep_system_root, devDemosDir);
|
|
}
|
|
if (directoryKey == NSDeveloperApplicationDirectory
|
|
|| directoryKey == NSAllApplicationsDirectory)
|
|
{
|
|
NSString *devAppsDir = [devDir stringByAppendingPathComponent: appsDir];
|
|
|
|
ADD_PATH (NSUserDomainMask, gnustep_user_root, devAppsDir);
|
|
ADD_PATH (NSLocalDomainMask, gnustep_local_root, devAppsDir);
|
|
ADD_PATH (NSNetworkDomainMask, gnustep_network_root, devAppsDir);
|
|
ADD_PATH (NSSystemDomainMask, gnustep_system_root, devAppsDir);
|
|
}
|
|
if (directoryKey == NSAdminApplicationDirectory
|
|
|| directoryKey == NSAllApplicationsDirectory)
|
|
{
|
|
NSString *devAdminDir = [devDir stringByAppendingPathComponent: adminDir];
|
|
|
|
/* FIXME - NSUserDomainMask ? - users have no Administrator directory */
|
|
ADD_PATH (NSLocalDomainMask, gnustep_local_root, devAdminDir);
|
|
ADD_PATH (NSNetworkDomainMask, gnustep_network_root, devAdminDir);
|
|
ADD_PATH (NSSystemDomainMask, gnustep_system_root, devAdminDir);
|
|
}
|
|
if (directoryKey == NSLibraryDirectory
|
|
|| directoryKey == NSAllLibrariesDirectory)
|
|
{
|
|
ADD_PATH (NSUserDomainMask, gnustep_user_root, libraryDir);
|
|
ADD_PATH (NSLocalDomainMask, gnustep_local_root, libraryDir);
|
|
ADD_PATH (NSNetworkDomainMask, gnustep_network_root, libraryDir);
|
|
ADD_PATH (NSSystemDomainMask, gnustep_system_root, libraryDir);
|
|
}
|
|
if (directoryKey == NSDeveloperDirectory)
|
|
{
|
|
ADD_PATH (NSUserDomainMask, gnustep_local_root, devDir);
|
|
ADD_PATH (NSLocalDomainMask, gnustep_local_root, devDir);
|
|
ADD_PATH (NSNetworkDomainMask, gnustep_network_root, devDir);
|
|
ADD_PATH (NSSystemDomainMask, gnustep_system_root, devDir);
|
|
}
|
|
if (directoryKey == NSUserDirectory)
|
|
{
|
|
if (domainMask & NSUserDomainMask)
|
|
{
|
|
[paths addObject: gnustep_user_root];
|
|
}
|
|
}
|
|
if (directoryKey == NSDocumentationDirectory)
|
|
{
|
|
ADD_PATH (NSUserDomainMask, gnustep_user_root, docDir);
|
|
ADD_PATH (NSLocalDomainMask, gnustep_local_root, docDir);
|
|
ADD_PATH (NSNetworkDomainMask, gnustep_network_root, docDir);
|
|
ADD_PATH (NSSystemDomainMask, gnustep_system_root, docDir);
|
|
}
|
|
if (directoryKey == GSLibrariesDirectory)
|
|
{
|
|
ADD_PATH (NSUserDomainMask, gnustep_user_root, libsDir);
|
|
ADD_PATH (NSLocalDomainMask, gnustep_local_root, libsDir);
|
|
ADD_PATH (NSNetworkDomainMask, gnustep_network_root, libsDir);
|
|
ADD_PATH (NSSystemDomainMask, gnustep_system_root, libsDir);
|
|
}
|
|
if (directoryKey == GSToolsDirectory)
|
|
{
|
|
ADD_PATH (NSUserDomainMask, gnustep_user_root, toolsDir);
|
|
ADD_PATH (NSLocalDomainMask, gnustep_local_root, toolsDir);
|
|
ADD_PATH (NSNetworkDomainMask, gnustep_network_root, toolsDir);
|
|
ADD_PATH (NSSystemDomainMask, gnustep_system_root, toolsDir);
|
|
}
|
|
#undef ADD_PATH
|
|
|
|
fm = [NSFileManager defaultManager];
|
|
|
|
count = [paths count];
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
path = [paths objectAtIndex: i];
|
|
// remove bad paths
|
|
if ([fm fileExistsAtPath: path] == NO)
|
|
{
|
|
[paths removeObjectAtIndex: i];
|
|
i--;
|
|
count--;
|
|
}
|
|
/*
|
|
* this may look like a performance hit at first glance, but if these
|
|
* string methods don't alter the string, they return the receiver
|
|
*/
|
|
else if (expandTilde == YES)
|
|
{
|
|
[paths replaceObjectAtIndex: i
|
|
withObject: [path stringByExpandingTildeInPath]];
|
|
}
|
|
else
|
|
{
|
|
[paths replaceObjectAtIndex: i
|
|
withObject: [path stringByAbbreviatingWithTildeInPath]];
|
|
}
|
|
}
|
|
|
|
AUTORELEASE (paths);
|
|
return paths;
|
|
}
|