Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preserve executability of files for tar archives #71

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions src/main/java/org/rauschig/jarchivelib/Archiver.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public interface Archiver {
* <br>
* If the archive parameter has no file extension (e.g. "archive" instead of "archive.zip"), the concrete archiver
* implementation should append it according to its file format (.zip, .tar, .tar.gz, ...).
*
*
* @param archive the name of the archive to create
* @param destination the destination directory where to place the created archive
* @param source the input file or directory to archive
Expand Down Expand Up @@ -65,7 +65,7 @@ public interface Archiver {
* Extracts the given archive file into the given destination directory.
* <br>
* The destination is expected to be a writable directory.
*
*
* @param archive the archive file to extract
* @param destination the directory to which to extract the files
* @throws IOException propagated I/O errors by {@code java.io}
Expand All @@ -86,7 +86,7 @@ public interface Archiver {
/**
* Reads the given archive file as an {@link ArchiveStream} which is used to access individual {@link ArchiveEntry}
* objects within the archive without extracting the archive onto the file system.
*
*
* @param archive the archive file to stream
* @return a new archive stream for the given archive
* @throws IOException propagated I/O errors by {@code java.io}
Expand All @@ -96,8 +96,15 @@ public interface Archiver {
/**
* Returns the filename extension that indicates the file format this archiver handles. E.g .tar" or ".zip". In case
* of compressed archives, it will return the composite filename extensions, e.g. ".tar.gz"
*
*
* @return a filename extension with a preceding dot
*/
String getFilenameExtension();

/**
* Returns the archiver's format
*
* @return archiver format
*/
ArchiveFormat getArchiveFormat();
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,16 @@
*/
class ArchiverCompressorDecorator implements Archiver {

private CommonsArchiver archiver;
private Archiver archiver;
private CommonsCompressor compressor;

/**
* Decorates the given Archiver with the given Compressor.
*
*
* @param archiver the archiver to decorate
* @param compressor the compressor used for compression
*/
ArchiverCompressorDecorator(CommonsArchiver archiver, CommonsCompressor compressor) {
ArchiverCompressorDecorator(Archiver archiver, CommonsCompressor compressor) {
this.archiver = archiver;
this.compressor = compressor;
}
Expand Down Expand Up @@ -119,13 +119,18 @@ public String getFilenameExtension() {
return archiver.getFilenameExtension() + compressor.getFilenameExtension();
}

@Override
public ArchiveFormat getArchiveFormat() {
return archiver.getArchiveFormat();
}

/**
* Returns a file name from the given archive name. The file extension suffix will be appended according to what is
* already present.
* <br>
* E.g. if the compressor uses the file extension "gz", the archiver "tar", and passed argument is "archive.tar",
* the returned value will be "archive.tar.gz".
*
*
* @param archive the existing archive file name
* @return the normalized archive file name including the correct file name extension
*/
Expand Down
16 changes: 9 additions & 7 deletions src/main/java/org/rauschig/jarchivelib/ArchiverFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ private ArchiverFactory() {
* Probes the given {@link File} for its file type and creates an {@link Archiver} based on this file type. If the
* File has a composite file extension such as ".tar.gz", the created {@link Archiver} will also handle ".gz"
* compression.
*
*
* @param archive the archive file to check.
* @return a new Archiver instance (that may also handle compression)
* @throws IllegalArgumentException if the given file is not a known archive
Expand All @@ -49,7 +49,7 @@ public static Archiver createArchiver(File archive) throws IllegalArgumentExcept
/**
* Creates an Archiver that handles the given {@link FileType}. The Archiver may handle compression inherently, if
* the {@link FileType} uses a compression type, such as ".tgz" might.
*
*
* @param fileType the file type
* @return a new Archiver instance (that may also handle compression)
*/
Expand All @@ -69,7 +69,7 @@ public static Archiver createArchiver(FileType fileType) {

/**
* Creates an Archiver for the given archive format that uses compression.
*
*
* @param archiveFormat the archive format e.g. "tar" or "zip"
* @param compression the compression algorithm name e.g. "gz"
* @return a new Archiver instance that also handles compression
Expand All @@ -88,21 +88,21 @@ public static Archiver createArchiver(String archiveFormat, String compression)

/**
* Creates an Archiver for the given archive format that uses compression.
*
*
* @param archiveFormat the archive format
* @param compression the compression algorithm
* @return a new Archiver instance that also handles compression
*/
public static Archiver createArchiver(ArchiveFormat archiveFormat, CompressionType compression) {
CommonsArchiver archiver = new CommonsArchiver(archiveFormat);
Archiver archiver = createArchiver(archiveFormat);
CommonsCompressor compressor = new CommonsCompressor(compression);

return new ArchiverCompressorDecorator(archiver, compressor);
}

/**
* Creates an Archiver for the given archive format.
*
*
* @param archiveFormat the archive format e.g. "tar" or "zip"
* @return a new Archiver instance
* @throws IllegalArgumentException if the archive format is unknown
Expand All @@ -117,7 +117,7 @@ public static Archiver createArchiver(String archiveFormat) throws IllegalArgume

/**
* Creates an Archiver for the given archive format.
*
*
* @param archiveFormat the archive format
* @return a new Archiver instance
*/
Expand All @@ -126,6 +126,8 @@ public static Archiver createArchiver(ArchiveFormat archiveFormat) {
return new SevenZArchiver();
} else if (archiveFormat == ArchiveFormat.ZIP) {
return new ZipFileArchiver();
} else if (archiveFormat == ArchiveFormat.TAR) {
return new TarArchiver();
}
return new CommonsArchiver(archiveFormat);
}
Expand Down
29 changes: 21 additions & 8 deletions src/main/java/org/rauschig/jarchivelib/CommonsArchiver.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.ArchiveOutputStream;
import org.apache.commons.compress.archivers.ArchiveStreamFactory;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;

/**
* Implementation of an {@link Archiver} that uses {@link ArchiveStreamFactory} to generate archive streams by a given
Expand All @@ -40,6 +41,7 @@ class CommonsArchiver implements Archiver {
this.archiveFormat = archiveFormat;
}

@Override
public ArchiveFormat getArchiveFormat() {
return archiveFormat;
}
Expand Down Expand Up @@ -120,7 +122,7 @@ public String getFilenameExtension() {
/**
* Returns a new ArchiveInputStream for reading archives. Subclasses can override this to return their own custom
* implementation.
*
*
* @param archive the archive file to stream from
* @return a new ArchiveInputStream for the given archive file
* @throws IOException propagated IO exceptions
Expand Down Expand Up @@ -152,7 +154,7 @@ protected ArchiveInputStream createArchiveInputStream(InputStream archive) throw
/**
* Returns a new ArchiveOutputStream for creating archives. Subclasses can override this to return their own custom
* implementation.
*
*
* @param archiveFile the archive file to stream to
* @return a new ArchiveOutputStream for the given archive file.
* @throws IOException propagated IO exceptions
Expand All @@ -167,7 +169,7 @@ protected ArchiveOutputStream createArchiveOutputStream(File archiveFile) throws

/**
* Asserts that the given File object is a readable file that can be used to extract from.
*
*
* @param archive the file to check
* @throws FileNotFoundException if the file does not exist
* @throws IllegalArgumentException if the file is a directory or not readable
Expand All @@ -185,7 +187,7 @@ protected void assertExtractSource(File archive) throws FileNotFoundException, I
/**
* Creates a new File in the given destination. The resulting name will always be "archive"."fileExtension". If the
* archive name parameter already ends with the given file name extension, it is not additionally appended.
*
*
* @param archive the name of the archive
* @param extension the file extension (e.g. ".tar")
* @param destination the parent path
Expand All @@ -207,7 +209,7 @@ protected File createNewArchiveFile(String archive, String extension, File desti
* Recursion entry point for {@link #writeToArchive(File, File[], ArchiveOutputStream)}.
* <br>
* Recursively writes all given source {@link File}s into the given {@link ArchiveOutputStream}.
*
*
* @param sources the files to write in to the archive
* @param archive the archive to write into
* @throws IOException when an I/O error occurs
Expand All @@ -220,14 +222,14 @@ protected void writeToArchive(File[] sources, ArchiveOutputStream archive) throw
throw new FileNotFoundException(source.getPath() + " (Permission denied)");
}

writeToArchive(source.getParentFile(), new File[]{ source }, archive);
writeToArchive(source.getParentFile(), new File[]{source}, archive);
}
}

/**
* Recursively writes all given source {@link File}s into the given {@link ArchiveOutputStream}. The paths of the
* sources in the archive will be relative to the given parent {@code File}.
*
*
* @param parent the parent file node for computing a relative path (see {@link IOUtils#relativePath(File, File)})
* @param sources the files to write in to the archive
* @param archive the archive to write into
Expand All @@ -245,18 +247,29 @@ protected void writeToArchive(File parent, File[] sources, ArchiveOutputStream a
}
}

/**
* Process archive entry before it's finalized / stored
* @param entry archive entry
*/
protected void processArchiveEntry(ArchiveEntry entry) {
// For specialized archivers to override. Default implementation is noop.
}

/**
* Creates a new {@link ArchiveEntry} in the given {@link ArchiveOutputStream}, and copies the given {@link File}
* into the new entry.
*
*
* @param file the file to add to the archive
* @param entryName the name of the archive entry
* @param archive the archive to write to
* @throws IOException when an I/O error occurs during FileInputStream creation or during copying
*/
protected void createArchiveEntry(File file, String entryName, ArchiveOutputStream archive) throws IOException {
ArchiveEntry entry = archive.createArchiveEntry(file, entryName);

// TODO #23: read permission from file, write it to the ArchiveEntry

this.processArchiveEntry(entry);
archive.putArchiveEntry(entry);

if (!entry.isDirectory()) {
Expand Down
32 changes: 16 additions & 16 deletions src/main/java/org/rauschig/jarchivelib/CommonsStreamFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,15 @@ static ArchiveInputStream createArchiveInputStream(String archiverName, InputStr
* @see {@link ArchiveStreamFactory#createArchiveInputStream(String, InputStream)}
*/
static ArchiveInputStream createArchiveInputStream(ArchiveFormat archiveFormat, InputStream in)
throws ArchiveException {
throws ArchiveException {
return createArchiveInputStream(archiveFormat.getName(), in);
}

/**
* @see {@link ArchiveStreamFactory#createArchiveInputStream(String, InputStream)}
*/
static ArchiveInputStream createArchiveInputStream(CommonsArchiver archiver, InputStream in)
throws ArchiveException {
static ArchiveInputStream createArchiveInputStream(Archiver archiver, InputStream in)
throws ArchiveException {
return createArchiveInputStream(archiver.getArchiveFormat(), in);
}

Expand All @@ -82,7 +82,7 @@ static ArchiveInputStream createArchiveInputStream(InputStream in) throws Archiv

/**
* Uses the {@link ArchiveStreamFactory} to create a new {@link ArchiveInputStream} for the given archive file.
*
*
* @param archive the archive file
* @return a new {@link ArchiveInputStream} for the given archive file
* @throws IOException propagated IOException when creating the FileInputStream.
Expand All @@ -96,34 +96,34 @@ static ArchiveInputStream createArchiveInputStream(File archive) throws IOExcept
* @see {@link ArchiveStreamFactory#createArchiveOutputStream(String, OutputStream)};
*/
static ArchiveOutputStream createArchiveOutputStream(String archiverName, OutputStream out)
throws ArchiveException {
throws ArchiveException {
return archiveStreamFactory.createArchiveOutputStream(archiverName, out);
}

static ArchiveOutputStream createArchiveOutputStream(ArchiveFormat format, File archive) throws IOException,
ArchiveException {
ArchiveException {
return createArchiveOutputStream(format.getName(), new FileOutputStream(archive));
}

/**
* Uses the {@link ArchiveStreamFactory} and the name of the given archiver to create a new
* {@link ArchiveOutputStream} for the given archive {@link File}.
*
*
* @param archiver the invoking archiver
* @param archive the archive file to create the {@link ArchiveOutputStream} for
* @return a new {@link ArchiveOutputStream}
* @throws IOException propagated IOExceptions when creating the FileOutputStream.
* @throws ArchiveException if the archiver name is not known
*/
static ArchiveOutputStream createArchiveOutputStream(CommonsArchiver archiver, File archive) throws IOException,
ArchiveException {
ArchiveException {
return createArchiveOutputStream(archiver.getArchiveFormat(), archive);
}

/**
* Uses the {@link CompressorStreamFactory} to create a new {@link CompressorInputStream} for the given source
* {@link File}.
*
*
* @param source the file to create the {@link CompressorInputStream} for
* @return a new {@link CompressorInputStream}
* @throws IOException if an I/O error occurs
Expand All @@ -136,22 +136,22 @@ static CompressorInputStream createCompressorInputStream(File source) throws IOE
/**
* Uses the {@link CompressorStreamFactory} to create a new {@link CompressorInputStream} for the compression type
* and wraps the given source {@link File} with it.
*
*
* @param source the file to create the {@link CompressorInputStream} for
* @return a new {@link CompressorInputStream}
* @throws IOException if an I/O error occurs
* @throws CompressorException if the compressor name is not known
*/
static CompressorInputStream createCompressorInputStream(CompressionType type, File source) throws IOException,
CompressorException {
CompressorException {
return createCompressorInputStream(type, new BufferedInputStream(new FileInputStream(source)));
}

/**
* @see {@link CompressorStreamFactory#createCompressorInputStream(String, java.io.InputStream)}
*/
static CompressorInputStream createCompressorInputStream(CompressionType compressionType, InputStream in)
throws CompressorException {
throws CompressorException {
return compressorStreamFactory.createCompressorInputStream(compressionType.getName(), in);
}

Expand All @@ -163,30 +163,30 @@ static CompressorInputStream createCompressorInputStream(InputStream in) throws
}

static CompressorOutputStream createCompressorOutputStream(CompressionType compressionType, File destination)
throws IOException, CompressorException {
throws IOException, CompressorException {
return createCompressorOutputStream(compressionType.getName(), new FileOutputStream(destination));
}

/**
* Uses the {@link CompressorStreamFactory} and the name of the given compressor to create a new
* {@link CompressorOutputStream} for the given destination {@link File}.
*
*
* @param compressor the invoking compressor
* @param destination the file to create the {@link CompressorOutputStream} for
* @return a new {@link CompressorOutputStream}
* @throws IOException if an I/O error occurs
* @throws CompressorException if the compressor name is not known
*/
static CompressorOutputStream createCompressorOutputStream(CommonsCompressor compressor, File destination)
throws IOException, CompressorException {
throws IOException, CompressorException {
return createCompressorOutputStream(compressor.getCompressionType(), destination);
}

/**
* @see {@link CompressorStreamFactory#createCompressorOutputStream(String, OutputStream)};
*/
static CompressorOutputStream createCompressorOutputStream(String compressorName, OutputStream out)
throws CompressorException {
throws CompressorException {
return compressorStreamFactory.createCompressorOutputStream(compressorName, out);
}

Expand Down
Loading