diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguageFile.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguageFile.java index 775fed826a..e1561d97a8 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguageFile.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguageFile.java @@ -130,9 +130,12 @@ public class SleighLanguageFile { } return new SleighLanguageFile(slaRFile, slaSpecRFile, null); } - - File lockFile = - new ResourceFile(slaRFile.getParentFile(), slaRFile.getName() + ".lock").getFile(false); + + // try to create lock file. Will fail in directories that the user doesn't have perms for + // and will be the same as single jar mode (no locking / compiling possible) + File lockFile = tryCreateLockFile( + new ResourceFile(slaRFile.getParentFile(), slaRFile.getName() + ".lock") + .getFile(false)); return new SleighLanguageFile(slaRFile, slaSpecRFile, lockFile); } @@ -228,6 +231,10 @@ public class SleighLanguageFile { return lockFile != null; } + public File getLockFile() { + return lockFile; + } + /** * Executes a runnable while a lock file is being held. * @@ -530,4 +537,15 @@ public class SleighLanguageFile { return matches; } + private static File tryCreateLockFile(File lockFile) { + if (lockFile == null) { + return null; + } + try (RandomAccessFile raf = new RandomAccessFile(lockFile, "rw")) { + return lockFile; + } + catch (IOException e) { + return null; + } + } } diff --git a/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/app/plugin/processors/sleigh/SleighLanguageProviderTest.java b/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/app/plugin/processors/sleigh/SleighLanguageProviderTest.java index c6a8728d95..066012e9f1 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/app/plugin/processors/sleigh/SleighLanguageProviderTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/app/plugin/processors/sleigh/SleighLanguageProviderTest.java @@ -16,9 +16,11 @@ package ghidra.app.plugin.processors.sleigh; import static org.junit.Assert.*; +import static org.junit.Assume.*; -import java.io.File; -import java.io.IOException; +import java.io.*; +import java.nio.file.Files; +import java.nio.file.attribute.PosixFilePermissions; import java.time.Duration; import java.util.ArrayList; import java.util.List; @@ -30,11 +32,13 @@ import org.junit.Test; import generic.jar.ResourceFile; import generic.test.AbstractGenericTest; import ghidra.framework.Application; +import ghidra.framework.OperatingSystem; import ghidra.program.model.lang.Language; import ghidra.program.model.lang.LanguageID; import ghidra.util.Msg; import ghidra.util.SystemUtilities; import ghidra.util.task.TaskMonitor; +import utilities.util.FileUtilities; public class SleighLanguageProviderTest extends AbstractGenericTest { @@ -124,6 +128,68 @@ public class SleighLanguageProviderTest extends AbstractGenericTest { testProc.assertExitNum(1); } + @Test + public void testSlaLockFileInReadOnlyDirectory() throws IOException { + assumeFalse(OperatingSystem.CURRENT_OPERATING_SYSTEM == OperatingSystem.WINDOWS); + + File tmpDir = createTempDirectory("sleighlockfiletest"); + FileUtilities.writeStringToFile(new File(tmpDir, "mylang.slaspec"), "slaspec"); + FileUtilities.writeStringToFile(new File(tmpDir, "mylang.sla"), "sla"); + + SleighLanguageFile slf = + SleighLanguageFile.fromSlaFilename(new ResourceFile(tmpDir), "mylang.sla"); + assertTrue(slf.canLock()); + + if (!slf.getLockFile().delete()) { + fail("failed to delete lock file"); + } + + Files.setPosixFilePermissions(tmpDir.toPath(), + PosixFilePermissions.fromString("r-x------")); + + try { + try (RandomAccessFile raf = + new RandomAccessFile(new File(tmpDir, "mylang.probe_permisssions"), "rw")) { + fail( + "Did not change actual perms on tmpDir " + tmpDir + " to test lock file logic"); + } + catch (IOException e) { + // good + } + + // now should fail to allow locking + SleighLanguageFile slf2 = + SleighLanguageFile.fromSlaFilename(new ResourceFile(tmpDir), "mylang.sla"); + assertFalse(slf2.canLock()); + } + finally { + // restore perms so its not too hard to cleanup tmp dir afterwards + Files.setPosixFilePermissions(tmpDir.toPath(), + PosixFilePermissions.fromString("rwx------")); + } + } + + @Test + public void testSlaLockFileReadOnlyFile() throws IOException { + assumeFalse(OperatingSystem.CURRENT_OPERATING_SYSTEM == OperatingSystem.WINDOWS); + + File tmpDir = createTempDirectory("sleighlockfiletest"); + FileUtilities.writeStringToFile(new File(tmpDir, "mylang.slaspec"), "slaspec"); + FileUtilities.writeStringToFile(new File(tmpDir, "mylang.sla"), "sla"); + + SleighLanguageFile slf = + SleighLanguageFile.fromSlaFilename(new ResourceFile(tmpDir), "mylang.sla"); + assertTrue(slf.canLock()); + + Files.setPosixFilePermissions(slf.getLockFile().toPath(), + PosixFilePermissions.fromString("r-x------")); + + // now should fail to allow locking + SleighLanguageFile slf2 = + SleighLanguageFile.fromSlaFilename(new ResourceFile(tmpDir), "mylang.sla"); + assertFalse(slf2.canLock()); + } + public void testSlaLanguage_FromOtherProcess() throws Throwable { // this is not a junit test entry point, but instead is what is run // in each sub-process launched by each TestProc instance.