Fixes to permit handlers to do less.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@15932 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-Macdonald 2003-02-11 10:26:17 +00:00
parent 0f92295f75
commit f4e4d96572
3 changed files with 207 additions and 199 deletions

View file

@ -1,3 +1,24 @@
i2003-02-11 Willem Rein Oudshoorn <woudshoo@xs4all.nl>
* Headers/Foundation/NSFileManager.h: Added a little bit to the
* documentation of the NSFileManagerHandler protocol.
(some documentation markup fixes by RFM also)
* Source/NSFileManager.m ([NSFileManager -copyPath:toPath:handler:]):
use new private methods to cope with handlers that do not implement
the informal protocol. Pass more information to the handler in case
of an error.
([NSFileManager -removeFileAtPath:handler:]): see above
([NSFileManager -movePath:toPath:handler:]): see above
([NSFileManager -_copyPath:toPath:handler:]): see above
([NSFileManager -_copyFile:toFile:handler:]): see above, also fixed
leaking of file descriptors in case of error without a handler.
([NSFileManager -_sendToHandler:handlerwillProcessPath:path]):
new method
([NSFileManager -_proceedAccordingToHandler:handlerforError:
errorinPath:path]): new method
([NSFileManager -_proceedAccordingToHandler:handlerforError:
errorinPath:pathfromPath:fromPathtoPath:toPath]): new method
2003-02-11 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSFileManager.m: ([+attributesAt:traverseLink:]) check for

View file

@ -102,11 +102,41 @@
*/
@interface NSObject (NSFileManagerHandler)
/**
* When an error occurs during a copy or move operation, the file manager
* <p>When an error occurs during a copy or move operation, the file manager
* will send this message to the handler, and will use the return value to
* determine whether the operation should proceed. If the method returns
* YES then the operation will proceed after the error, if it returns NO
* then it will be aborted.
* </p>
* <p>If the handler does not implement this method it will be treated as
* if it returns NO.
* </p>
* The error dictionary contains the following
* <list>
* <item><strong>"Error"</strong>
* contains a description of the error.
* </item>
* <item><strong>"Path"</strong>
* contains the path that is being processed when
* an error occured. If an error occurs during an
* operation involving two files, like copying, and
* it is not clear which file triggers the error it
* will default to the source file.
* </item>
* <item><strong>"FromPath"</strong>
* (Optional) contains the path involved in reading.
* </item>
* <item><strong>"ToPath"</strong>
* (Optional) contains the path involved in writing.
* </item>
* </list>
*
* <p>Note that the <code>FromPath</code> is a GNUstep extension.
* </p>
* <p>Also the <code>FromPath</code> and <code>ToPath</code> are filled
* in when appropriate. So when copying a file they will typically
* both have a value and when reading only <code>FromPath</code>.
* </p>
*/
- (BOOL) fileManager: (NSFileManager*)fileManager
shouldProceedAfterError: (NSDictionary*)errorDictionary;
@ -115,7 +145,7 @@
* The file manager sends this method to the handler immediately before
* performing part of a directory move or copy operation. This provides
* the handler object with information it can use in the event of an
* error, to decide whether p[rocessing should proceed after the error.
* error, to decide whether processing should proceed after the error.
*/
- (void) fileManager: (NSFileManager*)fileManager
willProcessPath: (NSString*)path;

View file

@ -203,6 +203,25 @@
toPath: (NSString*)destination
handler: (id)handler;
/* encapsulates the will Process check for existence of selector. */
- (void) _sendToHandler: (id) handler
willProcessPath: (NSString*) path;
/* methods to encapsulates setting up and calling the handler
in case of an error */
- (BOOL) _proceedAccordingToHandler: (id) handler
forError: (NSString*) error
inPath: (NSString*) path;
- (BOOL) _proceedAccordingToHandler: (id) handler
forError: (NSString*) error
inPath: (NSString*) path
fromPath: (NSString*) frompath
toPath: (NSString*) toPath;
@end /* NSFileManager (PrivateMethods) */
/**
@ -805,21 +824,15 @@ static NSFileManager* defaultManager = nil;
return NO;
}
[handler fileManager: self willProcessPath: destination];
[self _sendToHandler: handler willProcessPath: destination];
if ([self createDirectoryAtPath: destination attributes: attrs] == NO)
{
if (handler)
{
NSDictionary* errorInfo
= [NSDictionary dictionaryWithObjectsAndKeys:
destination, @"Path", _lastError, @"Error", nil];
return [handler fileManager: self
shouldProceedAfterError: errorInfo];
}
else
{
return NO;
}
return [self _proceedAccordingToHandler: handler
forError: _lastError
inPath: destination
fromPath: source
toPath: destination];
}
if ([self _copyPath: source toPath: destination handler: handler] == NO)
@ -832,21 +845,18 @@ static NSFileManager* defaultManager = nil;
NSString *path;
BOOL result;
[handler fileManager: self willProcessPath: source];
[self _sendToHandler: handler willProcessPath: source];
path = [self pathContentOfSymbolicLinkAtPath: source];
result = [self createSymbolicLinkAtPath: destination pathContent: path];
if (result == NO)
{
if (handler != nil)
{
NSDictionary *errorInfo
= [NSDictionary dictionaryWithObjectsAndKeys:
source, @"Path", destination, @"ToPath",
@"cannot link to file", @"Error",
nil];
result = [handler fileManager: self
shouldProceedAfterError: errorInfo];
}
result = [self _proceedAccordingToHandler: handler
forError: @"cannot link to file"
inPath: source
fromPath: source
toPath: destination];
if (result == NO)
{
return NO;
@ -855,7 +865,8 @@ static NSFileManager* defaultManager = nil;
}
else
{
[handler fileManager: self willProcessPath: source];
[self _sendToHandler: handler willProcessPath: source];
if ([self _copyFile: source toFile: destination handler: handler] == NO)
{
return NO;
@ -923,22 +934,15 @@ static NSFileManager* defaultManager = nil;
{
/* source and destination are on the same device so we can simply
invoke rename on source. */
[handler fileManager: self willProcessPath: source];
[self _sendToHandler: handler willProcessPath: source];
if (rename (sourcePath, destPath) == -1)
{
if (handler)
{
NSDictionary* errorInfo
= [NSDictionary dictionaryWithObjectsAndKeys:
source, @"Path",
destination, @"ToPath",
@"cannot move file", @"Error",
nil];
if ([handler fileManager: self
shouldProceedAfterError: errorInfo])
return YES;
}
return NO;
return [self _proceedAccordingToHandler: handler
forError: @"cannot move file"
inPath: source
fromPath: source
toPath: destination];
}
return YES;
}
@ -979,10 +983,8 @@ static NSFileManager* defaultManager = nil;
format: @"Attempt to remove illegal path"];
}
if (handler != nil)
{
[handler fileManager: self willProcessPath: path];
}
[self _sendToHandler: handler willProcessPath: path];
cpath = [self fileSystemRepresentationWithPath: path];
if (cpath == 0 || *cpath == '\0')
{
@ -1025,26 +1027,9 @@ static NSFileManager* defaultManager = nil;
if (unlink(cpath) < 0)
#endif
{
BOOL result;
if (handler)
{
NSMutableDictionary *info;
info = [[NSMutableDictionary alloc] initWithCapacity: 3];
[info setObject: path forKey: @"Path"];
[info setObject: [NSString stringWithCString:
GSLastErrorStr(errno)]
forKey: @"Error"];
result = [handler fileManager: self
shouldProceedAfterError: info];
RELEASE(info);
}
else
{
result = NO;
}
return result;
return [self _proceedAccordingToHandler: handler
forError: [NSString stringWithCString: GSLastErrorStr (errno)]
inPath: path];
}
else
{
@ -1076,26 +1061,9 @@ static NSFileManager* defaultManager = nil;
if (rmdir([path fileSystemRepresentation]) < 0)
{
BOOL result;
if (handler)
{
NSMutableDictionary *info;
info = [[NSMutableDictionary alloc] initWithCapacity: 3];
[info setObject: path forKey: @"Path"];
[info setObject: [NSString stringWithCString:
GSLastErrorStr(errno)]
forKey: @"Error"];
result = [handler fileManager: self
shouldProceedAfterError: info];
RELEASE(info);
}
else
{
result = NO;
}
return result;
return [self _proceedAccordingToHandler: handler
forError: [NSString stringWithCString: GSLastErrorStr (errno)]
inPath: path];
}
else
{
@ -2323,21 +2291,13 @@ static SEL swfsSel = 0;
{
return YES;
}
if (handler != nil)
{
NSDictionary *errorInfo
= [NSDictionary dictionaryWithObjectsAndKeys:
source, @"Path",
@"cannot copy file", @"Error",
destination, @"ToPath",
nil];
return [handler fileManager: self
shouldProceedAfterError: errorInfo];
}
else
{
return NO;
}
return [self _proceedAccordingToHandler: handler
forError: @"cannot copy file"
inPath: source
fromPath: source
toPath: destination];
#else
NSDictionary *attributes;
int i;
@ -2366,20 +2326,11 @@ static SEL swfsSel = 0;
GSBINIO|O_RDONLY);
if (sourceFd < 0)
{
if (handler != nil)
{
NSDictionary *errorInfo
= [NSDictionary dictionaryWithObjectsAndKeys:
source, @"Path",
@"cannot open file for reading", @"Error",
nil];
return [handler fileManager: self
shouldProceedAfterError: errorInfo];
}
else
{
return NO;
}
return [self _proceedAccordingToHandler: handler
forError: @"cannot open file for reading"
inPath: source
fromPath: source
toPath: destination];
}
/* Open the destination file. In case of error call the handler. */
@ -2387,23 +2338,15 @@ static SEL swfsSel = 0;
GSBINIO|O_WRONLY|O_CREAT|O_TRUNC, fileMode);
if (destFd < 0)
{
if (handler != nil)
{
NSDictionary *errorInfo
= [NSDictionary dictionaryWithObjectsAndKeys:
destination, @"ToPath",
@"cannot open file for writing", @"Error",
nil];
close (sourceFd);
return [handler fileManager: self
shouldProceedAfterError: errorInfo];
}
else
{
return NO;
}
}
close (sourceFd);
return [self _proceedAccordingToHandler: handler
forError: @"cannot open file for writing"
inPath: destination
fromPath: source
toPath: destination];
}
/* Read bufsize bytes from source file and write them into the destination
file. In case of errors call the handler and abort the operation. */
for (i = 0; i < fileSize; i += rbytes)
@ -2411,45 +2354,28 @@ static SEL swfsSel = 0;
rbytes = read (sourceFd, buffer, bufsize);
if (rbytes < 0)
{
if (handler != nil)
{
NSDictionary *errorInfo
= [NSDictionary dictionaryWithObjectsAndKeys:
source, @"Path",
@"cannot read from file", @"Error",
nil];
close (sourceFd);
close (destFd);
return [handler fileManager: self
shouldProceedAfterError: errorInfo];
}
else
{
return NO;
}
}
close (sourceFd);
close (destFd);
return [self _proceedAccordingToHandler: handler
forError: @"cannot read from file"
inPath: source
fromPath: source
toPath: destination];
}
wbytes = write (destFd, buffer, rbytes);
if (wbytes != rbytes)
{
if (handler != nil)
{
NSDictionary *errorInfo
= [NSDictionary dictionaryWithObjectsAndKeys:
source, @"Path",
destination, @"ToPath",
@"cannot write to file", @"Error",
nil];
close (sourceFd);
close (destFd);
return [handler fileManager: self
shouldProceedAfterError: errorInfo];
}
else
{
return NO;
}
}
close (sourceFd);
close (destFd);
return [self _proceedAccordingToHandler: handler
forError: @"cannot write to file"
inPath: destination
fromPath: source
toPath: destination];
}
}
close (sourceFd);
close (destFd);
@ -2480,32 +2406,28 @@ static SEL swfsSel = 0;
destinationFile
= [destination stringByAppendingPathComponent: dirEntry];
[handler fileManager: self willProcessPath: sourceFile];
[self _sendToHandler: handler willProcessPath: sourceFile];
if ([fileType isEqual: NSFileTypeDirectory])
{
if (![self createDirectoryAtPath: destinationFile
attributes: attributes])
{
if (handler)
{
NSDictionary *errorInfo;
errorInfo = [NSDictionary dictionaryWithObjectsAndKeys:
destinationFile, @"Path",
_lastError, @"Error", nil];
if (![handler fileManager: self
shouldProceedAfterError: errorInfo])
return NO;
}
else
return NO;
if (![self _proceedAccordingToHandler: handler
forError: _lastError
inPath: destinationFile
fromPath: sourceFile
toPath: destinationFile])
{
return NO;
}
}
else
{
[enumerator skipDescendents];
if (![self _copyPath: sourceFile
toPath: destinationFile
handler: handler])
toPath: destinationFile
handler: handler])
return NO;
}
}
@ -2524,24 +2446,14 @@ static SEL swfsSel = 0;
if (![self createSymbolicLinkAtPath: destinationFile
pathContent: path])
{
if (handler)
{
NSDictionary *errorInfo
= [NSDictionary dictionaryWithObjectsAndKeys:
sourceFile, @"Path",
destinationFile, @"ToPath",
@"cannot create symbolic link", @"Error",
nil];
if (![handler fileManager: self
shouldProceedAfterError: errorInfo])
{
return NO;
}
}
else
{
return NO;
}
if (![self _proceedAccordingToHandler: handler
forError: @"cannot create symbolic link"
inPath: sourceFile
fromPath: sourceFile
toPath: destinationFile])
{
return NO;
}
}
}
else
@ -2561,6 +2473,51 @@ static SEL swfsSel = 0;
return YES;
}
- (void) _sendToHandler: (id) handler
willProcessPath: (NSString*) path
{
if ([handler respondsToSelector: @selector (fileManager:willProcessPath:)])
{
[handler fileManager: self willProcessPath: path];
}
}
- (BOOL) _proceedAccordingToHandler: (id) handler
forError: (NSString*) error
inPath: (NSString*) path
{
if ([handler respondsToSelector:
@selector (fileManager:shouldProceedAfterError:)])
{
NSDictionary *errorInfo = [NSDictionary dictionaryWithObjectsAndKeys:
path, @"Path",
error, @"Error", nil];
return [handler fileManager: self
shouldProceedAfterError: errorInfo];
}
return NO;
}
- (BOOL) _proceedAccordingToHandler: (id) handler
forError: (NSString*) error
inPath: (NSString*) path
fromPath: (NSString*) fromPath
toPath: (NSString*) toPath
{
if ([handler respondsToSelector:
@selector (fileManager:shouldProceedAfterError:)])
{
NSDictionary *errorInfo = [NSDictionary dictionaryWithObjectsAndKeys:
path, @"Path",
fromPath, @"FromPath",
toPath, @"ToPath",
error, @"Error", nil];
return [handler fileManager: self
shouldProceedAfterError: errorInfo];
}
return NO;
}
@end /* NSFileManager (PrivateMethods) */