File access improvements

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@3764 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
richard 1999-02-20 21:19:15 +00:00
parent 34a325522b
commit eaea323e1a
7 changed files with 340 additions and 145 deletions

View file

@ -1,3 +1,23 @@
Sat Feb 20 20:30:00 1999 Richard Frith-Macdonald <richard@brainstorm.co.uk>
* Source/NSUser.m: Added GSSetUserName() and rewrote NSUserName() to
work consistently - use the LOGNAME environment variable as first
choice of username.
* Source/include/NSPathUtilities.h: Added GSSetUserName()
* Source/NSUserDefaults.m: Added GNUstep specific method -
([+resetUserDefaults]) to reset the standard defaults in the event of
a change os username. Also changed to create defaults withe correct
ownership, and to create a defaults file containing a valid (empty)
dictionary.
* Source/include/NSUserDefaults.h: Added ([+resetUserDefaults])
* Source/NSData.m: Try to preserve file ownership etc with
([-writeToFile:atomically:])
* Source/NSFileManager.m: ([-changeFileAttributes:atPath:]) added
code to handle owner and group names if owner and group IDs are not
supplied. Also added code to ensure that programs running setuid to
root create new files and directories with the ownership of their
actual login user by default.
1999-02-19 Michael Hanni <mhanni@sprintmail.com
* Source/NSArray.m: Added @end for NSArrayEnumeratorReverse.

View file

@ -27,6 +27,18 @@
#include <base/preface.h>
#include <Foundation/NSString.h>
#ifndef NO_GNUSTEP
/*
* This extension permits a change of username from that specified in the
* LOGNAME environment variable. Using it will almost certainly cause
* trouble if the process does not posess the file access priviliges of the
* new name. This is provided primarily for use by processes that run as
* system-manager and need to act as particular users. If uses the
* [NSUserDefaults +resetUserDefaults] extension to reset the defaults system
* to use the defaults belonging to the new user.
*/
extern void GSSetUserName(NSString *name);
#endif
extern NSString *NSUserName();
extern NSString *NSHomeDirectory();
extern NSString *NSHomeDirectoryForUser(NSString *userName);

View file

@ -124,6 +124,13 @@ extern NSString* const NSDateTimeOrdering;
/* Getting the Shared Instance */
+ (NSUserDefaults*) standardUserDefaults;
#ifndef NO_GNUSTEP
/*
* Called by GSSetUserName() to get the defaults system to use the defaults
* of a new user.
*/
+ (void) resetUserDefaults;
#endif
+ (NSArray*) userLanguages;
+ (void) setUserLanguages: (NSArray*)languages;

View file

@ -71,6 +71,8 @@
#include <Foundation/NSString.h>
#include <Foundation/NSException.h>
#include <Foundation/NSDebug.h>
#include <Foundation/NSFileManager.h>
#include <Foundation/NSPathUtilities.h>
#include <string.h> /* for memset() */
#include <unistd.h> /* SEEK_* on SunOS 4 */
@ -500,6 +502,7 @@ failure:
NSLog(@"Open (%s) attempt failed - bad path", theRealPath);
return NO;
}
#ifdef HAVE_MKSTEMP
if (useAuxiliaryFile)
{
@ -576,17 +579,43 @@ failure:
}
/* If we used a temporary file, we still need to rename() it be the
* real file. Am I forgetting anything here? */
* real file. Also, we need to try to retain the file attributes of
* the original file we are overwriting (if we are) */
if (useAuxiliaryFile)
{
c = rename(thePath, theRealPath);
NSFileManager *mgr = [NSFileManager defaultManager];
NSMutableDictionary *att = nil;
if (c != 0) /* Many things could go wrong, I
* guess. */
if ([mgr fileExistsAtPath: path])
{
att = [[mgr fileAttributesAtPath:path traverseLink:YES] mutableCopy];
if (att)
[att autorelease];
}
c = rename(thePath, theRealPath);
if (c != 0) /* Many things could go wrong, I guess. */
{
NSLog(@"Rename (%s) failed - %s", thePath, strerror(errno));
goto failure;
}
if (att)
{
/*
* We have created a new file - so we attempt to make it's
* attributes match that of the original.
*/
[att removeObjectForKey: NSFileSize];
[att removeObjectForKey: NSFileModificationDate];
[att removeObjectForKey: NSFileReferenceCount];
[att removeObjectForKey: NSFileSystemNumber];
[att removeObjectForKey: NSFileSystemFileNumber];
[att removeObjectForKey: NSFileDeviceIdentifier];
[att removeObjectForKey: NSFileType];
if ([mgr changeFileAttributes: att atPath: path] == NO)
NSLog(@"Unable to correctly set all attributes for '%@'", path);
}
}
/* success: */

View file

@ -194,15 +194,26 @@ static NSFileManager* defaultManager = nil;
char dirpath[PATH_MAX+1];
struct stat statbuf;
int len, cur;
NSDictionary *needChown = nil;
/*
* If there is no file owner specified, and we are running setuid to
* root, then we assume we need to change ownership to correct user.
*/
if ([attributes objectForKey: NSFileOwnerAccountName] == nil
&& [attributes objectForKey: NSFileOwnerAccountNumber] == nil
&& geteuid() == 0 && [@"root" isEqualToString: NSUserName()] == NO)
{
needChown = [NSDictionary dictionaryWithObjectsAndKeys:
NSFileOwnerAccountName, NSUserName(), nil];
}
cpath = [self fileSystemRepresentationWithPath:path];
len = strlen(cpath);
if (len > PATH_MAX)
// name too long
if (len > PATH_MAX) // name too long
return NO;
if (strcmp(cpath, "/") == 0 || len == 0)
// cannot use "/" or "" as a new dir path
if (strcmp(cpath, "/") == 0 || len == 0) // cannot use "/" or ""
return NO;
strcpy(dirpath, cpath);
@ -211,34 +222,53 @@ static NSFileManager* defaultManager = nil;
dirpath[len-1] = '\0';
cur = 0;
do {
do
{
// find next '/'
while (dirpath[cur] != '/' && cur < len)
cur++;
// if first char is '/' then again; (cur == len) -> last component
if (cur == 0) {
if (cur == 0)
{
cur++;
continue;
}
// check if path from 0 to cur is valid
dirpath[cur] = '\0';
if (stat(dirpath, &statbuf) == 0) {
if (stat(dirpath, &statbuf) == 0)
{
if (cur == len)
return NO; // already existing last path
}
else {
else
{
// make new directory
if (mkdir(dirpath, 0777) != 0)
return NO; // could not create component
// if last directory and attributes then change
if (cur == len && attributes)
return [self changeFileAttributes:attributes
{
if ([self changeFileAttributes:attributes
atPath:[self stringWithFileSystemRepresentation:dirpath
length:cur]];
length:cur]] == NO)
return NO;
if (needChown)
{
if ([self changeFileAttributes: needChown
atPath:[self stringWithFileSystemRepresentation:dirpath
length:cur]] == NO)
{
NSLog(@"Failed to change ownership of '%s' to '%@'",
dirpath, NSUserName());
}
}
return YES;
}
}
dirpath[cur] = '/';
cur++;
} while (cur < len);
}
while (cur < len);
return YES;
#endif /* WIN32 */
@ -485,7 +515,8 @@ static NSFileManager* defaultManager = nil;
}
}
- (BOOL)createFileAtPath:(NSString*)path contents:(NSData*)contents
- (BOOL) createFileAtPath: (NSString*)path
contents: (NSData*)contents
attributes: (NSDictionary*)attributes
{
int fd, len, written;
@ -495,11 +526,29 @@ static NSFileManager* defaultManager = nil;
if (fd < 0)
return NO;
if (![self changeFileAttributes:attributes atPath:path]) {
if (![self changeFileAttributes: attributes atPath: path])
{
close (fd);
return NO;
}
/*
* If there is no file owner specified, and we are running setuid to
* root, then we assume we need to change ownership to correct user.
*/
if ([attributes objectForKey: NSFileOwnerAccountName] == nil
&& [attributes objectForKey: NSFileOwnerAccountNumber] == nil
&& geteuid() == 0 && [@"root" isEqualToString: NSUserName()] == NO)
{
attributes = [NSDictionary dictionaryWithObjectsAndKeys:
NSFileOwnerAccountName, NSUserName(), nil];
if (![self changeFileAttributes: attributes atPath: path])
{
NSLog(@"Failed to change ownership of '%@' to '%@'",
path, NSUserName());
}
}
len = [contents length];
if (len)
written = write (fd, [contents bytes], len);
@ -785,28 +834,67 @@ static NSFileManager* defaultManager = nil;
{
const char *cpath = [self fileSystemRepresentationWithPath:path];
NSNumber *num;
NSString *str;
NSDate *date;
BOOL allOk = YES;
#ifndef __WIN32__
num = [attributes objectForKey: NSFileOwnerAccountNumber];
if (num) {
if (num)
{
allOk &= (chown(cpath, [num intValue], -1) == 0);
}
else
{
if ((str = [attributes objectForKey:NSFileOwnerAccountName]) != nil)
{
#if HAVE_PWD_H
struct passwd *pw = getpwnam([str cString]);
if (pw)
{
allOk &= (chown(cpath, pw->pw_uid, -1) == 0);
chown(cpath, -1, pw->pw_gid);
}
else
allOk = NO;
#else
allOk = NO;
#endif
}
}
num = [attributes objectForKey:NSFileGroupOwnerAccountNumber];
if (num) {
if (num)
{
allOk &= (chown(cpath, -1, [num intValue]) == 0);
}
else if ((str = [attributes objectForKey:NSFileGroupOwnerAccountName]) != nil)
#if HAVE_GRP_H
{
struct group *gp = getgrnam([str cString]);
if (gp)
{
allOk &= (chown(cpath, -1, gp->gr_gid) == 0);
}
else
allOk = NO;
}
#else
allOk = NO;
#endif
#endif
num = [attributes objectForKey:NSFilePosixPermissions];
if (num) {
if (num)
{
allOk &= (chmod(cpath, [num intValue]) == 0);
}
date = [attributes objectForKey:NSFileModificationDate];
if (date) {
if (date)
{
struct stat sb;
#ifdef _POSIX_VERSION
struct utimbuf ub;
@ -816,7 +904,8 @@ static NSFileManager* defaultManager = nil;
if (stat(cpath, &sb) != 0)
allOk = NO;
else {
else
{
#ifdef _POSIX_VERSION
ub.actime = sb.st_atime;
ub.modtime = [date timeIntervalSince1970];

View file

@ -26,11 +26,13 @@
#include <base/preface.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/NSValue.h>
#include <Foundation/NSUserDefaults.h>
#include <stdlib.h> // for getenv()
#if !defined(__WIN32__) && !defined(_WIN32)
@ -39,47 +41,69 @@
#endif
#include <sys/types.h>
/* Return the caller's login name as an NSString object. */
static NSString *theUserName = nil;
void
GSSetUserName(NSString* name)
{
if (theUserName == nil)
theUserName = RETAIN(name);
else if ([theUserName isEqualToString: name] == NO)
{
ASSIGN(theUserName, name);
[NSUserDefaults resetUserDefaults];
}
}
/*
* 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.
*/
NSString *
NSUserName ()
{
if (theUserName == nil)
{
const char *login_name = 0;
#if defined(__WIN32__) || defined(_WIN32)
/* The GetUserName function returns the current user name */
char buf[1024];
DWORD n = 1024;
if (GetUserName(buf, &n))
return [NSString stringWithCString: buf];
else
return [NSString stringWithCString: ""];
#elif __SOLARIS__ || defined(BSD)
if (GetEnvironmentVariable("LOGNAME", buf, 1024);
login_name = buf;
else if (GetUserName(buf, &n))
login_name = buf;
#else
login_name = getenv("LOGNAME");
if (login_name == 0 || getpwnam(login_name) == 0)
{
# if __SOLARIS__ || defined(BSD)
int uid = geteuid(); // get the effective user id
struct passwd *pwent = getpwuid (uid);
NSString* name = [NSString stringWithCString: pwent->pw_name];
return name;
login_name = pwent->pw_name;
# else
const char *login_name = getlogin ();
login_name = getlogin();
if (!login_name)
login_name = cuserid(NULL);
if (!login_name)
login_name= getenv ("LOGNAME");
if (login_name)
return [NSString stringWithCString: login_name];
else
return nil;
# endif
}
#endif
if (login_name)
GSSetUserName([NSString stringWithCString: login_name]);
else
[NSException raise: NSInternalInconsistencyException
format: @"Unable to determine curren user name"];
}
return theUserName;
}
/* Return the caller's home directory as an NSString object. */
NSString *
NSHomeDirectory ()
{
return NSHomeDirectoryForUser (NSUserName ());
/* xxx Was using this. Is there a reason to prefer it?
return [NSString stringWithCString: getenv ("HOME")]; */
}
/* Return LOGIN_NAME's home directory as an NSString object. */

View file

@ -79,6 +79,17 @@ static NSMutableString *processName = nil;
/*************************************************************************
*** Getting the Shared Instance
*************************************************************************/
static BOOL setSharedDefaults = NO; /* Flag to prevent infinite recursion */
+ (void) resetUserDefaults
{
id defs = sharedDefaults;
setSharedDefaults = NO;
sharedDefaults = nil;
[defs release];
}
+ (NSUserDefaults *)standardUserDefaults
/*
Returns the shared defaults object. If it doesn't exist yet, it's
@ -88,11 +99,9 @@ static NSMutableString *processName = nil;
convenience; other instances may also be created.
*/
{
static BOOL beenHere = NO; /* Flag to prevent infinite recursion */
if (beenHere)
if (setSharedDefaults)
return sharedDefaults;
beenHere = YES;
setSharedDefaults = YES;
// Create new sharedDefaults (NOTE: Not added to the autorelease pool!)
sharedDefaults = [[self alloc] init];
@ -663,10 +672,15 @@ static NSMutableString *processName = nil;
}
else
{
NSDictionary *attr;
attr = [NSDictionary dictionaryWithObjectsAndKeys:
NSUserName(), NSFileOwnerAccountName, nil];
NSLog(@"Creating defaults database file %@", defaultsDatabase);
[[NSFileManager defaultManager] createFileAtPath: defaultsDatabase
contents: nil
attributes: nil];
attributes: attr];
[[NSDictionary dictionary] writeToFile: defaultsDatabase atomically: YES];
}
if (!newDict)