summaryrefslogblamecommitdiffstats
path: root/src/main/java/org/openslx/satserver/util/Archive.java
blob: 8ad2123d0e57b3126abacbe374b277a205d0fd39 (plain) (tree)




























































































                                                                                                                                           


                                                                                                             


























































































































                                                                                                                                                               
package org.openslx.satserver.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Calendar;
import java.util.GregorianCalendar;

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.ArchiveStreamFactory;
import org.apache.commons.compress.archivers.ar.ArArchiveEntry;
import org.apache.commons.compress.archivers.cpio.CpioArchiveEntry;
import org.apache.commons.compress.archivers.dump.DumpArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.compressors.CompressorStreamFactory;
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
import org.apache.commons.compress.compressors.xz.XZCompressorOutputStream;
import org.apache.commons.io.FileUtils;

public class Archive
{

	/**
	 * Create input stream from given archive file. The archive format will be guessed
	 * from the firt couple of bytes in the file, which should work for most archive
	 * formats (see apache commons-compress docs for detailed information)
	 * 
	 * @param fileName archive to open for reading
	 * @return ArchiveInputStream stream to read archive from
	 * @throws FileNotFoundException
	 * @throws ArchiveException
	 * @throws IllegalArgumentException
	 */
	public static ArchiveInputStream getArchiveInputStream( String fileName )
			throws FileNotFoundException, ArchiveException, IllegalArgumentException
	{
		// Get an input stream for the archive handler
		// 1) Get input stream from file
		InputStream fileStream = new BufferedInputStream( new FileInputStream( fileName ) );
		// 2) Might be compressed, so try to get a decompressed stream
		InputStream archiveStream;
		try {
			archiveStream = new BufferedInputStream( new CompressorStreamFactory().createCompressorInputStream( fileStream ) );
		} catch ( Exception e ) {
			// Might be uncompressed archive, like tar - just try file input stream
			archiveStream = fileStream;
		}
		// 3) Try to create archive input stream - if it succeeds we can read the archive :)
		return new ArchiveStreamFactory().createArchiveInputStream( archiveStream );
	}

	/**
	 * Create tar archive with the given name. Optional compression method is
	 * determined by the file extension.
	 * 
	 * @param outputFile name of archive to create; can be relative or absolute path
	 * @return {@link TarArchiveOutputStream} to write archive entries to
	 * @throws IOException
	 */
	@SuppressWarnings( "resource" )
	public static TarArchiveOutputStream createTarArchive( String outputFile ) throws IOException
	{
		OutputStream outputStream = new BufferedOutputStream( new FileOutputStream( outputFile ) );
		OutputStream compressedOutputStream;
		if ( outputFile.endsWith( ".tar.gz" ) || outputFile.endsWith( ".tgz" ) ) {
			compressedOutputStream = new BufferedOutputStream( new GzipCompressorOutputStream( outputStream ) );
		} else if ( outputFile.endsWith( ".tar.bz2" ) || outputFile.endsWith( ".tbz" ) ) {
			compressedOutputStream = new BufferedOutputStream( new BZip2CompressorOutputStream( outputStream ) );
		} else if ( outputFile.endsWith( ".tar.xz" ) || outputFile.endsWith( ".txz" ) ) {
			compressedOutputStream = new BufferedOutputStream( new XZCompressorOutputStream( outputStream ) );
		} else if ( outputFile.endsWith( ".tar.Z" ) || outputFile.endsWith( ".tar.z" ) || outputFile.endsWith( ".tz" ) ) {
			compressedOutputStream = new BufferedOutputStream( new XZCompressorOutputStream( outputStream ) );
		} else if ( outputFile.endsWith( ".tar.lzma" ) ) {
			compressedOutputStream = new BufferedOutputStream( new XZCompressorOutputStream( outputStream ) );
		} else if ( outputFile.endsWith( ".tar" ) ) {
			compressedOutputStream = outputStream;
		} else {
			outputStream.close();
			return null;
		}
		try {
			TarArchiveOutputStream stream = new TarArchiveOutputStream( compressedOutputStream );
			stream.setLongFileMode( TarArchiveOutputStream.LONGFILE_POSIX );
			return stream;
		} catch ( Throwable t ) {
			compressedOutputStream.close();
			return null;
		}
	}

