From 26630b36afe58fcae7e6158a02e06ae21ac7dbd3 Mon Sep 17 00:00:00 2001 From: Julius Parishy Date: Wed, 9 May 2012 23:53:22 -0400 Subject: [PATCH] Fix for mailing tests regarding unicode filenames and symbolic links. See my note about ZIPs lack of documentation for symbolic links. A lot of this seems to be trial and error on my part as the implementation isn't documented. This seems to do the trick, however, and all of the tests are now passing on my end. As always, send more problems my way. --- SSZipArchive.m | 21 ++++++++++----- "Tests/Hello.\n" | 1 + "Tests/Nothing to see here. Move along.\n" | 1 + Tests/SSZipArchiveTests.m | 29 +++++++++++++++++---- Tests/SymbolicLink.zip | Bin 1196 -> 1372 bytes Tests/SymbolicLink/GitHub.app | 1 + Tests/SymbolicLink/Icon.icns | 1 + 7 files changed, 42 insertions(+), 12 deletions(-) create mode 100644 "Tests/Hello.\n" create mode 100644 "Tests/Nothing to see here. Move along.\n" create mode 120000 Tests/SymbolicLink/GitHub.app create mode 120000 Tests/SymbolicLink/Icon.icns diff --git a/SSZipArchive.m b/SSZipArchive.m index ccd7691..cb48b91 100644 --- a/SSZipArchive.m +++ b/SSZipArchive.m @@ -11,6 +11,8 @@ #import "zlib.h" #import "zconf.h" +#include + #define CHUNK 16384 @interface SSZipArchive () @@ -116,23 +118,28 @@ // http://www.pkware.com/documents/casestudies/APPNOTE.TXT // // ...to deduce this method of detecting whether the file in the ZIP is a symbolic link. - // If it is, it is listed as a directory but has an uncompressed data size greater than - // zero (real directories have it equal to 0) and the included, uncompressed data is the - // symbolic link path. + // If it is, it is listed as a directory but has a data size greater than zero (real + // directories have it equal to 0) and the included, uncompressed data is the symbolic link path. + // + // ZIP files did not originally include support for symbolic links so the specification + // doesn't include anything in them that isn't part of a unix extension that isn't being used + // by the archivers we're testing. Most of this is figured out through trial and error and + // reading ZIP headers in hex editors. This seems to do the trick though. // - const uLong ZipDirectoryVersion = 10; const uLong ZipCompressionMethodStore = 0; BOOL fileIsSymbolicLink = NO; - if((fileInfo.version_needed == ZipDirectoryVersion) && // Is it a directory? - (fileInfo.compression_method == ZipCompressionMethodStore) && // Is it compressed? - (fileInfo.compressed_size > 0)) // Is there any data there? + if((fileInfo.compression_method == ZipCompressionMethodStore) && // Is it compressed? + (S_ISDIR(fileInfo.external_fa)) && // Is it marked as a directory + (fileInfo.compressed_size > 0)) // Is there any data? { fileIsSymbolicLink = YES; } + NSLog(@"%s, link: %@, dir: %@", filename, S_ISLNK(fileInfo.external_fa) ? @"Yes" : @"NO", S_ISDIR(fileInfo.external_fa) ? @"Yes" : @"No"); + //NSLog(@"\"%s\" is symbolic link? %@", filename, fileIsSymbolicLink ? @"Yes." : @"No."); // Check if it contains directory diff --git "a/Tests/Hello.\n" "b/Tests/Hello.\n" new file mode 100644 index 0000000..18832d3 --- /dev/null +++ "b/Tests/Hello.\n" @@ -0,0 +1 @@ +Hello. diff --git "a/Tests/Nothing to see here. Move along.\n" "b/Tests/Nothing to see here. Move along.\n" new file mode 100644 index 0000000..c7ddc72 --- /dev/null +++ "b/Tests/Nothing to see here. Move along.\n" @@ -0,0 +1 @@ +Nothing to see here. Move along. diff --git a/Tests/SSZipArchiveTests.m b/Tests/SSZipArchiveTests.m index 98f1a75..bc45c64 100644 --- a/Tests/SSZipArchiveTests.m +++ b/Tests/SSZipArchiveTests.m @@ -91,16 +91,35 @@ [SSZipArchive unzipFileAtPath:zipPath toDestination:outputPath delegate:self]; - NSString* testSymlink = [outputPath stringByAppendingPathComponent:@"SymbolicLink/GitHub.app"]; + NSString *testSymlinkFolder = [outputPath stringByAppendingPathComponent:@"SymbolicLink/GitHub.app"]; + NSString *testSymlinkFile = [outputPath stringByAppendingPathComponent:@"SymbolicLink/Icon.icns"]; - NSError* error = nil; - NSString* symlinkPath = [[NSFileManager defaultManager] destinationOfSymbolicLinkAtPath:testSymlink error:&error]; + NSError *error = nil; + NSString *symlinkFolderPath = [[NSFileManager defaultManager] destinationOfSymbolicLinkAtPath:testSymlinkFolder error:&error]; + bool symbolicLinkToFolderPersists = ((symlinkFolderPath != nil) && [symlinkFolderPath isEqualToString:@"/Applications/GitHub.app"]) && (error == nil); - bool symbolicLinkPersists = ((symlinkPath != nil) && [symlinkPath isEqualToString:@"/Applications/GitHub.app"]) && (error == nil); + error = nil; - STAssertTrue(symbolicLinkPersists, @"Symbolic links should persist from the original archive to the outputted files."); + NSString *symlinkFilePath = [[NSFileManager defaultManager] destinationOfSymbolicLinkAtPath:testSymlinkFile error:&error]; + bool symbolicLinkToFilePersists = ((symlinkFilePath != nil) && [symlinkFilePath isEqualToString:@"/Applications/GitHub.app/Contents/Resources/AppIcon.icns"]) && (error == nil); + + STAssertTrue(symbolicLinkToFilePersists && symbolicLinkToFolderPersists, @"Symbolic links should persist from the original archive to the outputted files."); } +- (void)testUnzippingWithUnicodeFilenameInside { + + NSString* zipPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"Unicode" ofType:@"zip"]; + NSString* outputPath = [self _cachesPath:@"Unicode"]; + + [SSZipArchive unzipFileAtPath:zipPath toDestination:outputPath delegate:self]; + + bool unicodeFilenameWasExtracted = [[NSFileManager defaultManager] fileExistsAtPath:[outputPath stringByAppendingPathComponent:@"Accént.txt"]]; + + bool unicodeFolderWasExtracted = [[NSFileManager defaultManager] fileExistsAtPath:[outputPath stringByAppendingPathComponent:@"Fólder/Nothing.txt"]]; + + STAssertTrue(unicodeFilenameWasExtracted, @"Files with filenames in unicode should be extracted properly."); + STAssertTrue(unicodeFolderWasExtracted, @"Folders with names in unicode should be extracted propertly."); +} // Commented out to avoid checking in several gig file into the repository. Simply add a file named // `LargeArchive.zip` to the project and uncomment out these lines to test. diff --git a/Tests/SymbolicLink.zip b/Tests/SymbolicLink.zip index 952827dda232c43374924979b32b02eae747654e..d2296a14ccdce5826d8423313199ef17d456282d 100644 GIT binary patch delta 440 zcmZ3(d54Q9z?+$civa|J_fF(d=G3!X?GM6VCt6r@ezsWc&*Hnv|LevYZbqi?y^}i` zW8VfnoAPCM|ZTM<)w0dy2vQiL4sv zp+aU|F_?$Yq_!|yu|uUMe`OBAY68%+@hp~;&oOcP?#1*c*d+`M4sREpVZ!C>0B=?{ PkUDlCV=m z+B&(8*;5Q=X@ECE8PN2*%(`MQ)6t|9SghEgQj-%|La>?uwD~lPr3fn<$g6BXc#4sM J;S3Xq2LQdDK<)ql diff --git a/Tests/SymbolicLink/GitHub.app b/Tests/SymbolicLink/GitHub.app new file mode 120000 index 0000000..495a80a --- /dev/null +++ b/Tests/SymbolicLink/GitHub.app @@ -0,0 +1 @@ +/Applications/GitHub.app \ No newline at end of file diff --git a/Tests/SymbolicLink/Icon.icns b/Tests/SymbolicLink/Icon.icns new file mode 120000 index 0000000..26497fb --- /dev/null +++ b/Tests/SymbolicLink/Icon.icns @@ -0,0 +1 @@ +/Applications/GitHub.app/Contents/Resources/AppIcon.icns \ No newline at end of file