diff --git a/src/main/java/org/codehaus/plexus/archiver/zip/PlexusIoZipFileResourceCollection.java b/src/main/java/org/codehaus/plexus/archiver/zip/PlexusIoZipFileResourceCollection.java index 8f09ec735..dea7b83bb 100644 --- a/src/main/java/org/codehaus/plexus/archiver/zip/PlexusIoZipFileResourceCollection.java +++ b/src/main/java/org/codehaus/plexus/archiver/zip/PlexusIoZipFileResourceCollection.java @@ -18,6 +18,7 @@ import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipFile; +import org.codehaus.plexus.components.io.functions.SymlinkDestinationSupplier; import org.codehaus.plexus.components.io.resources.AbstractPlexusIoArchiveResourceCollection; import org.codehaus.plexus.components.io.resources.EncodingSupported; import org.codehaus.plexus.components.io.resources.PlexusIoResource; @@ -79,6 +80,59 @@ public URL getResource( String name ) private static class ZipFileResourceIterator implements Iterator, Closeable { + private class ZipFileResource + extends PlexusIoURLResource + { + private ZipFileResource( ZipArchiveEntry entry ) + { + super( entry.getName(), entry.getTime() == -1 ? PlexusIoResource.UNKNOWN_MODIFICATION_DATE : entry.getTime(), + entry.isDirectory() ? PlexusIoResource.UNKNOWN_RESOURCE_SIZE : entry.getSize(), + !entry.isDirectory(), entry.isDirectory(), true ); + } + + public URL getURL() + throws IOException + { + String spec = getName(); + if ( spec.startsWith( "/" ) ) + { + // Code path for PLXCOMP-170. Note that urlClassloader does not seem to produce correct + // urls for this. Which again means files loaded via this path cannot have file names + // requiring url encoding + spec = "./" + spec; + return new URL( url, spec ); + } + return urlClassLoader.getResource( spec ); + } + } + + private class ZipFileSymlinkResource + extends ZipFileResource + implements SymlinkDestinationSupplier + { + private final ZipArchiveEntry entry; + + private ZipFileSymlinkResource( ZipArchiveEntry entry ) + { + super( entry ); + + this.entry = entry; + } + + @Override + public String getSymlinkDestination() + throws IOException + { + return zipFile.getUnixSymlink( entry ); + } + + @Override + public boolean isSymbolicLink() + { + return true; + } + } + private final Enumeration en; private final URL url; @@ -103,28 +157,10 @@ public boolean hasNext() public PlexusIoResource next() { final ZipArchiveEntry entry = en.nextElement(); - long l = entry.getTime(); - final long lastModified = l == -1 ? PlexusIoResource.UNKNOWN_MODIFICATION_DATE : l; - final boolean dir = entry.isDirectory(); - final long size = dir ? PlexusIoResource.UNKNOWN_RESOURCE_SIZE : entry.getSize(); - return new PlexusIoURLResource( entry.getName(), lastModified, size, !dir, dir, true ) - { - public URL getURL() - throws IOException - { - String spec = getName(); - if ( spec.startsWith( "/" ) ) - { - // Code path for PLXCOMP-170. Note that urlClassloader does not seem to produce correct - // urls for this. Which again means files loaded via this path cannot have file names - // requiring url encoding - spec = "./" + spec; - return new URL( url, spec ); - } - return urlClassLoader.getResource( spec ); - } - }; + return entry.isUnixSymlink() + ? new ZipFileSymlinkResource( entry ) + : new ZipFileResource( entry ); } public void remove() diff --git a/src/test/java/org/codehaus/plexus/archiver/zip/PlexusIoZipFileResourceCollectionTest.java b/src/test/java/org/codehaus/plexus/archiver/zip/PlexusIoZipFileResourceCollectionTest.java index a8b065d6d..9f22317e5 100644 --- a/src/test/java/org/codehaus/plexus/archiver/zip/PlexusIoZipFileResourceCollectionTest.java +++ b/src/test/java/org/codehaus/plexus/archiver/zip/PlexusIoZipFileResourceCollectionTest.java @@ -2,6 +2,7 @@ import org.apache.commons.io.IOUtils; import org.codehaus.plexus.PlexusTestCase; +import org.codehaus.plexus.components.io.functions.SymlinkDestinationSupplier; import org.codehaus.plexus.components.io.resources.*; import java.io.BufferedReader; @@ -9,8 +10,10 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.Map; import java.util.Set; public class PlexusIoZipFileResourceCollectionTest @@ -87,4 +90,39 @@ public void testFilesThatAreNotThere() } } + public void testSymlinkEntries() + throws Exception + { + File testZip = new File( getBasedir(), "src/test/resources/symlinks/symlinks.zip" ); + Map symLinks = new HashMap(); + symLinks.put( "symDir", "targetDir/" ); + symLinks.put( "symLinkToDirOnTheOutside", "../dirOnTheOutside/" ); + symLinks.put( "symLinkToTheOutside", "../onTheOutside.txt" ); + symLinks.put( "symR", "fileR.txt" ); + symLinks.put( "symW", "fileW.txt" ); + symLinks.put( "symX", "fileX.txt" ); + PlexusIoZipFileResourceCollection + prc = new PlexusIoZipFileResourceCollection(); + prc.setFile( testZip ); + final Iterator entries = prc.getEntries(); + while ( entries.hasNext() ) + { + final PlexusIoResource next = entries.next(); + String symLinkTarget = symLinks.remove( next.getName() ); + if ( symLinkTarget != null ) + { + assertTrue( next.getName() + " must be symlink", next.isSymbolicLink() ); + assertTrue( next instanceof SymlinkDestinationSupplier ); + assertEquals( symLinkTarget, + ( (SymlinkDestinationSupplier) next ).getSymlinkDestination() ); + } + else + { + assertFalse( next.getName() + " must not be symlink", next.isSymbolicLink() ); + } + } + + assertTrue( symLinks.isEmpty() ); + } + }