From 8c73785d19c78c4ac66c1d6c8165072adfdfcfb8 Mon Sep 17 00:00:00 2001 From: MartinLau Date: Mon, 24 Jun 2019 20:11:16 +0800 Subject: [PATCH 01/14] Support archival and restoration of POSIX permissions (#84) Merging @MartinLau7's code from PR #84, as a WIP --- Source/UZKArchive.h | 62 +++++++++--------- Source/UZKArchive.m | 56 ++++++++++++++-- Source/UZKFileInfo.h | 15 ++++- Source/UZKFileInfo.m | 22 ++++++- Tests/FileDescriptorUsageTests.m | 1 + Tests/PrmissionsTests.m | 64 +++++++++++++++++++ Tests/Test Data/Test Permissions Archive.zip | Bin 0 -> 4165 bytes Tests/UZKArchiveTestCase.m | 3 +- UnzipKit.xcodeproj/project.pbxproj | 16 +++-- 9 files changed, 195 insertions(+), 44 deletions(-) create mode 100644 Tests/PrmissionsTests.m create mode 100644 Tests/Test Data/Test Permissions Archive.zip diff --git a/Source/UZKArchive.h b/Source/UZKArchive.h index a77856f..3b77d96 100644 --- a/Source/UZKArchive.h +++ b/Source/UZKArchive.h @@ -593,26 +593,26 @@ compressionMethod:(UZKCompressionMethod)method error:(NSError **)error __deprecated_msg("Use -writeData:filePath:fileDate:compressionMethod:password:error: instead, and if using the progress block, replace with NSProgress as described in the README"); /** - * Writes the data to the zip file, overwriting only if specified with the overwrite flag. Overwriting - * presents a tradeoff: the whole archive needs to be copied (minus the file to be overwritten) before - * the write begins. For a large archive, this can be slow. On the other hand, when not overwriting, - * the size of the archive will grow each time the file is written. - * - * @param data Data to write into the archive - * @param filePath The full path to the target file in the archive - * @param fileDate The timestamp of the file in the archive. Uses the current time if nil - * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) - * @param password Override the password associated with the archive (not recommended) - * @param overwrite If YES, and the file exists, delete it before writing. If NO, append - * the data into the archive without removing it first (legacy Objective-Zip - * behavior) - * @param error Contains an NSError object when there was an error writing to the archive - * - * @return YES if successful, NO on error + Writes the data to the zip file, overwriting only if specified with the overwrite flag. Overwriting + presents a tradeoff: the whole archive needs to be copied (minus the file to be overwritten) before + the write begins. For a large archive, this can be slow. On the other hand, when not overwriting, + the size of the archive will grow each time the file is written. + + @param data Data to write into the archive + @param filePath The full path to the target file in the archive + @param fileDate The timestamp of the file in the archive. Uses the current time if nil + @param posixPermissions the source posix permissions of the file in the archive + @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + @param password Override the password associated with the archive (not recommended) + @param overwrite If YES, and the file exists, delete it before writing. If NO, + append the data into the archive without removing it first (legacy Objective-Zip behavior) + @param error Contains an NSError object when there was an error writing to the archive + @return YES if successful, NO on error */ - (BOOL)writeData:(NSData *)data filePath:(NSString *)filePath fileDate:(nullable NSDate *)fileDate + posixPermissions:(unsigned long)posixPermissions compressionMethod:(UZKCompressionMethod)method password:(nullable NSString *)password overwrite:(BOOL)overwrite @@ -800,20 +800,21 @@ compressionMethod:(UZKCompressionMethod)method * be slow. On the other hand, when not overwriting, the size of the archive will grow each time * the file is written. * - * @param filePath The full path to the target file in the archive - * @param fileDate The timestamp of the file in the archive. Uses the current time if nil - * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) - * @param overwrite If YES, and the file exists, delete it before writing. If NO, append - * the data into the archive without removing it first (legacy Objective-Zip - * behavior) - * @param preCRC The CRC-32 for the data being sent. Only necessary if encrypting the file. - Pass 0 otherwise - * @param password Override the password associated with the archive (not recommended) - * @param error Contains an NSError object when there was an error writing to the archive - * @param action Contains your code to loop through the source bytes and write them to the - * archive. Each time a chunk of data is ready to be written, call writeData, - * passing in a pointer to the bytes and their length. Return YES if successful, - * or NO on error (in which case, you should assign the actionError parameter + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param posixPermissions the source posix permissions of the file in the archive + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @param preCRC The CRC-32 for the data being sent. Only necessary if encrypting the file. + Pass 0 otherwise + * @param password Override the password associated with the archive (not recommended) + * @param error Contains an NSError object when there was an error writing to the archive + * @param action Contains your code to loop through the source bytes and write them to the + * archive. Each time a chunk of data is ready to be written, call writeData, + * passing in a pointer to the bytes and their length. Return YES if successful, + * or NO on error (in which case, you should assign the actionError parameter * * - *writeData* Call this block to write some bytes into the archive. It returns NO if the * write failed. If this happens, you should return from the action block, and @@ -824,6 +825,7 @@ compressionMethod:(UZKCompressionMethod)method */ - (BOOL)writeIntoBuffer:(NSString *)filePath fileDate:(nullable NSDate *)fileDate + posixPermissions:(unsigned long)posixPermissions compressionMethod:(UZKCompressionMethod)method overwrite:(BOOL)overwrite CRC:(unsigned long)preCRC diff --git a/Source/UZKArchive.m b/Source/UZKArchive.m index 78f58ea..22660bc 100644 --- a/Source/UZKArchive.m +++ b/Source/UZKArchive.m @@ -626,7 +626,10 @@ - (BOOL)extractFilesTo:(NSString *)destinationDirectory UZKLogDebug("Closing file handle"); [deflatedFileHandle closeFile]; - NSDictionary* attribs = [NSDictionary dictionaryWithObjectsAndKeys:info.timestamp, NSFileModificationDate, nil]; + // Retain the permission attribute of a file + NSDictionary* attribs = @{NSFileModificationDate: info.timestamp, + NSFilePosixPermissions: info.posixPermissions}; + [[NSFileManager defaultManager] setAttributes:attribs ofItemAtPath:path error:nil]; if (!extractSuccess) { @@ -1058,6 +1061,7 @@ - (BOOL)writeData:(NSData *)data return [self writeData:data filePath:filePath fileDate:nil + posixPermissions:0 compressionMethod:UZKCompressionMethodDefault password:nil overwrite:YES @@ -1072,6 +1076,7 @@ - (BOOL)writeData:(NSData *)data return [self writeData:data filePath:filePath fileDate:nil + posixPermissions:0 compressionMethod:UZKCompressionMethodDefault password:nil overwrite:YES @@ -1087,6 +1092,7 @@ - (BOOL)writeData:(NSData *)data return [self writeData:data filePath:filePath fileDate:fileDate + posixPermissions:0 compressionMethod:UZKCompressionMethodDefault password:nil overwrite:YES @@ -1119,6 +1125,7 @@ - (BOOL)writeData:(NSData *)data return [self writeData:data filePath:filePath fileDate:fileDate + posixPermissions:0 compressionMethod:method password:password overwrite:YES @@ -1145,18 +1152,20 @@ - (BOOL)writeData:(NSData *)data - (BOOL)writeData:(NSData *)data filePath:(NSString *)filePath - fileDate:(NSDate *)fileDate + fileDate:(nullable NSDate *)fileDate + posixPermissions:(unsigned long)posixPermissions compressionMethod:(UZKCompressionMethod)method - password:(NSString *)password + password:(nullable NSString *)password overwrite:(BOOL)overwrite - error:(NSError * __autoreleasing*)error + error:(NSError *__autoreleasing*)error { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" return [self writeData:data filePath:filePath fileDate:fileDate - compressionMethod:method + posixPermissions:posixPermissions + compressionMethod:UZKCompressionMethodDefault password:password overwrite:overwrite progress:nil @@ -1172,6 +1181,27 @@ - (BOOL)writeData:(NSData *)data overwrite:(BOOL)overwrite progress:(void (^)(CGFloat percentCompressed))progressBlock error:(NSError * __autoreleasing*)error +{ + return [self writeData:data + filePath:filePath + fileDate:fileDate + posixPermissions:0 + compressionMethod:method + password:password + overwrite:overwrite + error:error]; +} + + +- (BOOL)writeData:(NSData *)data + filePath:(NSString *)filePath + fileDate:(NSDate *)fileDate + posixPermissions:(unsigned long)posixPermissions +compressionMethod:(UZKCompressionMethod)method + password:(NSString *)password + overwrite:(BOOL)overwrite + progress:(void (^)(CGFloat percentCompressed))progressBlock + error:(NSError * __autoreleasing*)error { UZKCreateActivity("Writing Data"); @@ -1228,6 +1258,7 @@ - (BOOL)writeData:(NSData *)data } filePath:filePath fileDate:fileDate + posixPermissions:posixPermissions compressionMethod:method password:password overwrite:overwrite @@ -1243,6 +1274,7 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath { return [self writeIntoBuffer:filePath fileDate:nil + posixPermissions:0 compressionMethod:UZKCompressionMethodDefault overwrite:YES CRC:0 @@ -1258,6 +1290,7 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath { return [self writeIntoBuffer:filePath fileDate:fileDate + posixPermissions:0 compressionMethod:UZKCompressionMethodDefault overwrite:YES CRC:0 @@ -1274,6 +1307,7 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath { return [self writeIntoBuffer:filePath fileDate:fileDate + posixPermissions:0 compressionMethod:method overwrite:YES CRC:0 @@ -1291,6 +1325,7 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath { return [self writeIntoBuffer:filePath fileDate:fileDate + posixPermissions:0 compressionMethod:method overwrite:overwrite CRC:0 @@ -1309,6 +1344,7 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath { return [self writeIntoBuffer:filePath fileDate:fileDate + posixPermissions:0 compressionMethod:method overwrite:overwrite CRC:preCRC @@ -1319,6 +1355,7 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath - (BOOL)writeIntoBuffer:(NSString *)filePath fileDate:(NSDate *)fileDate + posixPermissions:(unsigned long)posixPermissions compressionMethod:(UZKCompressionMethod)method overwrite:(BOOL)overwrite CRC:(uLong)preCRC @@ -1380,6 +1417,7 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath } filePath:filePath fileDate:fileDate + posixPermissions:posixPermissions compressionMethod:method password:password overwrite:overwrite @@ -1922,6 +1960,7 @@ - (BOOL)performActionWithArchiveOpen:(void(^)(NSError * __autoreleasing*innerErr - (BOOL)performWriteAction:(int(^)(uLong *crc, NSError * __autoreleasing*innerError))write filePath:(NSString *)filePath fileDate:(NSDate *)fileDate + posixPermissions:(unsigned long)posixPermissions compressionMethod:(UZKCompressionMethod)method password:(NSString *)password overwrite:(BOOL)overwrite @@ -1973,6 +2012,12 @@ - (BOOL)performWriteAction:(int(^)(uLong *crc, NSError * __autoreleasing*innerEr UZKLogDebug("Making zip_fileinfo struct for date %{time_t}ld", lrint(fileDate.timeIntervalSince1970)); zip_fileinfo zi = [UZKArchive zipFileInfoForDate:fileDate]; + if (posixPermissions > 0) { + + // Revert the value of NSFilePosixPermissions to zip external_fa raw data + zi.external_fa = (posixPermissions + 32768) << 16; + } + const char *passwordStr = NULL; if (password) { @@ -2653,6 +2698,7 @@ + (zip_fileinfo)zipFileInfoForDate:(NSDate *)fileDate zi.tmz_date.tm_year = (uInt)date.year; zi.internal_fa = 0; zi.external_fa = 0; +// zi.external_fa = 2175008768; // default posixPermissions value on zip: 2175008768 (0644U) zi.dosDate = 0; return zi; diff --git a/Source/UZKFileInfo.h b/Source/UZKFileInfo.h index 0d7f0f6..7560e1e 100644 --- a/Source/UZKFileInfo.h +++ b/Source/UZKFileInfo.h @@ -73,11 +73,24 @@ typedef NS_ENUM(NSInteger, UZKCompressionMethod) { */ @property (readonly) BOOL isDirectory; +/** + * YES if the item is a symLink + */ +@property (readonly) BOOL isSymLink; + +/** + * YES if the item is a resource fork + */ +@property (readonly) BOOL isResourceFork; + /** * The type of compression */ @property (readonly) UZKCompressionMethod compressionMethod; - +/** + @brief posixPermissions (posixPermissions of the file,The value from the file attributes - NSFilePosixPermissions) + */ +@property (nonatomic, readonly) NSNumber *posixPermissions; @end diff --git a/Source/UZKFileInfo.m b/Source/UZKFileInfo.m index 1e070a7..ebfef7e 100644 --- a/Source/UZKFileInfo.m +++ b/Source/UZKFileInfo.m @@ -35,14 +35,18 @@ - (instancetype)initWithFileInfo:(unz_file_info64 *)fileInfo filename:(NSString _zipTMUDate = fileInfo->tmu_date; _CRC = fileInfo->crc; _isEncryptedWithPassword = (fileInfo->flag & 1) != 0; - _isDirectory = [filename hasSuffix:@"/"]; +// _isDirectory = [filename hasSuffix:@"/"]; + _isDirectory = [self isDirectoryWith:fileInfo]; + _isSymLink = [self isSymLinkWith:fileInfo->external_fa]; if (_isDirectory) { _filename = [_filename substringToIndex:_filename.length - 1]; } + _isResourceFork = [[filename pathComponents].firstObject isEqualToString:@"__MACOSX"]; _compressionMethod = [self readCompressionMethod:fileInfo->compression_method flag:fileInfo->flag]; + _posixPermissions = @((fileInfo->external_fa >> 16) ? (fileInfo->external_fa >> 16) : 0755U); } return self; } @@ -102,4 +106,20 @@ - (NSDate *)readDate:(tm_unz)date return [calendar dateFromComponents:components]; } +- (BOOL)isDirectoryWith:(unz_file_info64 *)fileInfo { +// NSLog(@"ISDIR__ %@", S_ISDIR(fileInfo->external_fa)?@"YES":@"NO"); + uLong type = fileInfo->external_fa >> 0x1D & 0x1F; + if (0 == (fileInfo->version >> 8)) { //is DOS-archive + type = fileInfo->external_fa >> 4; + return (type == 0x01) && ![self isSymLinkWith:fileInfo->external_fa]; + } + return (0x02 == type) && ![self isSymLinkWith:fileInfo->external_fa]; +} + +- (BOOL)isSymLinkWith:(uLong)externalFileAttributes { + + uLong type = externalFileAttributes >> 0x1D & 0x1F; + return 0x05 == type; +} + @end diff --git a/Tests/FileDescriptorUsageTests.m b/Tests/FileDescriptorUsageTests.m index a824da7..481a69e 100644 --- a/Tests/FileDescriptorUsageTests.m +++ b/Tests/FileDescriptorUsageTests.m @@ -146,6 +146,7 @@ - (void)testFileDescriptorUsage_WriteIntoArchive BOOL writeResult = [archive writeData:newFileData filePath:fileName fileDate:[NSDate date] + posixPermissions:0 compressionMethod:UZKCompressionMethodDefault password:nil overwrite:YES diff --git a/Tests/PrmissionsTests.m b/Tests/PrmissionsTests.m new file mode 100644 index 0000000..69defe0 --- /dev/null +++ b/Tests/PrmissionsTests.m @@ -0,0 +1,64 @@ +// +// PrmissionsTests.m +// UnzipKitTests +// +// Created by MartinLau on 2019/6/24. +// Copyright © 2019 Abbey Code. All rights reserved. +// + +#import "UnzipKit.h" +#import "UZKArchiveTestCase.h" + +@interface PrmissionsTests : UZKArchiveTestCase + +@end + +@implementation PrmissionsTests + +- (void)setUp { + // Put setup code here. This method is called before the invocation of each test method in the class. + [super setUp]; +} + +- (void)tearDown { + // Put teardown code here. This method is called after the invocation of each test method in the class. + +} + +- (void)testExtract { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:self.testFileURLs[@"Test Permissions Archive.zip"] error:nil]; + NSString *extractDirectory = [self randomDirectoryWithPrefix:archive.filename.stringByDeletingPathExtension]; + + // show zip file posixPermissions value + NSArray *archiveItems = [archive listFileInfo:nil]; + for (UZKFileInfo *item in archiveItems) { + + if (![item isDirectory] && ![item isResourceFork]) { + + NSLog(@"zip file %@ : posixPermissions_%ld", item.filename, [item.posixPermissions unsignedLongValue] - 32768); + } + } + + printf("====================="); + + NSError *extractError = nil; + BOOL success = [archive extractFilesTo:extractDirectory overwrite:NO error:&extractError]; + XCTAssert(success, @"extract error %@", extractError); + + // show local file posixPermissions value + NSArray *localItems = [[NSFileManager defaultManager] subpathsAtPath:extractDirectory]; + [localItems enumerateObjectsUsingBlock:^(NSString *_Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + + BOOL isDir = NO; + if ([[NSFileManager defaultManager] fileExistsAtPath:[extractDirectory stringByAppendingPathComponent:obj] isDirectory:&isDir] && !isDir) { + + NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[extractDirectory stringByAppendingPathComponent:obj] error:nil]; + NSLog(@"local file %@: posixPermissions_ %lu", obj , [attributes filePosixPermissions]); + } + }]; +} + +@end diff --git a/Tests/Test Data/Test Permissions Archive.zip b/Tests/Test Data/Test Permissions Archive.zip new file mode 100644 index 0000000000000000000000000000000000000000..158a90e5e9dd4e977050b710fe4949cf72523fb3 GIT binary patch literal 4165 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 za Date: Mon, 24 Jun 2019 08:48:23 -0400 Subject: [PATCH 02/14] Rolled back new isDirectory and isSymLink properties. This is a great idea, @MartinLau7, but it belongs in a separate PR. Let's work on that after we tackle the POSIX permissions changes --- Source/UZKFileInfo.h | 10 ---------- Source/UZKFileInfo.m | 21 +-------------------- Tests/PrmissionsTests.m | 8 ++------ 3 files changed, 3 insertions(+), 36 deletions(-) diff --git a/Source/UZKFileInfo.h b/Source/UZKFileInfo.h index 7560e1e..803c11e 100644 --- a/Source/UZKFileInfo.h +++ b/Source/UZKFileInfo.h @@ -73,16 +73,6 @@ typedef NS_ENUM(NSInteger, UZKCompressionMethod) { */ @property (readonly) BOOL isDirectory; -/** - * YES if the item is a symLink - */ -@property (readonly) BOOL isSymLink; - -/** - * YES if the item is a resource fork - */ -@property (readonly) BOOL isResourceFork; - /** * The type of compression */ diff --git a/Source/UZKFileInfo.m b/Source/UZKFileInfo.m index ebfef7e..b93f617 100644 --- a/Source/UZKFileInfo.m +++ b/Source/UZKFileInfo.m @@ -35,15 +35,12 @@ - (instancetype)initWithFileInfo:(unz_file_info64 *)fileInfo filename:(NSString _zipTMUDate = fileInfo->tmu_date; _CRC = fileInfo->crc; _isEncryptedWithPassword = (fileInfo->flag & 1) != 0; -// _isDirectory = [filename hasSuffix:@"/"]; - _isDirectory = [self isDirectoryWith:fileInfo]; - _isSymLink = [self isSymLinkWith:fileInfo->external_fa]; + _isDirectory = [filename hasSuffix:@"/"]; if (_isDirectory) { _filename = [_filename substringToIndex:_filename.length - 1]; } - _isResourceFork = [[filename pathComponents].firstObject isEqualToString:@"__MACOSX"]; _compressionMethod = [self readCompressionMethod:fileInfo->compression_method flag:fileInfo->flag]; _posixPermissions = @((fileInfo->external_fa >> 16) ? (fileInfo->external_fa >> 16) : 0755U); @@ -106,20 +103,4 @@ - (NSDate *)readDate:(tm_unz)date return [calendar dateFromComponents:components]; } -- (BOOL)isDirectoryWith:(unz_file_info64 *)fileInfo { -// NSLog(@"ISDIR__ %@", S_ISDIR(fileInfo->external_fa)?@"YES":@"NO"); - uLong type = fileInfo->external_fa >> 0x1D & 0x1F; - if (0 == (fileInfo->version >> 8)) { //is DOS-archive - type = fileInfo->external_fa >> 4; - return (type == 0x01) && ![self isSymLinkWith:fileInfo->external_fa]; - } - return (0x02 == type) && ![self isSymLinkWith:fileInfo->external_fa]; -} - -- (BOOL)isSymLinkWith:(uLong)externalFileAttributes { - - uLong type = externalFileAttributes >> 0x1D & 0x1F; - return 0x05 == type; -} - @end diff --git a/Tests/PrmissionsTests.m b/Tests/PrmissionsTests.m index 69defe0..84170ab 100644 --- a/Tests/PrmissionsTests.m +++ b/Tests/PrmissionsTests.m @@ -35,14 +35,10 @@ - (void)testExtract { // show zip file posixPermissions value NSArray *archiveItems = [archive listFileInfo:nil]; for (UZKFileInfo *item in archiveItems) { - - if (![item isDirectory] && ![item isResourceFork]) { - - NSLog(@"zip file %@ : posixPermissions_%ld", item.filename, [item.posixPermissions unsignedLongValue] - 32768); - } + NSLog(@"zip file %@ : posixPermissions_%ld", item.filename, [item.posixPermissions unsignedLongValue] - 32768); } - printf("====================="); + NSLog(@"====================="); NSError *extractError = nil; BOOL success = [archive extractFilesTo:extractDirectory overwrite:NO error:&extractError]; From 67c87acbc2941f0c519f34085ca7758961b830f2 Mon Sep 17 00:00:00 2001 From: Dov Frankel Date: Mon, 24 Jun 2019 09:06:24 -0400 Subject: [PATCH 03/14] Began cleaning up and starting implementing my suggestions from PR #84, getting the build to succeed --- Source/UZKArchive.h | 165 ++++++++++++++---- Source/UZKArchive.m | 53 +++--- Source/UZKFileInfo.h | 5 +- Tests/FileDescriptorUsageTests.m | 1 - .../{PrmissionsTests.m => PermissionsTests.m} | 8 +- UnzipKit.xcodeproj/project.pbxproj | 20 +-- 6 files changed, 184 insertions(+), 68 deletions(-) rename Tests/{PrmissionsTests.m => PermissionsTests.m} (93%) diff --git a/Source/UZKArchive.h b/Source/UZKArchive.h index 3b77d96..ee22dc0 100644 --- a/Source/UZKArchive.h +++ b/Source/UZKArchive.h @@ -593,26 +593,54 @@ compressionMethod:(UZKCompressionMethod)method error:(NSError **)error __deprecated_msg("Use -writeData:filePath:fileDate:compressionMethod:password:error: instead, and if using the progress block, replace with NSProgress as described in the README"); /** - Writes the data to the zip file, overwriting only if specified with the overwrite flag. Overwriting - presents a tradeoff: the whole archive needs to be copied (minus the file to be overwritten) before - the write begins. For a large archive, this can be slow. On the other hand, when not overwriting, - the size of the archive will grow each time the file is written. - - @param data Data to write into the archive - @param filePath The full path to the target file in the archive - @param fileDate The timestamp of the file in the archive. Uses the current time if nil - @param posixPermissions the source posix permissions of the file in the archive - @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) - @param password Override the password associated with the archive (not recommended) - @param overwrite If YES, and the file exists, delete it before writing. If NO, - append the data into the archive without removing it first (legacy Objective-Zip behavior) - @param error Contains an NSError object when there was an error writing to the archive - @return YES if successful, NO on error + * Writes the data to the zip file, overwriting only if specified with the overwrite flag. Overwriting + * presents a tradeoff: the whole archive needs to be copied (minus the file to be overwritten) before + * the write begins. For a large archive, this can be slow. On the other hand, when not overwriting, + * the size of the archive will grow each time the file is written. + * + * @param data Data to write into the archive + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param password Override the password associated with the archive (not recommended) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @param error Contains an NSError object when there was an error writing to the archive + * + * @return YES if successful, NO on error + */ +- (BOOL)writeData:(NSData *)data + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate +compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + overwrite:(BOOL)overwrite + error:(NSError **)error; + +/** + * Writes the data to the zip file, overwriting only if specified with the overwrite flag. Overwriting + * presents a tradeoff: the whole archive needs to be copied (minus the file to be overwritten) before + * the write begins. For a large archive, this can be slow. On the other hand, when not overwriting, + * the size of the archive will grow each time the file is written. + * + * @param data Data to write into the archive + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param permissions The desired POSIX permissions of the file in the archive + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param password Override the password associated with the archive (not recommended) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @param error Contains an NSError object when there was an error writing to the archive + * + * @return YES if successful, NO on error */ - (BOOL)writeData:(NSData *)data filePath:(NSString *)filePath fileDate:(nullable NSDate *)fileDate - posixPermissions:(unsigned long)posixPermissions + posixPermissions:(unsigned long)permissions compressionMethod:(UZKCompressionMethod)method password:(nullable NSString *)password overwrite:(BOOL)overwrite @@ -649,6 +677,39 @@ compressionMethod:(UZKCompressionMethod)method progress:(nullable void (^)(CGFloat percentCompressed))progress error:(NSError **)error __deprecated_msg("Use -writeData:filePath:fileDate:compressionMethod:password:overwrite:error: instead, and if using the progress block, replace with NSProgress as described in the README"); +/** + * **DEPRECATED:** Writes the data to the zip file, overwriting only if specified with the overwrite flag. Overwriting + * presents a tradeoff: the whole archive needs to be copied (minus the file to be overwritten) before + * the write begins. For a large archive, this can be slow. On the other hand, when not overwriting, + * the size of the archive will grow each time the file is written. + * + * @param data Data to write into the archive + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param permissions The desired POSIX permissions of the file in the archive + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param password Override the password associated with the archive (not recommended) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @param progress Called every so often to report the progress of the compression + * + * - *percentCompressed* The percentage of the file that has been compressed + * + * @param error Contains an NSError object when there was an error writing to the archive + * + * @return YES if successful, NO on error + */ +- (BOOL)writeData:(NSData *)data + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + posixPermissions:(unsigned long)permissions +compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + overwrite:(BOOL)overwrite + progress:(nullable void (^)(CGFloat percentCompressed))progress + error:(NSError **)error __deprecated_msg("Use -writeData:filePath:fileDate:permissions:compressionMethod:password:overwrite:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + /** * Writes data to the zip file in pieces, allowing you to stream the write, so the entire contents * don't need to reside in memory at once. It overwrites an existing file with the same name. @@ -800,21 +861,61 @@ compressionMethod:(UZKCompressionMethod)method * be slow. On the other hand, when not overwriting, the size of the archive will grow each time * the file is written. * - * @param filePath The full path to the target file in the archive - * @param fileDate The timestamp of the file in the archive. Uses the current time if nil - * @param posixPermissions the source posix permissions of the file in the archive - * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) - * @param overwrite If YES, and the file exists, delete it before writing. If NO, append - * the data into the archive without removing it first (legacy Objective-Zip - * behavior) - * @param preCRC The CRC-32 for the data being sent. Only necessary if encrypting the file. - Pass 0 otherwise - * @param password Override the password associated with the archive (not recommended) - * @param error Contains an NSError object when there was an error writing to the archive - * @param action Contains your code to loop through the source bytes and write them to the - * archive. Each time a chunk of data is ready to be written, call writeData, - * passing in a pointer to the bytes and their length. Return YES if successful, - * or NO on error (in which case, you should assign the actionError parameter + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @param preCRC The CRC-32 for the data being sent. Only necessary if encrypting the file. + * Pass 0 otherwise + * @param password Override the password associated with the archive (not recommended) + * @param error Contains an NSError object when there was an error writing to the archive + * @param action Contains your code to loop through the source bytes and write them to the + * archive. Each time a chunk of data is ready to be written, call writeData, + * passing in a pointer to the bytes and their length. Return YES if successful, + * or NO on error (in which case, you should assign the actionError parameter + * + * - *writeData* Call this block to write some bytes into the archive. It returns NO if the + * write failed. If this happens, you should return from the action block, and + * handle the NSError returned into the error reference + * - *actionError* Assign to an NSError instance before returning NO + * + * @return YES if successful, NO on error + */ +- (BOOL)writeIntoBuffer:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + compressionMethod:(UZKCompressionMethod)method + overwrite:(BOOL)overwrite + CRC:(unsigned long)preCRC + password:(nullable NSString *)password + error:(NSError **)error + block:(BOOL(^)(BOOL(^writeData)(const void *bytes, unsigned int length), NSError **actionError))action; + + +/** + * Writes data to the zip file in pieces, allowing you to stream the write, so the entire contents + * don't need to reside in memory at once. It overwrites an existing file with the same name, only if + * specified with the overwrite flag. Overwriting presents a tradeoff: the whole archive needs to be + * copied (minus the file to be overwritten) before the write begins. For a large archive, this can + * be slow. On the other hand, when not overwriting, the size of the archive will grow each time + * the file is written. + * + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param permissions The desired POSIX permissions of the file in the archive + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @param preCRC The CRC-32 for the data being sent. Only necessary if encrypting the file. + * Pass 0 otherwise + * @param password Override the password associated with the archive (not recommended) + * @param error Contains an NSError object when there was an error writing to the archive + * @param action Contains your code to loop through the source bytes and write them to the + * archive. Each time a chunk of data is ready to be written, call writeData, + * passing in a pointer to the bytes and their length. Return YES if successful, + * or NO on error (in which case, you should assign the actionError parameter * * - *writeData* Call this block to write some bytes into the archive. It returns NO if the * write failed. If this happens, you should return from the action block, and @@ -825,7 +926,7 @@ compressionMethod:(UZKCompressionMethod)method */ - (BOOL)writeIntoBuffer:(NSString *)filePath fileDate:(nullable NSDate *)fileDate - posixPermissions:(unsigned long)posixPermissions + posixPermissions:(unsigned long)permissions compressionMethod:(UZKCompressionMethod)method overwrite:(BOOL)overwrite CRC:(unsigned long)preCRC diff --git a/Source/UZKArchive.m b/Source/UZKArchive.m index 22660bc..85384ed 100644 --- a/Source/UZKArchive.m +++ b/Source/UZKArchive.m @@ -626,10 +626,9 @@ - (BOOL)extractFilesTo:(NSString *)destinationDirectory UZKLogDebug("Closing file handle"); [deflatedFileHandle closeFile]; - // Retain the permission attribute of a file + // Restore the timestamp and permission attributes of the file NSDictionary* attribs = @{NSFileModificationDate: info.timestamp, NSFilePosixPermissions: info.posixPermissions}; - [[NSFileManager defaultManager] setAttributes:attribs ofItemAtPath:path error:nil]; if (!extractSuccess) { @@ -1061,7 +1060,6 @@ - (BOOL)writeData:(NSData *)data return [self writeData:data filePath:filePath fileDate:nil - posixPermissions:0 compressionMethod:UZKCompressionMethodDefault password:nil overwrite:YES @@ -1076,7 +1074,6 @@ - (BOOL)writeData:(NSData *)data return [self writeData:data filePath:filePath fileDate:nil - posixPermissions:0 compressionMethod:UZKCompressionMethodDefault password:nil overwrite:YES @@ -1092,7 +1089,6 @@ - (BOOL)writeData:(NSData *)data return [self writeData:data filePath:filePath fileDate:fileDate - posixPermissions:0 compressionMethod:UZKCompressionMethodDefault password:nil overwrite:YES @@ -1125,7 +1121,6 @@ - (BOOL)writeData:(NSData *)data return [self writeData:data filePath:filePath fileDate:fileDate - posixPermissions:0 compressionMethod:method password:password overwrite:YES @@ -1152,20 +1147,18 @@ - (BOOL)writeData:(NSData *)data - (BOOL)writeData:(NSData *)data filePath:(NSString *)filePath - fileDate:(nullable NSDate *)fileDate - posixPermissions:(unsigned long)posixPermissions + fileDate:(NSDate *)fileDate compressionMethod:(UZKCompressionMethod)method - password:(nullable NSString *)password + password:(NSString *)password overwrite:(BOOL)overwrite - error:(NSError *__autoreleasing*)error + error:(NSError * __autoreleasing*)error { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" return [self writeData:data filePath:filePath fileDate:fileDate - posixPermissions:posixPermissions - compressionMethod:UZKCompressionMethodDefault + compressionMethod:method password:password overwrite:overwrite progress:nil @@ -1189,6 +1182,7 @@ - (BOOL)writeData:(NSData *)data compressionMethod:method password:password overwrite:overwrite + progress:progressBlock error:error]; } @@ -1196,7 +1190,7 @@ - (BOOL)writeData:(NSData *)data - (BOOL)writeData:(NSData *)data filePath:(NSString *)filePath fileDate:(NSDate *)fileDate - posixPermissions:(unsigned long)posixPermissions + posixPermissions:(unsigned long)permissions compressionMethod:(UZKCompressionMethod)method password:(NSString *)password overwrite:(BOOL)overwrite @@ -1258,7 +1252,7 @@ - (BOOL)writeData:(NSData *)data } filePath:filePath fileDate:fileDate - posixPermissions:posixPermissions + posixPermissions:permissions compressionMethod:method password:password overwrite:overwrite @@ -1355,7 +1349,27 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath - (BOOL)writeIntoBuffer:(NSString *)filePath fileDate:(NSDate *)fileDate - posixPermissions:(unsigned long)posixPermissions + compressionMethod:(UZKCompressionMethod)method + overwrite:(BOOL)overwrite + CRC:(uLong)preCRC + password:(NSString *)password + error:(NSError *__autoreleasing *)error + block:(BOOL (^)(BOOL (^)(const void *, unsigned int), NSError *__autoreleasing *))action +{ + return [self writeIntoBuffer:filePath + fileDate:fileDate + posixPermissions:0 + compressionMethod:method + overwrite:overwrite + CRC:preCRC + password:password + error:error + block:action]; +} + +- (BOOL)writeIntoBuffer:(NSString *)filePath + fileDate:(NSDate *)fileDate + posixPermissions:(unsigned long)permissions compressionMethod:(UZKCompressionMethod)method overwrite:(BOOL)overwrite CRC:(uLong)preCRC @@ -1417,7 +1431,7 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath } filePath:filePath fileDate:fileDate - posixPermissions:posixPermissions + posixPermissions:permissions compressionMethod:method password:password overwrite:overwrite @@ -1960,7 +1974,7 @@ - (BOOL)performActionWithArchiveOpen:(void(^)(NSError * __autoreleasing*innerErr - (BOOL)performWriteAction:(int(^)(uLong *crc, NSError * __autoreleasing*innerError))write filePath:(NSString *)filePath fileDate:(NSDate *)fileDate - posixPermissions:(unsigned long)posixPermissions + posixPermissions:(unsigned long)permissions compressionMethod:(UZKCompressionMethod)method password:(NSString *)password overwrite:(BOOL)overwrite @@ -2012,10 +2026,10 @@ - (BOOL)performWriteAction:(int(^)(uLong *crc, NSError * __autoreleasing*innerEr UZKLogDebug("Making zip_fileinfo struct for date %{time_t}ld", lrint(fileDate.timeIntervalSince1970)); zip_fileinfo zi = [UZKArchive zipFileInfoForDate:fileDate]; - if (posixPermissions > 0) { + if (permissions > 0) { // Revert the value of NSFilePosixPermissions to zip external_fa raw data - zi.external_fa = (posixPermissions + 32768) << 16; + zi.external_fa = (permissions + 32768) << 16; } const char *passwordStr = NULL; @@ -2698,7 +2712,6 @@ + (zip_fileinfo)zipFileInfoForDate:(NSDate *)fileDate zi.tmz_date.tm_year = (uInt)date.year; zi.internal_fa = 0; zi.external_fa = 0; -// zi.external_fa = 2175008768; // default posixPermissions value on zip: 2175008768 (0644U) zi.dosDate = 0; return zi; diff --git a/Source/UZKFileInfo.h b/Source/UZKFileInfo.h index 803c11e..7119241 100644 --- a/Source/UZKFileInfo.h +++ b/Source/UZKFileInfo.h @@ -79,8 +79,11 @@ typedef NS_ENUM(NSInteger, UZKCompressionMethod) { @property (readonly) UZKCompressionMethod compressionMethod; /** - @brief posixPermissions (posixPermissions of the file,The value from the file attributes - NSFilePosixPermissions) + The POSIX permissions of the file, like you would get by retrieving the `NSFilePosixPermissions` + key from the attributes NSFileManager returns. The value is a short integer */ @property (nonatomic, readonly) NSNumber *posixPermissions; + + @end diff --git a/Tests/FileDescriptorUsageTests.m b/Tests/FileDescriptorUsageTests.m index 481a69e..a824da7 100644 --- a/Tests/FileDescriptorUsageTests.m +++ b/Tests/FileDescriptorUsageTests.m @@ -146,7 +146,6 @@ - (void)testFileDescriptorUsage_WriteIntoArchive BOOL writeResult = [archive writeData:newFileData filePath:fileName fileDate:[NSDate date] - posixPermissions:0 compressionMethod:UZKCompressionMethodDefault password:nil overwrite:YES diff --git a/Tests/PrmissionsTests.m b/Tests/PermissionsTests.m similarity index 93% rename from Tests/PrmissionsTests.m rename to Tests/PermissionsTests.m index 84170ab..9476ee8 100644 --- a/Tests/PrmissionsTests.m +++ b/Tests/PermissionsTests.m @@ -1,19 +1,19 @@ // -// PrmissionsTests.m +// PermissionsTests.m // UnzipKitTests // -// Created by MartinLau on 2019/6/24. +// Created by Martin Lau on 6/24/19 // Copyright © 2019 Abbey Code. All rights reserved. // #import "UnzipKit.h" #import "UZKArchiveTestCase.h" -@interface PrmissionsTests : UZKArchiveTestCase +@interface PermissionsTests : UZKArchiveTestCase @end -@implementation PrmissionsTests +@implementation PermissionsTests - (void)setUp { // Put setup code here. This method is called before the invocation of each test method in the class. diff --git a/UnzipKit.xcodeproj/project.pbxproj b/UnzipKit.xcodeproj/project.pbxproj index 7496d91..4476b86 100644 --- a/UnzipKit.xcodeproj/project.pbxproj +++ b/UnzipKit.xcodeproj/project.pbxproj @@ -7,7 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - 5B5A9B9522C0B0CB00CD64D1 /* PrmissionsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B5A9B9422C0B0CB00CD64D1 /* PrmissionsTests.m */; }; 7A00291B1F93DB9200618503 /* ioapi.c in Sources */ = {isa = PBXBuildFile; fileRef = 96EA65C31A40C44300685B6D /* ioapi.c */; }; 7A00291C1F93DB9200618503 /* mztools.c in Sources */ = {isa = PBXBuildFile; fileRef = 96EA65C51A40C44300685B6D /* mztools.c */; }; 7A00291D1F93DB9200618503 /* unzip.c in Sources */ = {isa = PBXBuildFile; fileRef = 96EA65C71A40C44300685B6D /* unzip.c */; }; @@ -20,6 +19,7 @@ 7A0029241F93DBF000618503 /* libminizip.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7A0029171F93DB5800618503 /* libminizip.a */; }; 7A5652241F90E01C006B782E /* CheckDataTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A5652231F90E01C006B782E /* CheckDataTests.m */; }; 7A5A97011F89808900BCA061 /* ProgressReportingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A5A97001F89808900BCA061 /* ProgressReportingTests.m */; }; + 7AFD5C3722C0FA910066CC92 /* PermissionsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B5A9B9422C0B0CB00CD64D1 /* PermissionsTests.m */; }; 961A9BB51B306881007C4C6B /* WriteDataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 961A9BB41B306881007C4C6B /* WriteDataTests.swift */; }; 962F9DA61D5D286B00205BEC /* UnzipKit.strings in Resources */ = {isa = PBXBuildFile; fileRef = 962F9DA41D5D286B00205BEC /* UnzipKit.strings */; }; 962F9DA81D5D288B00205BEC /* UnzipKitResources.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 962F9D9E1D5D281E00205BEC /* UnzipKitResources.bundle */; }; @@ -76,7 +76,6 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 5B5A9B9422C0B0CB00CD64D1 /* PrmissionsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PrmissionsTests.m; sourceTree = ""; }; 7A0029171F93DB5800618503 /* libminizip.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libminizip.a; sourceTree = BUILT_PRODUCTS_DIR; }; 7A5652231F90E01C006B782E /* CheckDataTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CheckDataTests.m; sourceTree = ""; }; 7A5A97001F89808900BCA061 /* ProgressReportingTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ProgressReportingTests.m; sourceTree = ""; }; @@ -109,6 +108,7 @@ 968C40DB1B586401004C128E /* CommentsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = CommentsTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 968C40DD1B58642C004C128E /* MultithreadingTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = MultithreadingTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 968C40DF1B586490004C128E /* PropertyTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PropertyTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 5B5A9B9422C0B0CB00CD64D1 /* PermissionsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PermissionsTests.m; sourceTree = ""; }; 969993951BE3BA89003D18DA /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.1.sdk/usr/lib/libz.tbd; sourceTree = DEVELOPER_DIR; }; 96DC15C01C5FFAA800B71F19 /* DTPerformanceSession.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DTPerformanceSession.framework; path = Library/Frameworks/DTPerformanceSession.framework; sourceTree = DEVELOPER_DIR; }; 96EA659E1A40AEAE00685B6D /* UnzipKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = UnzipKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -242,30 +242,30 @@ children = ( 96EA65BF1A40BF1A00685B6D /* Test Data */, 961A9BB61B306902007C4C6B /* UZKArchiveTestCase.h */, + 96FCC8401B306CDD00726AC7 /* UZKArchiveTestCase.m */, + 963386B71EE89A49006B16BF /* UtilityMethods.swift */, 7A5652231F90E01C006B782E /* CheckDataTests.m */, 968C40DB1B586401004C128E /* CommentsTests.m */, 968C40D51B586380004C128E /* DeleteFileTests.m */, 968C40D71B5863A9004C128E /* ErrorHandlingTests.m */, 968C40CF1B5862A0004C128E /* ExtractBufferedDataTests.m */, 968C40C91B586227004C128E /* ExtractDataTests.m */, + 9630C0371C6D27A4000693EE /* ExtractDataTests_Swift.swift */, 968C40C71B5861F4004C128E /* ExtractFilesTests.m */, + 7A5A97001F89808900BCA061 /* ProgressReportingTests.m */, 968C40D91B5863D9004C128E /* FileDescriptorUsageTests.m */, - 968C40C51B5861C3004C128E /* ListFileInfoTests.m */, 968C40C31B58619C004C128E /* ListFilenamesTests.m */, + 968C40C51B5861C3004C128E /* ListFileInfoTests.m */, 968C40BF1B585FDE004C128E /* ModesTests.m */, 968C40DD1B58642C004C128E /* MultithreadingTests.m */, 968C40D11B586310004C128E /* PasswordProtectionTests.m */, 968C40CD1B586277004C128E /* PerformOnDataTests.m */, 968C40CB1B586253004C128E /* PerformOnFilesTests.m */, - 5B5A9B9422C0B0CB00CD64D1 /* PrmissionsTests.m */, - 7A5A97001F89808900BCA061 /* ProgressReportingTests.m */, + 5B5A9B9422C0B0CB00CD64D1 /* PermissionsTests.m */, 968C40DF1B586490004C128E /* PropertyTests.m */, - 96FCC8401B306CDD00726AC7 /* UZKArchiveTestCase.m */, 968C40D31B586345004C128E /* WriteBufferedDataTests.m */, - 968C40C11B586132004C128E /* ZipFileDetectionTests.m */, - 9630C0371C6D27A4000693EE /* ExtractDataTests_Swift.swift */, - 963386B71EE89A49006B16BF /* UtilityMethods.swift */, 961A9BB41B306881007C4C6B /* WriteDataTests.swift */, + 968C40C11B586132004C128E /* ZipFileDetectionTests.m */, 96EA65AE1A40AEAE00685B6D /* Supporting Files */, ); name = UnzipKitTests; @@ -518,7 +518,6 @@ files = ( 96EA65BD1A40B2EC00685B6D /* UZKArchive.m in Sources */, 96EA66021A40E31900685B6D /* UZKFileInfo.m in Sources */, - 5B5A9B9522C0B0CB00CD64D1 /* PrmissionsTests.m in Sources */, 965CF00C1D241A8F00C80A88 /* NSURL+UnzipKitExtensions.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -549,6 +548,7 @@ 963386B91EE89A51006B16BF /* UtilityMethods.swift in Sources */, 968C40C81B5861F4004C128E /* ExtractFilesTests.m in Sources */, 968C40D01B5862A0004C128E /* ExtractBufferedDataTests.m in Sources */, + 7AFD5C3722C0FA910066CC92 /* PermissionsTests.m in Sources */, 968C40CE1B586277004C128E /* PerformOnDataTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; From c23b261cbf85bfe8f064a6a6704c7f06aad4c3f5 Mon Sep 17 00:00:00 2001 From: Dov Frankel Date: Mon, 24 Jun 2019 16:39:11 -0400 Subject: [PATCH 04/14] Whoops - added missing overload definition --- Source/UZKArchive.m | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Source/UZKArchive.m b/Source/UZKArchive.m index 85384ed..b20b1cd 100644 --- a/Source/UZKArchive.m +++ b/Source/UZKArchive.m @@ -1186,6 +1186,28 @@ - (BOOL)writeData:(NSData *)data error:error]; } +- (BOOL)writeData:(NSData *)data + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + posixPermissions:(unsigned long)permissions +compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + overwrite:(BOOL)overwrite + error:(NSError * __autoreleasing*)error +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + return [self writeData:data + filePath:filePath + fileDate:fileDate + posixPermissions:permissions + compressionMethod:method + password:password + overwrite:overwrite + progress:nil + error:error]; +#pragma clang diagnostic pop +} - (BOOL)writeData:(NSData *)data filePath:(NSString *)filePath From a4161e5bf5aec4309db91f036ea8df4fe7f436fd Mon Sep 17 00:00:00 2001 From: Dov Frankel Date: Mon, 24 Jun 2019 17:06:27 -0400 Subject: [PATCH 05/14] Rewrote PermissionsTests in Swift, and got it working --- Tests/PermissionsTests.m | 60 ------------------------------ Tests/PermissionsTests.swift | 32 ++++++++++++++++ UnzipKit.xcodeproj/project.pbxproj | 8 ++-- 3 files changed, 36 insertions(+), 64 deletions(-) delete mode 100644 Tests/PermissionsTests.m create mode 100644 Tests/PermissionsTests.swift diff --git a/Tests/PermissionsTests.m b/Tests/PermissionsTests.m deleted file mode 100644 index 9476ee8..0000000 --- a/Tests/PermissionsTests.m +++ /dev/null @@ -1,60 +0,0 @@ -// -// PermissionsTests.m -// UnzipKitTests -// -// Created by Martin Lau on 6/24/19 -// Copyright © 2019 Abbey Code. All rights reserved. -// - -#import "UnzipKit.h" -#import "UZKArchiveTestCase.h" - -@interface PermissionsTests : UZKArchiveTestCase - -@end - -@implementation PermissionsTests - -- (void)setUp { - // Put setup code here. This method is called before the invocation of each test method in the class. - [super setUp]; -} - -- (void)tearDown { - // Put teardown code here. This method is called after the invocation of each test method in the class. - -} - -- (void)testExtract { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. - - UZKArchive *archive = [[UZKArchive alloc] initWithURL:self.testFileURLs[@"Test Permissions Archive.zip"] error:nil]; - NSString *extractDirectory = [self randomDirectoryWithPrefix:archive.filename.stringByDeletingPathExtension]; - - // show zip file posixPermissions value - NSArray *archiveItems = [archive listFileInfo:nil]; - for (UZKFileInfo *item in archiveItems) { - NSLog(@"zip file %@ : posixPermissions_%ld", item.filename, [item.posixPermissions unsignedLongValue] - 32768); - } - - NSLog(@"====================="); - - NSError *extractError = nil; - BOOL success = [archive extractFilesTo:extractDirectory overwrite:NO error:&extractError]; - XCTAssert(success, @"extract error %@", extractError); - - // show local file posixPermissions value - NSArray *localItems = [[NSFileManager defaultManager] subpathsAtPath:extractDirectory]; - [localItems enumerateObjectsUsingBlock:^(NSString *_Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { - - BOOL isDir = NO; - if ([[NSFileManager defaultManager] fileExistsAtPath:[extractDirectory stringByAppendingPathComponent:obj] isDirectory:&isDir] && !isDir) { - - NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[extractDirectory stringByAppendingPathComponent:obj] error:nil]; - NSLog(@"local file %@: posixPermissions_ %lu", obj , [attributes filePosixPermissions]); - } - }]; -} - -@end diff --git a/Tests/PermissionsTests.swift b/Tests/PermissionsTests.swift new file mode 100644 index 0000000..b0279e6 --- /dev/null +++ b/Tests/PermissionsTests.swift @@ -0,0 +1,32 @@ +// +// PermissionsTests.swift +// UnzipKitTests +// +// Created by Dov Frankel on 6/24/19. +// Copyright © 2019 Abbey Code. All rights reserved. +// + +import XCTest + +class PermissionsTests: UZKArchiveTestCase { + + func testExtraction() { + let archive = try! UZKArchive(url: self.testFileURLs!.value(forKey: "Test Permissions Archive.zip") as! URL) + + let extractDirectory = self.randomDirectory(withPrefix: "PermissionsTest")! + let extractURL = self.tempDirectory.appendingPathComponent(extractDirectory) + + try! archive.extractFiles(to: extractURL.path, overwrite: false) + let file700 = extractURL.appendingPathComponent("test/1.txt") + let file664 = extractURL.appendingPathComponent("test/paging.m4a") + + NSLog("Extracted to \(extractURL.path)") + + let file700Permissions = try! FileManager.default.attributesOfItem(atPath: file700.path)[.posixPermissions] as! NSNumber + XCTAssertEqual(file700Permissions.int16Value, 0o700) + + let file664Permissions = try! FileManager.default.attributesOfItem(atPath: file664.path)[.posixPermissions] as! NSNumber + XCTAssertEqual(file664Permissions.int16Value, 0o664) + } + +} diff --git a/UnzipKit.xcodeproj/project.pbxproj b/UnzipKit.xcodeproj/project.pbxproj index 4476b86..2986ac9 100644 --- a/UnzipKit.xcodeproj/project.pbxproj +++ b/UnzipKit.xcodeproj/project.pbxproj @@ -19,7 +19,7 @@ 7A0029241F93DBF000618503 /* libminizip.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7A0029171F93DB5800618503 /* libminizip.a */; }; 7A5652241F90E01C006B782E /* CheckDataTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A5652231F90E01C006B782E /* CheckDataTests.m */; }; 7A5A97011F89808900BCA061 /* ProgressReportingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A5A97001F89808900BCA061 /* ProgressReportingTests.m */; }; - 7AFD5C3722C0FA910066CC92 /* PermissionsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B5A9B9422C0B0CB00CD64D1 /* PermissionsTests.m */; }; + 7AA77FC822C16CF600121052 /* PermissionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AA77FC722C16CF600121052 /* PermissionsTests.swift */; }; 961A9BB51B306881007C4C6B /* WriteDataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 961A9BB41B306881007C4C6B /* WriteDataTests.swift */; }; 962F9DA61D5D286B00205BEC /* UnzipKit.strings in Resources */ = {isa = PBXBuildFile; fileRef = 962F9DA41D5D286B00205BEC /* UnzipKit.strings */; }; 962F9DA81D5D288B00205BEC /* UnzipKitResources.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 962F9D9E1D5D281E00205BEC /* UnzipKitResources.bundle */; }; @@ -79,6 +79,7 @@ 7A0029171F93DB5800618503 /* libminizip.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libminizip.a; sourceTree = BUILT_PRODUCTS_DIR; }; 7A5652231F90E01C006B782E /* CheckDataTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CheckDataTests.m; sourceTree = ""; }; 7A5A97001F89808900BCA061 /* ProgressReportingTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ProgressReportingTests.m; sourceTree = ""; }; + 7AA77FC722C16CF600121052 /* PermissionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermissionsTests.swift; sourceTree = ""; }; 961A9BB31B306880007C4C6B /* UnzipKitTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "UnzipKitTests-Bridging-Header.h"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 961A9BB41B306881007C4C6B /* WriteDataTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WriteDataTests.swift; sourceTree = ""; }; 961A9BB61B306902007C4C6B /* UZKArchiveTestCase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UZKArchiveTestCase.h; sourceTree = ""; }; @@ -108,7 +109,6 @@ 968C40DB1B586401004C128E /* CommentsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = CommentsTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 968C40DD1B58642C004C128E /* MultithreadingTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = MultithreadingTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 968C40DF1B586490004C128E /* PropertyTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PropertyTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; - 5B5A9B9422C0B0CB00CD64D1 /* PermissionsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PermissionsTests.m; sourceTree = ""; }; 969993951BE3BA89003D18DA /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.1.sdk/usr/lib/libz.tbd; sourceTree = DEVELOPER_DIR; }; 96DC15C01C5FFAA800B71F19 /* DTPerformanceSession.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DTPerformanceSession.framework; path = Library/Frameworks/DTPerformanceSession.framework; sourceTree = DEVELOPER_DIR; }; 96EA659E1A40AEAE00685B6D /* UnzipKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = UnzipKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -261,7 +261,7 @@ 968C40D11B586310004C128E /* PasswordProtectionTests.m */, 968C40CD1B586277004C128E /* PerformOnDataTests.m */, 968C40CB1B586253004C128E /* PerformOnFilesTests.m */, - 5B5A9B9422C0B0CB00CD64D1 /* PermissionsTests.m */, + 7AA77FC722C16CF600121052 /* PermissionsTests.swift */, 968C40DF1B586490004C128E /* PropertyTests.m */, 968C40D31B586345004C128E /* WriteBufferedDataTests.m */, 961A9BB41B306881007C4C6B /* WriteDataTests.swift */, @@ -546,9 +546,9 @@ 968C40DC1B586401004C128E /* CommentsTests.m in Sources */, 968C40D21B586310004C128E /* PasswordProtectionTests.m in Sources */, 963386B91EE89A51006B16BF /* UtilityMethods.swift in Sources */, + 7AA77FC822C16CF600121052 /* PermissionsTests.swift in Sources */, 968C40C81B5861F4004C128E /* ExtractFilesTests.m in Sources */, 968C40D01B5862A0004C128E /* ExtractBufferedDataTests.m in Sources */, - 7AFD5C3722C0FA910066CC92 /* PermissionsTests.m in Sources */, 968C40CE1B586277004C128E /* PerformOnDataTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; From 77c301539e82242d3db485b8ebc8ebe17477abf6 Mon Sep 17 00:00:00 2001 From: Dov Frankel Date: Mon, 24 Jun 2019 17:33:55 -0400 Subject: [PATCH 06/14] Removed Mac-specific metadata from Test Permissions Archive.zip --- Tests/Test Data/Test Permissions Archive.zip | Bin 4165 -> 3099 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Tests/Test Data/Test Permissions Archive.zip b/Tests/Test Data/Test Permissions Archive.zip index 158a90e5e9dd4e977050b710fe4949cf72523fb3..51c98ef1b167b0e78c9407ce85a55d4c222c3268 100644 GIT binary patch literal 3099 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 za Date: Mon, 24 Jun 2019 17:40:55 -0400 Subject: [PATCH 07/14] Added two new Permissions test cases, and fixed permissions reading, using a bitmask instead of the original addition method --- Source/UZKFileInfo.m | 2 +- Tests/PermissionsTests.swift | 41 ++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/Source/UZKFileInfo.m b/Source/UZKFileInfo.m index b93f617..fdf2511 100644 --- a/Source/UZKFileInfo.m +++ b/Source/UZKFileInfo.m @@ -43,7 +43,7 @@ - (instancetype)initWithFileInfo:(unz_file_info64 *)fileInfo filename:(NSString _compressionMethod = [self readCompressionMethod:fileInfo->compression_method flag:fileInfo->flag]; - _posixPermissions = @((fileInfo->external_fa >> 16) ? (fileInfo->external_fa >> 16) : 0755U); + _posixPermissions = @((fileInfo->external_fa >> 16) & 0777U); } return self; } diff --git a/Tests/PermissionsTests.swift b/Tests/PermissionsTests.swift index b0279e6..ba4b8e2 100644 --- a/Tests/PermissionsTests.swift +++ b/Tests/PermissionsTests.swift @@ -10,6 +10,25 @@ import XCTest class PermissionsTests: UZKArchiveTestCase { + func testReadFileInfo() { + let archive = try! UZKArchive(url: self.testFileURLs!.value(forKey: "Test Permissions Archive.zip") as! URL) + + let fileInfo = try! archive.listFileInfo() + + let expectedPermissions: [String: Int16] = [ + "test/1.txt": 0o700, + "test/paging.m4a": 0o664 + ] + let actualPermissions = fileInfo.reduce([String: Int16]()) { + var resultDict = $0 + resultDict[$1.filename] = $1.posixPermissions.int16Value + return resultDict + } + .filter { expectedPermissions.keys.contains($0.key) } + + XCTAssertEqual(actualPermissions, expectedPermissions) + } + func testExtraction() { let archive = try! UZKArchive(url: self.testFileURLs!.value(forKey: "Test Permissions Archive.zip") as! URL) @@ -28,5 +47,27 @@ class PermissionsTests: UZKArchiveTestCase { let file664Permissions = try! FileManager.default.attributesOfItem(atPath: file664.path)[.posixPermissions] as! NSNumber XCTAssertEqual(file664Permissions.int16Value, 0o664) } + + func testWriteData_NonDefault() { + let testArchiveURL = tempDirectory.appendingPathComponent("PermissionsTestWriteData.zip") + let testFilename = nonZipTestFilePaths.first as! String + let testFileURL = testFileURLs[testFilename] as! URL + let testFileData = try! Data(contentsOf: testFileURL) + + let writeArchive = try! UZKArchive(url: testArchiveURL) + + let expectedPermissions: Int16 = 0o700 + + try! writeArchive.write(testFileData, filePath: testFilename, fileDate: nil, posixPermissions: UInt(expectedPermissions), + compressionMethod: .default, password: nil, overwrite: true) + + let readArchive = try! UZKArchive(url: testArchiveURL) + let fileList = try! readArchive.listFileInfo() + + let writtenFileInfo = fileList.first { $0.filename == testFilename } + let actualPermissions = writtenFileInfo!.posixPermissions.int16Value + + XCTAssertEqual(actualPermissions, expectedPermissions) + } } From bcb9600a446e54c4f31e54be68148c3d5aa9f80c Mon Sep 17 00:00:00 2001 From: Dov Frankel Date: Mon, 24 Jun 2019 21:35:47 -0400 Subject: [PATCH 08/14] Updated value written to the permissions attribute to use all permission bits --- Tests/PermissionsTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/PermissionsTests.swift b/Tests/PermissionsTests.swift index ba4b8e2..a9d21c1 100644 --- a/Tests/PermissionsTests.swift +++ b/Tests/PermissionsTests.swift @@ -56,7 +56,7 @@ class PermissionsTests: UZKArchiveTestCase { let writeArchive = try! UZKArchive(url: testArchiveURL) - let expectedPermissions: Int16 = 0o700 + let expectedPermissions: Int16 = 0o742 try! writeArchive.write(testFileData, filePath: testFilename, fileDate: nil, posixPermissions: UInt(expectedPermissions), compressionMethod: .default, password: nil, overwrite: true) From 4fc50d8c6a9f51236639071a3af002f3d5492b93 Mon Sep 17 00:00:00 2001 From: Dov Frankel Date: Mon, 24 Jun 2019 21:48:04 -0400 Subject: [PATCH 09/14] Added test case for regression, to make sure the default permissions (when none are specified) match previous releases. They didn't (were getting written with 0 permissions), and so I fixed with 0644, which is what the old behavior under previous versions did --- Source/UZKFileInfo.m | 4 +++- Tests/PermissionsTests.swift | 32 ++++++++++++++++++++++++++------ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/Source/UZKFileInfo.m b/Source/UZKFileInfo.m index fdf2511..d734284 100644 --- a/Source/UZKFileInfo.m +++ b/Source/UZKFileInfo.m @@ -43,7 +43,9 @@ - (instancetype)initWithFileInfo:(unz_file_info64 *)fileInfo filename:(NSString _compressionMethod = [self readCompressionMethod:fileInfo->compression_method flag:fileInfo->flag]; - _posixPermissions = @((fileInfo->external_fa >> 16) & 0777U); + + uLong permissions = (fileInfo->external_fa >> 16) & 0777U; + _posixPermissions = @(permissions ? permissions : 0644U); } return self; } diff --git a/Tests/PermissionsTests.swift b/Tests/PermissionsTests.swift index a9d21c1..41c0117 100644 --- a/Tests/PermissionsTests.swift +++ b/Tests/PermissionsTests.swift @@ -48,25 +48,45 @@ class PermissionsTests: UZKArchiveTestCase { XCTAssertEqual(file664Permissions.int16Value, 0o664) } + func testWriteData_Default() { + let testArchiveURL = tempDirectory.appendingPathComponent("PermissionsTestWriteData.zip") + let testFilename = nonZipTestFilePaths.first as! String + let testFileURL = testFileURLs[testFilename] as! URL + let testFileData = try! Data(contentsOf: testFileURL) + + let writeArchive = try! UZKArchive(url: testArchiveURL) + + try! writeArchive.write(testFileData, filePath: testFilename, fileDate: nil, + compressionMethod: .default, password: nil, overwrite: true) + + let readArchive = try! UZKArchive(url: testArchiveURL) + let fileList = try! readArchive.listFileInfo() + + let writtenFileInfo = fileList.first { $0.filename == testFilename } + let actualPermissions = writtenFileInfo!.posixPermissions.int16Value + + XCTAssertEqual(actualPermissions, 0o644) + } + func testWriteData_NonDefault() { let testArchiveURL = tempDirectory.appendingPathComponent("PermissionsTestWriteData.zip") let testFilename = nonZipTestFilePaths.first as! String let testFileURL = testFileURLs[testFilename] as! URL let testFileData = try! Data(contentsOf: testFileURL) - + let writeArchive = try! UZKArchive(url: testArchiveURL) - + let expectedPermissions: Int16 = 0o742 - + try! writeArchive.write(testFileData, filePath: testFilename, fileDate: nil, posixPermissions: UInt(expectedPermissions), - compressionMethod: .default, password: nil, overwrite: true) - + compressionMethod: .default, password: nil, overwrite: true) + let readArchive = try! UZKArchive(url: testArchiveURL) let fileList = try! readArchive.listFileInfo() let writtenFileInfo = fileList.first { $0.filename == testFilename } let actualPermissions = writtenFileInfo!.posixPermissions.int16Value - + XCTAssertEqual(actualPermissions, expectedPermissions) } From 828843966fad8d554d34bebf904381fcad4fff2d Mon Sep 17 00:00:00 2001 From: Dov Frankel Date: Tue, 25 Jun 2019 08:13:48 -0400 Subject: [PATCH 10/14] Added type annotation to -[UZKArchiveTestCase archiveWIthFiles:] and -[UZKArchiveTestCase archiveWIthFiles:password:] --- Tests/UZKArchiveTestCase.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/UZKArchiveTestCase.h b/Tests/UZKArchiveTestCase.h index e9c5c8c..1373471 100644 --- a/Tests/UZKArchiveTestCase.h +++ b/Tests/UZKArchiveTestCase.h @@ -42,8 +42,8 @@ #if !TARGET_OS_IPHONE - (NSInteger)numberOfOpenFileHandles; -- (NSURL *)archiveWithFiles:(NSArray *)fileURLs; -- (NSURL *)archiveWithFiles:(NSArray *)fileURLs password:(NSString *)password; +- (NSURL *)archiveWithFiles:(NSArray *)fileURLs; +- (NSURL *)archiveWithFiles:(NSArray *)fileURLs password:(NSString *)password; - (BOOL)extractArchive:(NSURL *)url password:(NSString *)password; - (NSURL *)largeArchive; #endif From 4345ee70ac01a06b8d78ae675aa95c38b8499643 Mon Sep 17 00:00:00 2001 From: Dov Frankel Date: Tue, 25 Jun 2019 08:14:52 -0400 Subject: [PATCH 11/14] Replaced included binary zip file with archive generated during test --- Tests/PermissionsTests.swift | 38 +++++++++++++++---- Tests/Test Data/Test Permissions Archive.zip | Bin 3099 -> 0 bytes 2 files changed, 31 insertions(+), 7 deletions(-) delete mode 100644 Tests/Test Data/Test Permissions Archive.zip diff --git a/Tests/PermissionsTests.swift b/Tests/PermissionsTests.swift index 41c0117..a6a9571 100644 --- a/Tests/PermissionsTests.swift +++ b/Tests/PermissionsTests.swift @@ -9,25 +9,49 @@ import XCTest class PermissionsTests: UZKArchiveTestCase { - + + #if os(OSX) func testReadFileInfo() { - let archive = try! UZKArchive(url: self.testFileURLs!.value(forKey: "Test Permissions Archive.zip") as! URL) + let permissionLevelsToTest: [Int16] = [ + 0o777, + 0o707, + 0o770, + 0o477, + 0o666, + 0o606, + 0o660, + 0o466, + ] + + let fileURLs: [URL] = permissionLevelsToTest.map { + let textFile = self.emptyTextFile(ofLength: 20)! + try! FileManager.default.setAttributes([.posixPermissions: $0], + ofItemAtPath: textFile.path) + return textFile + } + + let archiveURL = self.archive(withFiles: fileURLs)! + + let archive = try! UZKArchive(url: archiveURL) let fileInfo = try! archive.listFileInfo() - let expectedPermissions: [String: Int16] = [ - "test/1.txt": 0o700, - "test/paging.m4a": 0o664 - ] + let expectedPermissions = zip( + fileURLs.map { $0.lastPathComponent }, + permissionLevelsToTest + ) + .reduce(into: [String:Int16]()) { result, pair in + result[pair.0] = pair.1 + } let actualPermissions = fileInfo.reduce([String: Int16]()) { var resultDict = $0 resultDict[$1.filename] = $1.posixPermissions.int16Value return resultDict } - .filter { expectedPermissions.keys.contains($0.key) } XCTAssertEqual(actualPermissions, expectedPermissions) } + #endif func testExtraction() { let archive = try! UZKArchive(url: self.testFileURLs!.value(forKey: "Test Permissions Archive.zip") as! URL) diff --git a/Tests/Test Data/Test Permissions Archive.zip b/Tests/Test Data/Test Permissions Archive.zip deleted file mode 100644 index 51c98ef1b167b0e78c9407ce85a55d4c222c3268..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3099 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 Date: Tue, 25 Jun 2019 08:22:27 -0400 Subject: [PATCH 12/14] Whoops. Fixed other unit tests --- Tests/PermissionsTests.swift | 41 ++++++++++++++++++++++++++---------- Tests/UZKArchiveTestCase.m | 11 ++++++---- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/Tests/PermissionsTests.swift b/Tests/PermissionsTests.swift index a6a9571..28d6100 100644 --- a/Tests/PermissionsTests.swift +++ b/Tests/PermissionsTests.swift @@ -31,7 +31,6 @@ class PermissionsTests: UZKArchiveTestCase { } let archiveURL = self.archive(withFiles: fileURLs)! - let archive = try! UZKArchive(url: archiveURL) let fileInfo = try! archive.listFileInfo() @@ -51,27 +50,47 @@ class PermissionsTests: UZKArchiveTestCase { XCTAssertEqual(actualPermissions, expectedPermissions) } - #endif func testExtraction() { - let archive = try! UZKArchive(url: self.testFileURLs!.value(forKey: "Test Permissions Archive.zip") as! URL) + let permissionLevelsToTest: [Int16] = [ + 0o777, + 0o707, + 0o770, + 0o477, + 0o666, + 0o606, + 0o660, + 0o466, + ] + + let fileURLs: [URL] = permissionLevelsToTest.map { + let textFile = self.emptyTextFile(ofLength: 20)! + try! FileManager.default.setAttributes([.posixPermissions: $0], + ofItemAtPath: textFile.path) + return textFile + } + + let archiveURL = self.archive(withFiles: fileURLs)! + let archive = try! UZKArchive(url: archiveURL) let extractDirectory = self.randomDirectory(withPrefix: "PermissionsTest")! let extractURL = self.tempDirectory.appendingPathComponent(extractDirectory) try! archive.extractFiles(to: extractURL.path, overwrite: false) - let file700 = extractURL.appendingPathComponent("test/1.txt") - let file664 = extractURL.appendingPathComponent("test/paging.m4a") - NSLog("Extracted to \(extractURL.path)") - let file700Permissions = try! FileManager.default.attributesOfItem(atPath: file700.path)[.posixPermissions] as! NSNumber - XCTAssertEqual(file700Permissions.int16Value, 0o700) + let expectedPermissions = zip( + fileURLs.map { extractURL.appendingPathComponent($0.lastPathComponent).path }, + permissionLevelsToTest + ) - let file664Permissions = try! FileManager.default.attributesOfItem(atPath: file664.path)[.posixPermissions] as! NSNumber - XCTAssertEqual(file664Permissions.int16Value, 0o664) + for (path, expectedPermissionLevel) in expectedPermissions { + let actualPermissions = try! FileManager.default.attributesOfItem(atPath: path)[.posixPermissions] as! NSNumber + XCTAssertEqual(actualPermissions.int16Value, expectedPermissionLevel, "Permissions mismatch for \(path)") + } } - + #endif + func testWriteData_Default() { let testArchiveURL = tempDirectory.appendingPathComponent("PermissionsTestWriteData.zip") let testFilename = nonZipTestFilePaths.first as! String diff --git a/Tests/UZKArchiveTestCase.m b/Tests/UZKArchiveTestCase.m index f7dfcf4..2cd9fe8 100644 --- a/Tests/UZKArchiveTestCase.m +++ b/Tests/UZKArchiveTestCase.m @@ -50,7 +50,8 @@ - (void)setUp { NSString *uniqueName = [self randomDirectoryName]; NSError *error = nil; - NSArray *testFiles = @[@"Test Archive.zip", + NSArray *testFiles = @[ + @"Test Archive.zip", @"Test Archive (Password).zip", @"L'incertain.zip", @"Aces.zip", @@ -62,12 +63,14 @@ - (void)setUp { @"Test File C.m4a", @"NotAZip-PK-ContentsUnknown", @"Modified CRC Archive.zip", - @"Test Permissions Archive.zip",]; + ]; - NSArray *unicodeFiles = @[@"Ⓣest Ⓐrchive.zip", + NSArray *unicodeFiles = @[ + @"Ⓣest Ⓐrchive.zip", @"Test File Ⓐ.txt", @"Test File Ⓑ.jpg", - @"Test File Ⓒ.m4a"]; + @"Test File Ⓒ.m4a", + ]; NSString *tempDirSubtree = [@"UnzipKitTest" stringByAppendingPathComponent:uniqueName]; From 2b2e1c4d641d90e6b708032015be130ddd1ecc7c Mon Sep 17 00:00:00 2001 From: Dov Frankel Date: Tue, 25 Jun 2019 08:30:43 -0400 Subject: [PATCH 13/14] Made `posixPermissions` property of UZKFileInfo a short instead of boxing it in an NSNumber --- Source/UZKArchive.m | 2 +- Source/UZKFileInfo.h | 7 ++++--- Source/UZKFileInfo.m | 2 +- Tests/PermissionsTests.swift | 6 +++--- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Source/UZKArchive.m b/Source/UZKArchive.m index b20b1cd..20678e8 100644 --- a/Source/UZKArchive.m +++ b/Source/UZKArchive.m @@ -628,7 +628,7 @@ - (BOOL)extractFilesTo:(NSString *)destinationDirectory // Restore the timestamp and permission attributes of the file NSDictionary* attribs = @{NSFileModificationDate: info.timestamp, - NSFilePosixPermissions: info.posixPermissions}; + NSFilePosixPermissions: @(info.posixPermissions)}; [[NSFileManager defaultManager] setAttributes:attribs ofItemAtPath:path error:nil]; if (!extractSuccess) { diff --git a/Source/UZKFileInfo.h b/Source/UZKFileInfo.h index 7119241..e14248e 100644 --- a/Source/UZKFileInfo.h +++ b/Source/UZKFileInfo.h @@ -79,10 +79,11 @@ typedef NS_ENUM(NSInteger, UZKCompressionMethod) { @property (readonly) UZKCompressionMethod compressionMethod; /** - The POSIX permissions of the file, like you would get by retrieving the `NSFilePosixPermissions` - key from the attributes NSFileManager returns. The value is a short integer + * The POSIX permissions of the file, like you would get by retrieving the `NSFilePosixPermissions` + * key from the attributes NSFileManager returns. Assign in octal form, like 0777 in Objective-C or + * 0o777 in Swift */ -@property (nonatomic, readonly) NSNumber *posixPermissions; +@property (nonatomic, readonly) short posixPermissions; diff --git a/Source/UZKFileInfo.m b/Source/UZKFileInfo.m index d734284..050adf6 100644 --- a/Source/UZKFileInfo.m +++ b/Source/UZKFileInfo.m @@ -45,7 +45,7 @@ - (instancetype)initWithFileInfo:(unz_file_info64 *)fileInfo filename:(NSString flag:fileInfo->flag]; uLong permissions = (fileInfo->external_fa >> 16) & 0777U; - _posixPermissions = @(permissions ? permissions : 0644U); + _posixPermissions = permissions ? permissions : 0644U; } return self; } diff --git a/Tests/PermissionsTests.swift b/Tests/PermissionsTests.swift index 28d6100..8c142da 100644 --- a/Tests/PermissionsTests.swift +++ b/Tests/PermissionsTests.swift @@ -44,7 +44,7 @@ class PermissionsTests: UZKArchiveTestCase { } let actualPermissions = fileInfo.reduce([String: Int16]()) { var resultDict = $0 - resultDict[$1.filename] = $1.posixPermissions.int16Value + resultDict[$1.filename] = $1.posixPermissions return resultDict } @@ -106,7 +106,7 @@ class PermissionsTests: UZKArchiveTestCase { let fileList = try! readArchive.listFileInfo() let writtenFileInfo = fileList.first { $0.filename == testFilename } - let actualPermissions = writtenFileInfo!.posixPermissions.int16Value + let actualPermissions = writtenFileInfo!.posixPermissions XCTAssertEqual(actualPermissions, 0o644) } @@ -128,7 +128,7 @@ class PermissionsTests: UZKArchiveTestCase { let fileList = try! readArchive.listFileInfo() let writtenFileInfo = fileList.first { $0.filename == testFilename } - let actualPermissions = writtenFileInfo!.posixPermissions.int16Value + let actualPermissions = writtenFileInfo!.posixPermissions XCTAssertEqual(actualPermissions, expectedPermissions) } From f4d0b7882dca783f92b16471ab1b4d21d9aecbfe Mon Sep 17 00:00:00 2001 From: Dov Frankel Date: Tue, 25 Jun 2019 09:12:26 -0400 Subject: [PATCH 14/14] Updated POSIX permissions API to use short value for all method overloads instead of unsigned long, moved the assignment of `external_fa` to the same method that writes the file date attribute, and added tests for writing buffered data with and without permissions --- Source/UZKArchive.h | 6 ++-- Source/UZKArchive.m | 23 ++++++++-------- Tests/PermissionsTests.swift | 53 ++++++++++++++++++++++++++++++++++-- 3 files changed, 65 insertions(+), 17 deletions(-) diff --git a/Source/UZKArchive.h b/Source/UZKArchive.h index ee22dc0..ce99538 100644 --- a/Source/UZKArchive.h +++ b/Source/UZKArchive.h @@ -640,7 +640,7 @@ compressionMethod:(UZKCompressionMethod)method - (BOOL)writeData:(NSData *)data filePath:(NSString *)filePath fileDate:(nullable NSDate *)fileDate - posixPermissions:(unsigned long)permissions + posixPermissions:(short)permissions compressionMethod:(UZKCompressionMethod)method password:(nullable NSString *)password overwrite:(BOOL)overwrite @@ -703,7 +703,7 @@ compressionMethod:(UZKCompressionMethod)method - (BOOL)writeData:(NSData *)data filePath:(NSString *)filePath fileDate:(nullable NSDate *)fileDate - posixPermissions:(unsigned long)permissions + posixPermissions:(short)permissions compressionMethod:(UZKCompressionMethod)method password:(nullable NSString *)password overwrite:(BOOL)overwrite @@ -926,7 +926,7 @@ compressionMethod:(UZKCompressionMethod)method */ - (BOOL)writeIntoBuffer:(NSString *)filePath fileDate:(nullable NSDate *)fileDate - posixPermissions:(unsigned long)permissions + posixPermissions:(short)permissions compressionMethod:(UZKCompressionMethod)method overwrite:(BOOL)overwrite CRC:(unsigned long)preCRC diff --git a/Source/UZKArchive.m b/Source/UZKArchive.m index 20678e8..a8ac32a 100644 --- a/Source/UZKArchive.m +++ b/Source/UZKArchive.m @@ -1189,7 +1189,7 @@ - (BOOL)writeData:(NSData *)data - (BOOL)writeData:(NSData *)data filePath:(NSString *)filePath fileDate:(nullable NSDate *)fileDate - posixPermissions:(unsigned long)permissions + posixPermissions:(short)permissions compressionMethod:(UZKCompressionMethod)method password:(nullable NSString *)password overwrite:(BOOL)overwrite @@ -1212,7 +1212,7 @@ - (BOOL)writeData:(NSData *)data - (BOOL)writeData:(NSData *)data filePath:(NSString *)filePath fileDate:(NSDate *)fileDate - posixPermissions:(unsigned long)permissions + posixPermissions:(short)permissions compressionMethod:(UZKCompressionMethod)method password:(NSString *)password overwrite:(BOOL)overwrite @@ -1391,7 +1391,7 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath - (BOOL)writeIntoBuffer:(NSString *)filePath fileDate:(NSDate *)fileDate - posixPermissions:(unsigned long)permissions + posixPermissions:(short)permissions compressionMethod:(UZKCompressionMethod)method overwrite:(BOOL)overwrite CRC:(uLong)preCRC @@ -1996,7 +1996,7 @@ - (BOOL)performActionWithArchiveOpen:(void(^)(NSError * __autoreleasing*innerErr - (BOOL)performWriteAction:(int(^)(uLong *crc, NSError * __autoreleasing*innerError))write filePath:(NSString *)filePath fileDate:(NSDate *)fileDate - posixPermissions:(unsigned long)permissions + posixPermissions:(short)permissions compressionMethod:(UZKCompressionMethod)method password:(NSString *)password overwrite:(BOOL)overwrite @@ -2046,13 +2046,8 @@ - (BOOL)performWriteAction:(int(^)(uLong *crc, NSError * __autoreleasing*innerEr UZKCreateActivity("Performing Write Action"); UZKLogDebug("Making zip_fileinfo struct for date %{time_t}ld", lrint(fileDate.timeIntervalSince1970)); - zip_fileinfo zi = [UZKArchive zipFileInfoForDate:fileDate]; - - if (permissions > 0) { - - // Revert the value of NSFilePosixPermissions to zip external_fa raw data - zi.external_fa = (permissions + 32768) << 16; - } + zip_fileinfo zi = [UZKArchive zipFileInfoForDate:fileDate + posixPermissions:permissions]; const char *passwordStr = NULL; @@ -2704,6 +2699,7 @@ + (NSString *)errorNameForErrorCode:(NSInteger)errorCode } + (zip_fileinfo)zipFileInfoForDate:(NSDate *)fileDate + posixPermissions:(short)permissions { NSCalendar *calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian]; @@ -2736,6 +2732,11 @@ + (zip_fileinfo)zipFileInfoForDate:(NSDate *)fileDate zi.external_fa = 0; zi.dosDate = 0; + if (permissions > 0) { + unsigned long permissionsMask = (permissions & 0777) << 16; + zi.external_fa |= permissionsMask; + } + return zi; } diff --git a/Tests/PermissionsTests.swift b/Tests/PermissionsTests.swift index 8c142da..7910068 100644 --- a/Tests/PermissionsTests.swift +++ b/Tests/PermissionsTests.swift @@ -99,8 +99,7 @@ class PermissionsTests: UZKArchiveTestCase { let writeArchive = try! UZKArchive(url: testArchiveURL) - try! writeArchive.write(testFileData, filePath: testFilename, fileDate: nil, - compressionMethod: .default, password: nil, overwrite: true) + try! writeArchive.write(testFileData, filePath: testFilename) let readArchive = try! UZKArchive(url: testArchiveURL) let fileList = try! readArchive.listFileInfo() @@ -121,7 +120,7 @@ class PermissionsTests: UZKArchiveTestCase { let expectedPermissions: Int16 = 0o742 - try! writeArchive.write(testFileData, filePath: testFilename, fileDate: nil, posixPermissions: UInt(expectedPermissions), + try! writeArchive.write(testFileData, filePath: testFilename, fileDate: nil, posixPermissions: expectedPermissions, compressionMethod: .default, password: nil, overwrite: true) let readArchive = try! UZKArchive(url: testArchiveURL) @@ -133,4 +132,52 @@ class PermissionsTests: UZKArchiveTestCase { XCTAssertEqual(actualPermissions, expectedPermissions) } + func testWriteIntoBuffer_Default() { + let testArchiveURL = tempDirectory.appendingPathComponent("PermissionsTestWriteBufferedData.zip") + let testFilename = nonZipTestFilePaths.first as! String + let testFileURL = testFileURLs[testFilename] as! URL + let testFileData = try! Data(contentsOf: testFileURL) + + let writeArchive = try! UZKArchive(url: testArchiveURL) + try! writeArchive.write(intoBuffer: testFilename) { (writeDataHandler, error) in + testFileData.withUnsafeBytes({ buffer in + writeDataHandler(buffer, UInt32(testFileData.count)) + }) + } + + let readArchive = try! UZKArchive(url: testArchiveURL) + let fileList = try! readArchive.listFileInfo() + + let writtenFileInfo = fileList.first { $0.filename == testFilename } + let actualPermissions = writtenFileInfo!.posixPermissions + + XCTAssertEqual(actualPermissions, 0o644) + } + + func testWriteIntoBuffer_NonDefault() { + let testArchiveURL = tempDirectory.appendingPathComponent("PermissionsTestWriteBufferedData_CustomPermissions.zip") + let testFilename = nonZipTestFilePaths.first as! String + let testFileURL = testFileURLs[testFilename] as! URL + let testFileData = try! Data(contentsOf: testFileURL) + + let expectedPermissions: Int16 = 0o764 + + let writeArchive = try! UZKArchive(url: testArchiveURL) + try! writeArchive.write(intoBuffer: testFilename, fileDate: nil, posixPermissions: expectedPermissions, + compressionMethod: .default, overwrite: false, crc: 0, password: nil) + { (writeDataHandler, error) in + testFileData.withUnsafeBytes({ buffer in + writeDataHandler(buffer, UInt32(testFileData.count)) + }) + } + + let readArchive = try! UZKArchive(url: testArchiveURL) + let fileList = try! readArchive.listFileInfo() + + let writtenFileInfo = fileList.first { $0.filename == testFilename } + let actualPermissions = writtenFileInfo!.posixPermissions + + XCTAssertEqual(actualPermissions, expectedPermissions) + } + }