diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/headless/HeadlessAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/headless/HeadlessAnalyzer.java
index c08498684f..d1d69c923f 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/headless/HeadlessAnalyzer.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/headless/HeadlessAnalyzer.java
@@ -603,9 +603,6 @@ public class HeadlessAnalyzer {
*/
private boolean checkUpdateOptions() {
- boolean isImport = !options.runScriptsNoImport;
- boolean commitAllowed = isCommitAllowed();
-
if (options.readOnly) {
String readOnlyError =
"Abort due to Headless analyzer error: The requested -readOnly option " +
@@ -621,7 +618,13 @@ public class HeadlessAnalyzer {
return false;
}
}
+ else if (!isInWritableProject()) {
+ Msg.error(this, "Processing files within read-only project/repository " +
+ "- the -readOnly option is required.");
+ return false;
+ }
+ boolean commitAllowed = isCommitAllowed();
if (options.commit && !commitAllowed) {
Msg.error(this,
"Commit to repository not possible (due to permission or connection issue)");
@@ -640,6 +643,7 @@ public class HeadlessAnalyzer {
}
if (options.overwrite) {
+ boolean isImport = !options.runScriptsNoImport;
if (!isImport) {
Msg.info(this,
"Ignoring -overwrite because it is not applicable to -process mode.");
@@ -654,6 +658,10 @@ public class HeadlessAnalyzer {
return true;
}
+ private boolean isInWritableProject() {
+ return project.getProjectData().getRootFolder().isInWritableProject();
+ }
+
private boolean isCommitAllowed() {
RepositoryAdapter repository = project.getRepository();
if (repository == null) {
@@ -666,7 +674,7 @@ public class HeadlessAnalyzer {
}
User user = repository.getUser();
if (!user.hasWritePermission()) {
- Msg.warn(this, "User '" + user.getName() +
+ Msg.error(this, "User '" + user.getName() +
"' does not have write permission to repository - commit not allowed");
return false;
}
@@ -1126,31 +1134,38 @@ public class HeadlessAnalyzer {
boolean keepFile = true; // if false file should be deleted after release
boolean terminateCheckoutWhenDone = false;
- boolean readOnlyFile = options.readOnly || domFile.isReadOnly();
+ boolean readOnlyFile =
+ options.readOnly || domFile.isReadOnly() || !domFile.isInWritableProject();
try {
// Exclusive checkout required when commit option specified
- if (!readOnlyFile) {
- if (domFile.isVersioned()) {
- if (!domFile.isCheckedOut()) {
- if (!domFile.checkout(options.commit, TaskMonitor.DUMMY)) {
- Msg.warn(this, "Skipped processing for " + domFile.getPathname() +
- " -- failed to get exclusive file checkout required for commit");
- return;
- }
- }
- else if (options.commit && !domFile.isCheckedOutExclusive()) {
- Msg.error(this, "Skipped processing for " + domFile.getPathname() +
- " -- file is checked-out non-exclusive (commit requires exclusive checkout)");
+ if (!readOnlyFile && domFile.isVersioned()) {
+ if (!domFile.isCheckedOut()) {
+ if (!domFile.canCheckout()) {
+ Msg.warn(this, "Skipped processing for " + domFile.getPathname() +
+ " within read-only repository");
return;
}
+ if (!domFile.checkout(options.commit, TaskMonitor.DUMMY)) {
+ Msg.warn(this, "Skipped processing for " + domFile.getPathname() +
+ " -- failed to get exclusive file checkout required for commit");
+ return;
+ }
+ // Only terminate checkout when done if we did the checkout
+ terminateCheckoutWhenDone = true;
+ }
+ else if (options.commit && !domFile.isCheckedOutExclusive()) {
+ Msg.error(this, "Skipped processing for " + domFile.getPathname() +
+ " -- file is checked-out non-exclusive (commit requires exclusive checkout)");
+ return;
}
- terminateCheckoutWhenDone = true;
}
program = (Program) domFile.getDomainObject(this, true, false, TaskMonitor.DUMMY);
- Msg.info(this, "REPORT: Processing project file: " + domFile.getPathname());
+ String readOnlyText = readOnlyFile ? "read-only " : "";
+ Msg.info(this,
+ "REPORT: Processing " + readOnlyText + "project file: " + domFile.getPathname());
// This method already takes into account whether the user has set the "noanalysis"
// flag or not
diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/protocol/ghidra/DefaultGhidraProtocolConnector.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/protocol/ghidra/DefaultGhidraProtocolConnector.java
index c0350f7bd8..db6fa89e6f 100644
--- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/protocol/ghidra/DefaultGhidraProtocolConnector.java
+++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/protocol/ghidra/DefaultGhidraProtocolConnector.java
@@ -65,28 +65,32 @@ public class DefaultGhidraProtocolConnector extends GhidraProtocolConnector {
repositoryServerAdapter =
ClientUtil.getRepositoryServer(url.getHost(), url.getPort(), true);
+ if (!repositoryServerAdapter.isConnected()) {
+ if (repositoryServerAdapter.isCancelled()) {
+ return statusCode;
+ }
+ Throwable t = repositoryServerAdapter.getLastConnectError();
+ if (t instanceof LoginException) {
+ statusCode = StatusCode.UNAUTHORIZED;
+ }
+ return statusCode;
+ }
if (repositoryName == null) {
+ if (repositoryServerAdapter.isReadOnly()) {
+ this.readOnly = true; // write access not permitted
+ Msg.warn(this, "User does not have write permission for server");
+ }
statusCode = StatusCode.OK;
return statusCode;
}
repositoryAdapter = repositoryServerAdapter.getRepository(repositoryName);
- if (repositoryServerAdapter.isConnected()) {
- try {
- repositoryAdapter.connect();
- }
- catch (RepositoryNotFoundException e) {
- statusCode = StatusCode.NOT_FOUND;
- return statusCode;
- }
+ try {
+ repositoryAdapter.connect();
}
- else if (!repositoryServerAdapter.isCancelled()) {
- Throwable t = repositoryServerAdapter.getLastConnectError();
- if (t instanceof LoginException) {
- statusCode = StatusCode.UNAUTHORIZED;
- }
- //throw new NotConnectedException("Not connected to repository server", t);
+ catch (RepositoryNotFoundException e) {
+ statusCode = StatusCode.NOT_FOUND;
return statusCode;
}
diff --git a/Ghidra/RuntimeScripts/Common/support/analyzeHeadlessREADME.html b/Ghidra/RuntimeScripts/Common/support/analyzeHeadlessREADME.html
index fedcfddef1..6f917e9d43 100644
--- a/Ghidra/RuntimeScripts/Common/support/analyzeHeadlessREADME.html
+++ b/Ghidra/RuntimeScripts/Common/support/analyzeHeadlessREADME.html
@@ -415,8 +415,10 @@ The Headless Analyzer uses the command-line parameters discussed below. See -readOnly
If present in -import mode, imported files will NOT be saved to the
project. If present in -process mode, any changes made to existing
- files by scripts or analysis are discarded. The -overwrite option
- will be ignored if this option is specified during import operations.
+ files by scripts or analysis are discarded. When processing a shared project or URL associated
+ with a read-only repository, such files will be skipped unless this option is specified.
+ The -overwrite option will be ignored if this option is specified
+ during import operations.