diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramSaveManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramSaveManager.java index 3d0d725487..f1a6e1a98d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramSaveManager.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramSaveManager.java @@ -79,22 +79,22 @@ class ProgramSaveManager { List saveList = new ArrayList<>(); List lockList = new ArrayList<>(); try { - for (int i = 0; i < programs.length; i++) { + for (Program program : programs) { // if (programs[i].isTemporary()) { // continue; // } - if (isOnlyToolConsumer(programs[i])) { - if (!acquireSaveLock(programs[i], "Close")) { + if (isOnlyToolConsumer(program)) { + if (!acquireSaveLock(program, "Close")) { return false; } - lockList.add(programs[i]); - saveList.add(programs[i]); + lockList.add(program); + saveList.add(program); } - else if (isAnalysisTool(programs[i])) { - if (!acquireSaveLock(programs[i], "Close")) { + else if (isAnalysisTool(program)) { + if (!acquireSaveLock(program, "Close")) { return false; } - lockList.add(programs[i]); + lockList.add(program); } } @@ -110,7 +110,7 @@ class ProgramSaveManager { } private boolean isOnlyToolConsumer(Program program) { - ArrayList consumers = program.getDomainFile().getConsumers(); + List consumers = program.getDomainFile().getConsumers(); for (Object consumer : consumers) { if ((consumer instanceof PluginTool) && consumer != tool) { return false; @@ -474,25 +474,15 @@ class ProgramSaveManager { return dataTreeSaveDialog; } - /** - * - */ class SaveFileTask extends Task { private DomainFile domainFile; - /** - * Construct new SaveFileTask. - * @param df domain file to save - */ SaveFileTask(DomainFile df) { super("Save Program", true, true, true); this.domainFile = df; } - /** - * @see ghidra.util.task.Task#run(TaskMonitor) - */ @Override public void run(TaskMonitor monitor) { monitor.setMessage("Saving Program..."); @@ -500,6 +490,7 @@ class ProgramSaveManager { domainFile.save(monitor); } catch (CancelledException e) { + // ignore } catch (NotConnectedException e) { ClientUtil.promptForReconnect(tool.getProject().getRepository(), @@ -525,7 +516,7 @@ class ProgramSaveManager { /** * Construct new SaveFileTask to do a "Save As" - * @param obj + * @param obj the object to save * @param folder new parent folder * @param newName name for domain object * @param doOverwrite true means the given name already exists and the user @@ -541,9 +532,6 @@ class ProgramSaveManager { this.doOverwrite = doOverwrite; } - /** - * @see ghidra.util.task.Task#run(TaskMonitor) - */ @Override public void run(TaskMonitor monitor) { monitor.setMessage("Saving Program..."); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/VersionControlDataTypeArchiveUndoCheckoutAction.java b/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/VersionControlDataTypeArchiveUndoCheckoutAction.java index 75fab28269..012820e7e9 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/VersionControlDataTypeArchiveUndoCheckoutAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/VersionControlDataTypeArchiveUndoCheckoutAction.java @@ -65,11 +65,12 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont undoCheckOut(); } - /** - * Returns true if at least one of the provided domain files is checked out from the repository. - */ @Override public boolean isEnabledForContext(DomainFileContext context) { + if (isFileSystemBusy()) { + return false; // don't block; we should get called again later + } + List domainFiles = context.getSelectedFiles(); for (DomainFile domainFile : domainFiles) { if (domainFile.isCheckedOut()) { @@ -91,8 +92,8 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont closeEditorsForUndoCheckOut(); List archiveList = archiveProvider.getArchives(); - List unmodifiedCheckOutsList = new ArrayList(); - List modifiedCheckOutsList = new ArrayList(); + List unmodifiedCheckOutsList = new ArrayList<>(); + List modifiedCheckOutsList = new ArrayList<>(); for (Archive archive2 : archiveList) { ProjectArchive archive = (ProjectArchive) archive2; DomainFile domainFile = archive.getDomainFile(); @@ -134,7 +135,7 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont * will be undone. * @param unmodifiedArchivesList the list of unmodified archives * @param modifiedArchivesList the list of archives that have been modified - * @throws CancelledException + * @throws CancelledException if canclled */ protected void undoCheckOuts(List unmodifiedArchivesList, List modifiedArchivesList) throws CancelledException { @@ -169,7 +170,7 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont private List getMatchingArchives(List archivesList, DomainFile[] selectedFiles) { List archiveList = - new ArrayList(selectedFiles.length); + new ArrayList<>(selectedFiles.length); for (DomainFile domainFile : selectedFiles) { DomainFileArchive archive = getArchiveForDomainFile(archivesList, domainFile); if (archive != null) { @@ -195,7 +196,7 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont } private List getDomainFileList(List modifiedArchivesList) { - List dfList = new ArrayList(modifiedArchivesList.size()); + List dfList = new ArrayList<>(modifiedArchivesList.size()); for (DomainFileArchive dfArchive : modifiedArchivesList) { dfList.add(dfArchive.getDomainFile()); } @@ -205,6 +206,7 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont /** * Saves all checked out changes. * @param changedList the list of changes + * @throws CancelledException if cancelled */ protected void saveCheckOutChanges(List changedList) throws CancelledException { if (changedList.size() > 0) { diff --git a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/FileSystemListenerList.java b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/FileSystemListenerList.java index b493812ae0..16b3c4f24e 100644 --- a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/FileSystemListenerList.java +++ b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/FileSystemListenerList.java @@ -55,7 +55,7 @@ public class FileSystemListenerList implements FileSystemListener { /** * Add a listener to this list. - * @param listener + * @param listener the listener */ public synchronized void add(FileSystemListener listener) { listenerList.add(listener); @@ -68,7 +68,7 @@ public class FileSystemListenerList implements FileSystemListener { /** * Remove a listener from this list. - * @param listener + * @param listener the listener */ public void remove(FileSystemListener listener) { listenerList.remove(listener); @@ -81,10 +81,6 @@ public class FileSystemListenerList implements FileSystemListener { listenerList.clear(); } - /** - * Forwards itemMoved callback to all listeners within this list. - * @see ghidra.framework.store.FileSystemListener#itemMoved(String, String, String, String) - */ @Override public void itemMoved(String parentPath, String name, String newParentPath, String newName) { if (enableAsynchronousDispatching) { @@ -97,10 +93,6 @@ public class FileSystemListenerList implements FileSystemListener { } } - /** - * Forwards itemRenamed callback to all listeners within this list. - * @see ghidra.framework.store.FileSystemListener#itemRenamed(String, String, String) - */ @Override public void itemRenamed(String parentPath, String itemName, String newName) { if (enableAsynchronousDispatching) { @@ -113,10 +105,6 @@ public class FileSystemListenerList implements FileSystemListener { } } - /** - * Forwards itemDeleted callback to all listeners within this list. - * @see ghidra.framework.store.FileSystemListener#itemDeleted(String, String) - */ @Override public void itemDeleted(String parentPath, String itemName) { if (enableAsynchronousDispatching) { @@ -129,10 +117,6 @@ public class FileSystemListenerList implements FileSystemListener { } } - /** - * Forwards folderRenamed callback to all listeners within this list. - * @see ghidra.framework.store.FileSystemListener#folderRenamed(String, String, String) - */ @Override public void folderRenamed(String parentPath, String folderName, String newFolderName) { if (enableAsynchronousDispatching) { @@ -145,10 +129,6 @@ public class FileSystemListenerList implements FileSystemListener { } } - /** - * Forwards folderMoved callback to all listeners within this list. - * @see ghidra.framework.store.FileSystemListener#folderMoved(String, String, String) - */ @Override public void folderMoved(String parentPath, String folderName, String newParentPath) { if (enableAsynchronousDispatching) { @@ -161,10 +141,6 @@ public class FileSystemListenerList implements FileSystemListener { } } - /** - * Forwards folderDeleted callback to all listeners within this list. - * @see ghidra.framework.store.FileSystemListener#folderDeleted(String, String) - */ @Override public void folderDeleted(String parentPath, String folderName) { if (enableAsynchronousDispatching) { @@ -177,10 +153,6 @@ public class FileSystemListenerList implements FileSystemListener { } } - /** - * Forwards itemCreated callback to all listeners within this list. - * @see ghidra.framework.store.FileSystemListener#itemCreated(String, String) - */ @Override public void itemCreated(String parentPath, String itemName) { if (enableAsynchronousDispatching) { @@ -193,10 +165,6 @@ public class FileSystemListenerList implements FileSystemListener { } } - /** - * Forwards folderCreated callback to all listeners within this list. - * @see ghidra.framework.store.FileSystemListener#folderCreated(String, String) - */ @Override public void folderCreated(String parentPath, String folderName) { if (enableAsynchronousDispatching) { @@ -209,10 +177,6 @@ public class FileSystemListenerList implements FileSystemListener { } } - /** - * Forwards itemChanged callback to all listeners within this list. - * @see ghidra.framework.store.FileSystemListener#itemChanged(String, String) - */ @Override public void itemChanged(String parentPath, String itemName) { if (enableAsynchronousDispatching) { @@ -225,10 +189,6 @@ public class FileSystemListenerList implements FileSystemListener { } } - /** - * Forwards syncronize callback to all listeners within this list. - * @see ghidra.framework.store.FileSystemListener#syncronize() - */ @Override public void syncronize() { if (enableAsynchronousDispatching) { @@ -303,6 +263,7 @@ public class FileSystemListenerList implements FileSystemListener { } } catch (InterruptedException e) { + // not sure why we are ignoring this } finally { isEventProcessingThreadWaiting = false; diff --git a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/FileSystemSynchronizer.java b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/FileSystemSynchronizer.java new file mode 100644 index 0000000000..8662ab8bf4 --- /dev/null +++ b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/FileSystemSynchronizer.java @@ -0,0 +1,47 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.framework.store; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * This class is essentially a global flag used to track the long running file system synchronizing + * operation. This class is a workaround to avoid rewriting the complicated file system locking. + */ +public class FileSystemSynchronizer { + + private static AtomicBoolean isSynchronizing = new AtomicBoolean(); + + /** + * Sets whether the synchronizing operation is running. + * @param b true if synchronizing + */ + public static void setSynchronizing(boolean b) { + isSynchronizing.set(b); + } + + /** + * Returns true the underlying file system is going through a long-running synchronization + * operation while holding the {@code filesystem} lock. Calling this method allows clients + * in the Swing thread to avoid calling methods that require a file system lock, which would + * cause the UI to lock during the synchronizing operation. + * + * @return true if synchronizing + */ + public static boolean isSynchronizing() { + return isSynchronizing.get(); + } +} diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/DomainFolderChangeListenerList.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/DomainFolderChangeListenerList.java index 72de8a0456..af523cc8be 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/DomainFolderChangeListenerList.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/DomainFolderChangeListenerList.java @@ -19,7 +19,7 @@ import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import ghidra.framework.model.*; -import ghidra.util.SystemUtilities; +import ghidra.util.Swing; class DomainFolderChangeListenerList implements DomainFolderChangeListener { @@ -47,7 +47,7 @@ class DomainFolderChangeListenerList implements DomainFolderChangeListener { if (list.isEmpty()) { return; } - SystemUtilities.runSwingLater(() -> { + Swing.runLater(() -> { for (DomainFolderChangeListener listener : list) { listener.domainFolderAdded(folder); } @@ -60,7 +60,7 @@ class DomainFolderChangeListenerList implements DomainFolderChangeListener { if (list.isEmpty()) { return; } - SystemUtilities.runSwingLater(() -> { + Swing.runLater(() -> { for (DomainFolderChangeListener listener : list) { listener.domainFileAdded(file); } @@ -73,7 +73,7 @@ class DomainFolderChangeListenerList implements DomainFolderChangeListener { if (list.isEmpty()) { return; } - SystemUtilities.runSwingLater(() -> { + Swing.runLater(() -> { for (DomainFolderChangeListener listener : list) { listener.domainFolderRemoved(parent, name); } @@ -87,7 +87,7 @@ class DomainFolderChangeListenerList implements DomainFolderChangeListener { if (list.isEmpty()) { return; } - SystemUtilities.runSwingLater(() -> { + Swing.runLater(() -> { for (DomainFolderChangeListener listener : list) { listener.domainFileRemoved(parent, name, fileID); } @@ -100,7 +100,7 @@ class DomainFolderChangeListenerList implements DomainFolderChangeListener { if (list.isEmpty()) { return; } - SystemUtilities.runSwingLater(() -> { + Swing.runLater(() -> { for (DomainFolderChangeListener listener : list) { listener.domainFolderRenamed(folder, oldName); } @@ -113,7 +113,7 @@ class DomainFolderChangeListenerList implements DomainFolderChangeListener { if (list.isEmpty()) { return; } - SystemUtilities.runSwingLater(() -> { + Swing.runLater(() -> { for (DomainFolderChangeListener listener : list) { listener.domainFileRenamed(file, oldName); } @@ -126,7 +126,7 @@ class DomainFolderChangeListenerList implements DomainFolderChangeListener { if (list.isEmpty()) { return; } - SystemUtilities.runSwingLater(() -> { + Swing.runLater(() -> { for (DomainFolderChangeListener listener : list) { listener.domainFolderMoved(folder, oldParent); } @@ -140,7 +140,7 @@ class DomainFolderChangeListenerList implements DomainFolderChangeListener { if (list.isEmpty()) { return; } - SystemUtilities.runSwingLater(() -> { + Swing.runLater(() -> { for (DomainFolderChangeListener listener : list) { listener.domainFileMoved(file, oldParent, oldName); } @@ -153,7 +153,7 @@ class DomainFolderChangeListenerList implements DomainFolderChangeListener { if (list.isEmpty()) { return; } - SystemUtilities.runSwingLater(() -> { + Swing.runLater(() -> { for (DomainFolderChangeListener listener : list) { listener.domainFolderSetActive(folder); } @@ -166,7 +166,7 @@ class DomainFolderChangeListenerList implements DomainFolderChangeListener { if (list.isEmpty()) { return; } - SystemUtilities.runSwingLater(() -> { + Swing.runLater(() -> { for (DomainFolderChangeListener listener : list) { listener.domainFileStatusChanged(file, fileIDset); } @@ -179,7 +179,7 @@ class DomainFolderChangeListenerList implements DomainFolderChangeListener { if (list.isEmpty()) { return; } - SystemUtilities.runSwingLater(() -> { + Swing.runLater(() -> { for (DomainFolderChangeListener listener : list) { listener.domainFileObjectOpenedForUpdate(file, object); } @@ -192,7 +192,7 @@ class DomainFolderChangeListenerList implements DomainFolderChangeListener { if (list.isEmpty()) { return; } - SystemUtilities.runSwingLater(() -> { + Swing.runLater(() -> { for (DomainFolderChangeListener listener : list) { listener.domainFileObjectClosed(file, object); } @@ -205,12 +205,11 @@ class DomainFolderChangeListenerList implements DomainFolderChangeListener { if (list.isEmpty()) { return; } - Runnable r = () -> { + Swing.runNow(() -> { for (DomainFolderChangeListener listener : list) { listener.domainFileObjectReplaced(file, oldObject); } - }; - SystemUtilities.runSwingNow(r); + }); } public void clearAll() { diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/GhidraFile.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/GhidraFile.java index e92a6e0af8..b725654e54 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/GhidraFile.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/GhidraFile.java @@ -512,7 +512,7 @@ public class GhidraFile implements DomainFile { public ArrayList getConsumers() { DomainObjectAdapter dobj = fileManager.getOpenedDomainObject(getPathname()); if (dobj == null) { - return new ArrayList(); + return new ArrayList<>(); } return dobj.getConsumerList(); } @@ -554,7 +554,7 @@ public class GhidraFile implements DomainFile { catch (IOException e) { fileError(e); } - return new HashMap(); + return new HashMap<>(); } void fileChanged() { diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/GhidraFolder.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/GhidraFolder.java index 8006a30ba1..12986ee1e3 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/GhidraFolder.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/GhidraFolder.java @@ -85,7 +85,8 @@ public class GhidraFolder implements DomainFolder { GhidraFolderData getFolderPathData(String folderPath) throws FileNotFoundException { GhidraFolderData parentData = (folderPath.startsWith(FileSystem.SEPARATOR)) - ? fileManager.getRootFolderData() : getFolderData(); + ? fileManager.getRootFolderData() + : getFolderData(); GhidraFolderData folderData = parentData.getFolderPathData(folderPath, false); if (folderData == null) { String path = (folderPath.startsWith(FileSystem.SEPARATOR)) ? folderPath 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 8ba125c7ea..970dc83ca8 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 @@ -24,16 +24,14 @@ import ghidra.framework.client.*; import ghidra.framework.model.*; import ghidra.framework.protocol.ghidra.GhidraURL; import ghidra.framework.remote.User; +import ghidra.framework.store.*; import ghidra.framework.store.FileSystem; -import ghidra.framework.store.FileSystemListener; -import ghidra.framework.store.FolderItem; import ghidra.framework.store.local.LocalFileSystem; import ghidra.framework.store.remote.RemoteFileSystem; import ghidra.util.*; import ghidra.util.exception.CancelledException; import ghidra.util.exception.DuplicateFileException; -import ghidra.util.task.TaskMonitor; -import ghidra.util.task.TaskMonitorAdapter; +import ghidra.util.task.*; import utilities.util.FileUtilities; /** @@ -143,9 +141,6 @@ public class ProjectFileManager implements ProjectData { } } - /** - * Constructor used for testing - */ ProjectFileManager(LocalFileSystem fileSystem, FileSystem versionedFileSystem) { this.localStorageLocator = new ProjectLocator(null, "Test"); owner = SystemUtilities.getUserName(); @@ -208,9 +203,6 @@ public class ProjectFileManager implements ProjectData { fileSystem.testValidName(name, isPath); } - /** - * @see ghidra.framework.model.ProjectData#getUser() - */ @Override public User getUser() { if (repository != null) { @@ -386,17 +378,11 @@ public class ProjectFileManager implements ProjectData { return owner; } - /** - * @see ghidra.framework.model.ProjectData#getRootFolder() - */ @Override public GhidraFolder getRootFolder() { return rootFolderData.getDomainFolder(); } - /** - * @see ghidra.framework.model.ProjectData#getFolder(java.lang.String) - */ @Override public DomainFolder getFolder(String path) { int len = path.length(); @@ -429,9 +415,8 @@ public class ProjectFileManager implements ProjectData { } } - // NOTE: we can't distinguish between files represented - // in both file counts so we will return the larger of - // the two counts obtained. + // NOTE: we can't distinguish between files represented in both file counts so we will + // return the larger of the two counts obtained. int privateFileCnt = -1; try { @@ -452,9 +437,6 @@ public class ProjectFileManager implements ProjectData { return Math.max(sharedFileCnt, privateFileCnt); } - /** - * @see ghidra.framework.model.ProjectData#getFile(java.lang.String) - */ @Override public DomainFile getFile(String path) { int len = path.length(); @@ -480,17 +462,11 @@ public class ProjectFileManager implements ProjectData { return null; } - /** - * @see ghidra.framework.model.ProjectData#getFileByID(java.lang.String) - */ @Override public DomainFile getFileByID(String fileID) { return fileIndex.getFileByID(fileID); } - /** - * @see ghidra.framework.model.ProjectData#getSharedFileURL(java.lang.String) - */ @Override public URL getSharedFileURL(String path) { if (repository != null) { @@ -504,10 +480,6 @@ public class ProjectFileManager implements ProjectData { return null; } - /** - * Releases all domain files for the specified consumer. - * @param consumer the domain object consumer - */ public void releaseDomainFiles(Object consumer) { for (DomainObjectAdapter domainObj : openDomainObjects.values()) { try { @@ -522,8 +494,7 @@ public class ProjectFileManager implements ProjectData { } /** - * Finds all changed domain files and appends - * them to the specified list. + * Finds all changed domain files and appends them to the specified list. * @param list the list to receive the changed domain files */ @Override @@ -533,52 +504,30 @@ public class ProjectFileManager implements ProjectData { } } - /** - * @see ghidra.framework.model.ProjectData#getProjectLocator() - */ @Override public ProjectLocator getProjectLocator() { return localStorageLocator; } - /** - * @see ghidra.framework.model.ProjectData#addDomainFolderChangeListener( - * ghidra.framework.model.DomainFolderChangeListener) - */ @Override public void addDomainFolderChangeListener(DomainFolderChangeListener l) { listenerList.addListener(l); } - /** - * @see ghidra.framework.model.ProjectData#removeDomainFolderChangeListener( - * ghidra.framework.model.DomainFolderChangeListener) - */ @Override public void removeDomainFolderChangeListener(DomainFolderChangeListener l) { listenerList.removeListener(l); } - /** - * Returns the private files system associated with this project file manager. - * @return the private files system associated with this project file manager - */ public FileSystem getPrivateFileSystem() { return fileSystem; } - /** - * Returns the repository associated with this project file manager. - * @return the repository associated with this project file manager - */ @Override public RepositoryAdapter getRepository() { return repository; } - /** - * @see ghidra.framework.model.ProjectData#refresh(boolean) - */ @Override public void refresh(boolean force) throws IOException { try { @@ -589,12 +538,6 @@ public class ProjectFileManager implements ProjectData { } } - /* - * (non-Javadoc) - * @see ghidra.framework.model.ProjectData#convertProjectToShared( - * ghidra.framework.client.RepositoryAdapter, - * ghidra.util.task.TaskMonitor) - */ @Override public void convertProjectToShared(RepositoryAdapter newRepository, TaskMonitor monitor) throws IOException, CancelledException { @@ -607,7 +550,7 @@ public class ProjectFileManager implements ProjectData { throw new IllegalStateException("Only private project may be converted to shared"); } - // 1) Convert versioned files (inclulding checked-out files) to private files + // 1) Convert versioned files (including checked-out files) to private files convertFilesToPrivate(getRootFolder(), monitor); // 2) Update the properties with server info @@ -621,12 +564,6 @@ public class ProjectFileManager implements ProjectData { FileUtilities.deleteDir(versionedFileSystemDir); } - /* - * (non-Javadoc) - * @see ghidra.framework.model.ProjectData#updateRepositoryInfo( - * ghidra.framework.client.RepositoryAdapter, - * ghidra.util.task.TaskMonitor) - */ @Override public void updateRepositoryInfo(RepositoryAdapter newRepository, TaskMonitor monitor) throws IOException, CancelledException { @@ -641,20 +578,20 @@ public class ProjectFileManager implements ProjectData { throws IOException, CancelledException { DomainFile[] files = folder.getFiles(); - for (int i = 0; i < files.length; i++) { + for (DomainFile file : files) { if (monitor.isCancelled()) { throw new CancelledException(); } - if (files[i].isCheckedOut()) { - throw new IOException("File " + files[i].getPathname() + " is checked out."); + if (file.isCheckedOut()) { + throw new IOException("File " + file.getPathname() + " is checked out."); } } DomainFolder[] folders = folder.getFolders(); - for (int i = 0; i < folders.length; i++) { + for (DomainFolder folder2 : folders) { if (monitor.isCancelled()) { throw new CancelledException(); } - findCheckedOutFiles(folders[i], monitor); + findCheckedOutFiles(folder2, monitor); } } @@ -662,12 +599,12 @@ public class ProjectFileManager implements ProjectData { throws IOException, CancelledException { DomainFile[] files = folder.getFiles(); - for (int i = 0; i < files.length; i++) { - ((GhidraFile) files[i]).convertToPrivateFile(monitor); + for (DomainFile file : files) { + ((GhidraFile) file).convertToPrivateFile(monitor); } DomainFolder[] folders = folder.getFolders(); - for (int i = 0; i < folders.length; i++) { - convertFilesToPrivate(folders[i], monitor); + for (DomainFolder folder2 : folders) { + convertFilesToPrivate(folder2, monitor); } } @@ -902,12 +839,32 @@ public class ProjectFileManager implements ProjectData { @Override public void syncronize() { + + if (SystemUtilities.isInHeadlessMode()) { + doSynchronize(); + return; + } + + try { + + FileSystemSynchronizer.setSynchronizing(true); + + // This operation can hold a lock for a long period. Block with a modal dialog to + // prevent UI live lock situations. + TaskLauncher.launchModal("Synchronizing Filesystem", this::doSynchronize); + } + finally { + FileSystemSynchronizer.setSynchronizing(false); + } + } + + private void doSynchronize() { try { rootFolderData.refresh(true, true, projectDisposalMonitor); scheduleUserDataReconcilation(); } catch (Exception e) { - // ignore + Msg.trace(this, "Exception synchronizing filesystem", e); } } } @@ -929,9 +886,6 @@ public class ProjectFileManager implements ProjectData { return buf.length() == 0 ? "unknown" : buf.toString(); } - /** - * Return the project directory. - */ public File getProjectDir() { return projectDir; } @@ -941,9 +895,6 @@ public class ProjectFileManager implements ProjectData { dispose(); } - /** - * Disposes this project file manager. - */ public void dispose() { synchronized (this) { @@ -978,12 +929,11 @@ public class ProjectFileManager implements ProjectData { /** * Set the open domain object (opened for update) associated with a file. - * NOTE: Caller is responsible for setting domain file on domain object after - * invoking this method. - * If a domain object saveAs was done, the previous file association + * NOTE: Caller is responsible for setting domain file on domain object after invoking this + * method. If a domain object saveAs was done, the previous file association * will be removed. - * @param pathname - * @param doa + * @param pathname the path name + * @param doa the domain object */ synchronized void setDomainObject(String pathname, DomainObjectAdapter doa) { if (openDomainObjects.containsKey(pathname)) { @@ -998,7 +948,8 @@ public class ProjectFileManager implements ProjectData { /** * Returns the open domain object (opened for update) for the specified path. - * @param pathname + * @param pathname the path name + * @return the domain object */ synchronized DomainObjectAdapter getOpenedDomainObject(String pathname) { return openDomainObjects.get(pathname); @@ -1006,7 +957,7 @@ public class ProjectFileManager implements ProjectData { /** * Clears the previously open domain object which has been closed. - * @param pathname + * @param pathname the path name * @return true if previously open domain file was cleared, else false */ synchronized boolean clearDomainObject(String pathname) { @@ -1028,7 +979,7 @@ public class ProjectFileManager implements ProjectData { /** * Remove specified fileID from index. - * @param fileID + * @param fileID the file ID */ public void removeFromIndex(String fileID) { fileIndex.removeFileEntry(fileID); @@ -1041,5 +992,4 @@ public class ProjectFileManager implements ProjectData { public TaskMonitor getProjectDisposalMonitor() { return projectDisposalMonitor; } - } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlAction.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlAction.java index 38e51ffa24..18e33d51e8 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlAction.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlAction.java @@ -22,8 +22,10 @@ import docking.widgets.OptionDialog; import ghidra.framework.client.*; import ghidra.framework.main.datatable.DomainFileContext; import ghidra.framework.main.datatable.DomainFileProviderContextAction; -import ghidra.framework.model.*; +import ghidra.framework.model.DomainFile; +import ghidra.framework.model.Project; import ghidra.framework.plugintool.PluginTool; +import ghidra.framework.store.FileSystemSynchronizer; import ghidra.util.HelpLocation; /** @@ -80,6 +82,14 @@ public abstract class VersionControlAction extends DomainFileProviderContextActi } } + /** + * True if the file system is locked by another thread for a long running operation + * @return true if locked + */ + protected boolean isFileSystemBusy() { + return FileSystemSynchronizer.isSynchronizing(); + } + /** * NOTE: do not call this from a non-Swing thread. * @return true if the repository is null or is connected. diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlAddAction.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlAddAction.java index ca89957324..363e8a6675 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlAddAction.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlAddAction.java @@ -57,11 +57,12 @@ public class VersionControlAddAction extends VersionControlAction { addToVersionControl(context.getSelectedFiles()); } - /** - * Returns true if at least one of the provided domain files can be added to the repository. - */ @Override public boolean isEnabledForContext(DomainFileContext context) { + if (isFileSystemBusy()) { + return false; // don't block; we should get called again later + } + List domainFiles = context.getSelectedFiles(); for (DomainFile domainFile : domainFiles) { if (domainFile.canAddToRepository()) { @@ -71,11 +72,6 @@ public class VersionControlAddAction extends VersionControlAction { return false; } - /** - * Adds all the non-version controlled domain files to the repository from the - * list of files from the DomainFileProvider. - * @param domainFiles - */ private void addToVersionControl(List domainFiles) { if (!checkRepositoryConnected()) { diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlCheckInAction.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlCheckInAction.java index dfaaf11bc0..6f19d215ea 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlCheckInAction.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlCheckInAction.java @@ -61,12 +61,12 @@ public class VersionControlCheckInAction extends VersionControlAction { doCheckIn(context.getSelectedFiles()); } - /** - * Returns true if at least one of the provided domain files can have its changes - * checked into the repository. - */ @Override public boolean isEnabledForContext(DomainFileContext context) { + if (isFileSystemBusy()) { + return false; // don't block; we should get called again later + } + List domainFiles = context.getSelectedFiles(); for (DomainFile domainFile : domainFiles) { if (domainFile.isCheckedOut() && domainFile.modifiedSinceCheckout()) { @@ -83,7 +83,7 @@ public class VersionControlCheckInAction extends VersionControlAction { if (!checkRepositoryConnected()) { return; } - List checkedOut = new ArrayList(); + List checkedOut = new ArrayList<>(); for (DomainFile domainFile : domainFiles) { if (domainFile.isCheckedOut() && domainFile.modifiedSinceCheckout()) { checkedOut.add(domainFile); @@ -112,8 +112,8 @@ public class VersionControlCheckInAction extends VersionControlAction { return; } - ArrayList changedList = new ArrayList(); - ArrayList list = new ArrayList(); + ArrayList changedList = new ArrayList<>(); + ArrayList list = new ArrayList<>(); for (int i = 0; i < fileList.size(); i++) { DomainFile df = fileList.get(i); if (df != null && df.canCheckin()) { diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlCheckOutAction.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlCheckOutAction.java index 87208e4e4d..e031fc1271 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlCheckOutAction.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlCheckOutAction.java @@ -64,12 +64,12 @@ public class VersionControlCheckOutAction extends VersionControlAction { checkOut(context.getSelectedFiles()); } - /** - * Returns true if at least one of the provided domain files can can be - * checked out of the repository. - */ @Override public boolean isEnabledForContext(DomainFileContext context) { + if (isFileSystemBusy()) { + return false; // don't block; we should get called again later + } + List providedList = context.getSelectedFiles(); for (DomainFile domainFile : providedList) { if (domainFile.canCheckout()) { diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlShowHistoryAction.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlShowHistoryAction.java index eba78f6a47..2388189792 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlShowHistoryAction.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlShowHistoryAction.java @@ -48,15 +48,16 @@ public class VersionControlShowHistoryAction extends VersionControlAction { showHistory(context.getSelectedFiles()); } - /** - * Returns true if a single version controlled domain file is being provided. - */ @Override public boolean isEnabledForContext(DomainFileContext context) { List domainFiles = context.getSelectedFiles(); if (domainFiles.size() != 1) { return false; } + if (isFileSystemBusy()) { + return false; // don't block; we should get called again later + } + DomainFile domainFile = domainFiles.get(0); return domainFile.isVersioned(); } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlUndoCheckOutAction.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlUndoCheckOutAction.java index c5bc1c76ef..84a411a5da 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlUndoCheckOutAction.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlUndoCheckOutAction.java @@ -61,11 +61,12 @@ public class VersionControlUndoCheckOutAction extends VersionControlAction { undoCheckOut(context.getSelectedFiles()); } - /** - * Returns true if at least one of the provided domain files is checked out from the repository. - */ @Override public boolean isEnabledForContext(DomainFileContext context) { + if (isFileSystemBusy()) { + return false; // don't block; we should get called again later + } + List domainFiles = context.getSelectedFiles(); for (DomainFile domainFile : domainFiles) { if (domainFile.isCheckedOut()) { @@ -83,8 +84,8 @@ public class VersionControlUndoCheckOutAction extends VersionControlAction { if (!checkRepositoryConnected()) { return; } - List unmodifiedCheckOutsList = new ArrayList(); - List modifiedCheckOutsList = new ArrayList(); + List unmodifiedCheckOutsList = new ArrayList<>(); + List modifiedCheckOutsList = new ArrayList<>(); for (DomainFile domainFile : domainFiles) { if (domainFile.isCheckedOut()) { if (domainFile.modifiedSinceCheckout()) { @@ -145,10 +146,9 @@ public class VersionControlUndoCheckOutAction extends VersionControlAction { /** * Creates a task for undoing checkouts of domain files. * @param unmodifiedCheckOutsList the list of unmodified checked out files - * @param modifiedCheckOutsList the list of checked out files that have been modified + * @param modifiedCheckedOutFiles the list of checked out files that have been modified * @param saveCopy true indicates that copies of the modified files should be made - * before undo of the checkout. - * @param listener the task listener to call when the task completes or is cancelled. + * before undo of the checkout */ UndoCheckOutTask(List unmodifiedCheckOutsList, DomainFile[] modifiedCheckedOutFiles, boolean saveCopy) { @@ -158,9 +158,6 @@ public class VersionControlUndoCheckOutAction extends VersionControlAction { this.saveCopy = saveCopy; } - /* (non-Javadoc) - * @see ghidra.util.task.Task#run(ghidra.util.task.TaskMonitor) - */ @Override public void run(TaskMonitor monitor) { try { diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlUndoHijackAction.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlUndoHijackAction.java index 61315c1ff8..c356876f12 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlUndoHijackAction.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlUndoHijackAction.java @@ -55,11 +55,12 @@ public class VersionControlUndoHijackAction extends VersionControlAction { undoHijackedFiles(context.getSelectedFiles()); } - /** - * Returns true if at least one of the provided domain files is hijacked. - */ @Override public boolean isEnabledForContext(DomainFileContext context) { + if (isFileSystemBusy()) { + return false; // don't block; we should get called again later + } + List domainFiles = context.getSelectedFiles(); for (DomainFile domainFile : domainFiles) { if (domainFile.isHijacked()) { @@ -77,7 +78,7 @@ public class VersionControlUndoHijackAction extends VersionControlAction { return; } - List hijackList = new ArrayList(); + List hijackList = new ArrayList<>(); for (DomainFile domainFile : domainFiles) { if (domainFile != null && domainFile.isHijacked()) { hijackList.add(domainFile); @@ -143,8 +144,7 @@ public class VersionControlUndoHijackAction extends VersionControlAction { * Creates a task for undoing hijacks of domain files. * @param hijackFiles the list of hijacked files * @param saveCopy true indicates that copies of the modified files should be made - * before undo of the checkout. - * @param listener the task listener to call when the task completes or is cancelled. + * before undo of the checkout */ UndoHijackTask(DomainFile[] hijackFiles, boolean saveCopy) { super("Undo Hijack", true, true, true); @@ -152,9 +152,6 @@ public class VersionControlUndoHijackAction extends VersionControlAction { this.saveCopy = saveCopy; } - /* (non-Javadoc) - * @see ghidra.util.task.Task#run(ghidra.util.task.TaskMonitor) - */ @Override public void run(TaskMonitor monitor) { try { diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlUpdateAction.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlUpdateAction.java index aec72cb460..5ff1b71427 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlUpdateAction.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlUpdateAction.java @@ -59,11 +59,12 @@ public class VersionControlUpdateAction extends VersionControlAction { update(context.getSelectedFiles()); } - /** - * Returns true if at least one checked out file has a newer version in the repository. - */ @Override public boolean isEnabledForContext(DomainFileContext context) { + if (isFileSystemBusy()) { + return false; // don't block; we should get called again later + } + List providedList = context.getSelectedFiles(); for (DomainFile domainFile : providedList) { if (domainFile.isVersioned() && @@ -83,7 +84,7 @@ public class VersionControlUpdateAction extends VersionControlAction { return; } - List updateList = new ArrayList(); + List updateList = new ArrayList<>(); for (DomainFile domainFile : domainFiles) { if (domainFile != null && domainFile.canMerge()) { if (!canCloseDomainFile(domainFile)) { diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlViewCheckOutAction.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlViewCheckOutAction.java index 6bc9b4352a..38549f0d66 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlViewCheckOutAction.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/VersionControlViewCheckOutAction.java @@ -50,15 +50,16 @@ public class VersionControlViewCheckOutAction extends VersionControlAction { viewCheckouts(context.getSelectedFiles()); } - /** - * Returns true if a single version controlled domain file is being provided. - */ @Override public boolean isEnabledForContext(DomainFileContext context) { List domainFiles = context.getSelectedFiles(); if (domainFiles.size() != 1) { return false; } + if (isFileSystemBusy()) { + return false; // don't block; we should get called again later + } + DomainFile domainFile = domainFiles.get(0); return domainFile.isVersioned(); } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/model/DomainFile.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/model/DomainFile.java index 2e022d81fd..abaa0af46e 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/model/DomainFile.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/model/DomainFile.java @@ -16,7 +16,7 @@ package ghidra.framework.model; import java.io.*; -import java.util.ArrayList; +import java.util.List; import java.util.Map; import javax.swing.Icon; @@ -28,10 +28,10 @@ import ghidra.util.exception.*; import ghidra.util.task.TaskMonitor; /** - * DomainFile provides a storage interface for project - * files. A DomainFile is an immutable reference to - * a file contained within a project. The state of a DomainFile - * object does not track name/parent changes made to the referenced project file. + * DomainFile provides a storage interface for project files. A + * DomainFile is an immutable reference to file contained within a project. The state + * of a DomainFile object does not track name/parent changes made to the referenced + * project file. */ public interface DomainFile extends Comparable { @@ -48,8 +48,8 @@ public interface DomainFile extends Comparable { public final static String READ_ONLY_PROPERTY = "READ_ONLY"; /** - * Get the name of the StoredObj that is associated with - * the data. + * Get the name of the StoredObj that is associated with the data. + * @return the name */ public String getName(); @@ -61,7 +61,7 @@ public interface DomainFile extends Comparable { /** * Returns a unique file-ID - * @return + * @return the ID */ public String getFileID(); @@ -79,27 +79,31 @@ public interface DomainFile extends Comparable { /** * Returns the path name to the domain object. + * @return the path name */ public String getPathname(); /** * Returns the local storage location for the project that this DomainFile belongs to. + * @return the location */ public ProjectLocator getProjectLocator(); /** * Returns content-type string + * @return the content type */ public String getContentType(); /** - * Returns the underlying Class for the domain object in this - * domain file. + * Returns the underlying Class for the domain object in this domain file. + * @return the class */ public Class getDomainObjectClass(); /** * Get the parent domain folder for this domain file. + * @return the parent */ public DomainFolder getParent(); @@ -210,21 +214,23 @@ public interface DomainFile extends Comparable { public boolean canRecover(); /** - * If the file has an updateable domain object with unsaved changes, generate a - * recovery snapshot. - * @return true if snapshot successful or not needed, false if file is busy - * which prevents snapshot, or snapshot was cancelled. - * @throws IOException + * If the file has an updatable domain object with unsaved changes, generate a recovery + * snapshot. + * @return true if snapshot successful or not needed, false if file is busy which prevents + * snapshot, or snapshot was cancelled. + * @throws IOException if there is an exception saving the snapshot */ public boolean takeRecoverySnapshot() throws IOException; /** * Returns true if this file is in a writable project. + * @return true if writable */ public boolean isInWritableProject(); /** * Get a long value representing the time when the data was last modified. + * @return the time */ public long getLastModifiedTime(); @@ -238,39 +244,44 @@ public interface DomainFile extends Comparable { /** * Returns true if this is a checked-out file. + * @return true if checked-out */ public boolean isCheckedOut(); /** * Returns true if this a checked-out file with exclusive access. + * @return true if checked-out exclusively */ public boolean isCheckedOutExclusive(); /** - * Returns true if this is a checked-out file which has been modified - * since it was checked-out. + * Returns true if this is a checked-out file which has been modified since it was checked-out. + * @return true if modified since check-out */ public boolean modifiedSinceCheckout(); /** * Returns true if this file may be checked-out from the associated repository. * User's with read-only repository access will not have checkout ability. + * @return true if can checkout */ public boolean canCheckout(); /** * Returns true if this file may be checked-in to the associated repository. + * @return true if can check-in */ public boolean canCheckin(); /** * Returns true if this file can be merged with the current versioned file. + * @return true if can merge */ public boolean canMerge(); /** - * Returns true if this private file may be added to the - * associated repository. + * Returns true if this private file may be added to the associated repository. + * @return true if can add to the repository */ public boolean canAddToRepository(); @@ -284,47 +295,53 @@ public interface DomainFile extends Comparable { public void setReadOnly(boolean state) throws IOException; /** - * Returns whether the object is read-only. From a - * framework point of view a read-only object can never be - * changed. + * Returns whether the object is read-only. From a framework point of view a read-only object + * can never be changed. + * @return true if read-only */ public boolean isReadOnly(); /** - * Returns true if the versioned filesystem can be used to store - * this files content type. + * Returns true if the versioned filesystem can be used to store this files content type. + * @return true if supports version control */ public boolean isVersionControlSupported(); /** * Return true if this is a versioned database, else false + * @return true if versioned */ public boolean isVersioned(); /** * Returns true if the file is versioned but a private copy also exists. + * @return true if hijacked */ public boolean isHijacked(); /** * Return the latest version + * @return the version */ public int getLatestVersion(); /** - * Returns true if this file represents the latest version of the - * associated domain object. + * Returns true if this file represents the latest version of the associated domain object. + * @return true if the latest version */ public boolean isLatestVersion(); /** * Return either the latest version if the file is not checked-out or the version that * was checked-out or a specific version that was requested. + * @return the version */ public int getVersion(); /** * Returns list of all available versions. + * @return the versions + * @throws IOException if there is an exception getting the history */ public Version[] getVersionHistory() throws IOException; @@ -334,8 +351,8 @@ public interface DomainFile extends Comparable { * @param keepCheckedOut if true, the file will be initially checked-out * @param monitor progress monitor * @throws FileInUseException if this file is in-use. - * @throws IOException thrown if an IO or access error occurs. Also - * thrown if file is not private. + * @throws IOException thrown if an IO or access error occurs. Also thrown if file is not + * private. * @throws CancelledException if the monitor cancelled the operation */ public void addToVersionControl(String comment, boolean keepCheckedOut, TaskMonitor monitor) @@ -393,7 +410,7 @@ public interface DomainFile extends Comparable { /** * Forcefully terminate a checkout for the associated versioned file. - * The user must be the owner of the checkout or have admin privilege + * The user must be the owner of the checkout or have administrator privilege * on the versioned filesystem (i.e., repository). * @param checkoutId checkout ID * @throws IOException if an IO or access error occurs @@ -456,7 +473,7 @@ public interface DomainFile extends Comparable { * @throws IOException thrown if an IO or access error occurs. * @throws CancelledException if task monitor cancelled operation. */ - DomainFile copyTo(DomainFolder newParent, TaskMonitor monitor) + public DomainFile copyTo(DomainFolder newParent, TaskMonitor monitor) throws IOException, CancelledException; /** @@ -464,47 +481,53 @@ public interface DomainFile extends Comparable { * @param version version to copy * @param destFolder destination parent folder * @param monitor task monitor + * @return the copied file * @throws IOException thrown if an IO or access error occurs. * @throws CancelledException if task monitor cancelled operation. */ - DomainFile copyVersionTo(int version, DomainFolder destFolder, TaskMonitor monitor) + public DomainFile copyVersionTo(int version, DomainFolder destFolder, TaskMonitor monitor) throws IOException, CancelledException; /** * Get the list of consumers (Objects) for this domain file. * @return empty array list if there are no consumers */ - ArrayList getConsumers(); + public List getConsumers(); /** * Return whether the domain object in this domain file has changed. + * @return true if changed */ - boolean isChanged(); + public boolean isChanged(); /** * Returns true if there is an open domainObject for this file. + * @return true if open */ - boolean isOpen(); + public boolean isOpen(); /** * Returns true if the domain object in this domain file exists and has an open transaction. + * @return true if busy */ - boolean isBusy(); + public boolean isBusy(); /** * Pack domain file into specified file. * Specified file will be overwritten if it already exists. * @param file destination file - * @param monitor - * @throws IOException + * @param monitor the task monitor + * @throws IOException if there is an exception packing the file * @throws CancelledException if monitor cancels operation */ public void packFile(File file, TaskMonitor monitor) throws IOException, CancelledException; /** - * Returns an ordered map containting the metadata that has been associated with the corresponding domain object. - * The map contains key,value pairs and are ordered by their insertion order. - * @return a map containting the metadata that has been associated with the corresponding domain object. + * Returns an ordered map containing the metadata that has been associated with the + * corresponding domain object. The map contains key,value pairs and are ordered by their + * insertion order. + * @return a map containing the metadata that has been associated with the corresponding domain + * object. */ public Map getMetadata(); diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/model/DomainFolder.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/model/DomainFolder.java index 4b2274ca18..61f43881f8 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/model/DomainFolder.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/model/DomainFolder.java @@ -24,10 +24,10 @@ import ghidra.util.exception.*; import ghidra.util.task.TaskMonitor; /** - * DomainFolder provides a storage interface for project - * folders. A DomainFolder is an immutable reference to - * a folder contained within a project. The state of a DomainFolder - * object does not track name/parent changes made to the referenced project folder. + * DomainFolder provides a storage interface for project folders. A + * DomainFolder is an immutable reference to a folder contained within a project. The + * state of a DomainFolder object does not track name/parent changes made to the + * referenced project folder. */ public interface DomainFolder extends Comparable { /** @@ -42,41 +42,51 @@ public interface DomainFolder extends Comparable { /** * Return this folder's name. + * @return the name */ public String getName(); /** * Set the name on this domain folder. * @param newName domain folder name - * @return renamed domain file (the original DomainFolder object becomes invalid since it is immutable) + * @return renamed domain file (the original DomainFolder object becomes invalid since it is + * immutable) * @throws InvalidNameException if newName contains illegal characters * @throws DuplicateFileException if a folder named newName * already exists in this files domain folder. - * @throws FileInUseException if any file within this folder or its - * decendents is in-use / checked-out. + * @throws FileInUseException if any file within this folder or its descendants is + * in-use / checked-out. * @throws IOException thrown if an IO or access error occurs. */ public DomainFolder setName(String newName) throws InvalidNameException, IOException; /** * Returns the local storage location for the project that this DomainFolder belongs to. + * @return the locator */ public ProjectLocator getProjectLocator(); + /** + * Returns the project data + * @return the project data + */ public ProjectData getProjectData(); /** * Returns the path name to the domain object. + * @return the path name */ public String getPathname(); /** - * Returns true if this file is in a writable project. + * Returns true if this file is in a writable project. + * @return true if writable */ public boolean isInWritableProject(); /** * Return parent folder or null if this DomainFolder is the root folder. + * @return the parent */ public DomainFolder getParent(); @@ -149,10 +159,11 @@ public interface DomainFolder extends Comparable { /** * Create a subfolder of this folder. * @param folderName sub-folder name + * @return the folder * @throws DuplicateFileException if a folder by * this name already exists - * @throws InvalidNameException if name is an empty string - * of if it contains characters other than alphanumerics. + * @throws InvalidNameException if name is an empty string of if it contains characters other + * than alphanumerics. * @throws IOException if IO or access error occurs */ public DomainFolder createFolder(String folderName) throws InvalidNameException, IOException; @@ -169,10 +180,11 @@ public interface DomainFolder extends Comparable { * this affects both private and repository folders and files. If not * connected, only private folders and files are affected. * @param newParent new parent folder within the same project - * @return the newly relocated folder (the original DomainFolder object becomes invalid since it is immutable) + * @return the newly relocated folder (the original DomainFolder object becomes invalid since + * it is immutable) * @throws DuplicateFileException if a folder with the same name * already exists in newParent folder. - * @throws FileInUseException if this folder or one of its decendents + * @throws FileInUseException if this folder or one of its descendants * contains a file which is in-use / checked-out. * @throws IOException thrown if an IO or access error occurs. */ @@ -182,6 +194,7 @@ public interface DomainFolder extends Comparable { * Copy this folder into the newParent folder. * @param newParent new parent folder * @param monitor the task monitor + * @return the copied folder * @throws DuplicateFileException if a folder or file by * this name already exists in the newParent folder * @throws IOException thrown if an IO or access error occurs. @@ -191,9 +204,7 @@ public interface DomainFolder extends Comparable { CancelledException; /** - * Allows the framework to react to a request to make this folder the - * "active" one. + * Allows the framework to react to a request to make this folder the "active" one. */ public void setActive(); - } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/model/DomainFolderChangeListener.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/model/DomainFolderChangeListener.java index 2672ef061c..43567d3024 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/model/DomainFolderChangeListener.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/model/DomainFolderChangeListener.java @@ -115,5 +115,4 @@ public interface DomainFolderChangeListener { * @param object domain object which was open for update */ public void domainFileObjectClosed(DomainFile file, DomainObject object); - }