	public static TarArchiveEntry createTarArchiveEntry( ArchiveEntry inEntry, int defaultUser, int defaultGroup, int defaultDirMode, int defaultFileMode )
	{
		if ( inEntry instanceof TarArchiveEntry ) {
			// Source is tar - easy
			return (TarArchiveEntry)inEntry;
		}
		final TarArchiveEntry outEntry = new TarArchiveEntry( inEntry.getName() );
		outEntry.setSize( inEntry.getSize() );
		if ( inEntry instanceof ArArchiveEntry ) {
			// Source is ar - has most of the stuff tar supports; transform
			outEntry.setIds( ( (ArArchiveEntry)inEntry ).getUserId(), ( (ArArchiveEntry)inEntry ).getGroupId() );
			outEntry.setMode( ( (ArArchiveEntry)inEntry ).getMode() );
			outEntry.setModTime( ( (ArArchiveEntry)inEntry ).getLastModifiedDate() );
		} else if ( inEntry instanceof DumpArchiveEntry ) {
			// Source is dump (whatever the fuck that is) - has most of the stuff tar supports; transform
			outEntry.setIds( ( (DumpArchiveEntry)inEntry ).getUserId(), ( (DumpArchiveEntry)inEntry ).getGroupId() );
			outEntry.setMode( ( (DumpArchiveEntry)inEntry ).getMode() );
			outEntry.setModTime( ( (DumpArchiveEntry)inEntry ).getLastModifiedDate() );
		} else if ( inEntry instanceof CpioArchiveEntry ) {
			// Source is cpio - has most of the stuff tar supports; transform
			outEntry.setIds( (int) ( (CpioArchiveEntry)inEntry ).getUID(), (int) ( (CpioArchiveEntry)inEntry ).getGID() );
			outEntry.setMode( (int) ( ( (CpioArchiveEntry)inEntry ).getMode() & 07777 ) );
			outEntry.setModTime( ( (CpioArchiveEntry)inEntry ).getLastModifiedDate() );
		} else if ( inEntry instanceof ZipArchiveEntry ) {
			// Source is ZIP - might not have unix stuff
			outEntry.setIds( defaultUser, defaultGroup );
			int mode = ( (ZipArchiveEntry)inEntry ).getUnixMode();
			if ( mode != 0 ) { // Has unix permissions
				outEntry.setMode( mode );
			} else if ( inEntry.isDirectory() ) { // Use default passed in
				outEntry.setMode( defaultDirMode );
			} else { // Use default passed in
				outEntry.setMode( defaultFileMode );
			}
			outEntry.setModTime( ( (ZipArchiveEntry)inEntry ).getLastModifiedDate() );
		} else {
			outEntry.setIds( defaultUser, defaultGroup );
			if ( inEntry.isDirectory() ) {
				outEntry.setMode( defaultDirMode );
			} else {
				outEntry.setMode( defaultFileMode );
				Calendar cal = GregorianCalendar.getInstance();
				cal.set( 2014, 4, 2, 13, 57 );
				outEntry.setModTime( cal.getTime() );
			}
		}
		return outEntry;
	}

	public static boolean tarAddFile( TarArchiveOutputStream tar, String inArchiveFileName, File sourceFile, int mode )
	{
		if ( !sourceFile.exists() || !sourceFile.isFile() )
			return false;
		InputStream in;
		try {
			in = new FileInputStream( sourceFile );
		} catch ( Exception e ) {
			e.printStackTrace();
			return false;
		}
		TarArchiveEntry entry = new TarArchiveEntry( inArchiveFileName );
		long size = FileUtils.sizeOf( sourceFile );
		entry.setIds( 0, 0 );
		entry.setMode( mode );
		entry.setSize( size );
		try {
			tar.putArchiveEntry( entry );
			Util.streamCopy( in, tar, size );
			tar.closeArchiveEntry();
		} catch ( IOException e ) {
			e.printStackTrace();
			return false;
		} finally {
			Util.multiClose( in );
		}
		return true;
	}

	public static boolean tarCreateFileFromString( TarArchiveOutputStream tar, String fileName, String contents, int mode )
	{
		return tarCreateFileFromString( tar, fileName, contents.getBytes( StandardCharsets.UTF_8 ), mode );
	}

	public static boolean tarCreateFileFromString( TarArchiveOutputStream tar, String fileName, byte[] contents, int mode )
	{
		TarArchiveEntry entry = new TarArchiveEntry( fileName );
		entry.setIds( 0, 0 );
		entry.setMode( mode );
		entry.setSize( contents.length );
		try {
			tar.putArchiveEntry( entry );
			tar.write( contents );
			tar.closeArchiveEntry();
		} catch ( IOException e ) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	public static boolean tarCreateSymlink( TarArchiveOutputStream tar, String target, String linkName )
	{
		TarArchiveEntry entry = new TarArchiveEntry( linkName, TarArchiveEntry.LF_SYMLINK );
		entry.setIds( 0, 0 );
		entry.setMode( 0777 );
		entry.setLinkName( target );
		try {
			tar.putArchiveEntry( entry );
			tar.closeArchiveEntry();
		} catch ( IOException e ) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

}