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/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 ); diff --git a/Tests/Fixtures/RelativeSymbolicLink.zip b/Tests/Fixtures/RelativeSymbolicLink.zip new file mode 100644 index 0000000..f4ce296 Binary files /dev/null and b/Tests/Fixtures/RelativeSymbolicLink.zip differ 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 {