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 Frith-MacDonald 1999-02-20 21:19:15 +00:00
parent 4091f6f778
commit 4d15192f41
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,9 +27,21 @@
#include <base/preface.h>
#include <Foundation/NSString.h>
extern NSString *NSUserName ();
extern NSString *NSHomeDirectory ();
extern NSString *NSHomeDirectoryForUser (NSString *userName);
#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);
#ifndef STRICT_OPENSTEP
extern NSString *NSFullUserName(void);

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

@ -184,63 +184,93 @@ static NSFileManager* defaultManager = nil;
#endif
}
- (BOOL)createDirectoryAtPath:(NSString*)path
attributes:(NSDictionary*)attributes
- (BOOL) createDirectoryAtPath:(NSString*)path
attributes:(NSDictionary*)attributes
{
#if defined(__WIN32__) || defined(_WIN32)
return CreateDirectory([self fileSystemRepresentationWithPath: path], NULL);
#else
const char* cpath;
char dirpath[PATH_MAX+1];
struct stat statbuf;
int len, cur;
const char* cpath;
char dirpath[PATH_MAX+1];
struct stat statbuf;
int len, cur;
NSDictionary *needChown = nil;
cpath = [self fileSystemRepresentationWithPath:path];
len = strlen(cpath);
if (len > PATH_MAX)
// name too long
return NO;
if (strcmp(cpath, "/") == 0 || len == 0)
// cannot use "/" or "" as a new dir path
return NO;
strcpy(dirpath, cpath);
dirpath[len] = '\0';
if (dirpath[len-1] == '/')
dirpath[len-1] = '\0';
cur = 0;
do {
// find next '/'
while (dirpath[cur] != '/' && cur < len)
cur++;
// if first char is '/' then again; (cur == len) -> last component
if (cur == 0) {
cur++;
continue;
}
// check if path from 0 to cur is valid
dirpath[cur] = '\0';
if (stat(dirpath, &statbuf) == 0) {
if (cur == len)
return NO; // already existing last path
}
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
atPath:[self stringWithFileSystemRepresentation:dirpath
length:cur]];
}
dirpath[cur] = '/';
cur++;
} while (cur < len);
/*
* 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];
}
return YES;
cpath = [self fileSystemRepresentationWithPath:path];
len = strlen(cpath);
if (len > PATH_MAX) // name too long
return NO;
if (strcmp(cpath, "/") == 0 || len == 0) // cannot use "/" or ""
return NO;
strcpy(dirpath, cpath);
dirpath[len] = '\0';
if (dirpath[len-1] == '/')
dirpath[len-1] = '\0';
cur = 0;
do
{
// find next '/'
while (dirpath[cur] != '/' && cur < len)
cur++;
// if first char is '/' then again; (cur == len) -> last component
if (cur == 0)
{
cur++;
continue;
}
// check if path from 0 to cur is valid
dirpath[cur] = '\0';
if (stat(dirpath, &statbuf) == 0)
{
if (cur == len)
return NO; // already existing last path
}
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)
{
if ([self changeFileAttributes:attributes
atPath:[self stringWithFileSystemRepresentation:dirpath
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);
return YES;
#endif /* WIN32 */
}
@ -267,7 +297,7 @@ static NSFileManager* defaultManager = nil;
// File operations
- (BOOL)copyPath:(NSString*)source toPath:(NSString*)destination
handler:handler
handler:handler
{
BOOL sourceIsDir, fileExists;
NSDictionary* attributes;
@ -327,7 +357,7 @@ static NSFileManager* defaultManager = nil;
}
- (BOOL)movePath:(NSString*)source toPath:(NSString*)destination
handler:handler
handler:handler
{
BOOL sourceIsDir, fileExists;
const char* sourcePath = [self fileSystemRepresentationWithPath:source];
@ -485,29 +515,48 @@ static NSFileManager* defaultManager = nil;
}
}
- (BOOL)createFileAtPath:(NSString*)path contents:(NSData*)contents
attributes:(NSDictionary*)attributes
- (BOOL) createFileAtPath: (NSString*)path
contents: (NSData*)contents
attributes: (NSDictionary*)attributes
{
int fd, len, written;
int fd, len, written;
fd = open ([self fileSystemRepresentationWithPath:path],
fd = open ([self fileSystemRepresentationWithPath:path],
O_WRONLY|O_TRUNC|O_CREAT, 0644);
if (fd < 0)
return NO;
if (fd < 0)
return NO;
if (![self changeFileAttributes:attributes atPath:path]) {
close (fd);
return NO;
if (![self changeFileAttributes: attributes atPath: path])
{
close (fd);
return NO;
}
len = [contents length];
if (len)
written = write (fd, [contents bytes], len);
else
written = 0;
close (fd);
/*
* 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());
}
}
return written == len;
len = [contents length];
if (len)
written = write (fd, [contents bytes], len);
else
written = 0;
close (fd);
return written == len;
}
// Getting and comparing file contents
@ -781,55 +830,95 @@ static NSFileManager* defaultManager = nil;
#endif /* WIN32 */
}
- (BOOL)changeFileAttributes:(NSDictionary*)attributes atPath:(NSString*)path
- (BOOL) changeFileAttributes: (NSDictionary*)attributes atPath: (NSString*)path
{
const char* cpath = [self fileSystemRepresentationWithPath:path];
NSNumber* num;
NSDate* date;
BOOL allOk = YES;
const char *cpath = [self fileSystemRepresentationWithPath:path];
NSNumber *num;
NSString *str;
NSDate *date;
BOOL allOk = YES;
#ifndef __WIN32__
num = [attributes objectForKey:NSFileOwnerAccountNumber];
if (num) {
allOk &= (chown(cpath, [num intValue], -1) == 0);
num = [attributes objectForKey: NSFileOwnerAccountNumber];
if (num)
{
allOk &= (chown(cpath, [num intValue], -1) == 0);
}
num = [attributes objectForKey:NSFileGroupOwnerAccountNumber];
if (num) {
allOk &= (chown(cpath, -1, [num intValue]) == 0);
}
#endif
num = [attributes objectForKey:NSFilePosixPermissions];
if (num) {
allOk &= (chmod(cpath, [num intValue]) == 0);
}
date = [attributes objectForKey:NSFileModificationDate];
if (date) {
struct stat sb;
#ifdef _POSIX_VERSION
struct utimbuf ub;
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
time_t ub[2];
allOk = NO;
#endif
}
}
num = [attributes objectForKey:NSFileGroupOwnerAccountNumber];
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
if (stat(cpath, &sb) != 0)
allOk = NO;
else {
num = [attributes objectForKey:NSFilePosixPermissions];
if (num)
{
allOk &= (chmod(cpath, [num intValue]) == 0);
}
date = [attributes objectForKey:NSFileModificationDate];
if (date)
{
struct stat sb;
#ifdef _POSIX_VERSION
ub.actime = sb.st_atime;
ub.modtime = [date timeIntervalSince1970];
allOk &= (utime(cpath, &ub) == 0);
struct utimbuf ub;
#else
ub[0] = sb.st_atime;
ub[1] = [date timeIntervalSince1970];
allOk &= (utime((char*)cpath, ub) == 0);
time_t ub[2];
#endif
if (stat(cpath, &sb) != 0)
allOk = NO;
else
{
#ifdef _POSIX_VERSION
ub.actime = sb.st_atime;
ub.modtime = [date timeIntervalSince1970];
allOk &= (utime(cpath, &ub) == 0);
#else
ub[0] = sb.st_atime;
ub[1] = [date timeIntervalSince1970];
allOk &= (utime((char*)cpath, ub) == 0);
#endif
}
}
return allOk;
return allOk;
}
// Discovering directory contents

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,38 +41,62 @@
#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;
/* 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)
int uid = geteuid(); // get the effective user id
struct passwd *pwent = getpwuid (uid);
NSString* name = [NSString stringWithCString: pwent->pw_name];
return name;
if (GetEnvironmentVariable("LOGNAME", buf, 1024);
login_name = buf;
else if (GetUserName(buf, &n))
login_name = buf;
#else
const char *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;
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);
login_name = pwent->pw_name;
# else
login_name = getlogin();
if (!login_name)
login_name = cuserid(NULL);
# 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. */
@ -78,8 +104,6 @@ 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];
contents: nil
attributes: attr];
[[NSDictionary dictionary] writeToFile: defaultsDatabase atomically: YES];
}
if (!newDict)