diff --git a/Ghidra/Features/GhidraServer/src/main/java/ghidra/server/store/RepositoryFile.java b/Ghidra/Features/GhidraServer/src/main/java/ghidra/server/store/RepositoryFile.java index 3025f6f5ab..6c399840c9 100644 --- a/Ghidra/Features/GhidraServer/src/main/java/ghidra/server/store/RepositoryFile.java +++ b/Ghidra/Features/GhidraServer/src/main/java/ghidra/server/store/RepositoryFile.java @@ -4,9 +4,9 @@ * 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. @@ -80,8 +80,9 @@ public class RepositoryFile { pathname += "/"; } pathname += name; - RepositoryManager.log(repository.getName(), pathname, "file is corrupt", null); - throw new FileNotFoundException(pathname + " is corrupt"); + RepositoryManager.log(repository.getName(), pathname, + "file is corrupt or unsupported", null); + throw new FileNotFoundException(pathname + " is corrupt or unsupported"); } this.databaseItem = (LocalDatabaseItem) folderItem; } diff --git a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/LocalFolderItem.java b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/LocalFolderItem.java index 695fdbd198..7424607d0f 100644 --- a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/LocalFolderItem.java +++ b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/LocalFolderItem.java @@ -4,9 +4,9 @@ * 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. @@ -154,9 +154,11 @@ public abstract class LocalFolderItem implements FolderItem { } /** - * Returns hidden database directory + * Returns hidden data directory. + * NOTE: Even if a data directory is not required this method will still return one to + * allow removal of an unknown item type that may or may not use it. */ - File getDataDir() { + final File getDataDir() { synchronized (fileSystem) { // Use hidden DB directory return new File(propertyFile.getFolder(), @@ -356,7 +358,7 @@ public abstract class LocalFolderItem implements FolderItem { * Files are restored to there original state if unable to remove * all files. */ - void deleteContent(String user) throws IOException { + final void deleteContent(String user) throws IOException { synchronized (fileSystem) { File dataDir = getDataDir(); File chkDir = new File(dataDir.getParentFile(), dataDir.getName() + ".delete"); @@ -457,7 +459,7 @@ public abstract class LocalFolderItem implements FolderItem { */ @Override public String getContentType() { - return propertyFile.getString(CONTENT_TYPE, null); + return propertyFile.getString(CONTENT_TYPE, UnknownFolderItem.UNKNOWN_CONTENT_TYPE); } /** @@ -809,17 +811,21 @@ public abstract class LocalFolderItem implements FolderItem { else if (fileType == DATABASE_FILE_TYPE) { return new LocalDatabaseItem(fileSystem, propertyFile); } + else if (fileType == UNKNOWN_FILE_TYPE) { + log.error("Folder item has unspecified file type: " + + new File(propertyFile.getFolder(), propertyFile.getStorageName())); + } else { - log.error("Item has unknown content type: " + + log.error("Folder item has unsupported file type (" + fileType + "): " + new File(propertyFile.getFolder(), propertyFile.getStorageName())); } } catch (FileNotFoundException e) { - log.error("Item may be corrupt due to missing file: " + + log.error("Folder item may be corrupt due to missing file: " + new File(propertyFile.getFolder(), propertyFile.getStorageName()), e); } catch (IOException e) { - log.error("Item may be corrupt: " + + log.error("Folder item may be corrupt: " + new File(propertyFile.getFolder(), propertyFile.getStorageName()), e); } return new UnknownFolderItem(fileSystem, propertyFile); diff --git a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/UnknownFolderItem.java b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/UnknownFolderItem.java index 70b54d2ca0..d1ec4f62d7 100644 --- a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/UnknownFolderItem.java +++ b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/UnknownFolderItem.java @@ -4,9 +4,9 @@ * 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. @@ -28,7 +28,9 @@ import ghidra.util.task.TaskMonitor; */ public class UnknownFolderItem extends LocalFolderItem { - public static final String UNKNOWN_CONTENT_TYPE = "Unknown"; + public static final String UNKNOWN_CONTENT_TYPE = "Unknown-File"; + + private final int fileType; /** * Constructor. @@ -37,6 +39,15 @@ public class UnknownFolderItem extends LocalFolderItem { */ UnknownFolderItem(LocalFileSystem fileSystem, PropertyFile propertyFile) { super(fileSystem, propertyFile); + fileType = propertyFile.getInt(FILE_TYPE, UNKNOWN_FILE_TYPE); + } + + /** + * Get the file type + * @return file type or -1 if unspecified + */ + public int getFileType() { + return fileType; } @Override diff --git a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/remote/RemoteFileSystem.java b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/remote/RemoteFileSystem.java index 6ab3c6b768..24f10a4700 100644 --- a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/remote/RemoteFileSystem.java +++ b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/remote/RemoteFileSystem.java @@ -4,9 +4,9 @@ * 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. @@ -24,6 +24,7 @@ import ghidra.framework.remote.RepositoryItem; import ghidra.framework.store.*; import ghidra.framework.store.FileSystem; import ghidra.util.InvalidNameException; +import ghidra.util.Msg; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; @@ -111,12 +112,19 @@ public class RemoteFileSystem implements FileSystem, RemoteAdapterListener { @Override public FolderItem[] getItems(String folderPath) throws IOException { RepositoryItem[] items = repository.getItemList(folderPath); + if (!folderPath.endsWith(FileSystem.SEPARATOR)) { + folderPath += FileSystem.SEPARATOR; + } FolderItem[] folderItems = new FolderItem[items.length]; for (int i = 0; i < items.length; i++) { - if (items[i].getItemType() != RepositoryItem.DATABASE) { - throw new IOException("Unsupported file type"); + if (items[i].getItemType() == RepositoryItem.DATABASE) { + folderItems[i] = new RemoteDatabaseItem(repository, items[i]); + } + else { + Msg.error(this, + "Unsupported respository item encountered (" + items[i].getItemType() + "): " + + folderPath + items[i].getName()); } - folderItems[i] = new RemoteDatabaseItem(repository, items[i]); } return folderItems; } @@ -130,7 +138,7 @@ public class RemoteFileSystem implements FileSystem, RemoteAdapterListener { if (item.getItemType() == RepositoryItem.DATABASE) { return new RemoteDatabaseItem(repository, item); } - throw new IOException("Unsupported file type"); + throw new IOException("Unsupported repository item type (" + item.getItemType() + ")"); } @Override @@ -142,7 +150,7 @@ public class RemoteFileSystem implements FileSystem, RemoteAdapterListener { if (item.getItemType() == RepositoryItem.DATABASE) { return new RemoteDatabaseItem(repository, item); } - throw new IOException("Unsupported file type"); + throw new IOException("Unsupported repository item type (" + item.getItemType() + ")"); } @Override diff --git a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/remote/RemoteFolderItem.java b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/remote/RemoteFolderItem.java index b027f3f401..1da09bb400 100644 --- a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/remote/RemoteFolderItem.java +++ b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/remote/RemoteFolderItem.java @@ -4,9 +4,9 @@ * 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. @@ -20,6 +20,7 @@ import java.io.IOException; import ghidra.framework.client.RepositoryAdapter; import ghidra.framework.remote.RepositoryItem; import ghidra.framework.store.*; +import ghidra.framework.store.local.UnknownFolderItem; /** * RemoteFolderItem provides an abstract FolderItem implementation @@ -46,7 +47,11 @@ public abstract class RemoteFolderItem implements FolderItem { this.repository = repository; parentPath = item.getParentPath(); itemName = item.getName(); - contentType = item.getContentType(); + String ct = item.getContentType(); + if (ct == null) { + ct = UnknownFolderItem.UNKNOWN_CONTENT_TYPE; + } + contentType = ct; fileID = item.getFileID(); version = item.getVersion(); diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/ContentHandler.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/ContentHandler.java index 78dda0a7de..39b0c04fef 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/ContentHandler.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/ContentHandler.java @@ -4,9 +4,9 @@ * 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. @@ -23,6 +23,7 @@ import javax.swing.Icon; import ghidra.framework.model.*; import ghidra.framework.store.FileSystem; import ghidra.framework.store.FolderItem; +import ghidra.framework.store.local.UnknownFolderItem; import ghidra.util.InvalidNameException; import ghidra.util.classfinder.ExtensionPoint; import ghidra.util.exception.CancelledException; @@ -42,7 +43,7 @@ import ghidra.util.task.TaskMonitor; */ public interface ContentHandler extends ExtensionPoint { - public static final String UNKNOWN_CONTENT = "Unknown-File"; + public static final String UNKNOWN_CONTENT = UnknownFolderItem.UNKNOWN_CONTENT_TYPE; public static final String MISSING_CONTENT = "Missing-File"; /** diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/GhidraFolderData.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/GhidraFolderData.java index 58707b10e0..42bf0ea340 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/GhidraFolderData.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/GhidraFolderData.java @@ -4,9 +4,9 @@ * 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. @@ -616,8 +616,9 @@ class GhidraFolderData { Map map = new HashMap<>(); int badItemCount = 0; int nullNameCount = 0; + int unknownItemCount = 0; for (T item : items) { - if (item == null || item instanceof UnknownFolderItem) { + if (item == null) { ++badItemCount; continue; } @@ -626,6 +627,16 @@ class GhidraFolderData { ++nullNameCount; continue; } + if (item instanceof UnknownFolderItem unk) { + if (unk.getFileType() == FolderItem.UNKNOWN_FILE_TYPE) { + ++badItemCount; + continue; + } + Msg.error(this, + "Unsupported folder item encountered (" + unk.getFileType() + "): " + + getPathname(item.getName())); + ++unknownItemCount; + } map.put(itemName, item); } if (badItemCount != 0) { @@ -636,6 +647,11 @@ class GhidraFolderData { Msg.error(this, "Project folder contains " + nullNameCount + " null items: " + getPathname()); } + if (badItemCount != 0) { + Msg.error(this, + "Project folder contains " + unknownItemCount + " unsupported items: " + + getPathname()); + } return map; } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndPlugin.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndPlugin.java index 5e5d71e62d..12759d162d 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndPlugin.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndPlugin.java @@ -41,8 +41,7 @@ import generic.theme.GIcon; import ghidra.app.plugin.PluginCategoryNames; import ghidra.framework.GenericRunInfo; import ghidra.framework.client.*; -import ghidra.framework.data.FolderLinkContentHandler; -import ghidra.framework.data.LinkedGhidraFolder; +import ghidra.framework.data.*; import ghidra.framework.main.datatable.ProjectDataTablePanel; import ghidra.framework.main.datatree.*; import ghidra.framework.main.projectdata.actions.*; @@ -1082,8 +1081,17 @@ public class FrontEndPlugin extends Plugin } public void openDomainFile(DomainFile domainFile) { + + String contentType = domainFile.getContentType(); + if (ContentHandler.UNKNOWN_CONTENT.equals(contentType)) { + Msg.showInfo(this, tool.getToolFrame(), "Cannot Find Tool", + "File type is unrecognized: " + + HTMLUtilities.escapeHTML(domainFile.getName()) + + ".

File may have been created with a neer version of Ghidra."); + return; + } - if (FolderLinkContentHandler.FOLDER_LINK_CONTENT_TYPE.equals(domainFile.getContentType())) { + if (FolderLinkContentHandler.FOLDER_LINK_CONTENT_TYPE.equals(contentType)) { showLinkedFolderInViewedProject(domainFile); return; } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/protocol/ghidra/ContentTypeQueryTask.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/protocol/ghidra/ContentTypeQueryTask.java index 8861896dd7..11714b6f50 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/protocol/ghidra/ContentTypeQueryTask.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/protocol/ghidra/ContentTypeQueryTask.java @@ -4,9 +4,9 @@ * 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. @@ -17,6 +17,7 @@ package ghidra.framework.protocol.ghidra; import java.net.URL; +import ghidra.framework.data.ContentHandler; import ghidra.framework.model.DomainFile; import ghidra.util.task.TaskMonitor; @@ -25,7 +26,7 @@ import ghidra.util.task.TaskMonitor; */ public class ContentTypeQueryTask extends GhidraURLQueryTask { - private String contentType = "Unknown"; + private String contentType = ContentHandler.UNKNOWN_CONTENT; /** * Construct a Ghidra URL content type query task