mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
Merge remote-tracking branch 'origin/GP-3678_ghidra1_DomainFileURLs--SQUASHED'
This commit is contained in:
commit
2b8e19a27a
13 changed files with 178 additions and 76 deletions
|
@ -540,7 +540,7 @@ class MultiProgramManager implements DomainObjectListener, TransactionListener {
|
||||||
this.program = p;
|
this.program = p;
|
||||||
this.domainFile = domainFile;
|
this.domainFile = domainFile;
|
||||||
if (domainFile instanceof LinkedDomainFile linkedDomainFile) {
|
if (domainFile instanceof LinkedDomainFile linkedDomainFile) {
|
||||||
this.ghidraURL = linkedDomainFile.getSharedProjectURL();
|
this.ghidraURL = linkedDomainFile.getSharedProjectURL(null);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.ghidraURL = null;
|
this.ghidraURL = null;
|
||||||
|
|
|
@ -27,6 +27,7 @@ import db.buffers.BufferFile;
|
||||||
import db.buffers.ManagedBufferFile;
|
import db.buffers.ManagedBufferFile;
|
||||||
import ghidra.framework.model.DomainFile;
|
import ghidra.framework.model.DomainFile;
|
||||||
import ghidra.framework.model.DomainFolder;
|
import ghidra.framework.model.DomainFolder;
|
||||||
|
import ghidra.framework.protocol.ghidra.GhidraURL;
|
||||||
import ghidra.framework.store.*;
|
import ghidra.framework.store.*;
|
||||||
import ghidra.framework.store.local.LocalFileSystem;
|
import ghidra.framework.store.local.LocalFileSystem;
|
||||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||||
|
@ -86,6 +87,15 @@ public class GhidraFileTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
deleteAll(sharedProjectDir);
|
deleteAll(sharedProjectDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLocalURL() throws IOException {
|
||||||
|
createDB(privateFS, "/a", "file1");
|
||||||
|
assertEquals(GhidraURL.makeURL(pfm.getProjectLocator(), "/a/file1", "xyz"),
|
||||||
|
pfm.getFile("/a/file1").getLocalProjectURL("xyz"));
|
||||||
|
assertEquals(GhidraURL.makeURL(pfm.getProjectLocator(), "/a/file1", null),
|
||||||
|
pfm.getFile("/a/file1").getLocalProjectURL(null));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFileID() throws IOException {
|
public void testFileID() throws IOException {
|
||||||
createDB(privateFS, "/a", "file1");
|
createDB(privateFS, "/a", "file1");
|
||||||
|
|
|
@ -23,6 +23,8 @@ import java.util.*;
|
||||||
|
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import ghidra.framework.client.*;
|
import ghidra.framework.client.*;
|
||||||
import ghidra.framework.model.*;
|
import ghidra.framework.model.*;
|
||||||
import ghidra.framework.protocol.ghidra.GhidraURL;
|
import ghidra.framework.protocol.ghidra.GhidraURL;
|
||||||
|
@ -116,16 +118,13 @@ public class DomainFileProxy implements DomainFile {
|
||||||
return parentPath + DomainFolder.SEPARATOR + getName();
|
return parentPath + DomainFolder.SEPARATOR + getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
private URL getSharedFileURL(URL sharedProjectURL) {
|
private URL getSharedFileURL(URL sharedProjectURL, String ref) {
|
||||||
try {
|
try {
|
||||||
// Direct URL construction done so that ghidra protocol
|
String spec = getPathname().substring(1); // remove leading '/'
|
||||||
// extension may be supported
|
if (!StringUtils.isEmpty(ref)) {
|
||||||
String urlStr = sharedProjectURL.toExternalForm();
|
spec += "#" + ref;
|
||||||
if (urlStr.endsWith("/")) {
|
|
||||||
urlStr = urlStr.substring(0, urlStr.length() - 1);
|
|
||||||
}
|
}
|
||||||
urlStr += getPathname();
|
return new URL(sharedProjectURL, spec);
|
||||||
return new URL(urlStr);
|
|
||||||
}
|
}
|
||||||
catch (MalformedURLException e) {
|
catch (MalformedURLException e) {
|
||||||
// ignore
|
// ignore
|
||||||
|
@ -133,7 +132,7 @@ public class DomainFileProxy implements DomainFile {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private URL getSharedFileURL(Properties properties) {
|
private URL getSharedFileURL(Properties properties, String ref) {
|
||||||
if (properties == null) {
|
if (properties == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -166,9 +165,8 @@ public class DomainFileProxy implements DomainFile {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
ServerInfo serverInfo = repository.getServerInfo();
|
ServerInfo serverInfo = repository.getServerInfo();
|
||||||
return GhidraURL.makeURL(serverInfo.getServerName(),
|
return GhidraURL.makeURL(serverInfo.getServerName(), serverInfo.getPortNumber(),
|
||||||
serverInfo.getPortNumber(), repository.getName(),
|
repository.getName(), item.getPathName(), ref);
|
||||||
item.getPathName());
|
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
// ignore
|
// ignore
|
||||||
|
@ -182,15 +180,27 @@ public class DomainFileProxy implements DomainFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public URL getSharedProjectURL() {
|
public URL getSharedProjectURL(String ref) {
|
||||||
if (projectLocation != null && version == DomainFile.DEFAULT_VERSION) {
|
if (projectLocation != null && version == DomainFile.DEFAULT_VERSION) {
|
||||||
URL projectURL = projectLocation.getURL();
|
URL projectURL = projectLocation.getURL();
|
||||||
if (GhidraURL.isServerRepositoryURL(projectURL)) {
|
if (GhidraURL.isServerRepositoryURL(projectURL)) {
|
||||||
return getSharedFileURL(projectURL);
|
return getSharedFileURL(projectURL, ref);
|
||||||
}
|
}
|
||||||
Properties properties =
|
Properties properties =
|
||||||
ProjectFileManager.readProjectProperties(projectLocation.getProjectDir());
|
ProjectFileManager.readProjectProperties(projectLocation.getProjectDir());
|
||||||
return getSharedFileURL(properties);
|
return getSharedFileURL(properties, ref);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URL getLocalProjectURL(String ref) {
|
||||||
|
if (projectLocation != null && version == DomainFile.DEFAULT_VERSION) {
|
||||||
|
URL projectURL = projectLocation.getURL();
|
||||||
|
if (GhidraURL.isServerRepositoryURL(projectURL)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return GhidraURL.makeURL(projectLocation, getPathname(), ref);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,9 +124,20 @@ public class GhidraFile implements DomainFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public URL getSharedProjectURL() {
|
public URL getSharedProjectURL(String ref) {
|
||||||
try {
|
try {
|
||||||
return getFileData().getSharedProjectURL();
|
return getFileData().getSharedProjectURL(ref);
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URL getLocalProjectURL(String ref) {
|
||||||
|
try {
|
||||||
|
return getFileData().getLocalProjectURL(ref);
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
// ignore
|
// ignore
|
||||||
|
@ -456,10 +467,9 @@ public class GhidraFile implements DomainFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkout(boolean exclusive, TaskMonitor monitor) throws IOException,
|
public boolean checkout(boolean exclusive, TaskMonitor monitor)
|
||||||
CancelledException {
|
throws IOException, CancelledException {
|
||||||
return getFileData().checkout(exclusive,
|
return getFileData().checkout(exclusive, monitor != null ? monitor : TaskMonitor.DUMMY);
|
||||||
monitor != null ? monitor : TaskMonitor.DUMMY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -470,10 +480,9 @@ public class GhidraFile implements DomainFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void merge(boolean okToUpgrade, TaskMonitor monitor) throws IOException,
|
public void merge(boolean okToUpgrade, TaskMonitor monitor)
|
||||||
VersionException, CancelledException {
|
throws IOException, VersionException, CancelledException {
|
||||||
getFileData().merge(okToUpgrade,
|
getFileData().merge(okToUpgrade, monitor != null ? monitor : TaskMonitor.DUMMY);
|
||||||
monitor != null ? monitor : TaskMonitor.DUMMY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -521,8 +530,8 @@ public class GhidraFile implements DomainFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DomainFile copyTo(DomainFolder newParent, TaskMonitor monitor) throws IOException,
|
public DomainFile copyTo(DomainFolder newParent, TaskMonitor monitor)
|
||||||
CancelledException {
|
throws IOException, CancelledException {
|
||||||
if (!GhidraFolder.class.isAssignableFrom(newParent.getClass())) {
|
if (!GhidraFolder.class.isAssignableFrom(newParent.getClass())) {
|
||||||
throw new UnsupportedOperationException("newParent does not support copyTo");
|
throw new UnsupportedOperationException("newParent does not support copyTo");
|
||||||
}
|
}
|
||||||
|
@ -559,8 +568,7 @@ public class GhidraFile implements DomainFile {
|
||||||
* @throws CancelledException if task is cancelled
|
* @throws CancelledException if task is cancelled
|
||||||
*/
|
*/
|
||||||
void convertToPrivateFile(TaskMonitor monitor) throws IOException, CancelledException {
|
void convertToPrivateFile(TaskMonitor monitor) throws IOException, CancelledException {
|
||||||
getFileData().convertToPrivateFile(
|
getFileData().convertToPrivateFile(monitor != null ? monitor : TaskMonitor.DUMMY);
|
||||||
monitor != null ? monitor : TaskMonitor.DUMMY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -24,6 +24,8 @@ import java.util.Map;
|
||||||
|
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import db.DBHandle;
|
import db.DBHandle;
|
||||||
import db.Field;
|
import db.Field;
|
||||||
import db.buffers.*;
|
import db.buffers.*;
|
||||||
|
@ -209,17 +211,21 @@ public class GhidraFileData {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a remote Ghidra URL for this domain file if available within a remote repository.
|
* Get a remote Ghidra URL for this domain file if available within a remote repository.
|
||||||
|
* @param ref reference within a file, may be null. NOTE: such reference interpretation
|
||||||
|
* is specific to a domain object and tooling with limited support.
|
||||||
* @return remote Ghidra URL for this file or null
|
* @return remote Ghidra URL for this file or null
|
||||||
*/
|
*/
|
||||||
URL getSharedProjectURL() {
|
URL getSharedProjectURL(String ref) {
|
||||||
synchronized (fileSystem) {
|
synchronized (fileSystem) {
|
||||||
RepositoryAdapter repository = parent.getProjectFileManager().getRepository();
|
RepositoryAdapter repository = parent.getProjectFileManager().getRepository();
|
||||||
if (versionedFolderItem != null && repository != null) {
|
if (versionedFolderItem != null && repository != null) {
|
||||||
URL folderURL = parent.getDomainFolder().getSharedProjectURL();
|
URL folderURL = parent.getDomainFolder().getSharedProjectURL();
|
||||||
try {
|
try {
|
||||||
// Direct URL construction done so that ghidra protocol
|
String spec = name;
|
||||||
// extension may be supported
|
if (!StringUtils.isEmpty(ref)) {
|
||||||
return new URL(folderURL.toExternalForm() + name);
|
spec += "#" + ref;
|
||||||
|
}
|
||||||
|
return new URL(folderURL, spec);
|
||||||
}
|
}
|
||||||
catch (MalformedURLException e) {
|
catch (MalformedURLException e) {
|
||||||
// ignore
|
// ignore
|
||||||
|
@ -229,6 +235,23 @@ public class GhidraFileData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a local Ghidra URL for this domain file if available within a non-transient local
|
||||||
|
* project. A null value is returned for a transient project.
|
||||||
|
* @param ref reference within a file, may be null. NOTE: such reference interpretation
|
||||||
|
* is specific to a domain object and tooling with limited support.
|
||||||
|
* @return local Ghidra URL for this file or null if transient or not applicable
|
||||||
|
*/
|
||||||
|
URL getLocalProjectURL(String ref) {
|
||||||
|
synchronized (fileSystem) {
|
||||||
|
ProjectLocator projectLocator = parent.getProjectLocator();
|
||||||
|
if (!projectLocator.isTransient()) {
|
||||||
|
return GhidraURL.makeURL(projectLocator, getPathname(), ref);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reassign a new file-ID to resolve file-ID conflict.
|
* Reassign a new file-ID to resolve file-ID conflict.
|
||||||
* Conflicts can occur as a result of a cancelled check-out.
|
* Conflicts can occur as a result of a cancelled check-out.
|
||||||
|
@ -453,8 +476,7 @@ public class GhidraFileData {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
DomainObjectAdapter dobj = fileManager.getOpenedDomainObject(getPathname());
|
DomainObjectAdapter dobj = fileManager.getOpenedDomainObject(getPathname());
|
||||||
if (!(dobj instanceof DomainObjectAdapterDB) ||
|
if (!(dobj instanceof DomainObjectAdapterDB) || !dobj.isChanged()) {
|
||||||
!dobj.isChanged()) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
LockingTaskMonitor monitor = null;
|
LockingTaskMonitor monitor = null;
|
||||||
|
@ -881,8 +903,8 @@ public class GhidraFileData {
|
||||||
: CheckoutType.NORMAL;
|
: CheckoutType.NORMAL;
|
||||||
}
|
}
|
||||||
ItemCheckoutStatus checkout =
|
ItemCheckoutStatus checkout =
|
||||||
versionedFolderItem.checkout(checkoutType, user, ItemCheckoutStatus.getProjectPath(
|
versionedFolderItem.checkout(checkoutType, user, ItemCheckoutStatus
|
||||||
projectLocator.toString(), projectLocator.isTransient()));
|
.getProjectPath(projectLocator.toString(), projectLocator.isTransient()));
|
||||||
if (checkout == null) {
|
if (checkout == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1690,10 +1712,8 @@ public class GhidraFileData {
|
||||||
BufferFile bufferFile = ((DatabaseItem) item).open();
|
BufferFile bufferFile = ((DatabaseItem) item).open();
|
||||||
try {
|
try {
|
||||||
newParentData.getLocalFileSystem()
|
newParentData.getLocalFileSystem()
|
||||||
.createDatabase(pathname, targetName,
|
.createDatabase(pathname, targetName, FileIDFactory.createFileID(),
|
||||||
FileIDFactory.createFileID(), bufferFile, null, contentType,
|
bufferFile, null, contentType, true, monitor, user);
|
||||||
true,
|
|
||||||
monitor, user);
|
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
bufferFile.dispose();
|
bufferFile.dispose();
|
||||||
|
@ -1703,8 +1723,8 @@ public class GhidraFileData {
|
||||||
InputStream istream = ((DataFileItem) item).getInputStream();
|
InputStream istream = ((DataFileItem) item).getInputStream();
|
||||||
try {
|
try {
|
||||||
newParentData.getLocalFileSystem()
|
newParentData.getLocalFileSystem()
|
||||||
.createDataFile(pathname, targetName,
|
.createDataFile(pathname, targetName, istream, null, contentType,
|
||||||
istream, null, contentType, monitor);
|
monitor);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
istream.close();
|
istream.close();
|
||||||
|
@ -1745,10 +1765,8 @@ public class GhidraFileData {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
destFolderData.getLocalFileSystem()
|
destFolderData.getLocalFileSystem()
|
||||||
.createDatabase(pathname, targetName,
|
.createDatabase(pathname, targetName, FileIDFactory.createFileID(),
|
||||||
FileIDFactory.createFileID(), bufferFile, null, contentType, true,
|
bufferFile, null, contentType, true, monitor, user);
|
||||||
monitor,
|
|
||||||
user);
|
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
bufferFile.dispose();
|
bufferFile.dispose();
|
||||||
|
|
|
@ -199,8 +199,7 @@ public class GhidraFolder implements DomainFolder {
|
||||||
repository.getName());
|
repository.getName());
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// Direct URL construction done so that ghidra protocol
|
// Direct URL construction done so that ghidra protocol extension may be supported
|
||||||
// extension may be supported
|
|
||||||
String urlStr = projectURL.toExternalForm();
|
String urlStr = projectURL.toExternalForm();
|
||||||
if (urlStr.endsWith(FileSystem.SEPARATOR)) {
|
if (urlStr.endsWith(FileSystem.SEPARATOR)) {
|
||||||
urlStr = urlStr.substring(0, urlStr.length() - 1);
|
urlStr = urlStr.substring(0, urlStr.length() - 1);
|
||||||
|
@ -217,6 +216,15 @@ public class GhidraFolder implements DomainFolder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URL getLocalProjectURL() {
|
||||||
|
ProjectLocator projectLocator = parent.getProjectLocator();
|
||||||
|
if (!projectLocator.isTransient()) {
|
||||||
|
return GhidraURL.makeURL(projectLocator, getPathname(), null);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInWritableProject() {
|
public boolean isInWritableProject() {
|
||||||
return !getProjectData().getLocalFileSystem().isReadOnly();
|
return !getProjectData().getLocalFileSystem().isReadOnly();
|
||||||
|
|
|
@ -43,7 +43,7 @@ import ghidra.util.task.TaskMonitor;
|
||||||
* @param <T> {@link URLLinkObject} implementation class
|
* @param <T> {@link URLLinkObject} implementation class
|
||||||
*/
|
*/
|
||||||
public abstract class LinkHandler<T extends DomainObjectAdapterDB> extends DBContentHandler<T> {
|
public abstract class LinkHandler<T extends DomainObjectAdapterDB> extends DBContentHandler<T> {
|
||||||
|
|
||||||
public static final String URL_METADATA_KEY = "link.url";
|
public static final String URL_METADATA_KEY = "link.url";
|
||||||
|
|
||||||
// 16x16 link icon where link is placed in lower-left corner
|
// 16x16 link icon where link is placed in lower-left corner
|
||||||
|
@ -93,11 +93,10 @@ public abstract class LinkHandler<T extends DomainObjectAdapterDB> extends DBCon
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private T getObject(FolderItem item, int version, Object consumer, TaskMonitor monitor,
|
private T getObject(FolderItem item, int version, Object consumer, TaskMonitor monitor,
|
||||||
boolean immutable)
|
boolean immutable) throws IOException, VersionException, CancelledException {
|
||||||
throws IOException, VersionException, CancelledException {
|
|
||||||
|
|
||||||
URL url = getURL(item);
|
URL url = getURL(item);
|
||||||
|
|
||||||
Class<?> domainObjectClass = getDomainObjectClass();
|
Class<?> domainObjectClass = getDomainObjectClass();
|
||||||
if (domainObjectClass == null) {
|
if (domainObjectClass == null) {
|
||||||
throw new UnsupportedOperationException("");
|
throw new UnsupportedOperationException("");
|
||||||
|
@ -105,6 +104,7 @@ public abstract class LinkHandler<T extends DomainObjectAdapterDB> extends DBCon
|
||||||
|
|
||||||
GhidraURLWrappedContent wrappedContent = null;
|
GhidraURLWrappedContent wrappedContent = null;
|
||||||
Object content = null;
|
Object content = null;
|
||||||
|
final Object transientConsumer = new Object();
|
||||||
try {
|
try {
|
||||||
GhidraURLConnection c = (GhidraURLConnection) url.openConnection();
|
GhidraURLConnection c = (GhidraURLConnection) url.openConnection();
|
||||||
Object obj = c.getContent(); // read-only access
|
Object obj = c.getContent(); // read-only access
|
||||||
|
@ -115,22 +115,21 @@ public abstract class LinkHandler<T extends DomainObjectAdapterDB> extends DBCon
|
||||||
throw new IOException("Unsupported linked content");
|
throw new IOException("Unsupported linked content");
|
||||||
}
|
}
|
||||||
wrappedContent = (GhidraURLWrappedContent) obj;
|
wrappedContent = (GhidraURLWrappedContent) obj;
|
||||||
content = wrappedContent.getContent(consumer);
|
content = wrappedContent.getContent(transientConsumer);
|
||||||
if (!(content instanceof DomainFile)) {
|
if (!(content instanceof DomainFile)) {
|
||||||
throw new IOException("Unsupported linked content: " + content.getClass());
|
throw new IOException("Unsupported linked content: " + content.getClass());
|
||||||
}
|
}
|
||||||
DomainFile linkedFile = (DomainFile) content;
|
DomainFile linkedFile = (DomainFile) content;
|
||||||
if (!getDomainObjectClass().isAssignableFrom(linkedFile.getDomainObjectClass())) {
|
if (!getDomainObjectClass().isAssignableFrom(linkedFile.getDomainObjectClass())) {
|
||||||
throw new BadLinkException(
|
throw new BadLinkException("Expected " + getDomainObjectClass() +
|
||||||
"Expected " + getDomainObjectClass() + " but linked to " +
|
" but linked to " + linkedFile.getDomainObjectClass());
|
||||||
linkedFile.getDomainObjectClass());
|
|
||||||
}
|
}
|
||||||
return immutable ? (T) linkedFile.getImmutableDomainObject(consumer, version, monitor)
|
return immutable ? (T) linkedFile.getImmutableDomainObject(consumer, version, monitor)
|
||||||
: (T) linkedFile.getReadOnlyDomainObject(consumer, version, monitor);
|
: (T) linkedFile.getReadOnlyDomainObject(consumer, version, monitor);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
if (content != null) {
|
if (content != null) {
|
||||||
wrappedContent.release(content, consumer);
|
wrappedContent.release(content, transientConsumer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,8 +150,7 @@ public abstract class LinkHandler<T extends DomainObjectAdapterDB> extends DBCon
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final DomainObjectMergeManager getMergeManager(DomainObject resultsObj,
|
public final DomainObjectMergeManager getMergeManager(DomainObject resultsObj,
|
||||||
DomainObject sourceObj,
|
DomainObject sourceObj, DomainObject originalObj, DomainObject latestObj) {
|
||||||
DomainObject originalObj, DomainObject latestObj) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,8 @@ import java.util.Map;
|
||||||
import javax.help.UnsupportedOperationException;
|
import javax.help.UnsupportedOperationException;
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import ghidra.framework.model.*;
|
import ghidra.framework.model.*;
|
||||||
import ghidra.framework.protocol.ghidra.GhidraURL;
|
import ghidra.framework.protocol.ghidra.GhidraURL;
|
||||||
import ghidra.framework.store.*;
|
import ghidra.framework.store.*;
|
||||||
|
@ -100,13 +102,15 @@ class LinkedGhidraFile implements LinkedDomainFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public URL getSharedProjectURL() {
|
public URL getSharedProjectURL(String ref) {
|
||||||
URL folderURL = parent.getSharedProjectURL();
|
URL folderURL = parent.getSharedProjectURL();
|
||||||
if (GhidraURL.isServerRepositoryURL(folderURL)) {
|
if (GhidraURL.isServerRepositoryURL(folderURL)) {
|
||||||
// Direct URL construction done so that ghidra protocol
|
|
||||||
// extension may be supported
|
|
||||||
try {
|
try {
|
||||||
return new URL(folderURL.toExternalForm() + fileName);
|
String spec = fileName;
|
||||||
|
if (!StringUtils.isEmpty(ref)) {
|
||||||
|
spec += "#" + ref;
|
||||||
|
}
|
||||||
|
return new URL(folderURL, spec);
|
||||||
}
|
}
|
||||||
catch (MalformedURLException e) {
|
catch (MalformedURLException e) {
|
||||||
// ignore
|
// ignore
|
||||||
|
@ -115,6 +119,15 @@ class LinkedGhidraFile implements LinkedDomainFile {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URL getLocalProjectURL(String ref) {
|
||||||
|
ProjectLocator projectLocator = parent.getProjectLocator();
|
||||||
|
if (!projectLocator.isTransient()) {
|
||||||
|
return GhidraURL.makeURL(projectLocator, getPathname(), ref);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProjectLocator getProjectLocator() {
|
public ProjectLocator getProjectLocator() {
|
||||||
return parent.getProjectLocator();
|
return parent.getProjectLocator();
|
||||||
|
|
|
@ -107,6 +107,15 @@ class LinkedGhidraSubFolder implements LinkedDomainFolder {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URL getLocalProjectURL() {
|
||||||
|
ProjectLocator projectLocator = parent.getProjectLocator();
|
||||||
|
if (!projectLocator.isTransient()) {
|
||||||
|
return GhidraURL.makeURL(projectLocator, getPathname(), null);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProjectLocator getProjectLocator() {
|
public ProjectLocator getProjectLocator() {
|
||||||
return parent.getProjectLocator();
|
return parent.getProjectLocator();
|
||||||
|
|
|
@ -89,12 +89,23 @@ public interface DomainFile extends Comparable<DomainFile> {
|
||||||
public String getPathname();
|
public String getPathname();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a remote Ghidra URL for this domain file if available within the associated shared
|
* Get a remote Ghidra URL for this domain file if available within an associated shared
|
||||||
* project repository. A null value will be returned if shared file does not exist and
|
* project repository. A null value will be returned if shared file does not exist and
|
||||||
* may be returned if shared repository is not connected or a connection error occurs.
|
* may also be returned if shared repository is not connected or a connection error occurs.
|
||||||
|
* @param ref reference within a file, may be null. NOTE: such reference interpretation
|
||||||
|
* is specific to a domain object and tooling with limited support.
|
||||||
* @return remote Ghidra URL for this file or null
|
* @return remote Ghidra URL for this file or null
|
||||||
*/
|
*/
|
||||||
public URL getSharedProjectURL();
|
public URL getSharedProjectURL(String ref);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a local Ghidra URL for this domain file if available within the associated non-transient
|
||||||
|
* local project. A null value will be returned if project is transient.
|
||||||
|
* @param ref reference within a file, may be null. NOTE: such reference interpretation
|
||||||
|
* is specific to a domain object and tooling with limited support.
|
||||||
|
* @return local Ghidra URL for this file or null if transient or not applicable
|
||||||
|
*/
|
||||||
|
public URL getLocalProjectURL(String ref);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the local storage location for the project that this DomainFile belongs to.
|
* Returns the local storage location for the project that this DomainFile belongs to.
|
||||||
|
|
|
@ -35,8 +35,7 @@ import ghidra.util.task.TaskMonitor;
|
||||||
*/
|
*/
|
||||||
public interface DomainFolder extends Comparable<DomainFolder> {
|
public interface DomainFolder extends Comparable<DomainFolder> {
|
||||||
|
|
||||||
public static final Icon OPEN_FOLDER_ICON =
|
public static final Icon OPEN_FOLDER_ICON = new GIcon("icon.datatree.node.domain.folder.open");
|
||||||
new GIcon("icon.datatree.node.domain.folder.open");
|
|
||||||
|
|
||||||
public static final Icon CLOSED_FOLDER_ICON =
|
public static final Icon CLOSED_FOLDER_ICON =
|
||||||
new GIcon("icon.datatree.node.domain.folder.closed");
|
new GIcon("icon.datatree.node.domain.folder.closed");
|
||||||
|
@ -90,13 +89,21 @@ public interface DomainFolder extends Comparable<DomainFolder> {
|
||||||
public String getPathname();
|
public String getPathname();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a remote Ghidra URL for this domain folder within the associated shared
|
* Get a remote Ghidra URL for this domain folder if available within an associated shared
|
||||||
* project repository. URL path will end with "/". A null value will be returned if not
|
* project repository. URL path will end with "/". A null value will be returned if shared
|
||||||
* associated with a shared project.
|
* folder does not exist and may also be returned if shared repository is not connected or a
|
||||||
|
* connection error occurs.
|
||||||
* @return remote Ghidra URL for this folder or null
|
* @return remote Ghidra URL for this folder or null
|
||||||
*/
|
*/
|
||||||
public URL getSharedProjectURL();
|
public URL getSharedProjectURL();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a local Ghidra URL for this domain file if available within the associated non-transient
|
||||||
|
* local project. A null value will be returned if project is transient.
|
||||||
|
* @return local Ghidra URL for this folder or null if transient or not applicable
|
||||||
|
*/
|
||||||
|
public URL getLocalProjectURL();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this file is in a writable project.
|
* Returns true if this file is in a writable project.
|
||||||
* @return true if writable
|
* @return true if writable
|
||||||
|
@ -219,8 +226,8 @@ public interface DomainFolder extends Comparable<DomainFolder> {
|
||||||
* @throws IOException thrown if an IO or access error occurs.
|
* @throws IOException thrown if an IO or access error occurs.
|
||||||
* @throws CancelledException if task monitor cancelled operation.
|
* @throws CancelledException if task monitor cancelled operation.
|
||||||
*/
|
*/
|
||||||
public DomainFolder copyTo(DomainFolder newParent, TaskMonitor monitor) throws IOException,
|
public DomainFolder copyTo(DomainFolder newParent, TaskMonitor monitor)
|
||||||
CancelledException;
|
throws IOException, CancelledException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy this folder into the newParent folder as a link file. Restrictions:
|
* Copy this folder into the newParent folder as a link file. Restrictions:
|
||||||
|
|
|
@ -102,7 +102,12 @@ public class TestDummyDomainFile implements DomainFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public URL getSharedProjectURL() {
|
public URL getSharedProjectURL(String ref) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URL getLocalProjectURL(String ref) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,6 +88,11 @@ public class TestDummyDomainFolder implements DomainFolder {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URL getLocalProjectURL() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInWritableProject() {
|
public boolean isInWritableProject() {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue