diff options
Diffstat (limited to 'src/main/java/org/openslx/taskmanager/tasks/RecompressArchive.java')
-rw-r--r-- | src/main/java/org/openslx/taskmanager/tasks/RecompressArchive.java | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/src/main/java/org/openslx/taskmanager/tasks/RecompressArchive.java b/src/main/java/org/openslx/taskmanager/tasks/RecompressArchive.java new file mode 100644 index 0000000..d428f03 --- /dev/null +++ b/src/main/java/org/openslx/taskmanager/tasks/RecompressArchive.java @@ -0,0 +1,193 @@ +package org.openslx.taskmanager.tasks; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.apache.commons.compress.archivers.ArchiveEntry; +import org.apache.commons.compress.archivers.ArchiveException; +import org.apache.commons.compress.archivers.ArchiveInputStream; +import org.apache.commons.compress.archivers.tar.TarArchiveEntry; +import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; +import org.openslx.satserver.util.Archive; +import org.openslx.satserver.util.Util; +import org.openslx.taskmanager.api.AbstractTask; + +import com.google.gson.annotations.Expose; + +public class RecompressArchive extends AbstractTask +{ + + @Expose + private String[] inputFiles; + + @Expose + private String outputFile; + + /* + * Own vars/constants not being deserialized + */ + + protected static final String[] ALLOWED_DIRS = + { "/tmp/", "/opt/openslx/configs/" }; + + private Output status = new Output(); + + /* + * Code + */ + + @Override + protected boolean execute() + { + if ( execute2() ) { + return true; + } + FileUtils.deleteQuietly( new File( this.outputFile ) ); + return false; + } + + private boolean execute2() + { + // Open output file archive + TarArchiveOutputStream outArchive = null; + try { + try { + FileUtils.forceMkdir( new File( new File( this.outputFile ).getParent() ) ); + outArchive = Archive.createTarArchive( this.outputFile ); + } catch ( IOException e2 ) { + status.error = e2.getMessage(); + status.errorCode = Output.ErrorCode.WRITE_FAILED; + return false; + } + + // Open input file archives, one by one + for ( final String inputFile : this.inputFiles ) { + ArchiveInputStream inArchive = null; + try { + try { + inArchive = Archive.getArchiveInputStream( inputFile ); + } catch ( FileNotFoundException e1 ) { + status.error = "(" + inputFile + ") " + e1.getMessage(); + status.errorCode = Output.ErrorCode.NOT_FOUND; + return false; + } catch ( IllegalArgumentException e1 ) { + status.error = "(" + inputFile + ") " + e1.getMessage(); + status.errorCode = Output.ErrorCode.UNKNOWN_ERROR; + return false; + } catch ( ArchiveException e1 ) { + status.error = "(" + inputFile + ") " + e1.getMessage(); + status.errorCode = Output.ErrorCode.UNKNOWN_FORMAT; + return false; + } + // It's open + ArchiveEntry inEntry; + + // Remember all files added, so we can issue warnings for duplicate entries + Set<String> entries = new HashSet<>(); + // Iterate over every entry + while ( ( inEntry = inArchive.getNextEntry() ) != null ) { + if ( !inArchive.canReadEntryData( inEntry ) ) + continue; // Skip unreadable entries + // Construct TarArchiveEntry - we want unix stuff like uid/gid, links, file/dir mode, so try to get from source archive + TarArchiveEntry outEntry = Archive.createTarArchiveEntry( inEntry, 0, 0, 0755, 0644 ); + // Ask lib if the entry can be written + if ( !outArchive.canWriteEntryData( outEntry ) ) { + status.warnings.add( "Commons-compress says entry '" + outEntry.getName() + "' cannot be written." ); + continue; + } + // Dupcheck + if ( entries.contains( outEntry.getName() ) ) { + status.warnings.add( "Duplicate entry: " + outEntry.getName() ); + } else { + entries.add( outEntry.getName() ); + } + // Actually add entry now + outArchive.putArchiveEntry( outEntry ); + if ( !Util.streamCopy( inArchive, outArchive, outEntry.getSize() ) ) { + status.error = "(" + inputFile + ") Could not copy entry '" + inEntry.getName() + "' to destination archive."; + status.errorCode = Output.ErrorCode.WRITE_FAILED; + return false; + } + outArchive.closeArchiveEntry(); + } // End entry + } catch ( IOException e ) { + return false; + } finally { + Util.multiClose( inArchive ); + } + } // End of loop over input archives + + return true; + } finally { + Util.multiClose( outArchive ); + } + } + + @Override + protected boolean initTask() + { + this.setStatusObject( this.status ); + // Input files + if ( this.inputFiles == null ) { + status.error = "Input: No archives given"; + status.errorCode = Output.ErrorCode.UNKNOWN_ERROR; + return false; + } + for ( int i = 0; i < this.inputFiles.length; ++i ) { + String inputFile = this.inputFiles[i]; + if ( inputFile == null || inputFile.length() == 0 || inputFile.charAt( 0 ) != '/' ) { + status.error = "Input: Need absolute path (got: " + inputFile + ")"; + status.errorCode = Output.ErrorCode.INVALID_DIRECTORY; + return false; + } + inputFile = FilenameUtils.normalize( inputFile ); + if ( inputFile == null || !Util.startsWith( inputFile, ALLOWED_DIRS ) ) { + status.error = "Input: File not in allowed directory"; + status.errorCode = Output.ErrorCode.INVALID_DIRECTORY; + return false; + } + this.inputFiles[i] = inputFile; + } + // Output file + if ( this.outputFile == null || this.outputFile.length() == 0 || this.outputFile.charAt( 0 ) != '/' ) { + status.error = "Output: Need absolute path."; + status.errorCode = Output.ErrorCode.INVALID_DIRECTORY; + return false; + } + this.outputFile = FilenameUtils.normalize( this.outputFile ); + if ( !Util.startsWith( this.outputFile, ALLOWED_DIRS ) ) { + status.error = "Output: File not in allowed directory"; + status.errorCode = Output.ErrorCode.INVALID_DIRECTORY; + return false; + } + return true; + } + + @SuppressWarnings( "unused" ) + private static class Output + { + protected String error = null; + + protected enum ErrorCode + { + NOT_FOUND, UNKNOWN_FORMAT, UNKNOWN_ERROR, INVALID_DIRECTORY, WRITE_FAILED + }; + + protected ErrorCode errorCode = null; + protected List<String> warnings = null; + + public static class Entry + { + protected String name = null; + protected boolean isdir = false; + protected long size = -1; + } + } + +} |