mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
Merge remote-tracking branch
'origin/GP-1096-dragonmacher-exception-closing-project' (Closes #3179)
This commit is contained in:
commit
1b9ed22359
1 changed files with 97 additions and 52 deletions
|
@ -20,24 +20,24 @@ import java.net.MalformedURLException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import ghidra.app.services.ProgramManager;
|
import ghidra.app.services.ProgramManager;
|
||||||
import ghidra.formats.gfilesystem.*;
|
import ghidra.formats.gfilesystem.FSRL;
|
||||||
|
import ghidra.formats.gfilesystem.FileSystemService;
|
||||||
import ghidra.framework.main.AppInfo;
|
import ghidra.framework.main.AppInfo;
|
||||||
import ghidra.framework.model.*;
|
import ghidra.framework.model.*;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.SystemUtilities;
|
|
||||||
import ghidra.util.datastruct.FixedSizeHashMap;
|
import ghidra.util.datastruct.FixedSizeHashMap;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a best-effort<sup>[1]</sup> mapping / association between Ghidra Program/DomainFile objects and
|
* Provides a best-effort<sup>[1]</sup> mapping / association between Ghidra Program/DomainFile
|
||||||
* GFilesystem files (identified by their {@link FSRL}).
|
* objects and GFilesystem files (identified by their {@link FSRL}).
|
||||||
* <p>
|
* <p>
|
||||||
* As there is no current feature that allows you to quickly query the metadata of Programs/DomainFile
|
* As there is no current feature that allows you to quickly query the metadata of
|
||||||
* objects in the current project, finding a Program by its MD5 or by a original source location
|
* Programs/DomainFile objects in the current project, finding a Program by its MD5 or by a
|
||||||
* string is not easily possible.
|
* original source location string is not easily possible.
|
||||||
* <p>
|
* <p>
|
||||||
* Threadsafe.
|
* Threadsafe.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -64,7 +64,7 @@ public class ProgramMappingService {
|
||||||
new FixedSizeHashMap<>(FSRL_TO_PATH_MAP_SIZE);
|
new FixedSizeHashMap<>(FSRL_TO_PATH_MAP_SIZE);
|
||||||
|
|
||||||
private ProgramMappingService() {
|
private ProgramMappingService() {
|
||||||
// nada
|
// utils class; cannot instantiate
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -90,8 +90,7 @@ public class ProgramMappingService {
|
||||||
public static boolean isFileOpen(FSRL fsrl) {
|
public static boolean isFileOpen(FSRL fsrl) {
|
||||||
String expectedMD5 = fsrl.getMD5();
|
String expectedMD5 = fsrl.getMD5();
|
||||||
|
|
||||||
List<DomainFile> openDomainFiles = new ArrayList<>();
|
List<DomainFile> openDomainFiles = findOpenFiles();
|
||||||
AppInfo.getActiveProject().getProjectData().findOpenFiles(openDomainFiles);
|
|
||||||
|
|
||||||
Object consumer = new Object();
|
Object consumer = new Object();
|
||||||
for (DomainFile df : openDomainFiles) {
|
for (DomainFile df : openDomainFiles) {
|
||||||
|
@ -140,33 +139,34 @@ public class ProgramMappingService {
|
||||||
* and not persisted.
|
* and not persisted.
|
||||||
* <p>
|
* <p>
|
||||||
* @param fsrl {@link FSRL} to search for
|
* @param fsrl {@link FSRL} to search for
|
||||||
* @return {@link DomainFile} that was previously associated via {@link #createAssociation(FSRL, DomainFile)}
|
* @return {@link DomainFile} that was previously associated via
|
||||||
* and friends.
|
* {@link #createAssociation(FSRL, DomainFile)} and friends.
|
||||||
*/
|
*/
|
||||||
public static DomainFile getCachedDomainFileFor(FSRL fsrl) {
|
public static DomainFile getCachedDomainFileFor(FSRL fsrl) {
|
||||||
String doPath = null;
|
String path = null;
|
||||||
synchronized (fsrlToProjectPathMap) {
|
synchronized (fsrlToProjectPathMap) {
|
||||||
doPath = fsrlToProjectPathMap.get(fsrl);
|
path = fsrlToProjectPathMap.get(fsrl);
|
||||||
if (doPath == null && fsrl.getMD5() != null) {
|
if (path == null && fsrl.getMD5() != null) {
|
||||||
fsrl = fsrl.withMD5(null);
|
fsrl = fsrl.withMD5(null);
|
||||||
doPath = fsrlToProjectPathMap.get(fsrl);
|
path = fsrlToProjectPathMap.get(fsrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (doPath != null) {
|
|
||||||
DomainFile domainFile = AppInfo.getActiveProject().getProjectData().getFile(doPath);
|
|
||||||
if (domainFile == null) {
|
|
||||||
// The domainFile will be null if the cached path is no longer valid. Remove
|
|
||||||
// the stale path from the cache.
|
|
||||||
synchronized (fsrlToProjectPathMap) {
|
|
||||||
if (SystemUtilities.isEqual(fsrlToProjectPathMap.get(fsrl), doPath)) {
|
|
||||||
fsrlToProjectPathMap.remove(fsrl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return domainFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
if (path == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
DomainFile domainFile = getProjectFile(path);
|
||||||
|
if (domainFile == null) {
|
||||||
|
// The domainFile will be null if the cached path is no longer valid. Remove
|
||||||
|
// the stale path from the cache.
|
||||||
|
synchronized (fsrlToProjectPathMap) {
|
||||||
|
if (Objects.equals(fsrlToProjectPathMap.get(fsrl), path)) {
|
||||||
|
fsrlToProjectPathMap.remove(fsrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return domainFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -245,7 +245,8 @@ public class ProgramMappingService {
|
||||||
* must release the consumer when done.
|
* must release the consumer when done.
|
||||||
* @param programManager {@link ProgramManager} that will be used to open DomainFiles
|
* @param programManager {@link ProgramManager} that will be used to open DomainFiles
|
||||||
* if necessary.
|
* if necessary.
|
||||||
* @param openState one of {@link ProgramManager#OPEN_VISIBLE}, {@link ProgramManager#OPEN_HIDDEN}, {@link ProgramManager#OPEN_VISIBLE}
|
* @param openState one of {@link ProgramManager#OPEN_VISIBLE},
|
||||||
|
* {@link ProgramManager#OPEN_HIDDEN}, {@link ProgramManager#OPEN_VISIBLE}
|
||||||
* @return {@link Program} which was imported from the specified FSRL, or null if not found.
|
* @return {@link Program} which was imported from the specified FSRL, or null if not found.
|
||||||
*/
|
*/
|
||||||
public static Program findMatchingProgramOpenIfNeeded(FSRL fsrl, Object consumer,
|
public static Program findMatchingProgramOpenIfNeeded(FSRL fsrl, Object consumer,
|
||||||
|
@ -265,7 +266,8 @@ public class ProgramMappingService {
|
||||||
* must release the consumer when done.
|
* must release the consumer when done.
|
||||||
* @param programManager {@link ProgramManager} that will be used to open DomainFiles
|
* @param programManager {@link ProgramManager} that will be used to open DomainFiles
|
||||||
* if necessary.
|
* if necessary.
|
||||||
* @param openState one of {@link ProgramManager#OPEN_VISIBLE}, {@link ProgramManager#OPEN_HIDDEN}, {@link ProgramManager#OPEN_VISIBLE}
|
* @param openState one of {@link ProgramManager#OPEN_VISIBLE},
|
||||||
|
* {@link ProgramManager#OPEN_HIDDEN}, {@link ProgramManager#OPEN_VISIBLE}
|
||||||
* @return {@link Program} which was imported from the specified FSRL, or null if not found.
|
* @return {@link Program} which was imported from the specified FSRL, or null if not found.
|
||||||
*/
|
*/
|
||||||
public static Program findMatchingProgramOpenIfNeeded(FSRL fsrl, DomainFile domainFile,
|
public static Program findMatchingProgramOpenIfNeeded(FSRL fsrl, DomainFile domainFile,
|
||||||
|
@ -306,7 +308,7 @@ public class ProgramMappingService {
|
||||||
// use a temp consumer to hold the domainObject open because the caller-supplied
|
// use a temp consumer to hold the domainObject open because the caller-supplied
|
||||||
// consumer might already have been used to open one of the files we are querying.
|
// consumer might already have been used to open one of the files we are querying.
|
||||||
Object tmpConsumer = new Object();
|
Object tmpConsumer = new Object();
|
||||||
List<DomainFile> openDomainFiles = AppInfo.getActiveProject().getOpenData();
|
List<DomainFile> openDomainFiles = getOpenFiles();
|
||||||
for (DomainFile df : openDomainFiles) {
|
for (DomainFile df : openDomainFiles) {
|
||||||
DomainObject openedDomainObject = df.getOpenedDomainObject(tmpConsumer);
|
DomainObject openedDomainObject = df.getOpenedDomainObject(tmpConsumer);
|
||||||
try {
|
try {
|
||||||
|
@ -336,22 +338,6 @@ public class ProgramMappingService {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, FSRL> buildFullyQualifiedFSRLMap(List<FSRL> fsrls,
|
|
||||||
TaskMonitor monitor) throws CancelledException {
|
|
||||||
Map<String, FSRL> result = new HashMap<>();
|
|
||||||
for (FSRL fsrl : fsrls) {
|
|
||||||
try {
|
|
||||||
FSRL fqFSRL = FileSystemService.getInstance().getFullyQualifiedFSRL(fsrl, monitor);
|
|
||||||
String expectedMD5 = fqFSRL.getMD5();
|
|
||||||
result.put(expectedMD5, fsrl);
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
// ignore and continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively searches the current active {@link Project} for {@link DomainFile}s that
|
* Recursively searches the current active {@link Project} for {@link DomainFile}s that
|
||||||
* have metadata that matches a {@link FSRL} in the specified list.
|
* have metadata that matches a {@link FSRL} in the specified list.
|
||||||
|
@ -364,7 +350,15 @@ public class ProgramMappingService {
|
||||||
*/
|
*/
|
||||||
public static Map<FSRL, DomainFile> searchProjectForMatchingFiles(List<FSRL> fsrls,
|
public static Map<FSRL, DomainFile> searchProjectForMatchingFiles(List<FSRL> fsrls,
|
||||||
TaskMonitor monitor) {
|
TaskMonitor monitor) {
|
||||||
int fc = AppInfo.getActiveProject().getProjectData().getFileCount();
|
|
||||||
|
Project project = AppInfo.getActiveProject();
|
||||||
|
if (project == null) {
|
||||||
|
// this should not be possible if this call is being run as a task
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectData projectData = project.getProjectData();
|
||||||
|
int fc = projectData.getFileCount();
|
||||||
if (fc > 0) {
|
if (fc > 0) {
|
||||||
monitor.setShowProgressValue(true);
|
monitor.setShowProgressValue(true);
|
||||||
monitor.setMaximum(fc);
|
monitor.setMaximum(fc);
|
||||||
|
@ -386,8 +380,8 @@ public class ProgramMappingService {
|
||||||
|
|
||||||
Map<FSRL, DomainFile> results = new HashMap<>();
|
Map<FSRL, DomainFile> results = new HashMap<>();
|
||||||
|
|
||||||
for (DomainFile domainFile : ProjectDataUtils.descendantFiles(
|
Iterable<DomainFile> files = ProjectDataUtils.descendantFiles(projectData.getRootFolder());
|
||||||
AppInfo.getActiveProject().getProjectData().getRootFolder())) {
|
for (DomainFile domainFile : files) {
|
||||||
if (monitor.isCancelled() || fsrlsToFindByMD5.isEmpty()) {
|
if (monitor.isCancelled() || fsrlsToFindByMD5.isEmpty()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -434,4 +428,55 @@ public class ProgramMappingService {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static DomainFile getProjectFile(String path) {
|
||||||
|
|
||||||
|
Project project = AppInfo.getActiveProject();
|
||||||
|
if (project != null) {
|
||||||
|
ProjectData data = project.getProjectData();
|
||||||
|
if (data != null) {
|
||||||
|
return data.getFile(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<DomainFile> getOpenFiles() {
|
||||||
|
|
||||||
|
List<DomainFile> files = new ArrayList<>();
|
||||||
|
Project project = AppInfo.getActiveProject();
|
||||||
|
if (project != null) {
|
||||||
|
files = project.getOpenData();
|
||||||
|
}
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<DomainFile> findOpenFiles() {
|
||||||
|
|
||||||
|
List<DomainFile> files = new ArrayList<>();
|
||||||
|
Project project = AppInfo.getActiveProject();
|
||||||
|
if (project != null) {
|
||||||
|
ProjectData data = project.getProjectData();
|
||||||
|
if (data != null) {
|
||||||
|
data.findOpenFiles(files);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, FSRL> buildFullyQualifiedFSRLMap(List<FSRL> fsrls,
|
||||||
|
TaskMonitor monitor) throws CancelledException {
|
||||||
|
Map<String, FSRL> result = new HashMap<>();
|
||||||
|
for (FSRL fsrl : fsrls) {
|
||||||
|
try {
|
||||||
|
FSRL fqFSRL = FileSystemService.getInstance().getFullyQualifiedFSRL(fsrl, monitor);
|
||||||
|
String expectedMD5 = fqFSRL.getMD5();
|
||||||
|
result.put(expectedMD5, fsrl);
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
// ignore and continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue