From c2f4fa7d6b4d5514cce581b418f35e91c76d7911 Mon Sep 17 00:00:00 2001 From: MartinLau Date: Thu, 13 Jun 2019 10:26:58 +0800 Subject: [PATCH 1/6] 1. Code rollback to update 2. Remove the permission to set the default 0644U, now the default is 0755U 3. Fix the damage caused by Xcode 4. Add to Test Code and Test File 5. Add the writeFile function --- Source/UZKArchive.h | 92 +++++++++++++ Source/UZKArchive.m | 133 ++++++++++++++++++- Source/UZKFileInfo.h | 5 +- Source/UZKFileInfo.m | 1 + Tests/Test Data/Test Permissions Archive.zip | Bin 0 -> 4165 bytes Tests/TestKeppPrmissions.m | 37 ++++++ Tests/UZKArchiveTestCase.m | 3 +- UnzipKit.xcodeproj/project.pbxproj | 5 + 8 files changed, 273 insertions(+), 3 deletions(-) create mode 100644 Tests/Test Data/Test Permissions Archive.zip create mode 100644 Tests/TestKeppPrmissions.m diff --git a/Source/UZKArchive.h b/Source/UZKArchive.h index a77856f..3337117 100644 --- a/Source/UZKArchive.h +++ b/Source/UZKArchive.h @@ -618,6 +618,32 @@ compressionMethod:(UZKCompressionMethod)method 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 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 + error:(NSError **)error; + /** * **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 @@ -831,6 +857,72 @@ compressionMethod:(UZKCompressionMethod)method 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 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 + * 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 + posixPermissions:(unsigned long)posixPermissions + 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 file 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 file The full path on local + @param zipPath The full path to the target 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 Assign to an NSError instance before returning NO + @return YES if successful, NO on error + */ +- (BOOL)writeFile:(NSString *)file + zipPath:(NSString *)zipPath +compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + overwrite:(BOOL)overwrite + error:(NSError **)error; + /** * Removes the given file from the archive * diff --git a/Source/UZKArchive.m b/Source/UZKArchive.m index d6e5296..ed93e60 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) { @@ -1164,9 +1167,52 @@ - (BOOL)writeData:(NSData *)data #pragma clang diagnostic pop } +- (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 + 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 + password:password + overwrite:overwrite + progress:nil + error:error]; +#pragma clang diagnostic pop +} + +- (BOOL)writeData:(NSData *)data + filePath:(NSString *)filePath + fileDate:(NSDate *)fileDate +compressionMethod:(UZKCompressionMethod)method + password:(NSString *)password + overwrite:(BOOL)overwrite + progress:(void (^)(CGFloat percentCompressed))progressBlock + error:(NSError * __autoreleasing*)error +{ + return [self writeData:data + filePath:filePath + fileDate:fileDate + posixPermissions:0 + compressionMethod:UZKCompressionMethodDefault + 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 @@ -1228,6 +1274,7 @@ - (BOOL)writeData:(NSData *)data } filePath:filePath fileDate:fileDate + posixPermissions:posixPermissions compressionMethod:method password:password overwrite:overwrite @@ -1325,6 +1372,27 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath 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)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 { UZKCreateActivity("Writing Into Buffer"); @@ -1380,6 +1448,7 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath } filePath:filePath fileDate:fileDate + posixPermissions:posixPermissions compressionMethod:method password:password overwrite:overwrite @@ -1389,6 +1458,60 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath return success; } +- (BOOL)writeFile:(NSString *)file + zipPath:(NSString *)zipPath +compressionMethod:(UZKCompressionMethod)method + password:(NSString *)password + overwrite:(BOOL)overwrite + error:(NSError * _Nullable __autoreleasing *)error { + + BOOL isDir = NO; + if ([[NSFileManager defaultManager] fileExistsAtPath:file isDirectory:&isDir] && !isDir) { + + NSError *attributeError = nil; + unsigned long posixPermissions = 0; + NSDictionary *attributeDict = [[NSFileManager defaultManager] attributesOfItemAtPath:file error:&attributeError]; + if ([attributeDict objectForKey:NSFilePosixPermissions]) { + + posixPermissions = attributeDict.filePosixPermissions; + } + + int blockSize = 10*10240; + return [self writeIntoBuffer:zipPath + fileDate:nil + posixPermissions:posixPermissions + compressionMethod:UZKCompressionMethodDefault + overwrite:YES + CRC:0 + password:nil + error:error + block:^BOOL(BOOL (^ _Nonnull writeData)(const void * _Nonnull, unsigned int), NSError * _Nullable __autoreleasing * _Nullable actionError) { + + NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:file]; + while (true) { + + @autoreleasepool { + + NSData *data = [fileHandle readDataOfLength:blockSize]; + if (data.length == 0) { + + break; + } + const void *bytes = data.bytes; + unsigned int length = (unsigned int)data.length; + if (!writeData(bytes, length)) { + + return NO; + } + } + } + [fileHandle closeFile]; + return YES; + }]; + } + return NO; +} + - (BOOL)deleteFile:(NSString *)filePath error:(NSError * __autoreleasing*)error { UZKCreateActivity("Deleting File"); @@ -1922,6 +2045,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 +2097,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 +2783,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..803c11e 100644 --- a/Source/UZKFileInfo.h +++ b/Source/UZKFileInfo.h @@ -78,6 +78,9 @@ typedef NS_ENUM(NSInteger, UZKCompressionMethod) { */ @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..b93f617 100644 --- a/Source/UZKFileInfo.m +++ b/Source/UZKFileInfo.m @@ -43,6 +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); } return self; } 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 + +@interface TestKeppPrmissions : XCTestCase + +@end + +@implementation TestKeppPrmissions + +- (void)setUp { + // Put setup code here. This method is called before the invocation of each test method in the class. +} + +- (void)tearDown { + // Put teardown code here. This method is called after the invocation of each test method in the class. +} + +- (void)testExample { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. +} + +- (void)testPerformanceExample { + // This is an example of a performance test case. + [self measureBlock:^{ + // Put the code you want to measure the time of here. + }]; +} + +@end diff --git a/Tests/UZKArchiveTestCase.m b/Tests/UZKArchiveTestCase.m index ff90e54..f7dfcf4 100644 --- a/Tests/UZKArchiveTestCase.m +++ b/Tests/UZKArchiveTestCase.m @@ -61,7 +61,8 @@ - (void)setUp { @"Test File B.jpg", @"Test File C.m4a", @"NotAZip-PK-ContentsUnknown", - @"Modified CRC Archive.zip"]; + @"Modified CRC Archive.zip", + @"Test Permissions Archive.zip",]; NSArray *unicodeFiles = @[@"Ⓣest Ⓐrchive.zip", @"Test File Ⓐ.txt", diff --git a/UnzipKit.xcodeproj/project.pbxproj b/UnzipKit.xcodeproj/project.pbxproj index 44111cb..2a6b5ab 100644 --- a/UnzipKit.xcodeproj/project.pbxproj +++ b/UnzipKit.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 5B82326A22B1E6060049B931 /* TestKeppPrmissions.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B82326922B1E6060049B931 /* TestKeppPrmissions.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 */; }; @@ -75,6 +76,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 5B82326922B1E6060049B931 /* TestKeppPrmissions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestKeppPrmissions.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 = ""; }; @@ -263,6 +265,7 @@ 968C40D31B586345004C128E /* WriteBufferedDataTests.m */, 961A9BB41B306881007C4C6B /* WriteDataTests.swift */, 968C40C11B586132004C128E /* ZipFileDetectionTests.m */, + 5B82326922B1E6060049B931 /* TestKeppPrmissions.m */, 96EA65AE1A40AEAE00685B6D /* Supporting Files */, ); name = UnzipKitTests; @@ -447,6 +450,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, base, ); @@ -529,6 +533,7 @@ 968C40D61B586380004C128E /* DeleteFileTests.m in Sources */, 96FCC8411B306CDD00726AC7 /* UZKArchiveTestCase.m in Sources */, 7A5A97011F89808900BCA061 /* ProgressReportingTests.m in Sources */, + 5B82326A22B1E6060049B931 /* TestKeppPrmissions.m in Sources */, 968C40C21B586132004C128E /* ZipFileDetectionTests.m in Sources */, 968C40D41B586345004C128E /* WriteBufferedDataTests.m in Sources */, 968C40CC1B586253004C128E /* PerformOnFilesTests.m in Sources */, From e7ed5a459b9d0e17c4b4d0d5173cbd44b03636be Mon Sep 17 00:00:00 2001 From: MartinLau Date: Thu, 13 Jun 2019 10:28:42 +0800 Subject: [PATCH 2/6] Update test code --- Tests/TestKeppPrmissions.m | 46 ++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/Tests/TestKeppPrmissions.m b/Tests/TestKeppPrmissions.m index 2e69def..7257e74 100644 --- a/Tests/TestKeppPrmissions.m +++ b/Tests/TestKeppPrmissions.m @@ -6,9 +6,12 @@ // Copyright © 2019 Abbey Code. All rights reserved. // -#import +#import "UZKArchiveTestCase.h" +#import "zip.h" +#import "UnzipKit.h" -@interface TestKeppPrmissions : XCTestCase + +@interface TestKeppPrmissions : UZKArchiveTestCase @end @@ -16,22 +19,51 @@ @implementation TestKeppPrmissions - (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)testExample { +- (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]; + + NSError *extractError = nil; + BOOL success = [archive extractFilesTo:extractDirectory overwrite:NO error:&extractError]; + XCTAssert(success, @"extract error %@", extractError); + // $ ls -l "extractURL.path" look up prmissions } -- (void)testPerformanceExample { - // This is an example of a performance test case. - [self measureBlock:^{ - // Put the code you want to measure the time of here. +- (void)testWriteFile { + + NSURL *testArchiveURL = [self.tempDirectory URLByAppendingPathComponent:@"WriteFile.zip"]; + [[NSFileManager defaultManager] removeItemAtURL:testArchiveURL error:nil]; + + UZKArchive *archive = [[UZKArchive alloc] initWithPath:testArchiveURL.path error:nil]; + + NSArray *array = [[NSFileManager defaultManager] subpathsAtPath:[testArchiveURL URLByDeletingLastPathComponent].path]; + [array enumerateObjectsUsingBlock:^(NSString *_Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + + if (![[obj pathExtension] hasSuffix:@"zip"]) { + + NSError *error = nil; + NSString *itemPath = [[testArchiveURL URLByDeletingLastPathComponent].path stringByAppendingPathComponent:obj]; + + BOOL success = [archive writeFile:itemPath + zipPath:obj + compressionMethod:UZKCompressionMethodDefault + password:nil + overwrite:NO + error:&error]; + XCTAssert(success, "write error %@", error); + } }]; + NSLog(@"%@", archive.filename); } @end From 42a009cd22935081bc0df969ed24e727d9b16c9b Mon Sep 17 00:00:00 2001 From: MartinLau Date: Thu, 13 Jun 2019 10:26:58 +0800 Subject: [PATCH 3/6] 1. Code rollback to update 2. Remove the permission to set the default 0644U, now the default is 0755U 3. Fix the damage caused by Xcode 4. Add to Test Code and Test File 5. Add the writeFile function --- Source/UZKArchive.h | 92 +++++++++++++ Source/UZKArchive.m | 133 ++++++++++++++++++- Source/UZKFileInfo.h | 5 +- Source/UZKFileInfo.m | 1 + Tests/Test Data/Test Permissions Archive.zip | Bin 0 -> 4165 bytes Tests/TestKeppPrmissions.m | 37 ++++++ Tests/UZKArchiveTestCase.m | 3 +- UnzipKit.xcodeproj/project.pbxproj | 5 + 8 files changed, 273 insertions(+), 3 deletions(-) create mode 100644 Tests/Test Data/Test Permissions Archive.zip create mode 100644 Tests/TestKeppPrmissions.m diff --git a/Source/UZKArchive.h b/Source/UZKArchive.h index a77856f..3337117 100644 --- a/Source/UZKArchive.h +++ b/Source/UZKArchive.h @@ -618,6 +618,32 @@ compressionMethod:(UZKCompressionMethod)method 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 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 + error:(NSError **)error; + /** * **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 @@ -831,6 +857,72 @@ compressionMethod:(UZKCompressionMethod)method 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 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 + * 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 + posixPermissions:(unsigned long)posixPermissions + 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 file 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 file The full path on local + @param zipPath The full path to the target 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 Assign to an NSError instance before returning NO + @return YES if successful, NO on error + */ +- (BOOL)writeFile:(NSString *)file + zipPath:(NSString *)zipPath +compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + overwrite:(BOOL)overwrite + error:(NSError **)error; + /** * Removes the given file from the archive * diff --git a/Source/UZKArchive.m b/Source/UZKArchive.m index 78f58ea..9843147 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) { @@ -1164,9 +1167,52 @@ - (BOOL)writeData:(NSData *)data #pragma clang diagnostic pop } +- (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 + 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 + password:password + overwrite:overwrite + progress:nil + error:error]; +#pragma clang diagnostic pop +} + +- (BOOL)writeData:(NSData *)data + filePath:(NSString *)filePath + fileDate:(NSDate *)fileDate +compressionMethod:(UZKCompressionMethod)method + password:(NSString *)password + overwrite:(BOOL)overwrite + progress:(void (^)(CGFloat percentCompressed))progressBlock + error:(NSError * __autoreleasing*)error +{ + return [self writeData:data + filePath:filePath + fileDate:fileDate + posixPermissions:0 + compressionMethod:UZKCompressionMethodDefault + 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 @@ -1228,6 +1274,7 @@ - (BOOL)writeData:(NSData *)data } filePath:filePath fileDate:fileDate + posixPermissions:posixPermissions compressionMethod:method password:password overwrite:overwrite @@ -1325,6 +1372,27 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath 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)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 { UZKCreateActivity("Writing Into Buffer"); @@ -1380,6 +1448,7 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath } filePath:filePath fileDate:fileDate + posixPermissions:posixPermissions compressionMethod:method password:password overwrite:overwrite @@ -1389,6 +1458,60 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath return success; } +- (BOOL)writeFile:(NSString *)file + zipPath:(NSString *)zipPath +compressionMethod:(UZKCompressionMethod)method + password:(NSString *)password + overwrite:(BOOL)overwrite + error:(NSError * _Nullable __autoreleasing *)error { + + BOOL isDir = NO; + if ([[NSFileManager defaultManager] fileExistsAtPath:file isDirectory:&isDir] && !isDir) { + + NSError *attributeError = nil; + unsigned long posixPermissions = 0; + NSDictionary *attributeDict = [[NSFileManager defaultManager] attributesOfItemAtPath:file error:&attributeError]; + if ([attributeDict objectForKey:NSFilePosixPermissions]) { + + posixPermissions = attributeDict.filePosixPermissions; + } + + int blockSize = 10*10240; + return [self writeIntoBuffer:zipPath + fileDate:nil + posixPermissions:posixPermissions + compressionMethod:UZKCompressionMethodDefault + overwrite:YES + CRC:0 + password:nil + error:error + block:^BOOL(BOOL (^ _Nonnull writeData)(const void * _Nonnull, unsigned int), NSError * _Nullable __autoreleasing * _Nullable actionError) { + + NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:file]; + while (true) { + + @autoreleasepool { + + NSData *data = [fileHandle readDataOfLength:blockSize]; + if (data.length == 0) { + + break; + } + const void *bytes = data.bytes; + unsigned int length = (unsigned int)data.length; + if (!writeData(bytes, length)) { + + return NO; + } + } + } + [fileHandle closeFile]; + return YES; + }]; + } + return NO; +} + - (BOOL)deleteFile:(NSString *)filePath error:(NSError * __autoreleasing*)error { UZKCreateActivity("Deleting File"); @@ -1922,6 +2045,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 +2097,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 +2783,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..803c11e 100644 --- a/Source/UZKFileInfo.h +++ b/Source/UZKFileInfo.h @@ -78,6 +78,9 @@ typedef NS_ENUM(NSInteger, UZKCompressionMethod) { */ @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..b93f617 100644 --- a/Source/UZKFileInfo.m +++ b/Source/UZKFileInfo.m @@ -43,6 +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); } return self; } 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 + +@interface TestKeppPrmissions : XCTestCase + +@end + +@implementation TestKeppPrmissions + +- (void)setUp { + // Put setup code here. This method is called before the invocation of each test method in the class. +} + +- (void)tearDown { + // Put teardown code here. This method is called after the invocation of each test method in the class. +} + +- (void)testExample { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. +} + +- (void)testPerformanceExample { + // This is an example of a performance test case. + [self measureBlock:^{ + // Put the code you want to measure the time of here. + }]; +} + +@end diff --git a/Tests/UZKArchiveTestCase.m b/Tests/UZKArchiveTestCase.m index ff90e54..f7dfcf4 100644 --- a/Tests/UZKArchiveTestCase.m +++ b/Tests/UZKArchiveTestCase.m @@ -61,7 +61,8 @@ - (void)setUp { @"Test File B.jpg", @"Test File C.m4a", @"NotAZip-PK-ContentsUnknown", - @"Modified CRC Archive.zip"]; + @"Modified CRC Archive.zip", + @"Test Permissions Archive.zip",]; NSArray *unicodeFiles = @[@"Ⓣest Ⓐrchive.zip", @"Test File Ⓐ.txt", diff --git a/UnzipKit.xcodeproj/project.pbxproj b/UnzipKit.xcodeproj/project.pbxproj index 44111cb..2a6b5ab 100644 --- a/UnzipKit.xcodeproj/project.pbxproj +++ b/UnzipKit.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 5B82326A22B1E6060049B931 /* TestKeppPrmissions.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B82326922B1E6060049B931 /* TestKeppPrmissions.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 */; }; @@ -75,6 +76,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 5B82326922B1E6060049B931 /* TestKeppPrmissions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestKeppPrmissions.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 = ""; }; @@ -263,6 +265,7 @@ 968C40D31B586345004C128E /* WriteBufferedDataTests.m */, 961A9BB41B306881007C4C6B /* WriteDataTests.swift */, 968C40C11B586132004C128E /* ZipFileDetectionTests.m */, + 5B82326922B1E6060049B931 /* TestKeppPrmissions.m */, 96EA65AE1A40AEAE00685B6D /* Supporting Files */, ); name = UnzipKitTests; @@ -447,6 +450,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, base, ); @@ -529,6 +533,7 @@ 968C40D61B586380004C128E /* DeleteFileTests.m in Sources */, 96FCC8411B306CDD00726AC7 /* UZKArchiveTestCase.m in Sources */, 7A5A97011F89808900BCA061 /* ProgressReportingTests.m in Sources */, + 5B82326A22B1E6060049B931 /* TestKeppPrmissions.m in Sources */, 968C40C21B586132004C128E /* ZipFileDetectionTests.m in Sources */, 968C40D41B586345004C128E /* WriteBufferedDataTests.m in Sources */, 968C40CC1B586253004C128E /* PerformOnFilesTests.m in Sources */, From 7a47fd757fb432ad67d21f1581359afc82bb3b02 Mon Sep 17 00:00:00 2001 From: MartinLau Date: Thu, 13 Jun 2019 10:28:42 +0800 Subject: [PATCH 4/6] Update test code --- Tests/TestKeppPrmissions.m | 46 ++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/Tests/TestKeppPrmissions.m b/Tests/TestKeppPrmissions.m index 2e69def..7257e74 100644 --- a/Tests/TestKeppPrmissions.m +++ b/Tests/TestKeppPrmissions.m @@ -6,9 +6,12 @@ // Copyright © 2019 Abbey Code. All rights reserved. // -#import +#import "UZKArchiveTestCase.h" +#import "zip.h" +#import "UnzipKit.h" -@interface TestKeppPrmissions : XCTestCase + +@interface TestKeppPrmissions : UZKArchiveTestCase @end @@ -16,22 +19,51 @@ @implementation TestKeppPrmissions - (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)testExample { +- (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]; + + NSError *extractError = nil; + BOOL success = [archive extractFilesTo:extractDirectory overwrite:NO error:&extractError]; + XCTAssert(success, @"extract error %@", extractError); + // $ ls -l "extractURL.path" look up prmissions } -- (void)testPerformanceExample { - // This is an example of a performance test case. - [self measureBlock:^{ - // Put the code you want to measure the time of here. +- (void)testWriteFile { + + NSURL *testArchiveURL = [self.tempDirectory URLByAppendingPathComponent:@"WriteFile.zip"]; + [[NSFileManager defaultManager] removeItemAtURL:testArchiveURL error:nil]; + + UZKArchive *archive = [[UZKArchive alloc] initWithPath:testArchiveURL.path error:nil]; + + NSArray *array = [[NSFileManager defaultManager] subpathsAtPath:[testArchiveURL URLByDeletingLastPathComponent].path]; + [array enumerateObjectsUsingBlock:^(NSString *_Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + + if (![[obj pathExtension] hasSuffix:@"zip"]) { + + NSError *error = nil; + NSString *itemPath = [[testArchiveURL URLByDeletingLastPathComponent].path stringByAppendingPathComponent:obj]; + + BOOL success = [archive writeFile:itemPath + zipPath:obj + compressionMethod:UZKCompressionMethodDefault + password:nil + overwrite:NO + error:&error]; + XCTAssert(success, "write error %@", error); + } }]; + NSLog(@"%@", archive.filename); } @end From 6c50353ea9873a63022e36db40876ff92ba6d884 Mon Sep 17 00:00:00 2001 From: MartinLau Date: Mon, 24 Jun 2019 15:17:45 +0800 Subject: [PATCH 5/6] 1. Remove writeFile method in this version 2. Add the UZKFileInfo property (isSymLink, isResourceFork) 3. UZKFileInfo isDirectory attribute value takes a new judgment function 4. Rebase branch to "PR84" --- Source/UZKArchive.h | 90 ------------------- Source/UZKArchive.m | 148 +++---------------------------- Source/UZKFileInfo.h | 10 +++ Source/UZKFileInfo.m | 21 ++++- Tests/FileDescriptorUsageTests.m | 1 + Tests/PrmissionsTests.m | 64 +++++++++++++ Tests/TestKeppPrmissions.m | 69 -------------- 7 files changed, 105 insertions(+), 298 deletions(-) create mode 100644 Tests/PrmissionsTests.m delete mode 100644 Tests/TestKeppPrmissions.m diff --git a/Source/UZKArchive.h b/Source/UZKArchive.h index 3337117..3b77d96 100644 --- a/Source/UZKArchive.h +++ b/Source/UZKArchive.h @@ -592,32 +592,6 @@ compressionMethod:(UZKCompressionMethod)method progress:(nullable void (^)(CGFloat percentCompressed))progress 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 - */ -- (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 @@ -818,45 +792,6 @@ compressionMethod:(UZKCompressionMethod)method 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 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 @@ -898,31 +833,6 @@ compressionMethod:(UZKCompressionMethod)method error:(NSError **)error block:(BOOL(^)(BOOL(^writeData)(const void *bytes, unsigned int length), NSError **actionError))action; -/** - Writes file 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 file The full path on local - @param zipPath The full path to the target 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 Assign to an NSError instance before returning NO - @return YES if successful, NO on error - */ -- (BOOL)writeFile:(NSString *)file - zipPath:(NSString *)zipPath -compressionMethod:(UZKCompressionMethod)method - password:(nullable NSString *)password - overwrite:(BOOL)overwrite - error:(NSError **)error; - /** * Removes the given file from the archive * diff --git a/Source/UZKArchive.m b/Source/UZKArchive.m index 3a4c8ae..22660bc 100644 --- a/Source/UZKArchive.m +++ b/Source/UZKArchive.m @@ -1061,6 +1061,7 @@ - (BOOL)writeData:(NSData *)data return [self writeData:data filePath:filePath fileDate:nil + posixPermissions:0 compressionMethod:UZKCompressionMethodDefault password:nil overwrite:YES @@ -1075,6 +1076,7 @@ - (BOOL)writeData:(NSData *)data return [self writeData:data filePath:filePath fileDate:nil + posixPermissions:0 compressionMethod:UZKCompressionMethodDefault password:nil overwrite:YES @@ -1090,6 +1092,7 @@ - (BOOL)writeData:(NSData *)data return [self writeData:data filePath:filePath fileDate:fileDate + posixPermissions:0 compressionMethod:UZKCompressionMethodDefault password:nil overwrite:YES @@ -1122,6 +1125,7 @@ - (BOOL)writeData:(NSData *)data return [self writeData:data filePath:filePath fileDate:fileDate + posixPermissions:0 compressionMethod:method password:password overwrite:YES @@ -1146,50 +1150,6 @@ - (BOOL)writeData:(NSData *)data error:error]; } -- (BOOL)writeData:(NSData *)data - filePath:(NSString *)filePath - fileDate:(NSDate *)fileDate -compressionMethod:(UZKCompressionMethod)method - password:(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 - compressionMethod:method - password:password - overwrite:overwrite - progress:nil - error:error]; -#pragma clang diagnostic pop -} - -- (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 - 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 - password:password - overwrite:overwrite - progress:nil - error:error]; -#pragma clang diagnostic pop -} - - (BOOL)writeData:(NSData *)data filePath:(NSString *)filePath fileDate:(nullable NSDate *)fileDate @@ -1226,31 +1186,12 @@ - (BOOL)writeData:(NSData *)data filePath:filePath fileDate:fileDate posixPermissions:0 - compressionMethod:UZKCompressionMethodDefault + 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 -{ - return [self writeData:data - filePath:filePath - fileDate:fileDate - posixPermissions:0 - compressionMethod:UZKCompressionMethodDefault - password:password - overwrite:overwrite - error:error]; -} - (BOOL)writeData:(NSData *)data filePath:(NSString *)filePath @@ -1333,6 +1274,7 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath { return [self writeIntoBuffer:filePath fileDate:nil + posixPermissions:0 compressionMethod:UZKCompressionMethodDefault overwrite:YES CRC:0 @@ -1348,6 +1290,7 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath { return [self writeIntoBuffer:filePath fileDate:fileDate + posixPermissions:0 compressionMethod:UZKCompressionMethodDefault overwrite:YES CRC:0 @@ -1364,6 +1307,7 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath { return [self writeIntoBuffer:filePath fileDate:fileDate + posixPermissions:0 compressionMethod:method overwrite:YES CRC:0 @@ -1381,6 +1325,7 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath { return [self writeIntoBuffer:filePath fileDate:fileDate + posixPermissions:0 compressionMethod:method overwrite:overwrite CRC:0 @@ -1396,25 +1341,6 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath CRC:(uLong)preCRC error:(NSError *__autoreleasing *)error block:(BOOL (^)(BOOL (^)(const void *, unsigned int), NSError *__autoreleasing *))action -{ - return [self writeIntoBuffer:filePath - fileDate:fileDate - compressionMethod:method - overwrite:overwrite - CRC:preCRC - password:nil - error:error - block:action]; -} - -- (BOOL)writeIntoBuffer:(NSString *)filePath - fileDate:(NSDate *)fileDate - 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 @@ -1422,7 +1348,7 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath compressionMethod:method overwrite:overwrite CRC:preCRC - password:password + password:nil error:error block:action]; } @@ -1501,60 +1427,6 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath return success; } -- (BOOL)writeFile:(NSString *)file - zipPath:(NSString *)zipPath -compressionMethod:(UZKCompressionMethod)method - password:(NSString *)password - overwrite:(BOOL)overwrite - error:(NSError * _Nullable __autoreleasing *)error { - - BOOL isDir = NO; - if ([[NSFileManager defaultManager] fileExistsAtPath:file isDirectory:&isDir] && !isDir) { - - NSError *attributeError = nil; - unsigned long posixPermissions = 0; - NSDictionary *attributeDict = [[NSFileManager defaultManager] attributesOfItemAtPath:file error:&attributeError]; - if ([attributeDict objectForKey:NSFilePosixPermissions]) { - - posixPermissions = attributeDict.filePosixPermissions; - } - - int blockSize = 10*10240; - return [self writeIntoBuffer:zipPath - fileDate:nil - posixPermissions:posixPermissions - compressionMethod:UZKCompressionMethodDefault - overwrite:YES - CRC:0 - password:nil - error:error - block:^BOOL(BOOL (^ _Nonnull writeData)(const void * _Nonnull, unsigned int), NSError * _Nullable __autoreleasing * _Nullable actionError) { - - NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:file]; - while (true) { - - @autoreleasepool { - - NSData *data = [fileHandle readDataOfLength:blockSize]; - if (data.length == 0) { - - break; - } - const void *bytes = data.bytes; - unsigned int length = (unsigned int)data.length; - if (!writeData(bytes, length)) { - - return NO; - } - } - } - [fileHandle closeFile]; - return YES; - }]; - } - return NO; -} - - (BOOL)deleteFile:(NSString *)filePath error:(NSError * __autoreleasing*)error { UZKCreateActivity("Deleting File"); diff --git a/Source/UZKFileInfo.h b/Source/UZKFileInfo.h index 803c11e..7560e1e 100644 --- a/Source/UZKFileInfo.h +++ b/Source/UZKFileInfo.h @@ -73,6 +73,16 @@ 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 b93f617..ebfef7e 100644 --- a/Source/UZKFileInfo.m +++ b/Source/UZKFileInfo.m @@ -35,12 +35,15 @@ - (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); @@ -103,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/TestKeppPrmissions.m b/Tests/TestKeppPrmissions.m deleted file mode 100644 index 7257e74..0000000 --- a/Tests/TestKeppPrmissions.m +++ /dev/null @@ -1,69 +0,0 @@ -// -// TestKeppPrmissions.m -// UnzipKitTests -// -// Created by MartinLau on 2019/6/13. -// Copyright © 2019 Abbey Code. All rights reserved. -// - -#import "UZKArchiveTestCase.h" -#import "zip.h" -#import "UnzipKit.h" - - -@interface TestKeppPrmissions : UZKArchiveTestCase - -@end - -@implementation TestKeppPrmissions - -- (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]; - - NSError *extractError = nil; - BOOL success = [archive extractFilesTo:extractDirectory overwrite:NO error:&extractError]; - XCTAssert(success, @"extract error %@", extractError); - // $ ls -l "extractURL.path" look up prmissions -} - -- (void)testWriteFile { - - NSURL *testArchiveURL = [self.tempDirectory URLByAppendingPathComponent:@"WriteFile.zip"]; - [[NSFileManager defaultManager] removeItemAtURL:testArchiveURL error:nil]; - - UZKArchive *archive = [[UZKArchive alloc] initWithPath:testArchiveURL.path error:nil]; - - NSArray *array = [[NSFileManager defaultManager] subpathsAtPath:[testArchiveURL URLByDeletingLastPathComponent].path]; - [array enumerateObjectsUsingBlock:^(NSString *_Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { - - if (![[obj pathExtension] hasSuffix:@"zip"]) { - - NSError *error = nil; - NSString *itemPath = [[testArchiveURL URLByDeletingLastPathComponent].path stringByAppendingPathComponent:obj]; - - BOOL success = [archive writeFile:itemPath - zipPath:obj - compressionMethod:UZKCompressionMethodDefault - password:nil - overwrite:NO - error:&error]; - XCTAssert(success, "write error %@", error); - } - }]; - NSLog(@"%@", archive.filename); -} - -@end From 34f4dbc1e1ae19fc211e5c7ef9441520256fe862 Mon Sep 17 00:00:00 2001 From: MartinLau Date: Mon, 24 Jun 2019 15:21:03 +0800 Subject: [PATCH 6/6] Roll back the Xcode file --- UnzipKit.xcodeproj/project.pbxproj | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/UnzipKit.xcodeproj/project.pbxproj b/UnzipKit.xcodeproj/project.pbxproj index 2a6b5ab..7496d91 100644 --- a/UnzipKit.xcodeproj/project.pbxproj +++ b/UnzipKit.xcodeproj/project.pbxproj @@ -7,7 +7,7 @@ objects = { /* Begin PBXBuildFile section */ - 5B82326A22B1E6060049B931 /* TestKeppPrmissions.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B82326922B1E6060049B931 /* TestKeppPrmissions.m */; }; + 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 */; }; @@ -76,7 +76,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 5B82326922B1E6060049B931 /* TestKeppPrmissions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestKeppPrmissions.m; sourceTree = ""; }; + 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 = ""; }; @@ -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 */, - 968C40C31B58619C004C128E /* ListFilenamesTests.m */, 968C40C51B5861C3004C128E /* ListFileInfoTests.m */, + 968C40C31B58619C004C128E /* ListFilenamesTests.m */, 968C40BF1B585FDE004C128E /* ModesTests.m */, 968C40DD1B58642C004C128E /* MultithreadingTests.m */, 968C40D11B586310004C128E /* PasswordProtectionTests.m */, 968C40CD1B586277004C128E /* PerformOnDataTests.m */, 968C40CB1B586253004C128E /* PerformOnFilesTests.m */, + 5B5A9B9422C0B0CB00CD64D1 /* PrmissionsTests.m */, + 7A5A97001F89808900BCA061 /* ProgressReportingTests.m */, 968C40DF1B586490004C128E /* PropertyTests.m */, + 96FCC8401B306CDD00726AC7 /* UZKArchiveTestCase.m */, 968C40D31B586345004C128E /* WriteBufferedDataTests.m */, - 961A9BB41B306881007C4C6B /* WriteDataTests.swift */, 968C40C11B586132004C128E /* ZipFileDetectionTests.m */, - 5B82326922B1E6060049B931 /* TestKeppPrmissions.m */, + 9630C0371C6D27A4000693EE /* ExtractDataTests_Swift.swift */, + 963386B71EE89A49006B16BF /* UtilityMethods.swift */, + 961A9BB41B306881007C4C6B /* WriteDataTests.swift */, 96EA65AE1A40AEAE00685B6D /* Supporting Files */, ); name = UnzipKitTests; @@ -450,7 +450,6 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( - English, en, base, ); @@ -519,6 +518,7 @@ files = ( 96EA65BD1A40B2EC00685B6D /* UZKArchive.m in Sources */, 96EA66021A40E31900685B6D /* UZKFileInfo.m in Sources */, + 5B5A9B9522C0B0CB00CD64D1 /* PrmissionsTests.m in Sources */, 965CF00C1D241A8F00C80A88 /* NSURL+UnzipKitExtensions.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -533,7 +533,6 @@ 968C40D61B586380004C128E /* DeleteFileTests.m in Sources */, 96FCC8411B306CDD00726AC7 /* UZKArchiveTestCase.m in Sources */, 7A5A97011F89808900BCA061 /* ProgressReportingTests.m in Sources */, - 5B82326A22B1E6060049B931 /* TestKeppPrmissions.m in Sources */, 968C40C21B586132004C128E /* ZipFileDetectionTests.m in Sources */, 968C40D41B586345004C128E /* WriteBufferedDataTests.m in Sources */, 968C40CC1B586253004C128E /* PerformOnFilesTests.m in Sources */,