summaryrefslogblamecommitdiffstats
path: root/src/main/java/org/openslx/satserver/util/Archive.java
blob: f622a0e5a2c8db0de5f1fc9f2d92b7f0b7e77c90 (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.lz4.BlockLZ4CompressorOutputStream;
import org.apache.commons.compress.compressors.xz.XZCompressorOutputStream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;

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<? extends ArchiveEntry> 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.lz4" ) ) {
			compressedOutputStream = new BufferedOutputStream( new BlockLZ4CompressorOutputStream( 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, boolean overrideUserGroup )
	{
		String name = inEntry.getName();
		if ( Util.isEmpty( name ) )
			return null;
		if ( !name.startsWith( "/" ) ) {
			name = "/" + name;
		}
		name = FilenameUtils.normalize( name );
		if ( name == null )
			return null;
		if ( Util.isEmpty( name ) )
			return null;
		final TarArchiveEntry outEntry = new TarArchiveEntry( name );
		outEntry.setSize( inEntry.getSize() );
		if ( inEntry instanceof TarArchiveEntry ) {
			// Source is tar - easy
			byte[] buffer = new byte[1000];
			( (TarArchiveEntry)inEntry ).writeEntryHeader( buffer );
			outEntry.parseTarHeader( buffer );
			outEntry.setName( name ); // Reset, as this was overwritten
			if ( overrideUserGroup ) {
				// Always replace these
				outEntry.setUserId( defaultUser );
				outEntry.setGroupId( defaultGroup );
				// TODO
				if ( defaultUser == 0 ) {
					outEntry.setUserName( "root" );
				}
				if ( defaultGroup == 0 ) {
					outEntry.setGroupName( "root" );
				}
			}
		} else 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 TarArchiveEntry createTarArchiveEntry( ArchiveEntry inEntry,
			int defaultUser, int defaultGroup, int defaultDirMode, int defaultFileMode )
	{
		return createTarArchiveEntry( inEntry, defaultUser, defaultGroup, defaultDirMode, defaultFileMode, false );
	}

	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;
	}

}