Index: src/OFFileManager.m ================================================================== --- src/OFFileManager.m +++ src/OFFileManager.m @@ -39,10 +39,11 @@ #import "OFURL.h" #import "OFURLHandler.h" #import "OFChangeCurrentDirectoryPathFailedException.h" #import "OFCopyItemFailedException.h" +#import "OFCreateDirectoryFailedException.h" #import "OFGetCurrentDirectoryPathFailedException.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFMoveItemFailedException.h" #import "OFOutOfMemoryException.h" @@ -318,10 +319,32 @@ if (!createParents) { [self createDirectoryAtURL: URL]; return; } + + /* + * Try blindly creating the directory first. + * + * The reason for this is that we might be sandboxed, so attempting to + * create any of the parent directories will fail, while creating the + * directory itself will work. + */ + if ([self directoryExistsAtURL: URL]) + return; + + @try { + [self createDirectoryAtURL: URL]; + return; + } @catch (OFCreateDirectoryFailedException *e) { + /* + * If we didn't fail because any of the parents is missing, + * there is no point in trying to create the parents. + */ + if ([e errNo] != ENOENT) + @throw e; + } components = [[URL URLEncodedPath] componentsSeparatedByString: @"/"]; for (OFString *component in components) { if (currentPath != nil) Index: src/OFString+PathAdditions.h ================================================================== --- src/OFString+PathAdditions.h +++ src/OFString+PathAdditions.h @@ -16,10 +16,16 @@ */ #import "OFString.h" OF_ASSUME_NONNULL_BEGIN + +#ifdef OF_AMIGAOS +# define OF_PATH_CURRENT_DIRECTORY @"" +#else +# define OF_PATH_CURRENT_DIRECTORY @"." +#endif #ifdef __cplusplus extern "C" { #endif extern int _OFString_PathAdditions_reference; Index: src/OFURLHandler_file.m ================================================================== --- src/OFURLHandler_file.m +++ src/OFURLHandler_file.m @@ -37,10 +37,11 @@ #import "OFURLHandler_file.h" #import "OFArray.h" #import "OFDate.h" #import "OFFile.h" +#import "OFFileManager.h" #import "OFLocale.h" #import "OFNumber.h" #import "OFURL.h" #ifdef OF_HAVE_THREADS Index: utils/ofarc/OFArc.m ================================================================== --- utils/ofarc/OFArc.m +++ utils/ofarc/OFArc.m @@ -173,23 +173,22 @@ of_string_encoding_t encoding = OF_STRING_ENCODING_AUTODETECT; OFArray OF_GENERIC(OFString *) *remainingArguments, *files; id archive; #ifdef OF_HAVE_SANDBOX - OFSandbox *sandbox = [[OFSandbox alloc] init]; - @try { - [sandbox setAllowsStdIO: true]; - [sandbox setAllowsReadingFiles: true]; - [sandbox setAllowsWritingFiles: true]; - [sandbox setAllowsCreatingFiles: true]; - [sandbox setAllowsChangingFileAttributes: true]; - [sandbox setAllowsUserDatabaseReading: true]; - - [OFApplication activateSandbox: sandbox]; - } @finally { - [sandbox release]; - } + OFSandbox *sandbox = [OFSandbox sandbox]; + + [sandbox setAllowsStdIO: true]; + [sandbox setAllowsReadingFiles: true]; + [sandbox setAllowsWritingFiles: true]; + [sandbox setAllowsCreatingFiles: true]; + [sandbox setAllowsChangingFileAttributes: true]; + [sandbox setAllowsUserDatabaseReading: true]; + /* Dropped after parsing options */ + [sandbox setAllowsUnveil: true]; + + [OFApplication activateSandbox: sandbox]; #endif #ifndef OF_AMIGAOS [OFLocale addLanguageDirectory: @LANGUAGE_DIR]; #else @@ -310,18 +309,10 @@ [OFApplication terminateWithStatus: 1]; } remainingArguments = [optionsParser remainingArguments]; - archive = [self openArchiveWithPath: [remainingArguments firstObject] - type: type - mode: mode - encoding: encoding]; - - if (outputDir != nil) - [[OFFileManager defaultManager] - changeCurrentDirectoryPath: outputDir]; switch (mode) { case 'a': case 'c': if ([remainingArguments count] < 1) @@ -328,34 +319,108 @@ help(of_stderr, false, 1); files = [remainingArguments objectsInRange: of_range(1, [remainingArguments count] - 1)]; +#ifdef OF_HAVE_SANDBOX + [sandbox unveilPath: [remainingArguments firstObject] + permissions: (mode == 'a' ? @"rwc" : @"wc")]; + + for (OFString *path in files) + [sandbox unveilPath: path + permissions: @"r"]; + + [sandbox setAllowsUnveil: false]; + [OFApplication activateSandbox: sandbox]; +#endif + + archive = [self + openArchiveWithPath: [remainingArguments firstObject] + type: type + mode: mode + encoding: encoding]; + [archive addFiles: files]; break; case 'l': if ([remainingArguments count] != 1) help(of_stderr, false, 1); +#ifdef OF_HAVE_SANDBOX + [sandbox unveilPath: [remainingArguments firstObject] + permissions: @"r"]; + [sandbox setAllowsUnveil: false]; + [OFApplication activateSandbox: sandbox]; +#endif + + archive = [self + openArchiveWithPath: [remainingArguments firstObject] + type: type + mode: mode + encoding: encoding]; + [archive listFiles]; break; case 'p': if ([remainingArguments count] < 1) help(of_stderr, false, 1); + +#ifdef OF_HAVE_SANDBOX + [sandbox unveilPath: [remainingArguments firstObject] + permissions: @"r"]; + [sandbox setAllowsUnveil: false]; + [OFApplication activateSandbox: sandbox]; +#endif files = [remainingArguments objectsInRange: of_range(1, [remainingArguments count] - 1)]; + archive = [self + openArchiveWithPath: [remainingArguments firstObject] + type: type + mode: mode + encoding: encoding]; + [archive printFiles: files]; break; case 'x': if ([remainingArguments count] < 1) help(of_stderr, false, 1); files = [remainingArguments objectsInRange: of_range(1, [remainingArguments count] - 1)]; +#ifdef OF_HAVE_SANDBOX + [sandbox unveilPath: [remainingArguments firstObject] + permissions: @"r"]; + + if ([files count] > 0) + for (OFString *path in files) + [sandbox unveilPath: path + permissions: @"wc"]; + else { + OFString *path = (outputDir != nil + ? outputDir : OF_PATH_CURRENT_DIRECTORY); + /* We need 'r' to change the directory to it. */ + [sandbox unveilPath: path + permissions: @"rwc"]; + } + + [sandbox setAllowsUnveil: false]; + [OFApplication activateSandbox: sandbox]; +#endif + + archive = [self + openArchiveWithPath: [remainingArguments firstObject] + type: type + mode: mode + encoding: encoding]; + + if (outputDir != nil) + [[OFFileManager defaultManager] + changeCurrentDirectoryPath: outputDir]; + @try { [archive extractFiles: files]; } @catch (OFCreateDirectoryFailedException *e) { OFString *error = [OFString stringWithCString: strerror([e errNo])