GP-5458: GhidraProject and DefaultProjectManager methods for opening

projects now throw more granular exceptions
This commit is contained in:
Ryan Kurtz
2025-03-06 11:38:37 -05:00
parent 5361a47df2
commit 1990d2ed4b
6 changed files with 51 additions and 58 deletions
@@ -4,9 +4,9 @@
* 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.
@@ -16,7 +16,6 @@
package ghidra.dbg.isf;
import java.io.File;
import java.io.IOException;
import ghidra.GhidraApplicationLayout;
import ghidra.GhidraLaunchable;
@@ -46,7 +45,7 @@ public class IsfServerLauncher implements GhidraLaunchable {
server.startServer();
}
GhidraProject parseArgs(String[] args) throws IOException {
GhidraProject parseArgs(String[] args) throws Exception {
if (args != null && args.length < 1) {
usage();
return null;
@@ -40,7 +40,6 @@ import ghidra.test.ProjectTestUtils;
import ghidra.util.*;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
import ghidra.util.task.TaskMonitorAdapter;
/**
* 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 projectName the name of the 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)
throws IOException {
throws NotFoundException, NotOwnerException, LockException, IOException {
return new GhidraProject(projectsDir, projectName, false);
}
@@ -82,15 +85,19 @@ public class GhidraProject {
* @param projectName the name of the ghidra project.
* @param restoreProject if true the project tool state is restored
* @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,
boolean restoreProject) throws IOException {
boolean restoreProject)
throws NotFoundException, NotOwnerException, LockException, IOException {
return new GhidraProject(projectsDir, projectName, restoreProject);
}
private GhidraProject(String projectParentDir, String projectName, boolean restoreProject)
throws IOException {
throws NotFoundException, NotOwnerException, LockException, IOException {
if (!ghidra.framework.Application.isInitialized()) {
throw new AssertException("The GhidraProject requires the system to be " +
"initialized before usage. See GhidraApplication.initialize() for more " +
@@ -98,25 +105,8 @@ public class GhidraProject {
}
ProjectLocator projectLocator = new ProjectLocator(projectParentDir, projectName);
try {
project = projectManager.openProject(projectLocator, restoreProject, false);
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);
}
project = projectManager.openProject(projectLocator, restoreProject, false);
projectData = project.getProjectData();
}
/**
@@ -146,9 +136,10 @@ public class GhidraProject {
*
* @param host Ghidra Server host
* @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
* @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,
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
* READ access only.
* {@return the underlying Project instance or null if project was opened for
* READ access only.}
*/
public Project getProject() {
return project;
}
/**
* Returns the underlying ProjectData instance.
* {@return the underlying ProjectData instance.}
*/
public ProjectData getProjectData() {
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() {
return projectData.getRootFolder();
@@ -490,7 +481,7 @@ public class GhidraProject {
throw new DuplicateFileException("File already exists: " + file);
}
}
program.saveToPackedFile(file, TaskMonitorAdapter.DUMMY);
program.saveToPackedFile(file, TaskMonitor.DUMMY);
}
catch (CancelledException e1) {
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
* what happens when the analyze call is made.
* what happens when the analyze call is made.}
*
* @param program
* 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
* instance. This will not delete the project between opening and closing and will restore
* 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);
Project project = gp.getProject();
ProjectLocator projectLocator = project.getProjectLocator();
@@ -4,9 +4,9 @@
* 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.
@@ -114,7 +114,7 @@ public abstract class AbstractToolSavingTest extends AbstractGhidraHeadedIntegra
testEnv.getProject().save();
testEnv.closeAndReopenProject();
}
catch (IOException e) {
catch (Exception e) {
AssertionFailedError afe = new AssertionFailedError();
afe.initCause(e);
throw afe;
@@ -4,9 +4,9 @@
* 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.
@@ -111,9 +111,10 @@ public interface ProjectManager {
* 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 there was an IO-related error
*/
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.
@@ -4,9 +4,9 @@
* 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.
@@ -119,12 +119,12 @@ public class DefaultProjectManager implements ProjectManager {
@Override
public Project openProject(ProjectLocator projectLocator, boolean doRestore, boolean resetOwner)
throws NotFoundException, NotOwnerException, LockException {
throws NotFoundException, NotOwnerException, LockException, IOException {
if (currentProject != null) {
Msg.error(this,
"Current project must be closed before establishing a new active project");
return null;
String msg = "Current project must be closed before establishing a new active project";
Msg.error(this, msg);
throw new LockException(msg);
}
if (!projectLocator.getMarkerFile().exists()) {
@@ -141,7 +141,6 @@ public class DefaultProjectManager implements ProjectManager {
try {
currentProject = new DefaultProject(this, projectLocator, resetOwner);
AppInfo.setActiveProject(currentProject);
if (doRestore) {
currentProject.restore();
}
@@ -152,17 +151,22 @@ public class DefaultProjectManager implements ProjectManager {
return currentProject;
}
catch (LockException e) {
return null;
Msg.showError(LOG, null, "Locked Project!",
"Cannot open locked project: " + projectLocator, e);
throw e;
}
catch (ReadOnlyException e) {
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) {
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 {
AppInfo.setActiveProject(currentProject);
if (currentProject == null) {
File dirFile = projectLocator.getProjectDir();
if (!dirFile.exists() || !dirFile.isDirectory()) {
@@ -170,8 +174,6 @@ public class DefaultProjectManager implements ProjectManager {
}
}
}
AppInfo.setActiveProject(null);
return null;
}
/**