mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
GT-3547 - Patch dir fix to allow loading of extension points
This commit is contained in:
parent
3c8f2bdeff
commit
3dced733df
9 changed files with 175 additions and 49 deletions
|
@ -58,15 +58,15 @@ public class ClassFinder {
|
|||
if ((lcPath.endsWith(".jar") || lcPath.endsWith(".zip")) && file.exists()) {
|
||||
|
||||
if (ClassJar.ignoreJar(lcPath)) {
|
||||
log.trace("Ignoring jar file: " + path);
|
||||
log.trace("Ignoring jar file: {}", path);
|
||||
continue;
|
||||
}
|
||||
|
||||
log.trace("Searching jar file: " + path);
|
||||
log.trace("Searching jar file: {}", path);
|
||||
classJars.add(new ClassJar(path, monitor));
|
||||
}
|
||||
else if (file.isDirectory()) {
|
||||
log.trace("Searching classpath directory: " + path);
|
||||
log.trace("Searching classpath directory: {}", path);
|
||||
classDirs.add(new ClassDir(path, monitor));
|
||||
}
|
||||
}
|
||||
|
@ -107,7 +107,6 @@ public class ClassFinder {
|
|||
return n1.compareTo(n2);
|
||||
});
|
||||
|
||||
|
||||
return classList;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,17 +17,23 @@ package ghidra.util.classfinder;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Set;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
|
||||
import generic.jar.ResourceFile;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import utility.application.ApplicationLayout;
|
||||
|
||||
class ClassJar {
|
||||
class ClassJar extends ClassLocation {
|
||||
|
||||
/**
|
||||
* Pattern for matching jar files in a module lib dir
|
||||
|
@ -36,24 +42,35 @@ class ClassJar {
|
|||
* <tt>build/libs</tt>, ending in <tt>.jar</tt> (non-capturing) and then
|
||||
* grab that dir's parent and the name of the jar file.
|
||||
*/
|
||||
private static Pattern ANY_MODULE_LIB_JAR_FILE_PATTERN =
|
||||
private static final Pattern ANY_MODULE_LIB_JAR_FILE_PATTERN =
|
||||
Pattern.compile(".*/(.*)/(?:lib|build/libs)/(.+).jar");
|
||||
|
||||
private static final String PATCH_DIR_PATH_FORWARD_SLASHED = getPatchDirPath();
|
||||
|
||||
private static String getPatchDirPath() {
|
||||
ApplicationLayout layout = Application.getApplicationLayout();
|
||||
ResourceFile installDir = layout.getApplicationInstallationDir();
|
||||
ResourceFile patchDir = new ResourceFile(installDir, "Ghidra/patch");
|
||||
String patchPath = patchDir.getAbsolutePath();
|
||||
String forwardSlashed = patchPath.replaceAll("\\\\", "/");
|
||||
return forwardSlashed;
|
||||
}
|
||||
|
||||
private String path;
|
||||
private Set<String> classNameList = new HashSet<>();
|
||||
private Set<Class<?>> classes = new HashSet<>();
|
||||
|
||||
ClassJar(String path, TaskMonitor monitor) throws CancelledException {
|
||||
this.path = path;
|
||||
|
||||
scan(monitor);
|
||||
scanJar(monitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
void getClasses(Set<Class<?>> set, TaskMonitor monitor) {
|
||||
checkForDuplicates(set);
|
||||
set.addAll(classes);
|
||||
}
|
||||
|
||||
private void scan(TaskMonitor monitor) throws CancelledException {
|
||||
private void scanJar(TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
File file = new File(path);
|
||||
|
||||
|
@ -88,25 +105,39 @@ class ClassJar {
|
|||
if (pathName.contains("ExternalLibraries")) {
|
||||
return true;
|
||||
}
|
||||
//
|
||||
// Production Mode - allow users to enter code in the 'patch' directory
|
||||
//
|
||||
String forwardSlashedPathName = pathName.replaceAll("\\\\", "/");
|
||||
if (isPatchJar(forwardSlashedPathName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Production Mode - In production, only module lib jar files are scanned.
|
||||
//
|
||||
if (isModuleDependencyJar(pathName)) {
|
||||
if (isModuleDependencyJar(forwardSlashedPathName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean isModuleDependencyJar(String pathName) {
|
||||
// Note: the path is expected to be using forward slashes
|
||||
private static boolean isPatchJar(String pathName) {
|
||||
String jarDirectory = FilenameUtils.getFullPathNoEndSeparator(pathName);
|
||||
return jarDirectory.equalsIgnoreCase(PATCH_DIR_PATH_FORWARD_SLASHED);
|
||||
}
|
||||
|
||||
// Note: the path is expected to be using forward slashes
|
||||
private static boolean isModuleDependencyJar(String pathName) {
|
||||
|
||||
if (ClassSearcher.SEARCH_ALL_JARS) {
|
||||
return true; // this will search all jar files
|
||||
}
|
||||
|
||||
String forwardSlashed = pathName.replaceAll("\\\\", "/");
|
||||
Matcher matcher = ANY_MODULE_LIB_JAR_FILE_PATTERN.matcher(forwardSlashed);
|
||||
// Note: the path is expected to be using forward slashes
|
||||
Matcher matcher = ANY_MODULE_LIB_JAR_FILE_PATTERN.matcher(pathName);
|
||||
if (!matcher.matches()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -121,15 +152,14 @@ class ClassJar {
|
|||
private void processClassFiles(JarEntry entry) {
|
||||
|
||||
String name = entry.getName();
|
||||
if (!name.endsWith(".class")) {
|
||||
if (!name.endsWith(CLASS_EXT)) {
|
||||
return;
|
||||
}
|
||||
name = name.substring(0, name.indexOf(".class"));
|
||||
name = name.substring(0, name.indexOf(CLASS_EXT));
|
||||
name = name.replace('/', '.');
|
||||
|
||||
Class<?> c = ClassFinder.loadExtensionPoint(path, name);
|
||||
if (c != null) {
|
||||
classNameList.add(name);
|
||||
classes.add(c);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.util.classfinder;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* Represents a place from which {@link Class}s can be obtained
|
||||
*/
|
||||
abstract class ClassLocation {
|
||||
|
||||
protected static final String CLASS_EXT = ".class";
|
||||
|
||||
final Logger log = LogManager.getLogger(getClass());
|
||||
|
||||
protected Set<Class<?>> classes = new HashSet<>();
|
||||
|
||||
abstract void getClasses(Set<Class<?>> set, TaskMonitor monitor) throws CancelledException;
|
||||
|
||||
void checkForDuplicates(Set<Class<?>> existingClasses) {
|
||||
if (!log.isTraceEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Class<?> c : classes) {
|
||||
if (existingClasses.contains(c)) {
|
||||
Module module = c.getModule();
|
||||
module.toString();
|
||||
log.trace("Attempting to load the same class twice: {}. " +
|
||||
"Keeping loaded class ; ignoring class from {}", c, this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -23,12 +23,11 @@ import ghidra.util.Msg;
|
|||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
class ClassPackage {
|
||||
class ClassPackage extends ClassLocation {
|
||||
|
||||
private static final FileFilter CLASS_FILTER =
|
||||
pathname -> pathname.getName().endsWith(".class");
|
||||
pathname -> pathname.getName().endsWith(CLASS_EXT);
|
||||
|
||||
private Set<Class<?>> classes = new HashSet<>();
|
||||
private Set<ClassPackage> children = new HashSet<>();
|
||||
private File rootDir;
|
||||
private File packageDir;
|
||||
|
@ -88,7 +87,11 @@ class ClassPackage {
|
|||
return new File(lRootDir, lPackageName.replace('.', File.separatorChar));
|
||||
}
|
||||
|
||||
@Override
|
||||
void getClasses(Set<Class<?>> set, TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
checkForDuplicates(set);
|
||||
|
||||
set.addAll(classes);
|
||||
|
||||
Iterator<ClassPackage> it = children.iterator();
|
||||
|
|
|
@ -248,7 +248,7 @@ public class ClassSearcher {
|
|||
|
||||
monitor.setMessage("Loading classes...");
|
||||
extensionPoints = searcher.getClasses(monitor);
|
||||
log.trace("Found extension classes: " + extensionPoints);
|
||||
log.trace("Found extension classes {}", extensionPoints);
|
||||
if (extensionPoints.isEmpty()) {
|
||||
throw new AssertException("Unable to location extension points!");
|
||||
}
|
||||
|
@ -307,7 +307,6 @@ public class ClassSearcher {
|
|||
}
|
||||
|
||||
private static void loadExtensionClassesFromJar() {
|
||||
// there will only be one root in jar file mode!
|
||||
ResourceFile appRoot = Application.getApplicationRootDirectory();
|
||||
ResourceFile extensionClassesFile = new ResourceFile(appRoot, "EXTENSION_POINT_CLASSES");
|
||||
try {
|
||||
|
@ -326,7 +325,8 @@ public class ClassSearcher {
|
|||
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new AssertException("Got unexpected IOException ", e);
|
||||
throw new AssertException("Unexpected IOException reading extension class file " +
|
||||
extensionClassesFile, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -338,7 +338,7 @@ public class ClassSearcher {
|
|||
throw new AssertException("Could not find modules for Class Searcher!");
|
||||
}
|
||||
|
||||
log.trace("Scanning module root directories: " + moduleRootDirectories);
|
||||
log.trace("Scanning module root directories: {}", moduleRootDirectories);
|
||||
|
||||
for (ResourceFile moduleRoot : moduleRootDirectories) {
|
||||
ResourceFile file = new ResourceFile(moduleRoot, "data/ExtensionPoint.manifest");
|
||||
|
@ -361,7 +361,7 @@ public class ClassSearcher {
|
|||
}
|
||||
buffy.append(')');
|
||||
extensionPointSuffixPattern = Pattern.compile(buffy.toString());
|
||||
log.trace("Using extension point pattern: " + extensionPointSuffixPattern);
|
||||
log.trace("Using extension point pattern: {}", extensionPointSuffixPattern);
|
||||
}
|
||||
|
||||
static boolean isExtensionPointName(String name) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue