From a5de5b6beff226d7c29a211d932a2675965469b7 Mon Sep 17 00:00:00 2001 From: Christopher Denter Date: Fri, 8 Nov 2013 19:04:42 +0100 Subject: [PATCH 1/2] Issue #85: Keep relative symbolic links relative. Before, the library resolved symbolic links that are relative into absolute paths, using the current working directory of the process that's doing the unzipping, which to me seems pretty wrong. This was due to using -[NSURL fileURLWithPath:], which transforms relative URLs to absolute URLs automatically. I don't see much of a reason to use NSFileManager here, so I made that use symlink() directly. Alternatively, one could also use -[NSURL URLWithString:]. This keeps relative symlinks relative after unzipping. --- SSZipArchive/SSZipArchive.m | 49 ++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/SSZipArchive/SSZipArchive.m b/SSZipArchive/SSZipArchive.m index 324e635..4b911d7 100644 --- a/SSZipArchive/SSZipArchive.m +++ b/SSZipArchive/SSZipArchive.m @@ -224,34 +224,27 @@ } } } - else - { - // Get the path for the symbolic link - - NSURL* symlinkURL = [NSURL fileURLWithPath:fullPath]; - NSMutableString* destinationPath = [NSMutableString string]; - - int bytesRead = 0; - while((bytesRead = unzReadCurrentFile(zip, buffer, 4096)) > 0) - { - buffer[bytesRead] = 0; - [destinationPath appendString:[NSString stringWithUTF8String:(const char*)buffer]]; - } - - //NSLog(@"Symlinking to: %@", destinationPath); - - NSURL* destinationURL = [NSURL fileURLWithPath:destinationPath]; - - // Create the symbolic link - NSError* symlinkError = nil; - [fileManager createSymbolicLinkAtURL:symlinkURL withDestinationURL:destinationURL error:&symlinkError]; - - if(symlinkError != nil) - { - NSLog(@"Failed to create symbolic link at \"%@\" to \"%@\". Error: %@", symlinkURL.absoluteString, destinationURL.absoluteString, symlinkError.localizedDescription); - } - } - + else + { + // Assemble the path for the symbolic link + NSMutableString* destinationPath = [NSMutableString string]; + int bytesRead = 0; + while((bytesRead = unzReadCurrentFile(zip, buffer, 4096)) > 0) + { + buffer[bytesRead] = 0; + [destinationPath appendString:[NSString stringWithUTF8String:(const char*)buffer]]; + } + + // Create the symbolic link (making sure it stays relative if it was relative before) + int symlinkError = symlink([destinationPath cStringUsingEncoding:NSUTF8StringEncoding], + [fullPath cStringUsingEncoding:NSUTF8StringEncoding]); + + if(symlinkError != 0) + { + NSLog(@"Failed to create symbolic link at \"%@\" to \"%@\". symlink() error code: %d", fullPath, destinationPath, errno); + } + } + unzCloseCurrentFile( zip ); ret = unzGoToNextFile( zip ); From f89c159b2ab14b5caa5f1d1e965f0900676b037e Mon Sep 17 00:00:00 2001 From: Christopher Denter Date: Fri, 8 Nov 2013 20:34:17 +0100 Subject: [PATCH 2/2] Issue #85: Add test for relative symlink preservation patch. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This test adds a fixture RelativeSymlinks.zip with the following structure: RelativeSymbolicLink ├── symlinkedFile ├── symlinkedFolder └── symlinks ├── fileSymlink -> ../symlinkedFile └── folderSymlink -> ../symlinkedFolder The test checks if both `fileSymlink` and `folderSymlink` still point to the respective files in the parent directory after the fixture has been unzipped. --- SSZipArchive.xcodeproj/project.pbxproj | 6 +++++ Tests/Fixtures/RelativeSymbolicLink.zip | Bin 0 -> 1083 bytes Tests/SSZipArchiveTests.m | 30 ++++++++++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 Tests/Fixtures/RelativeSymbolicLink.zip diff --git a/SSZipArchive.xcodeproj/project.pbxproj b/SSZipArchive.xcodeproj/project.pbxproj index 550bc84..c4f826c 100644 --- a/SSZipArchive.xcodeproj/project.pbxproj +++ b/SSZipArchive.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 011F4B96182D71B700DE704F /* RelativeSymbolicLink.zip in Resources */ = {isa = PBXBuildFile; fileRef = 011F4B95182D71B700DE704F /* RelativeSymbolicLink.zip */; }; + 011F4B97182D72B400DE704F /* RelativeSymbolicLink.zip in Resources */ = {isa = PBXBuildFile; fileRef = 011F4B95182D71B700DE704F /* RelativeSymbolicLink.zip */; }; 210D525417DEFB880060D41A /* ioapi.c in Sources */ = {isa = PBXBuildFile; fileRef = 210D524C17DEFB880060D41A /* ioapi.c */; }; 210D525517DEFB880060D41A /* ioapi.c in Sources */ = {isa = PBXBuildFile; fileRef = 210D524C17DEFB880060D41A /* ioapi.c */; }; 210D525617DEFB880060D41A /* mztools.c in Sources */ = {isa = PBXBuildFile; fileRef = 210D524E17DEFB880060D41A /* mztools.c */; }; @@ -48,6 +50,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 011F4B95182D71B700DE704F /* RelativeSymbolicLink.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = RelativeSymbolicLink.zip; sourceTree = ""; }; 210D524B17DEFB880060D41A /* crypt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crypt.h; sourceTree = ""; }; 210D524C17DEFB880060D41A /* ioapi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ioapi.c; sourceTree = ""; }; 210D524D17DEFB880060D41A /* ioapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ioapi.h; sourceTree = ""; }; @@ -179,6 +182,7 @@ 21CC41EF17DB7D3500201DDC /* Fixtures */ = { isa = PBXGroup; children = ( + 011F4B95182D71B700DE704F /* RelativeSymbolicLink.zip */, 21CC41F017DB7D3500201DDC /* IncorrectHeaders.zip */, 21CC41F117DB7D3500201DDC /* PermissionsTestApp.app */, 21CC41F217DB7D3500201DDC /* SymbolicLink.zip */, @@ -303,6 +307,7 @@ buildActionMask = 2147483647; files = ( 21CC420F17DB7D6F00201DDC /* Images.xcassets in Resources */, + 011F4B96182D71B700DE704F /* RelativeSymbolicLink.zip in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -310,6 +315,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 011F4B97182D72B400DE704F /* RelativeSymbolicLink.zip in Resources */, 21CC41F817DB7D3500201DDC /* IncorrectHeaders.zip in Resources */, 21CC41FD17DB7D3500201DDC /* Unicode.zip in Resources */, 21CC41FA17DB7D3500201DDC /* SymbolicLink.zip in Resources */, diff --git a/Tests/Fixtures/RelativeSymbolicLink.zip b/Tests/Fixtures/RelativeSymbolicLink.zip new file mode 100644 index 0000000000000000000000000000000000000000..f4ce2968570da0e106928bee964cd2e89a452abc GIT binary patch literal 1083 zcmWIWW@h1H0D)7BGMvE-C?U!qzz~$0lUR~jmKt1{o0OlEne3C9m#rTf!NVY9RU7oi zvNq@|qXRtnf)uM_7T@v2z5h3R@x%bf*FkgRF=6U=5n}s)Vi2&q+xw zg8OJQl8+!p-bFJ~j)0NHaI*w~Ap{E@h*{TxW=+>A@e=?#8iX~07;6ASL#J3j4H!DW zpa%t&o}NBRpdow>a^eLWrc@!IaUiTs*jTWyu^9}O2=HcP5@p7fD0qOzgMq_aM-YwG z2cZ!h@FW5;4v|2R<4%bIVce2NQ1ZiS9E#6DX2X&TvQsf*A7S=e$3uk8hNT6F(?Mwg z*?7#9fNZ=dBYvlY(gnm^P`W@i7h9?Tg)0y^yj_?`&|IW6f^00dQ~@y+Wb6*Y#v-SY V0B=?{kY+X@6k=jv5C&of1^~R*8`%H= literal 0 HcmV?d00001 diff --git a/Tests/SSZipArchiveTests.m b/Tests/SSZipArchiveTests.m index 7ef2ca5..8e0c63e 100644 --- a/Tests/SSZipArchiveTests.m +++ b/Tests/SSZipArchiveTests.m @@ -120,6 +120,36 @@ XCTAssertTrue(symbolicLinkToFilePersists && symbolicLinkToFolderPersists, @"Symbolic links should persist from the original archive to the outputted files."); } +- (void)testUnzippingWithRelativeSymlink { + + NSString *resourceName = @"RelativeSymbolicLink"; + NSString* zipPath = [[NSBundle bundleForClass:[self class]] pathForResource:resourceName ofType:@"zip"]; + NSString* outputPath = [self _cachesPath:resourceName]; + + [SSZipArchive unzipFileAtPath:zipPath toDestination:outputPath delegate:self]; + + // Determine where the symlinks are + NSString *subfolderName = @"symlinks"; + NSString *testBasePath = [NSString pathWithComponents:@[outputPath, resourceName]]; + NSString *testSymlinkFolder = [NSString pathWithComponents:@[testBasePath, subfolderName, @"folderSymlink"]]; + NSString *testSymlinkFile = [NSString pathWithComponents:@[testBasePath, subfolderName, @"fileSymlink"]]; + + // Determine where the files they link to are + NSString *parentDir = @"../"; + NSString *testSymlinkFolderTarget = [NSString pathWithComponents:@[parentDir, @"symlinkedFolder"]]; + NSString *testSymlinkFileTarget = [NSString pathWithComponents:@[parentDir, @"symlinkedFile"]]; + + NSError *error = nil; + NSString *symlinkFolderPath = [[NSFileManager defaultManager] destinationOfSymbolicLinkAtPath:testSymlinkFolder error:&error]; + bool symbolicLinkToFolderPersists = ((symlinkFolderPath != nil) && [symlinkFolderPath isEqualToString:testSymlinkFolderTarget]) && (error == nil); + + error = nil; + + NSString *symlinkFilePath = [[NSFileManager defaultManager] destinationOfSymbolicLinkAtPath:testSymlinkFile error:&error]; + bool symbolicLinkToFilePersists = ((symlinkFilePath != nil) && [symlinkFilePath isEqualToString:testSymlinkFileTarget]) && (error == nil); + + XCTAssertTrue(symbolicLinkToFilePersists && symbolicLinkToFolderPersists, @"Relative symbolic links should persist from the original archive to the outputted files (and also remain relative)."); +} - (void)testUnzippingWithUnicodeFilenameInside {