From deacf5e4cb6e6a6e197b0887be687c99b1f6f96a Mon Sep 17 00:00:00 2001 From: Markus KARG Date: Wed, 19 Sep 2018 12:25:18 +0200 Subject: [PATCH] Parameter `fileMapper` for unpack path rewriting The new parameter `fileMapper` (default: null) can be set to an implementation of the `org.codehaus.plexus.components.io.filemappers.FileMapper` interface to rewrite the target path of each unpacked file. This is useful in case prefixes of target files names within the target directory shall be added (using `PrefixFileMapper`), changed or omitted (using `RegExpFileMapper`). Signed-off-by: Markus KARG --- .../plexus/archiver/AbstractUnArchiver.java | 27 ++++- .../codehaus/plexus/archiver/UnArchiver.java | 20 ++++ .../plexus/archiver/tar/TarUnArchiver.java | 9 +- .../archiver/zip/AbstractZipUnArchiver.java | 9 +- .../archiver/AbstractUnArchiverTest.java | 100 ++++++++++++++++++ 5 files changed, 155 insertions(+), 10 deletions(-) create mode 100644 src/test/java/org/codehaus/plexus/archiver/AbstractUnArchiverTest.java diff --git a/src/main/java/org/codehaus/plexus/archiver/AbstractUnArchiver.java b/src/main/java/org/codehaus/plexus/archiver/AbstractUnArchiver.java index 96758801f..10c585813 100644 --- a/src/main/java/org/codehaus/plexus/archiver/AbstractUnArchiver.java +++ b/src/main/java/org/codehaus/plexus/archiver/AbstractUnArchiver.java @@ -27,6 +27,7 @@ import java.util.List; import org.codehaus.plexus.archiver.util.ArchiveEntryUtils; import org.codehaus.plexus.components.io.attributes.SymlinkUtils; +import org.codehaus.plexus.components.io.filemappers.FileMapper; import org.codehaus.plexus.components.io.fileselectors.FileSelector; import org.codehaus.plexus.components.io.resources.PlexusIoResource; import org.codehaus.plexus.logging.AbstractLogEnabled; @@ -51,6 +52,8 @@ public abstract class AbstractUnArchiver private boolean overwrite = true; + private FileMapper[] fileMappers; + private List finalizers; private FileSelector[] fileSelectors; @@ -125,6 +128,18 @@ public void setOverwrite( final boolean b ) overwrite = b; } + @Override + public FileMapper[] getFileMappers() + { + return fileMappers; + } + + @Override + public void setFileMappers( final FileMapper[] fileMappers ) + { + this.fileMappers = fileMappers; + } + @Override public final void extract() throws ArchiverException @@ -301,10 +316,18 @@ public void setIgnorePermissions( final boolean ignorePermissions ) } protected void extractFile( final File srcF, final File dir, final InputStream compressedInputStream, - final String entryName, final Date entryDate, final boolean isDirectory, - final Integer mode, String symlinkDestination ) + String entryName, final Date entryDate, final boolean isDirectory, + final Integer mode, String symlinkDestination, final FileMapper[] fileMappers ) throws IOException, ArchiverException { + if ( fileMappers != null ) + { + for ( final FileMapper fileMapper : fileMappers ) + { + entryName = fileMapper.getMappedFileName( entryName ); + } + } + // Hmm. Symlinks re-evaluate back to the original file here. Unsure if this is a good thing... final File f = FileUtils.resolveFile( dir, entryName ); diff --git a/src/main/java/org/codehaus/plexus/archiver/UnArchiver.java b/src/main/java/org/codehaus/plexus/archiver/UnArchiver.java index 1e3491710..6a58ffb89 100644 --- a/src/main/java/org/codehaus/plexus/archiver/UnArchiver.java +++ b/src/main/java/org/codehaus/plexus/archiver/UnArchiver.java @@ -17,6 +17,7 @@ package org.codehaus.plexus.archiver; import java.io.File; +import org.codehaus.plexus.components.io.filemappers.FileMapper; import org.codehaus.plexus.components.io.fileselectors.FileSelector; public interface UnArchiver @@ -72,6 +73,25 @@ void extract( String path, File outputDirectory ) */ void setOverwrite( boolean b ); + /** + * Get chain of components which rewrite the target path of each unpacked file. + * + * @return {@link FileMapper}s to be used for rewriting each target path, or {@code null} if no rewriting shall happen. + * + * @since 3.7.0 + */ + FileMapper[] getFileMappers(); + + /*** + * Sets chain of components to be used for rewriting target path of each unpacked file. + * + * @param fileMappers {@link FileMapper} to be used for rewriting each target path, or {@code null} if no + * rewriting shall happen. + * + * @since 3.7.0 + */ + void setFileMappers( FileMapper[] fileMappers ); + /** * Sets a set of {@link FileSelector} instances, which may be used to select the files to extract from the archive. * If file selectors are present, then a file is only extracted, if it is confirmed by all file selectors. diff --git a/src/main/java/org/codehaus/plexus/archiver/tar/TarUnArchiver.java b/src/main/java/org/codehaus/plexus/archiver/tar/TarUnArchiver.java index 4bc94a49e..5de589d3d 100644 --- a/src/main/java/org/codehaus/plexus/archiver/tar/TarUnArchiver.java +++ b/src/main/java/org/codehaus/plexus/archiver/tar/TarUnArchiver.java @@ -29,6 +29,7 @@ import org.codehaus.plexus.archiver.AbstractUnArchiver; import org.codehaus.plexus.archiver.ArchiverException; import org.codehaus.plexus.archiver.util.Streams; +import org.codehaus.plexus.components.io.filemappers.FileMapper; import org.codehaus.plexus.util.IOUtil; import org.iq80.snappy.SnappyInputStream; @@ -84,16 +85,16 @@ public void setEncoding( String encoding ) protected void execute() throws ArchiverException { - execute( getSourceFile(), getDestDirectory() ); + execute( getSourceFile(), getDestDirectory(), getFileMappers() ); } @Override protected void execute( String path, File outputDirectory ) { - execute( new File( path ), getDestDirectory() ); + execute( new File( path ), getDestDirectory(), getFileMappers() ); } - protected void execute( File sourceFile, File destDirectory ) + protected void execute( File sourceFile, File destDirectory, FileMapper[] fileMappers ) throws ArchiverException { TarArchiveInputStream tis = null; @@ -111,7 +112,7 @@ protected void execute( File sourceFile, File destDirectory ) { final String symlinkDestination = te.isSymbolicLink() ? te.getLinkName() : null; extractFile( sourceFile, destDirectory, tis, te.getName(), te.getModTime(), te.isDirectory(), - te.getMode() != 0 ? te.getMode() : null, symlinkDestination ); + te.getMode() != 0 ? te.getMode() : null, symlinkDestination, fileMappers ); } } diff --git a/src/main/java/org/codehaus/plexus/archiver/zip/AbstractZipUnArchiver.java b/src/main/java/org/codehaus/plexus/archiver/zip/AbstractZipUnArchiver.java index bed3e2bad..8703f439f 100644 --- a/src/main/java/org/codehaus/plexus/archiver/zip/AbstractZipUnArchiver.java +++ b/src/main/java/org/codehaus/plexus/archiver/zip/AbstractZipUnArchiver.java @@ -30,6 +30,7 @@ import org.apache.commons.compress.utils.IOUtils; import org.codehaus.plexus.archiver.AbstractUnArchiver; import org.codehaus.plexus.archiver.ArchiverException; +import org.codehaus.plexus.components.io.filemappers.FileMapper; import org.codehaus.plexus.components.io.resources.PlexusIoResource; /** @@ -178,7 +179,7 @@ protected void execute() extractFileIfIncluded( getSourceFile(), getDestDirectory(), in, fileInfo.getName(), new Date( ze.getTime() ), ze.isDirectory(), ze.getUnixMode() != 0 ? ze.getUnixMode() : null, - resolveSymlink( zf, ze ) ); + resolveSymlink( zf, ze ), getFileMappers() ); in.close(); in = null; @@ -216,10 +217,10 @@ private String resolveSymlink( ZipFile zf, ZipArchiveEntry ze ) private void extractFileIfIncluded( final File sourceFile, final File destDirectory, final InputStream inputStream, final String name, final Date time, final boolean isDirectory, - final Integer mode, String symlinkDestination ) + final Integer mode, String symlinkDestination, final FileMapper[] fileMappers ) throws IOException, ArchiverException { - extractFile( sourceFile, destDirectory, inputStream, name, time, isDirectory, mode, symlinkDestination ); + extractFile( sourceFile, destDirectory, inputStream, name, time, isDirectory, mode, symlinkDestination, fileMappers ); } @Override @@ -250,7 +251,7 @@ protected void execute( final String path, final File outputDirectory ) extractFileIfIncluded( getSourceFile(), outputDirectory, in, ze.getName(), new Date( ze.getTime() ), ze.isDirectory(), ze.getUnixMode() != 0 ? ze.getUnixMode() : null, - resolveSymlink( zipFile, ze ) ); + resolveSymlink( zipFile, ze ), getFileMappers() ); in.close(); in = null; diff --git a/src/test/java/org/codehaus/plexus/archiver/AbstractUnArchiverTest.java b/src/test/java/org/codehaus/plexus/archiver/AbstractUnArchiverTest.java new file mode 100644 index 000000000..0fd224ba5 --- /dev/null +++ b/src/test/java/org/codehaus/plexus/archiver/AbstractUnArchiverTest.java @@ -0,0 +1,100 @@ +/** + * + * Copyright 2018 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.codehaus.plexus.archiver; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; + +import org.codehaus.plexus.components.io.filemappers.FileMapper; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +/** + * Unit test for {@link AbstractUnArchiver} + * + * @author Markus KARG + */ +public class AbstractUnArchiverTest +{ + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private AbstractUnArchiver abstractUnArchiver; + + @Before + public void setUp() + { + this.abstractUnArchiver = new AbstractUnArchiver() + { + @Override + protected void execute( final String path, final File outputDirectory ) + throws ArchiverException + { + // unused + } + + @Override + protected void execute() + throws ArchiverException + { + // unused + } + }; + } + + @After + public void tearDown() + { + this.abstractUnArchiver = null; + } + + @Test + public void shouldThrowExceptionBecauseRewrittenPathIsOutOfDirectory() + throws ArchiverException, IOException + { + // given + this.thrown.expectMessage( "Entry is outside of the target directory (../PREFIX/ENTRYNAME.SUFFIX)" ); + final File targetFolder = Files.createTempDirectory( null ).toFile(); + final FileMapper[] fileMappers = new FileMapper[] { new FileMapper() + { + @Override + public String getMappedFileName( String pName ) + { + return "../PREFIX/" + pName; + } + }, new FileMapper() + { + @Override + public String getMappedFileName( String pName ) + { + return pName + ".SUFFIX"; + } + } }; + + // when + this.abstractUnArchiver.extractFile( null, targetFolder, null, "ENTRYNAME", null, false, null, null, + fileMappers ); + + // then + // ArchiverException is thrown providing the rewritten path + } + +}