/
ArchiveExtractor.java
166 lines (147 loc) · 6.74 KB
/
ArchiveExtractor.java
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
package com.github.eirslett.maven.plugins.frontend.lib;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.AccessDeniedException;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.apache.commons.io.IOUtils;
import org.codehaus.plexus.util.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class ArchiveExtractionException extends Exception {
ArchiveExtractionException(String message) {
super(message);
}
ArchiveExtractionException(String message, Throwable cause) {
super(message, cause);
}
}
interface ArchiveExtractor {
public void extract(String archive, String destinationDirectory) throws ArchiveExtractionException;
}
final class DefaultArchiveExtractor implements ArchiveExtractor {
private static final Logger LOG = LoggerFactory.getLogger(DefaultArchiveExtractor.class);
private void prepDestination(File path, boolean directory) throws IOException {
if (directory) {
path.mkdirs();
} else {
if (!path.getParentFile().exists()) {
path.getParentFile().mkdirs();
}
if (!path.getParentFile().canWrite()) {
throw new AccessDeniedException(
String.format("Could not get write permissions for '%s'", path.getParentFile().getAbsolutePath()));
}
}
}
@Override
public void extract(String archive, String destinationDirectory) throws ArchiveExtractionException {
final File archiveFile = new File(archive);
try (FileInputStream fis = new FileInputStream(archiveFile)) {
if ("msi".equals(FileUtils.getExtension(archiveFile.getAbsolutePath()))) {
String command = "msiexec /a " + archiveFile.getAbsolutePath() + " /qn TARGETDIR=\""
+ destinationDirectory + "\"";
Process child = Runtime.getRuntime().exec(command);
try {
int result = child.waitFor();
if (result != 0) {
throw new ArchiveExtractionException(
"Could not extract " + archiveFile.getAbsolutePath() + "; return code " + result);
}
} catch (InterruptedException e) {
throw new ArchiveExtractionException(
"Unexpected interruption of while waiting for extraction process", e);
}
} else if ("zip".equals(FileUtils.getExtension(archiveFile.getAbsolutePath()))) {
ZipFile zipFile = new ZipFile(archiveFile);
try {
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
final File destPath = new File(destinationDirectory + File.separator + entry.getName());
prepDestination(destPath, entry.isDirectory());
if (!entry.isDirectory()) {
InputStream in = null;
OutputStream out = null;
try {
in = zipFile.getInputStream(entry);
out = new FileOutputStream(destPath);
IOUtils.copy(in, out);
} finally {
IOUtils.closeQuietly(in);
IOUtils.closeQuietly(out);
}
}
}
} finally {
zipFile.close();
}
} else {
// TarArchiveInputStream can be constructed with a normal FileInputStream if
// we ever need to extract regular '.tar' files.
TarArchiveInputStream tarIn = null;
try {
tarIn = new TarArchiveInputStream(new GzipCompressorInputStream(fis));
TarArchiveEntry tarEntry = tarIn.getNextTarEntry();
while (tarEntry != null) {
// Create a file for this tarEntry
final File destPath = new File(destinationDirectory + File.separator + tarEntry.getName());
prepDestination(destPath, tarEntry.isDirectory());
if (!startsWithPath(destPath.getCanonicalPath(), destinationDirectory)) {
throw new IOException(
"Expanding " + tarEntry.getName() + " would create file outside of " + destinationDirectory
);
}
if (!tarEntry.isDirectory()) {
destPath.createNewFile();
boolean isExecutable = (tarEntry.getMode() & 0100) > 0;
destPath.setExecutable(isExecutable);
OutputStream out = null;
try {
out = new FileOutputStream(destPath);
IOUtils.copy(tarIn, out);
} finally {
IOUtils.closeQuietly(out);
}
}
tarEntry = tarIn.getNextTarEntry();
}
} finally {
IOUtils.closeQuietly(tarIn);
}
}
} catch (IOException e) {
throw new ArchiveExtractionException("Could not extract archive: '"
+ archive
+ "'", e);
}
}
/**
* Do multiple file system checks that should enable the plugin to work on any file system
* whether or not it's case sensitive or not.
*
* @param destPath
* @param destDir
* @return
*/
private boolean startsWithPath(String destPath, String destDir) {
if (destPath.startsWith(destDir)) {
return true;
} else if (destDir.length() > destPath.length()) {
return false;
} else {
if (new File(destPath).exists() && !(new File(destPath.toLowerCase()).exists())) {
return false;
}
return destPath.toLowerCase().startsWith(destDir.toLowerCase());
}
}
}