Merge remote-tracking branch 'origin/GP-7206_ryanmkurtz_unzip'

This commit is contained in:
Ryan Kurtz
2026-09-02 05:32:29 -04:00
3 changed files with 223 additions and 100 deletions
File diff suppressed because it is too large Load Diff
@@ -16,20 +16,18 @@
package ghidra.util.extensions;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.attribute.PosixFilePermission;
import java.util.*;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import generic.jar.ResourceFile;
import ghidra.framework.Application;
import ghidra.util.Msg;
import ghidra.util.SecureZipExtractor;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import utilities.util.FileUtilities;
@@ -578,21 +576,8 @@ public class ExtensionUtils {
return false;
}
try (ZipFile zipFile = new ZipFile.Builder().setFile(file).get()) {
Enumeration<ZipArchiveEntry> entries = zipFile.getEntries();
while (entries.hasMoreElements()) {
monitor.checkCancelled();
ZipArchiveEntry entry = entries.nextElement();
File destination = FileUtilities.getSecureFile(installDirRoot, entry.getName());
if (entry.isDirectory()) {
destination.mkdirs();
}
else {
writeZipEntryToFile(zipFile, entry, destination);
}
}
try {
SecureZipExtractor.extractSecurely(file, installDirRoot, monitor);
}
catch (IOException e) {
if (!FileUtilities.deleteDir(destinationFolder)) {
@@ -620,73 +605,4 @@ public class ExtensionUtils {
}
return false;
}
private static void writeZipEntryToFile(ZipFile zFile, ZipArchiveEntry entry, File destination)
throws IOException {
try (OutputStream outputStream =
new BufferedOutputStream(new FileOutputStream(destination))) {
// Create the file at the new location...
IOUtils.copy(zFile.getInputStream(entry), outputStream);
// ...and update its permissions. But only continue if the zip was created on a unix
//platform. If not, we cannot use the posix libraries to set permissions.
if (entry.getPlatform() != ZipArchiveEntry.PLATFORM_UNIX) {
return;
}
int mode = entry.getUnixMode();
if (mode != 0) { // 0 indicates non-unix platform
Set<PosixFilePermission> perms = getPermissions(mode);
try {
Files.setPosixFilePermissions(destination.toPath(), perms);
}
catch (UnsupportedOperationException e) {
// Need to catch this, as Windows does not support the posix call. This is not
// an error, however, and should just silently fail.
}
}
}
}
/**
* Converts Unix permissions to a set of {@link PosixFilePermission}s.
*
* @param unixMode integer representation of file permissions
* @return set of POSIX file permissions
*/
private static Set<PosixFilePermission> getPermissions(int unixMode) {
Set<PosixFilePermission> permissions = new HashSet<>();
if ((unixMode & 0400) != 0) {
permissions.add(PosixFilePermission.OWNER_READ);
}
if ((unixMode & 0200) != 0) {
permissions.add(PosixFilePermission.OWNER_WRITE);
}
if ((unixMode & 0100) != 0) {
permissions.add(PosixFilePermission.OWNER_EXECUTE);
}
if ((unixMode & 0040) != 0) {
permissions.add(PosixFilePermission.GROUP_READ);
}
if ((unixMode & 0020) != 0) {
permissions.add(PosixFilePermission.GROUP_WRITE);
}
if ((unixMode & 0010) != 0) {
permissions.add(PosixFilePermission.GROUP_EXECUTE);
}
if ((unixMode & 0004) != 0) {
permissions.add(PosixFilePermission.OTHERS_READ);
}
if ((unixMode & 0002) != 0) {
permissions.add(PosixFilePermission.OTHERS_WRITE);
}
if ((unixMode & 0001) != 0) {
permissions.add(PosixFilePermission.OTHERS_EXECUTE);
}
return permissions;
}
}
@@ -17,13 +17,13 @@ package generic.theme;
import java.io.*;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.apache.commons.io.FileUtils;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import ghidra.framework.Application;
import ghidra.util.Msg;
import ghidra.util.SecureZipExtractor;
import utilities.util.FileUtilities;
/**
@@ -70,18 +70,18 @@ class ThemeReader extends AbstractThemeReader {
}
private GTheme readZipTheme() throws IOException {
try (ZipFile zipFile = new ZipFile(file)) {
Enumeration<? extends ZipEntry> entries = zipFile.entries();
try (ZipFile archive = ZipFile.builder().setFile(file).get()) {
Enumeration<ZipArchiveEntry> entries = archive.getEntries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
ZipArchiveEntry entry = entries.nextElement();
String name = entry.getName();
try (InputStream is = zipFile.getInputStream(entry)) {
if (name.endsWith(".theme")) {
if (name.endsWith(".theme")) {
try (InputStream is = archive.getInputStream(entry)) {
processThemeData(name, is);
}
else {
processIconFile(name, is);
}
}
else {
processIconFile(name, entry, archive);
}
}
}
@@ -131,7 +131,8 @@ class ThemeReader extends AbstractThemeReader {
"Custom sections not allowed in theme files! " + section.getName());
}
private void processIconFile(String path, InputStream is) throws IOException {
private void processIconFile(String path, ZipArchiveEntry entry, ZipFile archive)
throws IOException {
int indexOf = path.indexOf("images/");
if (indexOf < 0) {
Msg.error(this, "Unknown file: " + path);
@@ -147,7 +148,8 @@ class ThemeReader extends AbstractThemeReader {
String relativePath = path.substring(indexOf, path.length());
File dir = Application.getUserSettingsDirectory();
File iconFile = FileUtilities.getSecureFile(dir, relativePath);
FileUtils.copyInputStreamToFile(is, iconFile);
iconFile.getParentFile().mkdirs();
SecureZipExtractor.extractSecurely(archive, entry, iconFile);
}
private void processThemeData(String name, InputStream is) throws IOException {