@@ -28,14 +28,17 @@ #endif #import "OFArray.h" #import "OFDate.h" #import "OFDictionary.h" -#import "OFFile.h" +#ifdef OF_HAVE_FILES +# import "OFFile.h" +#endif #import "OFFileManager.h" #import "OFLocale.h" #import "OFNumber.h" +#import "OFStream.h" #import "OFString.h" #import "OFSystemInfo.h" #import "OFURL.h" #import "OFURLHandler.h" @@ -44,14 +47,16 @@ #import "OFCreateDirectoryFailedException.h" #import "OFGetCurrentDirectoryPathFailedException.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFMoveItemFailedException.h" +#import "OFNotImplementedException.h" #import "OFOutOfMemoryException.h" #import "OFOutOfRangeException.h" #import "OFRemoveItemFailedException.h" #import "OFRetrieveItemAttributesFailedException.h" +#import "OFUndefinedKeyException.h" #import "OFUnsupportedProtocolException.h" #ifdef OF_WINDOWS # include # include @@ -70,10 +75,42 @@ #endif @interface OFFileManager_default: OFFileManager @end +const of_file_attribute_key_t of_file_attribute_key_size = + @"of_file_attribute_key_size"; +const of_file_attribute_key_t of_file_attribute_key_type = + @"of_file_attribute_key_type"; +const of_file_attribute_key_t of_file_attribute_key_posix_permissions = + @"of_file_attribute_key_posix_permissions"; +const of_file_attribute_key_t of_file_attribute_key_posix_uid = + @"of_file_attribute_key_posix_uid"; +const of_file_attribute_key_t of_file_attribute_key_posix_gid = + @"of_file_attribute_key_posix_gid"; +const of_file_attribute_key_t of_file_attribute_key_owner = + @"of_file_attribute_key_owner"; +const of_file_attribute_key_t of_file_attribute_key_group = + @"of_file_attribute_key_group"; +const of_file_attribute_key_t of_file_attribute_key_last_access_date = + @"of_file_attribute_key_last_access_date"; +const of_file_attribute_key_t of_file_attribute_key_modification_date = + @"of_file_attribute_key_modification_date"; +const of_file_attribute_key_t of_file_attribute_key_status_change_date = + @"of_file_attribute_key_status_change_date"; +const of_file_attribute_key_t of_file_attribute_key_symbolic_link_destination = + @"of_file_attribute_key_symbolic_link_destination"; + +const of_file_type_t of_file_type_regular = @"of_file_type_regular"; +const of_file_type_t of_file_type_directory = @"of_file_type_directory"; +const of_file_type_t of_file_type_symbolic_link = @"of_file_type_symbolic_link"; +const of_file_type_t of_file_type_fifo = @"of_file_type_fifo"; +const of_file_type_t of_file_type_character_special = + @"of_file_type_character_special"; +const of_file_type_t of_file_type_block_special = @"of_file_type_block_special"; +const of_file_type_t of_file_type_socket = @"of_file_type_socket"; + #ifdef OF_AMIGAOS4 extern struct ExecIFace *IExec; static struct Library *DOSBase = NULL; static struct DOSIFace *IDOS = NULL; #endif @@ -96,10 +133,23 @@ if (DOSBase != NULL) CloseLibrary(DOSBase); # endif } #endif + +static id +attributeForKeyOrException(of_file_attributes_t attributes, + of_file_attribute_key_t key) +{ + id object = [attributes objectForKey: key]; + + if (object == nil) + @throw [OFUndefinedKeyException exceptionWithObject: attributes + key: key]; + + return object; +} @implementation OFFileManager + (void)initialize { if (self != [OFFileManager class]) @@ -114,27 +164,30 @@ GetInterface(DOSBase, "main", 1, NULL)) == NULL) @throw [OFInitializationFailedException exceptionWithClass: self]; #endif +#ifdef OF_HAVE_FILES /* * Make sure OFFile is initialized. * On some systems, this is needed to initialize the file system driver. */ [OFFile class]; +#endif defaultManager = [[OFFileManager_default alloc] init]; } + (OFFileManager *)defaultManager { return defaultManager; } +#ifdef OF_HAVE_FILES - (OFString *)currentDirectoryPath { -#if defined(OF_WINDOWS) +# if defined(OF_WINDOWS) OFString *ret; wchar_t *buffer = _wgetcwd(NULL, 0); @try { ret = [OFString stringWithUTF16String: buffer]; @@ -141,11 +194,11 @@ } @finally { free(buffer); } return ret; -#elif defined(OF_AMIGAOS) +# elif defined(OF_AMIGAOS) char buffer[512]; if (!NameFromLock(((struct Process *)FindTask(NULL))->pr_CurrentDir, buffer, 512)) { if (IoErr() == ERROR_LINE_TOO_LONG) @@ -154,30 +207,30 @@ return nil; } return [OFString stringWithCString: buffer encoding: [OFLocale encoding]]; -#else +# else char buffer[PATH_MAX]; if ((getcwd(buffer, PATH_MAX)) == NULL) @throw [OFGetCurrentDirectoryPathFailedException exceptionWithErrNo: errno]; -# ifdef OF_DJGPP +# ifdef OF_DJGPP /* * For some reason, getcwd() returns forward slashes on DJGPP, even * though the native format is to use backwards slashes. */ for (char *tmp = buffer; *tmp != '\0'; tmp++) if (*tmp == '/') *tmp = '\\'; -# endif +# endif return [OFString stringWithCString: buffer encoding: [OFLocale encoding]]; -#endif +# endif } - (OFURL *)currentDirectoryURL { void *pool = objc_autoreleasePoolPush(); @@ -187,10 +240,11 @@ [ret retain]; objc_autoreleasePoolPop(pool); return [ret autorelease]; } +#endif - (of_file_attributes_t)attributesOfItemAtURL: (OFURL *)URL { OFURLHandler *URLHandler; @@ -201,10 +255,11 @@ @throw [OFUnsupportedProtocolException exceptionWithURL: URL]; return [URLHandler attributesOfItemAtURL: URL]; } +#ifdef OF_HAVE_FILES - (of_file_attributes_t)attributesOfItemAtPath: (OFString *)path { void *pool = objc_autoreleasePoolPush(); of_file_attributes_t ret; @@ -214,10 +269,11 @@ objc_autoreleasePoolPop(pool); return [ret autorelease]; } +#endif - (void)setAttributes: (of_file_attributes_t)attributes ofItemAtURL: (OFURL *)URL { OFURLHandler *URLHandler; @@ -230,10 +286,11 @@ [URLHandler setAttributes: attributes ofItemAtURL: URL]; } +#ifdef OF_HAVE_FILES - (void)setAttributes: (of_file_attributes_t)attributes ofItemAtPath: (OFString *)path { void *pool = objc_autoreleasePoolPush(); @@ -240,10 +297,11 @@ [self setAttributes: attributes ofItemAtURL: [OFURL fileURLWithPath: path]]; objc_autoreleasePoolPop(pool); } +#endif - (bool)fileExistsAtURL: (OFURL *)URL { OFURLHandler *URLHandler; @@ -254,10 +312,11 @@ @throw [OFUnsupportedProtocolException exceptionWithURL: URL]; return [URLHandler fileExistsAtURL: URL]; } +#ifdef OF_HAVE_FILES - (bool)fileExistsAtPath: (OFString *)path { void *pool = objc_autoreleasePoolPush(); bool ret; @@ -265,10 +324,11 @@ objc_autoreleasePoolPop(pool); return ret; } +#endif - (bool)directoryExistsAtURL: (OFURL *)URL { OFURLHandler *URLHandler; @@ -279,10 +339,11 @@ @throw [OFUnsupportedProtocolException exceptionWithURL: URL]; return [URLHandler directoryExistsAtURL: URL]; } +#ifdef OF_HAVE_FILES - (bool)directoryExistsAtPath: (OFString *)path { void *pool = objc_autoreleasePoolPush(); bool ret; @@ -290,10 +351,11 @@ objc_autoreleasePoolPop(pool); return ret; } +#endif - (void)createDirectoryAtURL: (OFURL *)URL { OFURLHandler *URLHandler; @@ -355,10 +417,11 @@ } objc_autoreleasePoolPop(pool); } +#ifdef OF_HAVE_FILES - (void)createDirectoryAtPath: (OFString *)path { void *pool = objc_autoreleasePoolPush(); [self createDirectoryAtURL: [OFURL fileURLWithPath: path]]; @@ -374,10 +437,11 @@ [self createDirectoryAtURL: [OFURL fileURLWithPath: path] createParents: createParents]; objc_autoreleasePoolPop(pool); } +#endif - (OFArray OF_GENERIC(OFString *) *)contentsOfDirectoryAtURL: (OFURL *)URL { OFURLHandler *URLHandler; @@ -388,10 +452,11 @@ @throw [OFUnsupportedProtocolException exceptionWithURL: URL]; return [URLHandler contentsOfDirectoryAtURL: URL]; } +#ifdef OF_HAVE_FILES - (OFArray OF_GENERIC(OFString *) *)contentsOfDirectoryAtPath: (OFString *)path { void *pool = objc_autoreleasePoolPush(); OFArray OF_GENERIC(OFString *) *ret; @@ -407,16 +472,16 @@ - (void)changeCurrentDirectoryPath: (OFString *)path { if (path == nil) @throw [OFInvalidArgumentException exception]; -#if defined(OF_WINDOWS) +# if defined(OF_WINDOWS) if (_wchdir(path.UTF16String) != 0) @throw [OFChangeCurrentDirectoryPathFailedException exceptionWithPath: path errNo: errno]; -#elif defined(OF_AMIGAOS) +# elif defined(OF_AMIGAOS) BPTR lock, oldLock; if ((lock = Lock([path cStringWithEncoding: [OFLocale encoding]], SHARED_LOCK)) == 0) { int errNo; @@ -445,16 +510,16 @@ originalDirLock = oldLock; else UnLock(oldLock); dirChanged = true; -#else +# else if (chdir([path cStringWithEncoding: [OFLocale encoding]]) != 0) @throw [OFChangeCurrentDirectoryPathFailedException exceptionWithPath: path errNo: errno]; -#endif +# endif } - (void)changeCurrentDirectoryURL: (OFURL *)URL { void *pool = objc_autoreleasePoolPush(); @@ -472,10 +537,11 @@ [self copyItemAtURL: [OFURL fileURLWithPath: source] toURL: [OFURL fileURLWithPath: destination]]; objc_autoreleasePoolPop(pool); } +#endif - (void)copyItemAtURL: (OFURL *)source toURL: (OFURL *)destination { void *pool; @@ -517,21 +583,27 @@ OFArray *contents; @try { [self createDirectoryAtURL: destination]; -#ifdef OF_FILE_MANAGER_SUPPORTS_PERMISSIONS - of_file_attribute_key_t key = - of_file_attribute_key_posix_permissions; - OFNumber *permissions = [attributes objectForKey: key]; - of_file_attributes_t destinationAttributes = - [OFDictionary dictionaryWithObject: permissions - forKey: key]; - - [self setAttributes: destinationAttributes - ofItemAtURL: destination]; -#endif + @try { + of_file_attribute_key_t key = + of_file_attribute_key_posix_permissions; + OFNumber *permissions = + [attributes objectForKey: key]; + of_file_attributes_t destinationAttributes; + + if (permissions != nil) { + destinationAttributes = [OFDictionary + dictionaryWithObject: permissions + forKey: key]; + [self + setAttributes: destinationAttributes + ofItemAtURL: destination]; + } + } @catch (OFNotImplementedException *e) { + } contents = [self contentsOfDirectoryAtURL: source]; } @catch (id e) { /* * Only convert exceptions to OFCopyItemFailedException @@ -588,21 +660,27 @@ length: pageSize]; [destinationStream writeBuffer: buffer length: length]; } -#ifdef OF_FILE_MANAGER_SUPPORTS_PERMISSIONS - of_file_attribute_key_t key = - of_file_attribute_key_posix_permissions; - OFNumber *permissions = [attributes objectForKey: key]; - of_file_attributes_t destinationAttributes = - [OFDictionary dictionaryWithObject: permissions - forKey: key]; - - [self setAttributes: destinationAttributes - ofItemAtURL: destination]; -#endif + @try { + of_file_attribute_key_t key = + of_file_attribute_key_posix_permissions; + OFNumber *permissions = [attributes + objectForKey: key]; + of_file_attributes_t destinationAttributes; + + if (permissions != nil) { + destinationAttributes = [OFDictionary + dictionaryWithObject: permissions + forKey: key]; + [self + setAttributes: destinationAttributes + ofItemAtURL: destination]; + } + } @catch (OFNotImplementedException *e) { + } } @catch (id e) { /* * Only convert exceptions to OFCopyItemFailedException * that have an errNo property. This covers all I/O * related exceptions from the operations used to copy @@ -618,11 +696,10 @@ } @finally { [sourceStream close]; [destinationStream close]; free(buffer); } -#ifdef OF_FILE_MANAGER_SUPPORTS_SYMLINKS } else if ([type isEqual: of_file_type_symbolic_link]) { @try { OFString *linkDestination = attributes.fileSymbolicLinkDestination; @@ -641,20 +718,20 @@ destinationURL: destination errNo: [e errNo]]; @throw e; } -#endif } else @throw [OFCopyItemFailedException exceptionWithSourceURL: source destinationURL: destination errNo: EINVAL]; objc_autoreleasePoolPop(pool); } +#ifdef OF_HAVE_FILES - (void)moveItemAtPath: (OFString *)source toPath: (OFString *)destination { void *pool = objc_autoreleasePoolPush(); @@ -661,10 +738,11 @@ [self moveItemAtURL: [OFURL fileURLWithPath: source] toURL: [OFURL fileURLWithPath: destination]]; objc_autoreleasePoolPop(pool); } +#endif - (void)moveItemAtURL: (OFURL *)source toURL: (OFURL *)destination { void *pool; @@ -729,18 +807,20 @@ @throw [OFUnsupportedProtocolException exceptionWithURL: URL]; [URLHandler removeItemAtURL: URL]; } +#ifdef OF_HAVE_FILES - (void)removeItemAtPath: (OFString *)path { void *pool = objc_autoreleasePoolPush(); [self removeItemAtURL: [OFURL fileURLWithPath: path]]; objc_autoreleasePoolPop(pool); } +#endif - (void)linkItemAtURL: (OFURL *)source toURL: (OFURL *)destination { void *pool = objc_autoreleasePoolPush(); @@ -829,5 +909,70 @@ - (unsigned int)retainCount { return OF_RETAIN_COUNT_MAX; } @end + +@implementation OFDictionary (FileAttributes) +- (uintmax_t)fileSize +{ + return [attributeForKeyOrException(self, of_file_attribute_key_size) + uIntMaxValue]; +} + +- (of_file_type_t)fileType +{ + return attributeForKeyOrException(self, of_file_attribute_key_type); +} + +- (uint16_t)filePOSIXPermissions +{ + return [attributeForKeyOrException(self, + of_file_attribute_key_posix_permissions) uInt16Value]; +} + +- (uint32_t)filePOSIXUID +{ + return [attributeForKeyOrException(self, + of_file_attribute_key_posix_uid) uInt32Value]; +} + +- (uint32_t)filePOSIXGID +{ + return [attributeForKeyOrException(self, + of_file_attribute_key_posix_gid) uInt32Value]; +} + +- (OFString *)fileOwner +{ + return attributeForKeyOrException(self, of_file_attribute_key_owner); +} + +- (OFString *)fileGroup +{ + return attributeForKeyOrException(self, of_file_attribute_key_group); +} + +- (OFDate *)fileLastAccessDate +{ + return attributeForKeyOrException(self, + of_file_attribute_key_last_access_date); +} + +- (OFDate *)fileModificationDate +{ + return attributeForKeyOrException(self, + of_file_attribute_key_modification_date); +} + +- (OFDate *)fileStatusChangeDate +{ + return attributeForKeyOrException(self, + of_file_attribute_key_status_change_date); +} + +- (OFString *)fileSymbolicLinkDestination +{ + return attributeForKeyOrException(self, + of_file_attribute_key_symbolic_link_destination); +} +@end