mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
GP-4563: Support for searching for libraries inside a GFileSystem
This commit is contained in:
parent
9911db9828
commit
9f883022a4
7 changed files with 140 additions and 62 deletions
|
@ -366,6 +366,7 @@ icon.plugin.fsbrowser.import = images/famfamfam_silk_icons_v013/application_get.
|
|||
icon.plugin.fsbrowser.ios = images/famfamfam_silk_icons_v013/phone.png
|
||||
icon.plugin.fsbrowser.open.all = images/famfamfam_silk_icons_v013/application_cascade.png
|
||||
icon.plugin.fsbrowser.list.mounted = downArrow.png
|
||||
icon.plugin.fsbrowser.library = images/imported_bookmark.gif
|
||||
|
||||
icon.base.util.fixed.bit.size.field = icon.pulldown
|
||||
|
||||
|
|
|
@ -90,6 +90,12 @@
|
|||
using the Batch Import dialog.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="FSB_Add_To_Program"></A>Add To Program</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>Adds the selected file into the currently active program.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="FSB_Export"></A>Export</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
|
@ -104,6 +110,13 @@
|
|||
local computer.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="FSB_Add_Library_Search_Path"></A>Add Library Search Path</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>Adds the currently selected file or folder to the list of library search paths which
|
||||
is used during program import.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="FSB_View_As_Image"></A>View As Image</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
|
|
|
@ -15,9 +15,16 @@
|
|||
*/
|
||||
package ghidra.app.util.importer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.formats.gfilesystem.FSRL;
|
||||
import ghidra.formats.gfilesystem.FileSystemService;
|
||||
import ghidra.framework.Platform;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* A simple class for managing the library search path
|
||||
|
@ -61,11 +68,39 @@ public class LibrarySearchPathManager {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns an array of directories to search for libraries
|
||||
* @return a list of directories to search for libraries
|
||||
* Returns a {@link List} of {@link FSRL}s to search for libraries
|
||||
* @param log The log
|
||||
* @param monitor A cancellable monitor
|
||||
* @return a {@link List} of {@link FSRL}s to search for libraries
|
||||
* @throws CancelledException if the user cancelled the operation
|
||||
*/
|
||||
public static List<String> getLibraryPathsList() {
|
||||
return new ArrayList<>(pathList);
|
||||
public static List<FSRL> getLibraryFsrlList(MessageLog log, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
FileSystemService fsService = FileSystemService.getInstance();
|
||||
List<FSRL> fsrlList = new ArrayList<>();
|
||||
for (String path : pathList) {
|
||||
monitor.checkCancelled();
|
||||
path = path.trim();
|
||||
FSRL fsrl = null;
|
||||
try {
|
||||
fsrl = FSRL.fromString(path);
|
||||
}
|
||||
catch (MalformedURLException e) {
|
||||
try {
|
||||
File f = new File(path);
|
||||
if (f.exists() && f.isAbsolute()) {
|
||||
fsrl = fsService.getLocalFSRL(f.getCanonicalFile());
|
||||
}
|
||||
}
|
||||
catch (IOException e2) {
|
||||
log.appendException(e2);
|
||||
}
|
||||
}
|
||||
if (fsrl != null) {
|
||||
fsrlList.add(fsrl);
|
||||
}
|
||||
}
|
||||
return fsrlList;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,9 +17,11 @@ package ghidra.app.util.opinion;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
|
@ -584,16 +586,13 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
|||
if (!success) {
|
||||
release(loadedPrograms, consumer);
|
||||
}
|
||||
for (FileSystemSearchPath fsSearchPath : localSearchPaths) {
|
||||
Stream.of(customSearchPaths, localSearchPaths, systemSearchPaths)
|
||||
.flatMap(Collection::stream)
|
||||
.forEach(fsSearchPath -> {
|
||||
if (!fsSearchPath.fsRef().isClosed()) {
|
||||
fsSearchPath.fsRef().close();
|
||||
}
|
||||
}
|
||||
for (FileSystemSearchPath fsSearchPath : systemSearchPaths) {
|
||||
if (!fsSearchPath.fsRef().isClosed()) {
|
||||
fsSearchPath.fsRef().close();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1061,9 +1060,10 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
|||
* @param monitor A cancelable task monitor
|
||||
* @return A {@link List} of priority-ordered custom {@link FileSystemSearchPath}s used to
|
||||
* search for libraries
|
||||
* @throws CancelledException if the user cancelled the load
|
||||
*/
|
||||
protected List<FileSystemSearchPath> getCustomLibrarySearchPaths(ByteProvider provider,
|
||||
List<Option> options, MessageLog log, TaskMonitor monitor) {
|
||||
List<Option> options, MessageLog log, TaskMonitor monitor) throws CancelledException {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
|
@ -1077,24 +1077,26 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
|||
* @param monitor A cancelable task monitor
|
||||
* @return A {@link List} of priority-ordered local {@link FileSystemSearchPath}s used to
|
||||
* search for libraries
|
||||
* @throws CancelledException if the user cancelled the load
|
||||
*/
|
||||
private List<FileSystemSearchPath> getLocalLibrarySearchPaths(ByteProvider provider,
|
||||
List<Option> options, MessageLog log, TaskMonitor monitor) {
|
||||
List<Option> options, MessageLog log, TaskMonitor monitor) throws CancelledException {
|
||||
if (!isLoadLocalLibraries(options) && !shouldSearchAllPaths(options)) {
|
||||
return List.of();
|
||||
}
|
||||
List<FileSystemSearchPath> result = new ArrayList<>();
|
||||
FileSystemService fsService = FileSystemService.getInstance();
|
||||
if (isLoadLocalLibraries(options) || shouldSearchAllPaths(options)) {
|
||||
FSRL providerFsrl = provider.getFSRL();
|
||||
if (providerFsrl != null) {
|
||||
try (RefdFile fileRef = fsService.getRefdFile(providerFsrl, monitor)) {
|
||||
GFile parentFile = fileRef.file.getParentFile();
|
||||
File f = new File(parentFile.getPath()); // File API will sanitize Windows-style paths
|
||||
result.add(new FileSystemSearchPath(fileRef.fsRef, f.toPath()));
|
||||
result.add(new FileSystemSearchPath(fileRef.fsRef.dup(), f.toPath()));
|
||||
}
|
||||
catch (IOException | CancelledException e) {
|
||||
catch (IOException e) {
|
||||
log.appendException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1107,41 +1109,32 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
|||
* @param monitor A cancelable task monitor
|
||||
* @return A {@link List} of priority-ordered system {@link FileSystemSearchPath}s used to
|
||||
* search for libraries
|
||||
* @throws CancelledException if the user cancelled the load
|
||||
*/
|
||||
private List<FileSystemSearchPath> getSystemLibrarySearchPaths(List<Option> options,
|
||||
MessageLog log, TaskMonitor monitor) {
|
||||
List<FileSystemSearchPath> result = new ArrayList<>();
|
||||
MessageLog log, TaskMonitor monitor) throws CancelledException {
|
||||
if (!isLoadSystemLibraries(options) && !shouldSearchAllPaths(options)) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
FileSystemService fsService = FileSystemService.getInstance();
|
||||
if (isLoadSystemLibraries(options) || shouldSearchAllPaths(options)) {
|
||||
List<Path> searchPaths = new ArrayList<>();
|
||||
for (String str : LibrarySearchPathManager.getLibraryPathsList()) {
|
||||
str = str.trim();
|
||||
if (str.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
List<FileSystemSearchPath> result = new ArrayList<>();
|
||||
boolean success = false;
|
||||
try {
|
||||
Path path = getCheckedPath(str).normalize();
|
||||
if (path.isAbsolute() && Files.exists(path)) {
|
||||
searchPaths.add(path);
|
||||
for (FSRL fsrl : LibrarySearchPathManager.getLibraryFsrlList(log, monitor)) {
|
||||
try (RefdFile fileRef = fsService.getRefdFile(fsrl, monitor)) {
|
||||
File f = new File(fileRef.file.getPath()); // File API will sanitize Windows-style paths
|
||||
result.add(new FileSystemSearchPath(fileRef.fsRef.dup(), f.toPath()));
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.appendMsg(e.getMessage());
|
||||
}
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
log.appendMsg("Skipping invalid system library search path: \"" + str + "\"");
|
||||
}
|
||||
}
|
||||
for (Path searchPath : searchPaths) {
|
||||
try {
|
||||
FSRL searchFSRL =
|
||||
fsService.getLocalFSRL(searchPath.toFile().getCanonicalFile());
|
||||
FileSystemRef fsRef =
|
||||
fsService.probeFileForFilesystem(searchFSRL, monitor, null);
|
||||
if (fsRef != null) {
|
||||
result.add(new FileSystemSearchPath(fsRef, null));
|
||||
}
|
||||
}
|
||||
catch (IOException | CancelledException e) {
|
||||
log.appendException(e);
|
||||
success = true;
|
||||
}
|
||||
finally {
|
||||
if (!success) {
|
||||
result.forEach(fsSearchPath -> fsSearchPath.fsRef().close());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -1205,7 +1198,7 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
|||
* case-insensitive lookup may be allowed, and filename extensions may be optional.
|
||||
*
|
||||
* @param fs The {@link GFileSystem file system} to resolve in
|
||||
* @param libraryParentPath The {@link Path} of the libraries parent directory, relative to the
|
||||
* @param libraryParentPath The {@link Path} of the library's parent directory, relative to the
|
||||
* given file system (could be null)
|
||||
* @param libraryName The library name
|
||||
* @return The library resolved to an existing {@link FSRL}, or null if it did not resolve
|
||||
|
|
|
@ -40,6 +40,7 @@ import docking.widgets.tree.GTreeNode;
|
|||
import ghidra.app.services.ProgramManager;
|
||||
import ghidra.app.services.TextEditorService;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.importer.LibrarySearchPathManager;
|
||||
import ghidra.formats.gfilesystem.*;
|
||||
import ghidra.formats.gfilesystem.crypto.CachedPasswordProvider;
|
||||
import ghidra.formats.gfilesystem.crypto.CryptoProviders;
|
||||
|
@ -83,6 +84,7 @@ class FSBActionManager {
|
|||
DockingAction actionCollapse;
|
||||
DockingAction actionImportBatch;
|
||||
DockingAction actionAddToProgram;
|
||||
DockingAction actionLibrarySearchPath;
|
||||
DockingAction actionCloseFileSystem;
|
||||
DockingAction actionClearCachedPasswords;
|
||||
/* end package visibility */
|
||||
|
@ -118,6 +120,7 @@ class FSBActionManager {
|
|||
actions.add((actionImport = createImportAction()));
|
||||
actions.add((actionImportBatch = createBatchImportAction()));
|
||||
actions.add((actionAddToProgram = createAddToProgramAction()));
|
||||
actions.add((actionLibrarySearchPath = createLibrarySearchPathAction()));
|
||||
actions.add((actionOpenFileSystemNewWindow = createOpenFileSystemNewWindowAction()));
|
||||
actions.add((actionOpenFileSystemNested = createOpenFileSystemNestedAction()));
|
||||
actions.add((actionOpenFileSystemChooser = createOpenNewFileSystemAction()));
|
||||
|
@ -516,11 +519,11 @@ class FSBActionManager {
|
|||
}
|
||||
|
||||
private DockingAction createGetInfoAction() {
|
||||
return new ActionBuilder("Get Info", plugin.getName())
|
||||
return new ActionBuilder("FSB Get Info", plugin.getName())
|
||||
.withContext(FSBActionContext.class)
|
||||
.enabledWhen(ac -> ac.notBusy() && ac.getFSRL(true) != null)
|
||||
.popupMenuPath("Get Info")
|
||||
.popupMenuGroup("A")
|
||||
.popupMenuGroup("A", "A")
|
||||
.popupMenuIcon(ImageManager.INFO)
|
||||
.description("Show information about a file")
|
||||
.onAction(
|
||||
|
@ -742,6 +745,36 @@ class FSBActionManager {
|
|||
.build();
|
||||
}
|
||||
|
||||
private DockingAction createLibrarySearchPathAction() {
|
||||
return new ActionBuilder("FSB Add Library Search Path", plugin.getName())
|
||||
.withContext(FSBActionContext.class)
|
||||
.enabledWhen(ac -> ac.notBusy() && ac.getFSRL(true) != null)
|
||||
.popupMenuPath("Add Library Search Path")
|
||||
.popupMenuGroup("F", "D")
|
||||
.popupMenuIcon(ImageManager.LIBRARY)
|
||||
.description("Add file/folder to library search paths")
|
||||
.onAction(ac -> {
|
||||
try {
|
||||
FSRL fsrl = ac.getFSRL(true);
|
||||
LocalFileSystem localFs = fsService.getLocalFS();
|
||||
String path = fsService.isLocal(fsrl) ? localFs.getLocalFile(fsrl).getPath()
|
||||
: fsrl.toString();
|
||||
if (LibrarySearchPathManager.addPath(path)) {
|
||||
Msg.showInfo(this, gTree, "Add Library Search Path",
|
||||
"Added '%s' to library search paths.".formatted(fsrl));
|
||||
}
|
||||
else {
|
||||
Msg.showInfo(this, gTree, "Add Library Search Path",
|
||||
"Library search path '%s' already exists.".formatted(fsrl));
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
Msg.showError(this, gTree, "Add Library Search Path", e);
|
||||
}
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
private DockingAction createClearCachedPasswordsAction() {
|
||||
return new ActionBuilder("FSB Clear Cached Passwords", plugin.getName())
|
||||
.withContext(FSBActionContext.class)
|
||||
|
|
|
@ -61,5 +61,6 @@ public class ImageManager {
|
|||
public final static Icon iOS = new GIcon("icon.plugin.fsbrowser.ios");
|
||||
public final static Icon OPEN_ALL = new GIcon("icon.plugin.fsbrowser.open.all");
|
||||
public final static Icon LIST_MOUNTED = new GIcon("icon.plugin.fsbrowser.list.mounted");
|
||||
public final static Icon LIBRARY = new GIcon("icon.plugin.fsbrowser.library");
|
||||
//@formatter:on
|
||||
}
|
||||
|
|
|
@ -278,8 +278,10 @@ public class PathnameTablePanel extends JPanel {
|
|||
pathName = "";
|
||||
}
|
||||
else {
|
||||
File file = new File(pathName);
|
||||
fileExists = file.exists();
|
||||
int colonSlashSlash = pathName.indexOf("://");
|
||||
if (colonSlashSlash <= 0) { // Assume FSRL/URLs always exist
|
||||
fileExists = new File(pathName).exists();
|
||||
}
|
||||
}
|
||||
|
||||
label.setText(pathName.toString());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue