libs-base/Source/NSUser.m
CaS 6674943831 Don't check file ownership if file does not exist.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@13627 72102866-910b-0410-8b05-ffd578937521
2002-05-11 05:21:46 +00:00

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;
}