/* EXGNUstepVFS.m Concrete class (partially a cluster) which relies on the GNUstep NSFileManager class for the files interaction Copyright (C) 2004 Quentin Mathe Author: Quentin Mathe Date: July 2004 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #import #import #import "EXAttribute.h" #import "EXFileManager.h" #import "EXVFSHandle.h" #import "EXGNUstepVFS.h" static NSFileManager *fileManager = nil; @interface EXGNUstepVFS (Private) - (void) _isNotFileURL: (NSURL *)url; @end @implementation EXGNUstepVFS + (void) initialize { if (self == [EXGNUstepVFS class]) { fileManager = [NSFileManager defaultManager]; } } - (id) init { // Nothing to initialize } /* - (BOOL) createDirectoryAtURL: (NSURL *)url withPermissions: (unsigned int)perm */ /* * Protocols related methods */ - (NSArray *) supportedProtocols { return [NSArray arrayWithObjects: @"file://", nil]; } /* * Destroy and create contexts */ - (BOOL) createEntityContextAtURL: (NSURL *)url error: (NSError **)error { BOOL result; if ([url isFileURL]) { result = [fileManager p_createDirectoryAtPath: [url path] attributes: nil]; } else { [self _isNotFileURL: url]; result = NO; } return result; } /* - (BOOL) createEntityContextAtURL: (NSURL *)url error: (NSError **)error VFSAttributes: (NSDictionary *) attributes { // TODO: convert EXVFS attributes to NSFileManager attributes return NO; } */ - (BOOL) createElementContextAtURL: (NSURL *)url error: (NSError **)error { BOOL result; if ([url isFileURL]) { result = [fileManager p_createFileAtPath: [url path] contents: nil attributes: nil]; } else { [self _isNotFileURL: url]; result = NO; } return result; } /* - (BOOL) createElementContextAtURL: (NSURL *)url error: (NSError **)error VFSAttributes: (NSDictionary *) attributes { // TODO: convert EXVFS attributes to NSFileManager attributes return NO; } */ - (BOOL) removeContextAtURL: (NSURL *)url handler: (id)handler { BOOL result; if ([url isFileURL]) { result = [fileManager p_removeFileAtPath: [url path] handler: self]; } else { [self _isNotFileURL: url]; result = NO; } return result; } - (BOOL) removeContextsAtURLs: (NSArray *)urls handler: (id)handler { NSEnumerator *e = [urls objectEnumerator]; NSURL *url; BOOL result; while ((url = [e nextObject]) != nil) { if ([url isFileURL]) { result = [fileManager p_removeFileAtPath: [url path] handler: self]; } else { [self _isNotFileURL: url]; result = NO; } } return result; } /* * Manipulate contexts */ - (BOOL) copyContextWithURL: (NSURL *)source toURL: (NSURL *)destination handler: (id)handler { BOOL result = NO; if ([destination isFileURL]) { if ([source isFileURL]) { result = [fileManager p_copyPath: [source path] toPath: [destination path] handler: self]; } else { [self _isNotFileURL: source]; result = NO; } } else { [self _isNotFileURL: destination]; result = NO; } return result; } - (BOOL) copyContextsWithURLs: (NSArray *)sources toURL: (NSURL *)destination handler: (id)handler { NSEnumerator *e = [sources objectEnumerator]; NSURL *url; BOOL result = NO; if ([destination isFileURL] == NO) { [self _isNotFileURL: url]; return NO; } while ((url = [e nextObject]) != nil) { if ([url isFileURL]) { result = [fileManager p_copyPath: [url path] toPath: [destination path] handler: self]; } else { [self _isNotFileURL: url]; result = NO; } } return result; } - (BOOL) linkContextWithURL: (NSURL *)source toURL: (NSURL *)destination handler: (id)handler linkStyle: (EXLinkStyle) style { BOOL result = NO; if ([destination isFileURL]) { if ([source isFileURL]) { result = [fileManager p_linkPath: [source path] toPath: [destination path] handler: self]; } else { [self _isNotFileURL: destination]; result = NO; } } else { [self _isNotFileURL: destination]; result = NO; } return result; } - (BOOL) moveContextWithURL: (NSURL *)source toURL: (NSURL *)destination handler: (id)handler { BOOL result = NO; if ([destination isFileURL]) { if ([source isFileURL]) { result = [fileManager p_movePath: [source path] toPath: [destination path] handler: self]; } else { [self _isNotFileURL: destination]; result = NO; } } else { [self _isNotFileURL: destination]; result = NO; } return result; } - (BOOL) moveContextsWithURLs: (NSArray *)sources toURL: (NSURL *)destination handler: (id)handler { NSEnumerator *e = [sources objectEnumerator]; NSURL *url; BOOL result = NO; if ([destination isFileURL] == NO) { [self _isNotFileURL: url]; return NO; } while ((url = [e nextObject]) != nil) { if ([url isFileURL]) { result = [fileManager p_movePath: [url path] toPath: [destination path] handler: self]; } else { [self _isNotFileURL: url]; result = NO; } } return result; } /* * Visit contexts */ - (NSArray *) subcontextsURLsAtURL: (NSURL *)url deep: (BOOL)flag { NSArray *paths; if ([url isFileURL] == NO) { [self _isNotFileURL: url]; return nil; } if (flag) { paths = [fileManager p_subpathsAtPath: [url path]]; } else { paths = [fileManager p_directoryContentsAtPath: [url path]]; } return paths; } /* * Open, close contexts */ - (EXVFSHandle *) openContextAtURL: (NSURL *)url mode: (EXVFSContentMode)mode { EXVFSHandle *handle; NSFileHandle *fh; if ([url isFileURL] == NO) { [self _isNotFileURL: url]; return nil; } switch (mode) { case EXVFSContentModeRead: fh = [NSFileHandle fileHandleForReadingAtPath: [url path]]; break; case EXVFSContentModeWrite: fh = [NSFileHandle fileHandleForWritingAtPath: [url path]]; break; case EXVFSContentModeReadWrite: fh = [NSFileHandle fileHandleForUpdatingAtPath: [url path]]; break; } return [[EXVFSHandle alloc] initWithFileHandle: fh]; } - (void) closeContextWithVFSHandle: (EXVFSHandle *)handle { NSFileHandle *fh = [handle fileHandle]; [fh closeFile]; } /* * Read, write contexts */ // We need to pass a context and not an URL, because the context can maintain a handle for a file which is open // with an URL, we would need to reopen the file each time we want the handle. - (NSData *) readContextWithVFSHandle: (EXVFSHandle *)handle length: (unsigned long long)length error: (NSError **)error { NSFileHandle *fh; NSData *data; if ([handle fileHandle] != nil) { //[self _isNotFileURL: url]; return NO; } fh = [handle fileHandle]; data = [fh readDataOfLength: length]; return data; } - (void) writeContextWithVFSHandle: (EXVFSHandle *)handle data: (NSData *)data length: (unsigned long long)length error: (NSError **)error { NSFileHandle *fh; NSData *subdata; if ([handle fileHandle] != nil) { //[self _isNotFileURL: url]; } fh = [handle fileHandle]; if ([data length] != length) { subdata = [NSData dataWithBytes: [data bytes] length: length]; } else { subdata = data; } [fh writeData: subdata]; } - (void) setPositionIntoContextWithVFSHandle: (EXVFSHandle *)handle start: (EXReadWritePosition)start offset: (long long)offset error: (NSError **)error { NSFileHandle *fh; NSData *data; unsigned long long size; if ([handle fileHandle] != nil) { //[self _isNotFileURL: url]; } fh = [handle fileHandle]; switch (start) { case EXReadWritePositionStart: [fh seekToFileOffset: offset]; break; case EXReadWritePositionEnd: size = [fh seekToEndOfFile]; [fh seekToFileOffset: size - offset]; break; } } - (long long) positionIntoContextWithVFSHandle: (EXVFSHandle *)handle error: (NSError **)error { NSFileHandle *fh; unsigned long long offset; if ([handle fileHandle] != nil) { //[self _isNotFileURL: url]; return NO; } fh = [handle fileHandle]; offset = [fh offsetInFile]; return offset; } /* * Posix attributes related methods */ - (NSDictionary *) posixAttributesAtURL: (NSURL *)url { NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity: 10]; NSDictionary *fmDict; NSString *value; if ([url isFileURL] == NO) { [self _isNotFileURL: url]; return nil; } fmDict = [fileManager p_fileAttributesAtPath: [url path] traverseLink: NO]; [dict setObject: [fmDict objectForKey: NSFileCreationDate] forKey: EXAttributeCreationDate]; [dict setObject: [fmDict objectForKey: NSFileSize] forKey: EXAttributeSize]; [dict setObject: [fmDict objectForKey: NSFileModificationDate] forKey: EXAttributeModificationDate]; [dict setObject: [fmDict objectForKey: NSFileType] forKey: EXAttributeFSType]; [dict setObject: [fmDict objectForKey: NSFilePosixPermissions] forKey: EXAttributePosixPermissions]; [dict setObject: [fmDict objectForKey: NSFileOwnerAccountID] forKey: EXAttributeOwnerNumber]; [dict setObject: [fmDict objectForKey: NSFileOwnerAccountName] forKey: EXAttributeOwnerName]; [dict setObject: [fmDict objectForKey: NSFileGroupOwnerAccountID] forKey: EXAttributeGroupOwnerNumber]; [dict setObject: [fmDict objectForKey: NSFileGroupOwnerAccountName] forKey: EXAttributeGroupOwnerName]; [dict setObject: [fmDict objectForKey: NSFileDeviceIdentifier] forKey: EXAttributeDeviceNumber]; [dict setObject: [fmDict objectForKey: NSFileSystemFileNumber] forKey: EXAttributeFSNumber]; value = [dict objectForKey: EXAttributeFSType]; if ([value isEqualToString: NSFileTypeDirectory]) [dict setObject: EXFSTypeDirectory forKey: EXAttributeFSType]; else if ([value isEqualToString: NSFileTypeRegular]) [dict setObject: EXFSTypeRegular forKey: EXAttributeFSType]; else if ([value isEqualToString: NSFileTypeSymbolicLink]) [dict setObject: EXFSTypeSymbolicLink forKey: EXAttributeFSType]; else if ([value isEqualToString: NSFileTypeSocket]) [dict setObject: EXFSTypeSocket forKey: EXAttributeFSType]; else if ([value isEqualToString: NSFileTypeCharacterSpecial]) [dict setObject: EXFSTypeCharacterSpecial forKey: EXAttributeFSType]; else if ([value isEqualToString: NSFileTypeBlockSpecial]) [dict setObject: EXFSTypeBlockSpecial forKey: EXAttributeFSType]; else if ([value isEqualToString: NSFileTypeUnknown]) [dict setObject: EXFSTypeUnknown forKey: EXAttributeFSType]; return dict; } - (id) posixAttributeWithName: (NSString *)name atURL: (NSURL *)url { return [[self posixAttributesAtURL: url] objectForKey: name]; } /* * Extra methods */ - (BOOL) isEntityContextAtURL: (NSURL *)url { BOOL isDir; BOOL result; if ([url isFileURL] == NO) { [self _isNotFileURL: url]; return NO; } result = [fileManager p_fileExistsAtPath: [url path] isDirectory: &isDir]; if (result && isDir) { return YES; } else { return NO; } } - (BOOL) isElementContextAtURL: (NSURL *)url { BOOL isDir; BOOL result; if ([url isFileURL] == NO) { [self _isNotFileURL: url]; return NO; } result = [fileManager p_fileExistsAtPath: [url path] isDirectory: &isDir]; if (result && !isDir) { return YES; } else { return NO; } } - (void) _isNotFileURL: (NSURL *)url { NSLog(@"GNUstep VFS backend doesn't support the URL %@ because it is not a local file.", url); } @end