summaryrefslogtreecommitdiffstats
path: root/src/main/java/org/openslx/satserver/util/Archive.java
blob: 8ad2123d0e57b3126abacbe374b277a205d0fd39 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
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;
	}

}