From f661d684f6911a2003ca5f7681891b52fbdc151e Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Fri, 7 Jul 2023 18:34:11 -0400 Subject: [PATCH] GP-3616 corrected DomainFileProxy.getSharedProjectURL --- .../ghidra/framework/client/ClientUtil.java | 15 ++++ .../framework/data/DomainFileProxy.java | 84 ++++++++++++++++--- .../framework/data/ProjectFileManager.java | 41 ++++++++- .../model/data/FileDataTypeManager.java | 52 +++++++++++- 4 files changed, 173 insertions(+), 19 deletions(-) diff --git a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/client/ClientUtil.java b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/client/ClientUtil.java index dffbef38a4..a196b96305 100644 --- a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/client/ClientUtil.java +++ b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/client/ClientUtil.java @@ -132,6 +132,21 @@ public class ClientUtil { return rsa; } + /** + * Determine if a connected {@link RepositoryServerAdapter} already exists for the specified server. + * @param host server name or address + * @param port server port, 0 indicates that default port applies. + * @return true if connection already exists, else false + */ + public static boolean isConnected(String host, int port) { + if (port <= 0) { + port = GhidraServerHandle.DEFAULT_PORT; + } + ServerInfo server = new ServerInfo(host, port); + RepositoryServerAdapter rsa = serverHandles.get(server); + return rsa != null && rsa.isConnected(); + } + /** * Eliminate the specified repository server from the connection cache * @param host host name or IP address diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/DomainFileProxy.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/DomainFileProxy.java index 7a13516e27..0bb4d082bf 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/DomainFileProxy.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/DomainFileProxy.java @@ -23,8 +23,10 @@ import java.util.*; import javax.swing.Icon; +import ghidra.framework.client.*; import ghidra.framework.model.*; import ghidra.framework.protocol.ghidra.GhidraURL; +import ghidra.framework.remote.RepositoryItem; import ghidra.framework.store.ItemCheckoutStatus; import ghidra.framework.store.Version; import ghidra.framework.store.db.PackedDatabase; @@ -114,25 +116,81 @@ public class DomainFileProxy implements DomainFile { return parentPath + DomainFolder.SEPARATOR + getName(); } + private URL getSharedFileURL(URL sharedProjectURL) { + try { + // Direct URL construction done so that ghidra protocol + // extension may be supported + String urlStr = sharedProjectURL.toExternalForm(); + if (urlStr.endsWith("/")) { + urlStr = urlStr.substring(0, urlStr.length() - 1); + } + urlStr += getPathname(); + return new URL(urlStr); + } + catch (MalformedURLException e) { + // ignore + } + return null; + } + + private URL getSharedFileURL(Properties properties) { + if (properties == null) { + return null; + } + String serverName = properties.getProperty(ProjectFileManager.SERVER_NAME); + String repoName = properties.getProperty(ProjectFileManager.REPOSITORY_NAME); + if (serverName == null || repoName == null) { + return null; + } + int port = Integer.parseInt(properties.getProperty(ProjectFileManager.PORT_NUMBER, "0")); + + if (!ClientUtil.isConnected(serverName, port)) { + return null; // avoid initiating a server connection. + } + + RepositoryAdapter repository = null; + try { + RepositoryServerAdapter repositoryServer = + ClientUtil.getRepositoryServer(serverName, port); + Set repoNames = Set.of(repositoryServer.getRepositoryNames()); + if (!repoNames.contains(repoName)) { + return null; // only consider repos which user has access to + } + repository = repositoryServer.getRepository(repoName); + if (repository == null) { + return null; + } + repository.connect(); + RepositoryItem item = repository.getItem(parentPath, name); + if (item == null || !Objects.equals(item.getFileID(), fileID)) { + return null; + } + ServerInfo serverInfo = repository.getServerInfo(); + return GhidraURL.makeURL(serverInfo.getServerName(), + serverInfo.getPortNumber(), repository.getName(), + item.getPathName()); + } + catch (IOException e) { + // ignore + } + finally { + if (repository != null) { + repository.disconnect(); + } + } + return null; + } + @Override public URL getSharedProjectURL() { if (projectLocation != null && version == DomainFile.DEFAULT_VERSION) { URL projectURL = projectLocation.getURL(); if (GhidraURL.isServerRepositoryURL(projectURL)) { - try { - // Direct URL construction done so that ghidra protocol - // extension may be supported - String urlStr = projectURL.toExternalForm(); - if (urlStr.endsWith("/")) { - urlStr = urlStr.substring(0, urlStr.length() - 1); - } - urlStr += getPathname(); - return new URL(urlStr); - } - catch (MalformedURLException e) { - // ignore - } + return getSharedFileURL(projectURL); } + Properties properties = + ProjectFileManager.readProjectProperties(projectLocation.getProjectDir()); + return getSharedFileURL(properties); } return null; } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/ProjectFileManager.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/ProjectFileManager.java index d19a74468c..0e43d51276 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/ProjectFileManager.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/ProjectFileManager.java @@ -49,10 +49,11 @@ public class ProjectFileManager implements ProjectData { private static final String TEST_REPOSITORY_PATH = System.getProperty("Repository"); - private static final String SERVER_NAME = "SERVER"; - private static final String PORT_NUMBER = "PORT_NUMBER"; - private static final String REPOSITORY_NAME = "REPOSITORY_NAME"; - private static final String OWNER = "OWNER"; + public static final String SERVER_NAME = "SERVER"; + public static final String PORT_NUMBER = "PORT_NUMBER"; + public static final String REPOSITORY_NAME = "REPOSITORY_NAME"; + public static final String OWNER = "OWNER"; + private static final String PROPERTY_FILENAME = "project"; private static final int USER_DATA_RECONCILE_DELAY_MS = 5 * 60 * 1000; // 5-minutes @@ -204,6 +205,38 @@ public class ProjectFileManager implements ProjectData { } } + /** + * Read the contents of the project properties file to include the following values if relavent: + * {@value #OWNER}, {@value #SERVER_NAME}, {@value #REPOSITORY_NAME}, {@value #PORT_NUMBER} + * @param projectDir project directory (*.rep) + * @return project properties or null if invalid project directory specified + */ + public static Properties readProjectProperties(File projectDir) { + try { + PropertyFile pf = + new PropertyFile(projectDir, PROPERTY_FILENAME, "/", PROPERTY_FILENAME); + if (pf.exists()) { + Properties properties = new Properties(); + + properties.setProperty(OWNER, pf.getString(OWNER, null)); + + String serverName = pf.getString(SERVER_NAME, null); + String repoName = pf.getString(REPOSITORY_NAME, null); + int port = pf.getInt(PORT_NUMBER, 0); + if (serverName != null && repoName != null) { + properties.setProperty(SERVER_NAME, serverName); + properties.setProperty(REPOSITORY_NAME, repoName); + properties.setProperty(PORT_NUMBER, Integer.toString(port)); + } + return properties; + } + } + catch (IOException e) { + // ignore + } + return null; + } + private void init(boolean create, boolean isInWritableProject) throws IOException, LockException { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FileDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FileDataTypeManager.java index 594973c4dd..fbf24a611e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FileDataTypeManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FileDataTypeManager.java @@ -22,8 +22,8 @@ import db.DBConstants; import generic.jar.ResourceFile; import ghidra.framework.store.db.PackedDBHandle; import ghidra.framework.store.db.PackedDatabase; -import ghidra.program.model.lang.CompilerSpec; -import ghidra.program.model.lang.Language; +import ghidra.program.model.lang.*; +import ghidra.program.util.DefaultLanguageService; import ghidra.util.InvalidNameException; import ghidra.util.UniversalID; import ghidra.util.exception.*; @@ -98,6 +98,54 @@ public class FileDataTypeManager extends StandAloneDataTypeManager } } + /** + * Create a new data-type file archive using the default data organization + * @param packedDbfile archive file (filename must end with DataTypeFileManager.SUFFIX) + * @return data-type manager backed by specified packedDbFile + * @throws IOException if an IO error occurs + */ + public static FileDataTypeManager createFileArchive(File packedDbfile, LanguageID languageId, + CompilerSpecID compilerSpecId) + throws LanguageNotFoundException, CompilerSpecNotFoundException, IOException { + try { + FileDataTypeManager dtm = + new FileDataTypeManager(new ResourceFile(packedDbfile), DBConstants.CREATE, + TaskMonitor.DUMMY); + + LanguageService languageService = DefaultLanguageService.getLanguageService(); + Language language = languageService.getLanguage(languageId); + CompilerSpec compilerSpec = language.getCompilerSpecByID(compilerSpecId); + + //dtm.setProgramArchitecture() + return dtm; + } + catch (CancelledException e) { + throw new AssertException(e); // unexpected without task monitor use + } + } + + /** + * Create a new data-type file archive using the default data organization + * @param packedDbfile archive file (filename must end with DataTypeFileManager.SUFFIX) + * @return data-type manager backed by specified packedDbFile + * @throws IOException if an IO error occurs + */ + public static FileDataTypeManager createFileArchive(File packedDbfile, String languageId, + String compilerSpecId) throws IOException { + try { + FileDataTypeManager dtm = + new FileDataTypeManager(new ResourceFile(packedDbfile), DBConstants.CREATE, + TaskMonitor.DUMMY); + + //dtm.setProgramArchitecture() + + return dtm; + } + catch (CancelledException e) { + throw new AssertException(e); // unexpected without task monitor use + } + } + /** * Open an existing data-type file archive using the default data organization. *