Error handling tweaks based on code/ideas by Sergey Golovin

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@35266 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
rfm 2012-07-08 15:50:58 +00:00
parent 7ccc71d1ab
commit a29118d5a0
2 changed files with 226 additions and 86 deletions

View file

@ -51,6 +51,7 @@
#import "Foundation/NSDate.h"
#import "Foundation/NSDictionary.h"
#import "Foundation/NSEnumerator.h"
#import "Foundation/NSError.h"
#import "Foundation/NSException.h"
#import "Foundation/NSFileManager.h"
#import "Foundation/NSLock.h"
@ -294,9 +295,16 @@ static Class GSAttrDictionaryClass = 0;
fromPath: (NSString*) fromPath
toPath: (NSString*) toPath;
/* A convenience method to return an NSError object.
* If the _lastError message is set, this creates an NSError using
* that message in the NSCocoaErrorDomain, otherwise it used the
* most recent system error and the Posix error domain.
* The userInfo is set to contain NSLocalizedDescriptionKey for the
* message text, 'Path' if only the fromPath argument is specified,
* and 'FromPath' and 'ToPath' if both path argument are specified.
*/
- (NSError*) _errorFrom: (NSString*)fromPath to: (NSString*)toPath;
@end /* NSFileManager (PrivateMethods) */
/**
@ -693,13 +701,30 @@ static NSStringEncoding defaultEncoding;
- (NSArray*) contentsOfDirectoryAtPath: (NSString*)path error: (NSError**)error
{
return [self directoryContentsAtPath: path];
NSArray *result;
DESTROY(_lastError);
result = [self directoryContentsAtPath: path];
if (error != NULL)
{
if (nil == result)
{
*error = [self _errorFrom: path to: nil];
}
else
{
*error = nil;
}
}
return result;
}
/**
* Creates a new directory and all intermediate directories
* if flag is YES, creates only the last directory in the path
* if flag is NO. The directory is created with the attributes
* Creates a new directory and all intermediate directories. if flag is YES.
* Creates only the last directory in the path if flag is NO.<br />
* The directory is created with the attributes
* specified in attributes and any error is returned in error.<br />
* returns YES on success, NO on failure.
*/
@ -710,17 +735,18 @@ static NSStringEncoding defaultEncoding;
{
BOOL result = NO;
if (flag == YES)
DESTROY(_lastError);
if (YES == flag)
{
NSEnumerator *paths = [[path pathComponents] objectEnumerator];
NSString *path = nil;
NSString *dir = [NSString string];
NSEnumerator *paths = [[path pathComponents] objectEnumerator];
NSString *path = nil;
NSString *dir = [NSString string];
while ((path = (NSString *)[paths nextObject]) != nil)
{
dir = [dir stringByAppendingPathComponent: path];
result = [self createDirectoryAtPath: dir
attributes: attributes];
attributes: attributes];
}
}
else
@ -736,14 +762,22 @@ static NSStringEncoding defaultEncoding;
else
{
result = NO;
ASSIGN(_lastError, @"Could not create directory - intermediate paths did not exist or were not a directory");
ASSIGN(_lastError, @"Could not create directory - intermediate path did not exist or was not a directory");
}
}
if (error != NULL)
{
*error = [NSError _last];
if (NO == result)
{
*error = [self _errorFrom: path to: nil];
}
else
{
*error = nil;
}
}
return result;
}
@ -769,7 +803,10 @@ static NSStringEncoding defaultEncoding;
/* This is consistent with MacOSX - just return NO for an invalid path. */
if ([path length] == 0)
return NO;
{
ASSIGN(_lastError, @"no path given");
return NO;
}
#if defined(__MINGW__)
while ((subPath = [paths nextObject]))
@ -927,7 +964,10 @@ static NSStringEncoding defaultEncoding;
/* This is consistent with MacOSX - just return NO for an invalid path. */
if ([path length] == 0)
return NO;
{
ASSIGN(_lastError, @"no path given");
return NO;
}
#if defined(__MINGW__)
fh = CreateFileW(lpath, GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
@ -1075,6 +1115,7 @@ static NSStringEncoding defaultEncoding;
if ([[destination stringByAppendingString: @"/"]
hasPrefix: [source stringByAppendingString: @"/"]])
{
ASSIGN(_lastError, @"Could not copy - destination is a descendant of source");
return NO;
}
@ -1145,9 +1186,23 @@ static NSStringEncoding defaultEncoding;
toPath: (NSString*)dst
error: (NSError**)error
{
BOOL result;
BOOL result;
DESTROY(_lastError);
result = [self copyPath: src toPath: dst handler: nil];
if (error != NULL)
{
if (NO == result)
{
*error = [self _errorFrom: src to: dst];
}
else
{
*error = nil;
}
}
return result;
}
@ -1200,6 +1255,7 @@ static NSStringEncoding defaultEncoding;
if (sourceIsDir && [[destination stringByAppendingString: @"/"]
hasPrefix: [source stringByAppendingString: @"/"]])
{
ASSIGN(_lastError, @"Could not move - destination is a descendant of source");
return NO;
}
@ -1241,9 +1297,23 @@ static NSStringEncoding defaultEncoding;
toPath: (NSString*)dst
error: (NSError**)error
{
BOOL result;
BOOL result;
DESTROY(_lastError);
result = [self movePath: src toPath: dst handler: nil];
if (error != NULL)
{
if (NO == result)
{
*error = [self _errorFrom: src to: dst];
}
else
{
*error = nil;
}
}
return result;
}
@ -1297,6 +1367,7 @@ static NSStringEncoding defaultEncoding;
if ([[destination stringByAppendingString: @"/"]
hasPrefix: [source stringByAppendingString: @"/"]])
{
ASSIGN(_lastError, @"Could not link - destination is a descendant of source");
return NO;
}
@ -1350,7 +1421,8 @@ static NSStringEncoding defaultEncoding;
[self changeFileAttributes: attrs atPath: destination];
return YES;
#else
return NO; // Links not supported on this platform
ASSIN(_lastError, @"Links not supported on this platform");
return NO;
#endif
}
@ -1378,6 +1450,7 @@ static NSStringEncoding defaultEncoding;
lpath = [self fileSystemRepresentationWithPath: path];
if (lpath == 0 || *lpath == 0)
{
ASSIGN(_lastError, @"Could not remove - no path");
return NO;
}
else
@ -1472,7 +1545,21 @@ static NSStringEncoding defaultEncoding;
{
BOOL result;
DESTROY(_lastError);
result = [self removeFileAtPath: path handler: nil];
if (error != NULL)
{
if (NO == result)
{
*error = [self _errorFrom: path to: nil];
}
else
{
*error = nil;
}
}
return result;
}
@ -1501,6 +1588,7 @@ static NSStringEncoding defaultEncoding;
if (lpath == 0 || *lpath == _NUL)
{
ASSIGN(_lastError, @"no path given");
return NO;
}
@ -1555,6 +1643,7 @@ static NSStringEncoding defaultEncoding;
if (lpath == 0 || *lpath == _NUL)
{
ASSIGN(_lastError, @"no path given");
return NO;
}
@ -1591,6 +1680,7 @@ static NSStringEncoding defaultEncoding;
if (lpath == 0 || *lpath == _NUL)
{
ASSIGN(_lastError, @"no path given");
return NO;
}
@ -1632,6 +1722,7 @@ static NSStringEncoding defaultEncoding;
if (lpath == 0 || *lpath == _NUL)
{
ASSIGN(_lastError, @"no path given");
return NO;
}
@ -1679,6 +1770,7 @@ static NSStringEncoding defaultEncoding;
if (lpath == 0 || *lpath == _NUL)
{
ASSIGN(_lastError, @"no path given");
return NO;
}
@ -1872,7 +1964,8 @@ static NSStringEncoding defaultEncoding;
error: (NSError**)error
{
NSDictionary *d;
DESTROY(_lastError);
d = [GSAttrDictionaryClass attributesAt:
[self fileSystemRepresentationWithPath: path] traverseLink: NO];
@ -1880,7 +1973,7 @@ static NSStringEncoding defaultEncoding;
{
if (nil == d)
{
*error = [NSError _last];
*error = [self _errorFrom: path to: nil];
}
else
{
@ -2013,6 +2106,7 @@ static NSStringEncoding defaultEncoding;
return [NSDictionary dictionaryWithObjects: values forKeys: keys count: 5];
#else
NSLog(@"NSFileManager", @"no support for filesystem attributes");
ASSIGN(_lastError, @"no support for filesystem attributes");
return nil;
#endif
#endif /* MINGW */
@ -2138,6 +2232,7 @@ static NSStringEncoding defaultEncoding;
return (symlink(oldpath, newpath) == 0);
#else
ASSIGN(_lastError, @"symbolic links not supported on this system");
return NO;
#endif
}
@ -2162,6 +2257,7 @@ static NSStringEncoding defaultEncoding;
return nil;
}
#else
ASSIGN(_lastError, @"symbolic links not supported on this system");
return nil;
#endif
}
@ -2934,6 +3030,7 @@ static inline void gsedRelease(GSEnumeratedDirectory X)
[pool drain];
return YES;
#else
ASSIGN(_lastError, @"Links not supported on this platform");
return NO;
#endif
}
@ -2983,6 +3080,57 @@ static inline void gsedRelease(GSEnumeratedDirectory X)
return NO;
}
- (NSError*) _errorFrom: (NSString *)fromPath to: (NSString *)toPath
{
NSError *error;
NSDictionary *errorInfo;
NSString *message;
NSString *domain;
NSInteger code;
if (_lastError)
{
message = _lastError;
domain = NSCocoaErrorDomain;
code = 0;
}
else
{
error = [NSError _last];
message = [error localizedDescription];
domain = [error domain];
code = [error code];
}
if (fromPath && toPath)
{
errorInfo = [NSDictionary dictionaryWithObjectsAndKeys:
fromPath, @"FromPath",
toPath, @"ToPath",
message, NSLocalizedDescriptionKey,
nil];
}
else if (fromPath)
{
errorInfo = [NSDictionary dictionaryWithObjectsAndKeys:
fromPath, @"Path",
message, NSLocalizedDescriptionKey,
nil];
}
else
{
errorInfo = [NSDictionary dictionaryWithObjectsAndKeys:
message, NSLocalizedDescriptionKey,
nil];
}
error = [NSError errorWithDomain: domain
code: code
userInfo: errorInfo];
DESTROY(_lastError);
return error;
}
@end /* NSFileManager (PrivateMethods) */

View file

@ -4,15 +4,20 @@
#import <Foundation/NSFileManager.h>
#import <Foundation/NSProcessInfo.h>
#import <Foundation/NSPathUtilities.h>
#import <Foundation/NSError.h>
int main()
{
NSAutoreleasePool *arp = [NSAutoreleasePool new];
NSFileManager *mgr = [NSFileManager defaultManager];
NSString *dir = @"NSFileManagerTestDir";
NSDictionary *attr;
NSString *dirInDir;
NSString *str1,*str2;
NSError *err;
NSDictionary *errInfo;
BOOL exists;
BOOL isDir;
dirInDir
= [@"TestDirectory" stringByAppendingPathComponent: @"WithinDirectory"];
@ -20,46 +25,38 @@ int main()
PASS(mgr != nil && [mgr isKindOfClass: [NSFileManager class]],
"NSFileManager understands +defaultManager");
/* remove test directory if it exists */
{
BOOL exists,isDir;
exists = [mgr fileExistsAtPath: dir isDirectory: &isDir];
if (exists)
{
[mgr removeFileAtPath: dir handler: nil];
}
}
/* remove test directory if it exists */
exists = [mgr fileExistsAtPath: dir isDirectory: &isDir];
if (exists)
{
[mgr removeFileAtPath: dir handler: nil];
}
PASS([mgr fileAttributesAtPath: dir traverseLink: NO] == nil,
"NSFileManager returns nil for attributes of non-existent file");
{
NSDictionary *attr;
BOOL isDir;
PASS([mgr createDirectoryAtPath: dir attributes: nil],
"NSFileManager can create a directory");
PASS([mgr fileExistsAtPath: dir isDirectory: &isDir] &&
isDir == YES,
"exists and is a directory");
PASS([mgr fileAttributesAtPath: dir traverseLink: NO] != nil,
"NSFileManager returns non-nil for attributes of existing file");
attr = [mgr fileAttributesAtPath: dir traverseLink: NO];
PASS(attr != nil,
"NSFileManager returns non-nil for attributes of existing file");
PASS([NSUserName() isEqual: [attr fileOwnerAccountName]],
"newly created file is owned by current user");
PASS([mgr createDirectoryAtPath: dir attributes: nil],
"NSFileManager can create a directory");
PASS([mgr fileExistsAtPath: dir isDirectory: &isDir] &&
isDir == YES,
"exists and is a directory");
PASS([mgr fileAttributesAtPath: dir traverseLink: NO] != nil,
"NSFileManager returns non-nil for attributes of existing file");
attr = [mgr fileAttributesAtPath: dir traverseLink: NO];
PASS(attr != nil,
"NSFileManager returns non-nil for attributes of existing file");
PASS([NSUserName() isEqual: [attr fileOwnerAccountName]],
"newly created file is owned by current user");
NSLog(@"'%@', '%@'", NSUserName(), [attr fileOwnerAccountName]);
attr = [mgr attributesOfItemAtPath: dir error: &err];
PASS(attr != nil && err == nil,
"[NSFileManager attributesOfItemAtPath:error:] returns non-nil for "
"attributes and nil for error in the case of existing file");
attr = [mgr attributesOfItemAtPath:
[dir stringByAppendingPathComponent:
@"thispathMUSTNOTexistatyoursystem"] error: &err];
PASS(attr == nil && err != nil,
"[NSFileManager attributesOfItemAtPath:error:] returns nil for "
"attributes and non-nil for error in the case of non-existent file");
}
attr = [mgr attributesOfItemAtPath: dir error: &err];
PASS(attr != nil && err == nil,
"[NSFileManager attributesOfItemAtPath:error:] returns non-nil for "
"attributes and nil for error in the case of existing file");
attr = [mgr attributesOfItemAtPath:
[dir stringByAppendingPathComponent:
@"thispathMUSTNOTexistatyoursystem"] error: &err];
PASS(attr == nil && err != nil,
"[NSFileManager attributesOfItemAtPath:error:] returns nil for "
"attributes and non-nil for error in the case of non-existent file");
PASS([mgr changeCurrentDirectoryPath: dir],
"NSFileManager can change directories");
@ -160,23 +157,23 @@ NSLog(@"'%@', '%@'", NSUserName(), [attr fileOwnerAccountName]);
PASS([mgr changeCurrentDirectoryPath: @"subdir"],
"NSFileManager can move into subdir");
{
BOOL isDir;
PASS([mgr createDirectoryAtPath: dirInDir
withIntermediateDirectories: NO
attributes: nil
error: NULL] == NO,
"NSFileManager refuses to create non-existent intermediate directories withIntermediateDirectories == NO");
PASS([mgr createDirectoryAtPath: dirInDir
withIntermediateDirectories: YES
attributes: nil
error: NULL],
"NSFileManager can create intermediate directories withIntermediateDirectories == YES");
PASS([mgr fileExistsAtPath: dirInDir isDirectory: &isDir] && isDir == YES,
"NSFileManager create directory and intermediate directory that actually exist");
PASS([mgr createDirectoryAtPath: dirInDir
withIntermediateDirectories: NO
attributes: nil
error: &err] == NO
&& err != nil && [[err domain] isEqual: NSCocoaErrorDomain]
&& (errInfo = [err userInfo]) != nil
&& [errInfo objectForKey: NSLocalizedDescriptionKey] != nil
&& [errInfo objectForKey: @"Path"] != nil,
"NSFileManager refuses to create intermediate directories");
}
PASS([mgr createDirectoryAtPath: dirInDir
withIntermediateDirectories: YES
attributes: nil
error: &err] && err == nil,
"NSFileManager can create intermediate directories");
PASS([mgr fileExistsAtPath: dirInDir isDirectory: &isDir] && isDir == YES,
"NSFileManager create directory and intermediate directory");
PASS_EXCEPTION([mgr removeFileAtPath: @"." handler: nil];,
NSInvalidArgumentException,
@ -186,19 +183,14 @@ NSLog(@"'%@', '%@'", NSUserName(), [attr fileOwnerAccountName]);
NSInvalidArgumentException,
"NSFileManager -removeFileAtPath: @\"..\" throws exception");
/* clean up */
{
BOOL exists,isDir;
[mgr changeCurrentDirectoryPath: [[[mgr currentDirectoryPath] stringByDeletingLastPathComponent] stringByDeletingLastPathComponent]];
exists = [mgr fileExistsAtPath: dir isDirectory: &isDir];
if (exists || isDir)
{
PASS([mgr removeFileAtPath: dir handler: nil],
"NSFileManager removes a directory");
PASS(![mgr fileExistsAtPath: dir],"directory no longer exists");
}
isDir = NO;
}
[mgr changeCurrentDirectoryPath: [[[mgr currentDirectoryPath] stringByDeletingLastPathComponent] stringByDeletingLastPathComponent]];
exists = [mgr fileExistsAtPath: dir isDirectory: &isDir];
if (exists || isDir)
{
PASS([mgr removeFileAtPath: dir handler: nil],
"NSFileManager removes a directory");
PASS(![mgr fileExistsAtPath: dir],"directory no longer exists");
}
[arp release]; arp = nil;
return 0;