Merge branch 'GP-5458_ryanmkurtz_GhidraProject-exceptions' (#7536)

This commit is contained in:
Ryan Kurtz
2025-03-06 12:38:28 -05:00
6 changed files with 51 additions and 58 deletions
@@ -16,7 +16,6 @@
package ghidra.dbg.isf; package ghidra.dbg.isf;
import java.io.File; import java.io.File;
import java.io.IOException;
import ghidra.GhidraApplicationLayout; import ghidra.GhidraApplicationLayout;
import ghidra.GhidraLaunchable; import ghidra.GhidraLaunchable;
@@ -46,7 +45,7 @@ public class IsfServerLauncher implements GhidraLaunchable {
server.startServer(); server.startServer();
} }
GhidraProject parseArgs(String[] args) throws IOException { GhidraProject parseArgs(String[] args) throws Exception {
if (args != null && args.length < 1) { if (args != null && args.length < 1) {
usage(); usage();
return null; return null;
@@ -40,7 +40,6 @@ import ghidra.test.ProjectTestUtils;
import ghidra.util.*; import ghidra.util.*;
import ghidra.util.exception.*; import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
import ghidra.util.task.TaskMonitorAdapter;
/** /**
* Helper class for using Ghidra in a "batch" mode. This class provides methods * Helper class for using Ghidra in a "batch" mode. This class provides methods
@@ -67,10 +66,14 @@ public class GhidraProject {
* @param projectsDir the directory containing the Ghidra project. * @param projectsDir the directory containing the Ghidra project.
* @param projectName the name of the ghidra project. * @param projectName the name of the ghidra project.
* @return an open ghidra project. * @return an open ghidra project.
* @throws IOException if there was a problem accessing the project * @throws NotFoundException if the file for the project was
* not found.
* @throws NotOwnerException if the project owner is not the user
* @throws LockException if the project is already opened by another user
* @throws IOException if an IO-related problem occurred
*/ */
public static GhidraProject openProject(String projectsDir, String projectName) public static GhidraProject openProject(String projectsDir, String projectName)
throws IOException { throws NotFoundException, NotOwnerException, LockException, IOException {
return new GhidraProject(projectsDir, projectName, false); return new GhidraProject(projectsDir, projectName, false);
} }
@@ -82,15 +85,19 @@ public class GhidraProject {
* @param projectName the name of the ghidra project. * @param projectName the name of the ghidra project.
* @param restoreProject if true the project tool state is restored * @param restoreProject if true the project tool state is restored
* @return an open ghidra project. * @return an open ghidra project.
* @throws IOException if there was a problem accessing the project * @throws NotFoundException if the file for the project was not found.
* @throws NotOwnerException if the project owner is not the user
* @throws LockException if the project is already opened by another user
* @throws IOException if an IO-related problem occurred
*/ */
public static GhidraProject openProject(String projectsDir, String projectName, public static GhidraProject openProject(String projectsDir, String projectName,
boolean restoreProject) throws IOException { boolean restoreProject)
throws NotFoundException, NotOwnerException, LockException, IOException {
return new GhidraProject(projectsDir, projectName, restoreProject); return new GhidraProject(projectsDir, projectName, restoreProject);
} }
private GhidraProject(String projectParentDir, String projectName, boolean restoreProject) private GhidraProject(String projectParentDir, String projectName, boolean restoreProject)
throws IOException { throws NotFoundException, NotOwnerException, LockException, IOException {
if (!ghidra.framework.Application.isInitialized()) { if (!ghidra.framework.Application.isInitialized()) {
throw new AssertException("The GhidraProject requires the system to be " + throw new AssertException("The GhidraProject requires the system to be " +
"initialized before usage. See GhidraApplication.initialize() for more " + "initialized before usage. See GhidraApplication.initialize() for more " +
@@ -98,25 +105,8 @@ public class GhidraProject {
} }
ProjectLocator projectLocator = new ProjectLocator(projectParentDir, projectName); ProjectLocator projectLocator = new ProjectLocator(projectParentDir, projectName);
try { project = projectManager.openProject(projectLocator, restoreProject, false);
project = projectManager.openProject(projectLocator, restoreProject, false); projectData = project.getProjectData();
if (project == null) {
throw new IOException("Failed to open project: " + projectName);
}
projectData = project.getProjectData();
}
catch (MalformedURLException e) {
throw new IOException("Bad Project URL: " + projectLocator, e);
}
catch (NotFoundException e) {
throw new IOException("Project not found: " + projectLocator, e);
}
catch (NotOwnerException e) {
throw new IOException("Not project owner: " + projectName, e);
}
catch (LockException e) {
throw new IOException("Project is locked: " + projectName, e);
}
} }
/** /**
@@ -146,9 +136,10 @@ public class GhidraProject {
* *
* @param host Ghidra Server host * @param host Ghidra Server host
* @param port Ghidra Server port (0 = use default port) * @param port Ghidra Server port (0 = use default port)
* @param repositoryName * @param repositoryName The repository name
* @param createIfNeeded if true repository will be created if it does not exist * @param createIfNeeded if true repository will be created if it does not exist
* @throws DuplicateNameException * @throws DuplicateNameException if the repository name already exists
* @return A {@link RepositoryAdapter handle} to the new repository
*/ */
public static RepositoryAdapter getServerRepository(String host, int port, public static RepositoryAdapter getServerRepository(String host, int port,
String repositoryName, boolean createIfNeeded) throws DuplicateNameException { String repositoryName, boolean createIfNeeded) throws DuplicateNameException {
@@ -226,15 +217,15 @@ public class GhidraProject {
} }
/** /**
* Returns the underlying Project instance or null if project was opened for * {@return the underlying Project instance or null if project was opened for
* READ access only. * READ access only.}
*/ */
public Project getProject() { public Project getProject() {
return project; return project;
} }
/** /**
* Returns the underlying ProjectData instance. * {@return the underlying ProjectData instance.}
*/ */
public ProjectData getProjectData() { public ProjectData getProjectData() {
return projectData; return projectData;
@@ -376,7 +367,7 @@ public class GhidraProject {
} }
/** /**
* Get the root folder for the Ghidra project. * {@return the root folder for the Ghidra project.}
*/ */
public DomainFolder getRootFolder() { public DomainFolder getRootFolder() {
return projectData.getRootFolder(); return projectData.getRootFolder();
@@ -490,7 +481,7 @@ public class GhidraProject {
throw new DuplicateFileException("File already exists: " + file); throw new DuplicateFileException("File already exists: " + file);
} }
} }
program.saveToPackedFile(file, TaskMonitorAdapter.DUMMY); program.saveToPackedFile(file, TaskMonitor.DUMMY);
} }
catch (CancelledException e1) { catch (CancelledException e1) {
throw new IOException("Cancelled"); throw new IOException("Cancelled");
@@ -563,9 +554,9 @@ public class GhidraProject {
} }
/** /**
* Returns a PropertList containing all the analysis option properties that * {@return a PropertList containing all the analysis option properties that
* can be set. Changing the value of the analysis properties will affect * can be set. Changing the value of the analysis properties will affect
* what happens when the analyze call is made. * what happens when the analyze call is made.}
* *
* @param program * @param program
* the program whose analysis options are to be set. * the program whose analysis options are to be set.
@@ -590,9 +590,9 @@ public class TestEnv {
* A convenience method to close and then reopen the default project created by this TestEnv * A convenience method to close and then reopen the default project created by this TestEnv
* instance. This will not delete the project between opening and closing and will restore * instance. This will not delete the project between opening and closing and will restore
* the project to its previous state. * the project to its previous state.
* @throws IOException if any exception occurs while saving and reopening * @throws Exception if any exception occurs while saving and reopening
*/ */
public void closeAndReopenProject() throws IOException { public void closeAndReopenProject() throws Exception {
gp.setDeleteOnClose(false); gp.setDeleteOnClose(false);
Project project = gp.getProject(); Project project = gp.getProject();
ProjectLocator projectLocator = project.getProjectLocator(); ProjectLocator projectLocator = project.getProjectLocator();
@@ -114,7 +114,7 @@ public abstract class AbstractToolSavingTest extends AbstractGhidraHeadedIntegra
testEnv.getProject().save(); testEnv.getProject().save();
testEnv.closeAndReopenProject(); testEnv.closeAndReopenProject();
} }
catch (IOException e) { catch (Exception e) {
AssertionFailedError afe = new AssertionFailedError(); AssertionFailedError afe = new AssertionFailedError();
afe.initCause(e); afe.initCause(e);
throw afe; throw afe;
@@ -111,9 +111,10 @@ public interface ProjectManager {
* not found. * not found.
* @throws NotOwnerException if the project owner is not the user * @throws NotOwnerException if the project owner is not the user
* @throws LockException if the project is already opened by another user * @throws LockException if the project is already opened by another user
* @throws IOException if there was an IO-related error
*/ */
public Project openProject(ProjectLocator projectLocator, boolean doRestore, boolean resetOwner) public Project openProject(ProjectLocator projectLocator, boolean doRestore, boolean resetOwner)
throws NotFoundException, NotOwnerException, LockException; throws NotFoundException, NotOwnerException, LockException, IOException;
/** /**
* Delete the project in the given location. * Delete the project in the given location.
@@ -119,12 +119,12 @@ public class DefaultProjectManager implements ProjectManager {
@Override @Override
public Project openProject(ProjectLocator projectLocator, boolean doRestore, boolean resetOwner) public Project openProject(ProjectLocator projectLocator, boolean doRestore, boolean resetOwner)
throws NotFoundException, NotOwnerException, LockException { throws NotFoundException, NotOwnerException, LockException, IOException {
if (currentProject != null) { if (currentProject != null) {
Msg.error(this, String msg = "Current project must be closed before establishing a new active project";
"Current project must be closed before establishing a new active project"); Msg.error(this, msg);
return null; throw new LockException(msg);
} }
if (!projectLocator.getMarkerFile().exists()) { if (!projectLocator.getMarkerFile().exists()) {
@@ -141,7 +141,6 @@ public class DefaultProjectManager implements ProjectManager {
try { try {
currentProject = new DefaultProject(this, projectLocator, resetOwner); currentProject = new DefaultProject(this, projectLocator, resetOwner);
AppInfo.setActiveProject(currentProject);
if (doRestore) { if (doRestore) {
currentProject.restore(); currentProject.restore();
} }
@@ -152,17 +151,22 @@ public class DefaultProjectManager implements ProjectManager {
return currentProject; return currentProject;
} }
catch (LockException e) { catch (LockException e) {
return null; Msg.showError(LOG, null, "Locked Project!",
"Cannot open locked project: " + projectLocator, e);
throw e;
} }
catch (ReadOnlyException e) { catch (ReadOnlyException e) {
Msg.showError(LOG, null, "Read-only Project!", Msg.showError(LOG, null, "Read-only Project!",
"Cannot open project for update: " + projectLocator); "Could not open project for update: " + projectLocator, e);
throw e;
} }
catch (IOException e) { catch (IOException e) {
Msg.showError(LOG, null, "Open Project Failed!", Msg.showError(LOG, null, "Open Project Failed!",
"Could not open project " + projectLocator + "\n \nCAUSE: " + e.getMessage()); "Could not open project " + projectLocator + "\n \nCAUSE: " + e.getMessage(), e);
throw e;
} }
finally { finally {
AppInfo.setActiveProject(currentProject);
if (currentProject == null) { if (currentProject == null) {
File dirFile = projectLocator.getProjectDir(); File dirFile = projectLocator.getProjectDir();
if (!dirFile.exists() || !dirFile.isDirectory()) { if (!dirFile.exists() || !dirFile.isDirectory()) {
@@ -170,8 +174,6 @@ public class DefaultProjectManager implements ProjectManager {
} }
} }
} }
AppInfo.setActiveProject(null);
return null;
} }
/** /**