mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
Extensions installed through the GUI now get put in the user settings
directory (rather than installation directory)
This commit is contained in:
parent
3ea1c2bb2b
commit
d70c6c256f
11 changed files with 116 additions and 80 deletions
|
@ -29,11 +29,17 @@ option on the project file menu.</p>
|
||||||
<h2>Dialog Components</h2>
|
<h2>Dialog Components</h2>
|
||||||
<h3>Extensions List</h3>
|
<h3>Extensions List</h3>
|
||||||
<blockquote>
|
<blockquote>
|
||||||
The list of extensions is populated when the dialog is launched. To build the list, Ghidra looks in two locations:
|
The list of extensions is populated when the dialog is launched. To build the list, Ghidra looks in several locations:
|
||||||
<ul>
|
<ul>
|
||||||
<li>Extensions Installation Directory: Contains any extensions that have been installed. This is located at <i>[installation dir]/Ghidra/Extensions/</i></li>
|
<li>Extension Installation Directories: Contains any extensions that have been installed. The directories are located at:</li>
|
||||||
|
<ul>
|
||||||
|
<li><i>[user dir]/.ghidra/.ghidra-[version]/Extensions</i> - Installed/uninstalled from this dialog</li>
|
||||||
|
<li><i>[installation dir]/Ghidra/Extensions/</i> - Installed/uninstalled from filesystem manually</li>
|
||||||
|
</ul>
|
||||||
<li>Extensions Archive Directory: This is where all archive files (zips) are stored. It is located at <i>[installation dir]/Extensions/Ghidra/</i></li>
|
<li>Extensions Archive Directory: This is where all archive files (zips) are stored. It is located at <i>[installation dir]/Extensions/Ghidra/</i></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<p><b>Note: </b> Extensions that have been installed directly into the Ghidra installation directory cannot be uninstalled
|
||||||
|
from this dialog. They must be manually removed from the filesystem.</p>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
<h3>Description Panel</h3>
|
<h3>Description Panel</h3>
|
||||||
|
|
|
@ -15,8 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.util.extensions;
|
package ghidra.util.extensions;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -57,7 +56,9 @@ public class ExtensionUtilsTest extends AbstractGenericTest {
|
||||||
// we start with a clean slate). If they're not empty, CORRECT THE SITUATION.
|
// we start with a clean slate). If they're not empty, CORRECT THE SITUATION.
|
||||||
if (!checkCleanInstall()) {
|
if (!checkCleanInstall()) {
|
||||||
FileUtilities.deleteDir(gLayout.getExtensionArchiveDir().getFile(false));
|
FileUtilities.deleteDir(gLayout.getExtensionArchiveDir().getFile(false));
|
||||||
FileUtilities.deleteDir(gLayout.getExtensionInstallationDir().getFile(false));
|
for (ResourceFile installDir : gLayout.getExtensionInstallationDirs()) {
|
||||||
|
FileUtilities.deleteDir(installDir.getFile(false));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createExtensionDirs();
|
createExtensionDirs();
|
||||||
|
@ -248,7 +249,7 @@ public class ExtensionUtilsTest extends AbstractGenericTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceFile installDir = gLayout.getExtensionInstallationDir();
|
ResourceFile installDir = gLayout.getExtensionInstallationDirs().get(0);
|
||||||
if (!installDir.exists()) {
|
if (!installDir.exists()) {
|
||||||
if (!installDir.mkdir()) {
|
if (!installDir.mkdir()) {
|
||||||
throw new IOException("Failed to create extension installation directory for test");
|
throw new IOException("Failed to create extension installation directory for test");
|
||||||
|
@ -260,7 +261,7 @@ public class ExtensionUtilsTest extends AbstractGenericTest {
|
||||||
* Verifies that the installation folder is empty.
|
* Verifies that the installation folder is empty.
|
||||||
*/
|
*/
|
||||||
private boolean checkCleanInstall() {
|
private boolean checkCleanInstall() {
|
||||||
ResourceFile[] files = gLayout.getExtensionInstallationDir().listFiles();
|
ResourceFile[] files = gLayout.getExtensionInstallationDirs().get(0).listFiles();
|
||||||
return (files == null || files.length == 0);
|
return (files == null || files.length == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,7 +272,7 @@ public class ExtensionUtilsTest extends AbstractGenericTest {
|
||||||
* @param name the name of the installed extension
|
* @param name the name of the installed extension
|
||||||
*/
|
*/
|
||||||
private void checkDirtyInstall(String name) {
|
private void checkDirtyInstall(String name) {
|
||||||
ResourceFile[] files = gLayout.getExtensionInstallationDir().listFiles();
|
ResourceFile[] files = gLayout.getExtensionInstallationDirs().get(0).listFiles();
|
||||||
assertTrue(files.length >= 1);
|
assertTrue(files.length >= 1);
|
||||||
assertTrue(files[0].getName().equals(name));
|
assertTrue(files[0].getName().equals(name));
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ package ghidra.server.remote;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
import ghidra.framework.ApplicationProperties;
|
import ghidra.framework.ApplicationProperties;
|
||||||
import ghidra.util.SystemUtilities;
|
import ghidra.util.SystemUtilities;
|
||||||
|
@ -51,7 +52,7 @@ public class GhidraServerApplicationLayout extends ApplicationLayout {
|
||||||
|
|
||||||
// Extension directories
|
// Extension directories
|
||||||
extensionArchiveDir = null;
|
extensionArchiveDir = null;
|
||||||
extensionInstallationDir = null;
|
extensionInstallationDirs = Collections.emptyList();
|
||||||
|
|
||||||
// User directories (don't let anything use the user home directory...there may not be one)
|
// User directories (don't let anything use the user home directory...there may not be one)
|
||||||
userTempDir = ApplicationUtilities.getDefaultUserTempDir(applicationProperties);
|
userTempDir = ApplicationUtilities.getDefaultUserTempDir(applicationProperties);
|
||||||
|
|
|
@ -17,6 +17,7 @@ package ghidra.framework.plugintool.dialog;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -33,6 +34,7 @@ import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.table.column.AbstractGColumnRenderer;
|
import ghidra.util.table.column.AbstractGColumnRenderer;
|
||||||
import ghidra.util.table.column.GColumnRenderer;
|
import ghidra.util.table.column.GColumnRenderer;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
import utilities.util.FileUtilities;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model for the {@link ExtensionTablePanel}. This defines 5 columns for displaying information in
|
* Model for the {@link ExtensionTablePanel}. This defines 5 columns for displaying information in
|
||||||
|
@ -95,7 +97,7 @@ class ExtensionTableModel extends ThreadedTableModel<ExtensionDetails, List<Exte
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
||||||
if (Application.inSingleJarMode()) {
|
if (Application.inSingleJarMode() || SystemUtilities.isInDevelopmentMode()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,6 +106,14 @@ class ExtensionTableModel extends ThreadedTableModel<ExtensionDetails, List<Exte
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Do not allow GUI uninstallation of extensions manually installed in installation
|
||||||
|
// directory
|
||||||
|
if (extension.getInstallPath() != null && FileUtilities.isPathContainedWithin(
|
||||||
|
Application.getApplicationLayout().getApplicationInstallationDir().getFile(false),
|
||||||
|
new File(extension.getInstallPath()))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return (columnIndex == INSTALLED_COL);
|
return (columnIndex == INSTALLED_COL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,7 +133,13 @@ class ExtensionTableModel extends ThreadedTableModel<ExtensionDetails, List<Exte
|
||||||
|
|
||||||
// If the user does not have write permissions on the installation dir, they cannot
|
// If the user does not have write permissions on the installation dir, they cannot
|
||||||
// install.
|
// install.
|
||||||
ResourceFile installDir = Application.getApplicationLayout().getExtensionInstallationDir();
|
ResourceFile installDir =
|
||||||
|
Application.getApplicationLayout().getExtensionInstallationDirs().get(0);
|
||||||
|
if (!installDir.exists() && !installDir.mkdir()) {
|
||||||
|
Msg.showError(this, null, "Directory Error",
|
||||||
|
"Cannot install/uninstall extensions: Failed to create extension installation directory.\n" +
|
||||||
|
"See the \"Ghidra Extension Notes\" section of the Ghidra Installation Guide for more information.");
|
||||||
|
}
|
||||||
if (!installDir.canWrite()) {
|
if (!installDir.canWrite()) {
|
||||||
Msg.showError(this, null, "Permissions Error",
|
Msg.showError(this, null, "Permissions Error",
|
||||||
"Cannot install/uninstall extensions: Invalid write permissions on installation directory.\n" +
|
"Cannot install/uninstall extensions: Invalid write permissions on installation directory.\n" +
|
||||||
|
|
|
@ -123,7 +123,12 @@ public class ExtensionTableProvider extends DialogComponentProvider {
|
||||||
// Don't let the user attempt to install anything if they don't have write
|
// Don't let the user attempt to install anything if they don't have write
|
||||||
// permissions on the installation dir.
|
// permissions on the installation dir.
|
||||||
ResourceFile installDir =
|
ResourceFile installDir =
|
||||||
Application.getApplicationLayout().getExtensionInstallationDir();
|
Application.getApplicationLayout().getExtensionInstallationDirs().get(0);
|
||||||
|
if (!installDir.exists() && !installDir.mkdir()) {
|
||||||
|
Msg.showError(this, null, "Directory Error",
|
||||||
|
"Cannot install/uninstall extensions: Failed to create extension installation directory.\n" +
|
||||||
|
"See the \"Ghidra Extension Notes\" section of the Ghidra Installation Guide for more information.");
|
||||||
|
}
|
||||||
if (!installDir.canWrite()) {
|
if (!installDir.canWrite()) {
|
||||||
Msg.showError(this, null, "Permissions Error",
|
Msg.showError(this, null, "Permissions Error",
|
||||||
"Cannot install/uninstall extensions: Invalid write permissions on installation directory.\n" +
|
"Cannot install/uninstall extensions: Invalid write permissions on installation directory.\n" +
|
||||||
|
|
|
@ -133,18 +133,17 @@ public class ExtensionUtils {
|
||||||
|
|
||||||
ApplicationLayout layout = Application.getApplicationLayout();
|
ApplicationLayout layout = Application.getApplicationLayout();
|
||||||
|
|
||||||
if (layout.getExtensionInstallationDir() == null ||
|
|
||||||
!layout.getExtensionInstallationDir().exists()) {
|
|
||||||
return Collections.emptySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
// The set to return;
|
// The set to return;
|
||||||
Set<ExtensionDetails> extensions = new HashSet<>();
|
Set<ExtensionDetails> extensions = new HashSet<>();
|
||||||
|
|
||||||
// Find all extension.properties or extension.properties.uninstalled files in
|
// Find all extension.properties or extension.properties.uninstalled files in
|
||||||
// the install directory and create a ExtensionDetails object for each.
|
// the install directory and create a ExtensionDetails object for each.
|
||||||
ResourceFile installDir = layout.getExtensionInstallationDir();
|
for (ResourceFile installDir : layout.getExtensionInstallationDirs()) {
|
||||||
List<ResourceFile> propFiles = findExtensionPropertyFiles(installDir, includeUninstalled);
|
if (!installDir.isDirectory()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
List<ResourceFile> propFiles =
|
||||||
|
findExtensionPropertyFiles(installDir, includeUninstalled);
|
||||||
for (ResourceFile propFile : propFiles) {
|
for (ResourceFile propFile : propFiles) {
|
||||||
|
|
||||||
ExtensionDetails details = createExtensionDetailsFromPropertyFile(propFile);
|
ExtensionDetails details = createExtensionDetailsFromPropertyFile(propFile);
|
||||||
|
@ -152,8 +151,17 @@ public class ExtensionUtils {
|
||||||
// We found this extension in the installation directory, so set the install path
|
// We found this extension in the installation directory, so set the install path
|
||||||
// property and add to the final set.
|
// property and add to the final set.
|
||||||
details.setInstallPath(propFile.getParentFile().getAbsolutePath());
|
details.setInstallPath(propFile.getParentFile().getAbsolutePath());
|
||||||
|
if (!extensions.contains(details)) {
|
||||||
extensions.add(details);
|
extensions.add(details);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
Msg.warn(null,
|
||||||
|
"Skipping extension \"" + details.getName() + "\" found at " +
|
||||||
|
details.getInstallPath() +
|
||||||
|
". Extension by that name installed in higher priority location.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return extensions;
|
return extensions;
|
||||||
}
|
}
|
||||||
|
@ -219,8 +227,13 @@ public class ExtensionUtils {
|
||||||
* @return true if installed
|
* @return true if installed
|
||||||
*/
|
*/
|
||||||
public static boolean isInstalled(String extensionName) {
|
public static boolean isInstalled(String extensionName) {
|
||||||
return new File(Application.getApplicationLayout().getExtensionInstallationDir() +
|
for (ResourceFile installDir : Application.getApplicationLayout()
|
||||||
File.separator + extensionName).exists();
|
.getExtensionInstallationDirs()) {
|
||||||
|
if (new ResourceFile(installDir, extensionName).exists()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -267,16 +280,15 @@ public class ExtensionUtils {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File installDir = new ResourceFile(
|
||||||
|
Application.getApplicationLayout().getExtensionInstallationDirs().get(0),
|
||||||
|
extension.getName()).getFile(false);
|
||||||
|
|
||||||
if (extension.getArchivePath() == null) {
|
if (extension.getArchivePath() == null) {
|
||||||
// Special Case: If the archive path is null then this must be an extension that
|
// Special Case: If the archive path is null then this must be an extension that
|
||||||
// was installed from an external location, then uninstalled. In this case, there
|
// was installed from an external location, then uninstalled. In this case, there
|
||||||
// should be a Module.manifest.uninstalled and extension.properties.uninstalled
|
// should be a Module.manifest.uninstalled and extension.properties.uninstalled
|
||||||
// present. If so, just restore them. If not, there's a problem.
|
// present. If so, just restore them. If not, there's a problem.
|
||||||
|
|
||||||
String installPath = Application.getApplicationLayout().getExtensionInstallationDir() +
|
|
||||||
File.separator + extension.getName();
|
|
||||||
File installDir = new File(installPath);
|
|
||||||
|
|
||||||
if (installDir.exists()) {
|
if (installDir.exists()) {
|
||||||
return restoreStateFiles(installDir);
|
return restoreStateFiles(installDir);
|
||||||
}
|
}
|
||||||
|
@ -300,18 +312,12 @@ public class ExtensionUtils {
|
||||||
// been removed yet; just the manifest file has been renamed. In this case we don't need to go through
|
// been removed yet; just the manifest file has been renamed. In this case we don't need to go through
|
||||||
// the full install process of unzipping or copying files to the install location. All we need
|
// the full install process of unzipping or copying files to the install location. All we need
|
||||||
// to do is rename the manifest file from Module.manifest.uninstall back to Module.manifest.
|
// to do is rename the manifest file from Module.manifest.uninstall back to Module.manifest.
|
||||||
String installPath = Application.getApplicationLayout().getExtensionInstallationDir() + File.separator +
|
|
||||||
extension.getName();
|
|
||||||
File installDir = new File(installPath);
|
|
||||||
|
|
||||||
if (installDir.exists()) {
|
if (installDir.exists()) {
|
||||||
return restoreStateFiles(installDir);
|
return restoreStateFiles(installDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (install(file)) {
|
if (install(file)) {
|
||||||
extension.setInstallPath(
|
extension.setInstallPath(installDir + File.separator + extension.getName());
|
||||||
Application.getApplicationLayout().getExtensionInstallationDir() + File.separator +
|
|
||||||
extension.getName());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -554,7 +560,9 @@ public class ExtensionUtils {
|
||||||
File errorFile = e.getErrorFile();
|
File errorFile = e.getErrorFile();
|
||||||
if (errorFile != null) {
|
if (errorFile != null) {
|
||||||
// Get the root of the extension in the install location.
|
// Get the root of the extension in the install location.
|
||||||
ResourceFile installDir = Application.getApplicationLayout().getExtensionInstallationDir();
|
ResourceFile installDir = Application.getApplicationLayout()
|
||||||
|
.getExtensionInstallationDirs()
|
||||||
|
.get(0);
|
||||||
|
|
||||||
// Get the root directory of the extension (strip off the install folder location and
|
// Get the root directory of the extension (strip off the install folder location and
|
||||||
// grab the first part of the remaining path).
|
// grab the first part of the remaining path).
|
||||||
|
@ -755,7 +763,7 @@ public class ExtensionUtils {
|
||||||
File newDir = null;
|
File newDir = null;
|
||||||
try {
|
try {
|
||||||
newDir =
|
newDir =
|
||||||
new File(Application.getApplicationLayout().getExtensionInstallationDir() +
|
new File(Application.getApplicationLayout().getExtensionInstallationDirs().get(0) +
|
||||||
File.separator + extension.getName());
|
File.separator + extension.getName());
|
||||||
FileUtilities.deleteDir(newDir, monitor);
|
FileUtilities.deleteDir(newDir, monitor);
|
||||||
FileUtilities.copyDir(extension, newDir, monitor);
|
FileUtilities.copyDir(extension, newDir, monitor);
|
||||||
|
@ -788,11 +796,10 @@ public class ExtensionUtils {
|
||||||
ExtensionExceptionType.ZIP_ERROR);
|
ExtensionExceptionType.ZIP_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (layout.getExtensionInstallationDir() == null ||
|
ResourceFile installDir = layout.getExtensionInstallationDirs().get(0);
|
||||||
!layout.getExtensionInstallationDir().exists()) {
|
if (installDir == null || !installDir.exists()) {
|
||||||
throw new ExtensionException(
|
throw new ExtensionException(
|
||||||
"Extension installation directory is not valid: " +
|
"Extension installation directory is not valid: " + installDir,
|
||||||
layout.getExtensionInstallationDir(),
|
|
||||||
ExtensionExceptionType.INVALID_INSTALL_LOCATION);
|
ExtensionExceptionType.INVALID_INSTALL_LOCATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -803,8 +810,7 @@ public class ExtensionUtils {
|
||||||
|
|
||||||
ZipArchiveEntry entry = entries.nextElement();
|
ZipArchiveEntry entry = entries.nextElement();
|
||||||
|
|
||||||
String filePath =
|
String filePath = installDir + File.separator + entry.getName();
|
||||||
(layout.getExtensionInstallationDir() + File.separator + entry.getName());
|
|
||||||
|
|
||||||
File file = new File(filePath);
|
File file = new File(filePath);
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ public class GhidraApplicationLayout extends ApplicationLayout {
|
||||||
getApplicationInstallationDir());
|
getApplicationInstallationDir());
|
||||||
|
|
||||||
// Extensions
|
// Extensions
|
||||||
extensionInstallationDir = findExtensionInstallationDirectory();
|
extensionInstallationDirs = findExtensionInstallationDirectories();
|
||||||
extensionArchiveDir = findExtensionArchiveDirectory();
|
extensionArchiveDir = findExtensionArchiveDirectory();
|
||||||
|
|
||||||
// Patch directory
|
// Patch directory
|
||||||
|
@ -217,16 +217,19 @@ public class GhidraApplicationLayout extends ApplicationLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the directory where all Ghidra extension archives should be
|
* Returns a prioritized list of directories where Ghidra extensions are installed. These
|
||||||
* installed. This should be at the following location:<br>
|
* should be at the following locations:<br>
|
||||||
* <ul>
|
* <ul>
|
||||||
|
* <li><code>[user settings dir]/Extensions</code></li>
|
||||||
* <li><code>[application install dir]/Ghidra/Extensions</code></li>
|
* <li><code>[application install dir]/Ghidra/Extensions</code></li>
|
||||||
* <li><code>ghidra/Ghidra/Extensions</code> (development mode)</li>
|
* <li><code>ghidra/Ghidra/Extensions</code> (development mode)</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @return the install folder, or null if can't be determined
|
* @return the install folder, or null if can't be determined
|
||||||
*/
|
*/
|
||||||
protected ResourceFile findExtensionInstallationDirectory() {
|
protected List<ResourceFile> findExtensionInstallationDirectories() {
|
||||||
|
|
||||||
|
List<ResourceFile> dirs = new ArrayList<>();
|
||||||
|
|
||||||
// Would like to find a better way to do this, but for the moment this seems the
|
// Would like to find a better way to do this, but for the moment this seems the
|
||||||
// only solution. We want to get the 'Extensions' directory in ghidra, but there's
|
// only solution. We want to get the 'Extensions' directory in ghidra, but there's
|
||||||
|
@ -237,13 +240,14 @@ public class GhidraApplicationLayout extends ApplicationLayout {
|
||||||
ResourceFile rootDir = getApplicationRootDirs().iterator().next();
|
ResourceFile rootDir = getApplicationRootDirs().iterator().next();
|
||||||
File temp = new File(rootDir.getFile(false), "Extensions");
|
File temp = new File(rootDir.getFile(false), "Extensions");
|
||||||
if (temp.exists()) {
|
if (temp.exists()) {
|
||||||
return new ResourceFile(temp);
|
dirs.add(new ResourceFile(temp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dirs.add(new ResourceFile(new File(userSettingsDir, "Extensions")));
|
||||||
|
dirs.add(new ResourceFile(applicationInstallationDir, "Ghidra/Extensions"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return dirs;
|
||||||
}
|
|
||||||
|
|
||||||
ResourceFile installDir = findGhidraApplicationInstallationDir();
|
|
||||||
return new ResourceFile(installDir, "Ghidra/Extensions");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,9 +75,9 @@ public class GhidraJarApplicationLayout extends GhidraApplicationLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ResourceFile findExtensionInstallationDirectory() {
|
protected List<ResourceFile> findExtensionInstallationDirectories() {
|
||||||
ResourceFile extensionInstallDir = new ResourceFile(
|
ResourceFile extensionInstallDir = new ResourceFile(
|
||||||
ApplicationLayout.class.getResource("/_Root/Ghidra/Extensions").toExternalForm());
|
ApplicationLayout.class.getResource("/_Root/Ghidra/Extensions").toExternalForm());
|
||||||
return extensionInstallDir;
|
return List.of(extensionInstallDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package ghidra;
|
package ghidra;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import generic.jar.ResourceFile;
|
import generic.jar.ResourceFile;
|
||||||
|
|
||||||
|
@ -51,9 +52,9 @@ public class GhidraTestApplicationLayout extends GhidraApplicationLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ResourceFile findExtensionInstallationDirectory() {
|
protected List<ResourceFile> findExtensionInstallationDirectories() {
|
||||||
File installDir = new File(getUserTempDir(), "ExtensionInstallDir");
|
File installDir = new File(getUserTempDir(), "ExtensionInstallDir");
|
||||||
return new ResourceFile(installDir);
|
return List.of(new ResourceFile(installDir));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -17,8 +17,7 @@ package utility.application;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import generic.jar.ResourceFile;
|
import generic.jar.ResourceFile;
|
||||||
import ghidra.framework.ApplicationProperties;
|
import ghidra.framework.ApplicationProperties;
|
||||||
|
@ -44,7 +43,7 @@ public abstract class ApplicationLayout {
|
||||||
protected File userSettingsDir;
|
protected File userSettingsDir;
|
||||||
protected ResourceFile patchDir;
|
protected ResourceFile patchDir;
|
||||||
protected ResourceFile extensionArchiveDir;
|
protected ResourceFile extensionArchiveDir;
|
||||||
protected ResourceFile extensionInstallationDir;
|
protected List<ResourceFile> extensionInstallationDirs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the application properties from the application layout
|
* Gets the application properties from the application layout
|
||||||
|
@ -121,13 +120,13 @@ public abstract class ApplicationLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the application Extensions installation folder.
|
* Returns an {@link List ordered list} of the application Extensions installation directories.
|
||||||
*
|
*
|
||||||
* @return the application Extensions installation directory. Could be null if the
|
* @return an {@link List ordered list} of the application Extensions installation directories.
|
||||||
* {@link ApplicationLayout} does not support application Extensions.
|
* Could be empty if the {@link ApplicationLayout} does not support application Extensions.
|
||||||
*/
|
*/
|
||||||
public final ResourceFile getExtensionInstallationDir() {
|
public final List<ResourceFile> getExtensionInstallationDirs() {
|
||||||
return extensionInstallationDir;
|
return extensionInstallationDirs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
<h1>Ghidra Installation Guide</h1>
|
<h1>Ghidra Installation Guide</h1>
|
||||||
<p>
|
<p>
|
||||||
The installation information provided is effective as of Ghidra 9.1 and is subject to change with
|
The installation information provided is effective as of Ghidra 9.2 and is subject to change with
|
||||||
future releases.
|
future releases.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
@ -363,17 +363,14 @@ can be found in the <i><GhidraInstallDir></i>/Extensions directory.</p>
|
||||||
</ol>
|
</ol>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Installing or uninstalling Ghidra extensions may fail if the user does not have write
|
Extensions installed from the Ghidra front-end GUI get installed at
|
||||||
permissions to <i><GhidraInstallDir></i>. This may occur if the user is running Ghidra
|
<i><UserDir></i>/.ghidra/.ghidra-[version]/Extensions.
|
||||||
from a shared installation location. In this situation, the owner of the Ghidra installation
|
|
||||||
directory will be responsible for managing what Ghidra extensions are available for that
|
|
||||||
particular installation of Ghidra.
|
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p>It is possible to install and uninstall Ghidra extensions manually when the Ghidra front-end
|
<p>It is possible to install Ghidra extensions directly into the Ghidra installation directory.
|
||||||
GUI is not available. This may be required if a system administrator is managing the Ghidra
|
This may be required if a system administrator is managing extensions for multiple users that
|
||||||
extensions of a shared Ghidra installation on behalf of a user, or if a user wishes to install
|
all use a shared installation of Ghidra. It may also be more convenient to manage extensions
|
||||||
an extension into a Ghidra installation that is only ever used headlessly.<p>
|
this way if a Ghidra installation is only ever used headlessly.<p>
|
||||||
<p>To install an extension in these cases, simply extract the desired Ghidra extension archive
|
<p>To install an extension in these cases, simply extract the desired Ghidra extension archive
|
||||||
file(s) to the <i><GhidraInstallDir></i>/Ghidra/Extensions directory. For example, on
|
file(s) to the <i><GhidraInstallDir></i>/Ghidra/Extensions directory. For example, on
|
||||||
Linux or macOS:</p>
|
Linux or macOS:</p>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue