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> 2003-02-11 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSFileManager.m: ([+attributesAt:traverseLink:]) check for * Source/NSFileManager.m: ([+attributesAt:traverseLink:]) check for

View file

@ -102,11 +102,41 @@
*/ */
@interface NSObject (NSFileManagerHandler) @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 * will send this message to the handler, and will use the return value to
* determine whether the operation should proceed. If the method returns * determine whether the operation should proceed. If the method returns
* YES then the operation will proceed after the error, if it returns NO * YES then the operation will proceed after the error, if it returns NO
* then it will be aborted. * 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 - (BOOL) fileManager: (NSFileManager*)fileManager
shouldProceedAfterError: (NSDictionary*)errorDictionary; shouldProceedAfterError: (NSDictionary*)errorDictionary;
@ -115,7 +145,7 @@
* The file manager sends this method to the handler immediately before * The file manager sends this method to the handler immediately before
* performing part of a directory move or copy operation. This provides * performing part of a directory move or copy operation. This provides
* the handler object with information it can use in the event of an * 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 - (void) fileManager: (NSFileManager*)fileManager
willProcessPath: (NSString*)path; willProcessPath: (NSString*)path;

View file

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