mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-25 20:05:52 +08:00
Merge remote-tracking branch
'origin/GP-5332_dev747368_FSRL_backslash_paths' (Closes #7278)
This commit is contained in:
@@ -177,7 +177,6 @@ public class FSRL {
|
||||
|
||||
FSRLRoot fsRoot = FSRLRoot.nestedFS(containerFile, proto);
|
||||
String decodedPath = FSUtilities.escapeDecode(path);
|
||||
decodedPath = decodedPath.replace('\\', '/');
|
||||
if (decodedPath.isEmpty()) {
|
||||
decodedPath = null;
|
||||
}
|
||||
@@ -289,6 +288,11 @@ public class FSRL {
|
||||
return null;
|
||||
}
|
||||
int cp = path.lastIndexOf('/');
|
||||
if (cp > 0 && cp == path.length() - 1) {
|
||||
// if the path ended with a '/', look for the slash before that
|
||||
// typically only for windows drive letter path like "/c:/"
|
||||
cp = path.lastIndexOf('/', cp - 1);
|
||||
}
|
||||
return cp >= 0 ? path.substring(cp + 1) : path;
|
||||
}
|
||||
|
||||
|
||||
+5
-2
@@ -273,10 +273,13 @@ class FileSystemInstanceManager implements FileSystemEventListener {
|
||||
* @param ref {@link FileSystemRef} to close
|
||||
*/
|
||||
public synchronized void releaseImmediate(FileSystemRef ref) {
|
||||
FSCacheInfo fsci = filesystems.get(ref.getFilesystem().getFSRL());
|
||||
FSRLRoot fsFSRL = ref.getFilesystem().getFSRL();
|
||||
FSCacheInfo fsci = filesystems.get(fsFSRL);
|
||||
ref.close();
|
||||
if (fsci == null) {
|
||||
Msg.warn(this, "Unknown file system reference: " + ref.getFilesystem().getFSRL());
|
||||
if (!rootFSRL.equals(fsFSRL) /* we don't store root FS refs */) {
|
||||
Msg.warn(this, "Unknown file system reference: " + fsFSRL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
FileSystemRefManager refManager = fsci.ref.getFilesystem().getRefManager();
|
||||
|
||||
+25
-10
@@ -22,6 +22,7 @@ import java.nio.file.AccessMode;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.collections4.map.ReferenceMap;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.bin.FileByteProvider;
|
||||
@@ -61,7 +62,7 @@ public class LocalFileSystem implements GFileSystem, GFileHashProvider {
|
||||
private final FileSystemRefManager refManager = new FileSystemRefManager(this);
|
||||
private final ReferenceMap<FileFingerprintRec, String> fileFingerprintToMD5Map =
|
||||
new ReferenceMap<>();
|
||||
private final boolean needsListRoots =
|
||||
private final boolean isWindows =
|
||||
OperatingSystem.CURRENT_OPERATING_SYSTEM == OperatingSystem.WINDOWS;
|
||||
|
||||
private LocalFileSystem(FSRLRoot fsrl) {
|
||||
@@ -126,7 +127,25 @@ public class LocalFileSystem implements GFileSystem, GFileHashProvider {
|
||||
* @return The {@link FSRL}
|
||||
*/
|
||||
public FSRL getLocalFSRL(File f) {
|
||||
return fsFSRL.withPath(FSUtilities.normalizeNativePath(f.getAbsolutePath()));
|
||||
String absPath = f.getAbsolutePath();
|
||||
if (isWindows) {
|
||||
// only force on windows... unix paths can have backslashes as part of filenames
|
||||
absPath = FilenameUtils.separatorsToUnix(absPath);
|
||||
}
|
||||
String fsrlPath = FSUtilities.appendPath("/", absPath);
|
||||
return fsFSRL.withPath(fsrlPath);
|
||||
}
|
||||
|
||||
private GFile getGFile(File f) {
|
||||
List<File> parts = LocalFileSystem.getFilePathParts(f); // [/subdir/subroot/file, /subdir/subroot, /subdir, /]
|
||||
GFile current = rootDir;
|
||||
for (int i = parts.size() - 2; i >= 0; i--) {
|
||||
File part = parts.get(i);
|
||||
FSRL childFSRL = getLocalFSRL(part);
|
||||
current =
|
||||
GFileImpl.fromFSRL(this, current, childFSRL, part.isDirectory(), part.length());
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -149,10 +168,9 @@ public class LocalFileSystem implements GFileSystem, GFileHashProvider {
|
||||
List<GFile> results = new ArrayList<>();
|
||||
directory = Objects.requireNonNullElse(directory, rootDir);
|
||||
|
||||
if (directory.equals(rootDir) && needsListRoots) {
|
||||
if (directory.equals(rootDir) && isWindows) {
|
||||
for (File f : File.listRoots()) {
|
||||
FSRL rootElemFSRL = fsFSRL.withPath(FSUtilities.normalizeNativePath(f.getName()));
|
||||
results.add(GFileImpl.fromFSRL(this, null, rootElemFSRL, f.isDirectory(), -1));
|
||||
results.add(GFileImpl.fromFSRL(this, null, getLocalFSRL(f), f.isDirectory(), -1));
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -219,8 +237,7 @@ public class LocalFileSystem implements GFileSystem, GFileHashProvider {
|
||||
@Override
|
||||
public GFile lookup(String path, Comparator<String> nameComp) throws IOException {
|
||||
File f = lookupFile(null, path, nameComp);
|
||||
return f != null ? GFileImpl.fromPathString(this,
|
||||
FSUtilities.normalizeNativePath(f.getPath()), null, f.isDirectory(), f.length()) : null;
|
||||
return f != null ? getGFile(f) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -259,9 +276,7 @@ public class LocalFileSystem implements GFileSystem, GFileHashProvider {
|
||||
if (f.equals(canonicalFile)) {
|
||||
return file;
|
||||
}
|
||||
return GFileImpl.fromPathString(this,
|
||||
FSUtilities.normalizeNativePath(canonicalFile.getPath()), null,
|
||||
canonicalFile.isDirectory(), canonicalFile.length());
|
||||
return getGFile(canonicalFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -107,7 +107,7 @@ public class LocalFileSystemSub implements GFileSystem, GFileHashProvider {
|
||||
|
||||
List<GFile> tmp = new ArrayList<>(localFiles.length);
|
||||
FSRL dirFSRL = directory.getFSRL();
|
||||
String relPath = FSUtilities.normalizeNativePath(directory.getPath());
|
||||
String relPath = directory.getPath(); // this is the clean relative path assigned to the dir GFile earlier
|
||||
|
||||
for (File f : localFiles) {
|
||||
boolean isSymlink = FSUtilities.isSymlink(f); // check this manually to allow broken symlinks to appear in listing
|
||||
|
||||
+28
-15
@@ -83,14 +83,14 @@ public class FSBComponentProvider extends ComponentProviderAdapter
|
||||
* @param fsRef {@link FileSystemRef} to a {@link GFileSystem}.
|
||||
*/
|
||||
public FSBComponentProvider(FileSystemBrowserPlugin plugin, FileSystemRef fsRef) {
|
||||
super(plugin.getTool(), fsRef.getFilesystem().getName(), plugin.getName());
|
||||
super(plugin.getTool(), getDescriptiveFSName(fsRef.getFilesystem()), plugin.getName());
|
||||
|
||||
this.plugin = plugin;
|
||||
this.rootNode = new FSBRootNode(fsRef);
|
||||
this.pm = plugin.getTool().getService(ProgramManager.class);
|
||||
|
||||
setTransient();
|
||||
setIcon(FSBIcons.PHOTO);
|
||||
setIcon(getFSIcon(fsRef.getFilesystem(), true, fsbIcons));
|
||||
|
||||
initTree();
|
||||
fsRef.getFilesystem().getRefManager().addListener(this);
|
||||
@@ -147,8 +147,8 @@ public class FSBComponentProvider extends ComponentProviderAdapter
|
||||
super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row,
|
||||
hasFocus);
|
||||
|
||||
if (value instanceof FSBRootNode fsRootNode) {
|
||||
renderFS(fsRootNode, selected);
|
||||
if (value instanceof FSBRootNode) {
|
||||
// do nothing
|
||||
}
|
||||
else if (value instanceof FSBDirNode) {
|
||||
// do nothing special, but exclude FSBFileNode
|
||||
@@ -160,16 +160,6 @@ public class FSBComponentProvider extends ComponentProviderAdapter
|
||||
return this;
|
||||
}
|
||||
|
||||
private void renderFS(FSBRootNode node, boolean selected) {
|
||||
FileSystemRef nodeFSRef = node.getFSRef();
|
||||
if (nodeFSRef == null || nodeFSRef.getFilesystem() == null) {
|
||||
return;
|
||||
}
|
||||
Icon image = fsbIcons.getIcon(node.getContainerName(),
|
||||
List.of(FSBIcons.FILESYSTEM_OVERLAY_ICON));
|
||||
setIcon(image);
|
||||
}
|
||||
|
||||
private void renderFile(FSBFileNode node, boolean selected) {
|
||||
FSRL fsrl = node.getFSRL();
|
||||
String filename = fsrl.getName();
|
||||
@@ -277,7 +267,10 @@ public class FSBComponentProvider extends ComponentProviderAdapter
|
||||
public void setProject(Project project) {
|
||||
gTree.runTask(monitor -> {
|
||||
projectIndex.setProject(project, monitor);
|
||||
Swing.runLater(() -> gTree.repaint()); // icons might need repainting after new info is available
|
||||
Swing.runLater(() -> {
|
||||
contextChanged();
|
||||
gTree.repaint();
|
||||
}); // icons might need repainting after new info is available
|
||||
});
|
||||
}
|
||||
|
||||
@@ -432,6 +425,9 @@ public class FSBComponentProvider extends ComponentProviderAdapter
|
||||
if (nested) {
|
||||
FSBFileNode modelFileNode =
|
||||
(FSBFileNode) gTree.getModelNodeForPath(node.getTreePath());
|
||||
if (modelFileNode == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
FSBRootNode nestedRootNode = new FSBRootNode(ref, modelFileNode);
|
||||
|
||||
@@ -587,4 +583,21 @@ public class FSBComponentProvider extends ComponentProviderAdapter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static String getDescriptiveFSName(GFileSystem fs) {
|
||||
return fs instanceof LocalFileSystem ? "My Computer" : fs.getName();
|
||||
}
|
||||
|
||||
static Icon getFSIcon(GFileSystem fs, boolean isRootNode, FSBIcons fsbIcons) {
|
||||
List<Icon> overlays = !isRootNode ? List.of(FSBIcons.FILESYSTEM_OVERLAY_ICON) : List.of();
|
||||
FSRL container = fs.getFSRL().getContainer();
|
||||
String containerName = container != null ? container.getName() : "/";
|
||||
Icon image = fs instanceof LocalFileSystem || fs instanceof LocalFileSystemSub
|
||||
? FSBIcons.MY_COMPUTER
|
||||
: fsbIcons.getIcon(containerName, overlays);
|
||||
if (image == FSBIcons.DEFAULT_ICON) {
|
||||
image = FSBIcons.PHOTO;
|
||||
}
|
||||
return image;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ public class FSBFileNode extends FSBNode {
|
||||
protected String filenameExtOverride;
|
||||
|
||||
FSBFileNode(GFile file) {
|
||||
super(file.getFSRL().getName());
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -74,6 +74,8 @@ public class FSBIcons {
|
||||
public static final Icon MISSING_PASSWORD_OVERLAY_ICON = new GIcon("icon.fsbrowser.file.overlay.missing.password");
|
||||
public static final Icon LINK_OVERLAY_ICON = new GIcon("icon.fsbrowser.file.overlay.link");
|
||||
public static final Icon DEFAULT_ICON = new GIcon("icon.fsbrowser.file.extension.default");
|
||||
|
||||
public static final Icon MY_COMPUTER = resources.ResourceManager.getScaledIcon(new GIcon("icon.filechooser.places.my.computer"), 16, 16);
|
||||
//@formatter:on
|
||||
|
||||
public static FSBIcons getInstance() {
|
||||
|
||||
@@ -35,6 +35,12 @@ import ghidra.util.task.TaskMonitor;
|
||||
*/
|
||||
public abstract class FSBNode extends GTreeSlowLoadingNode {
|
||||
|
||||
protected String name;
|
||||
|
||||
protected FSBNode(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link FSRL} of the filesystem object that this node represents.
|
||||
* <p>
|
||||
@@ -64,7 +70,7 @@ public abstract class FSBNode extends GTreeSlowLoadingNode {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return getFSRL().getName();
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,6 +19,8 @@ import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
import docking.widgets.tree.GTreeNode;
|
||||
import ghidra.formats.gfilesystem.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
@@ -40,15 +42,20 @@ public class FSBRootNode extends FSBNode {
|
||||
private FSBFileNode prevNode;
|
||||
private FSBRootNode modelNode;
|
||||
private boolean cryptoStatusUpdated;
|
||||
private Icon icon;
|
||||
|
||||
FSBRootNode(FileSystemRef fsRef) {
|
||||
this(fsRef, null);
|
||||
}
|
||||
|
||||
FSBRootNode(FileSystemRef fsRef, FSBFileNode prevNode) {
|
||||
super(FSBComponentProvider.getDescriptiveFSName(fsRef.getFilesystem()));
|
||||
|
||||
this.fsRef = fsRef;
|
||||
this.prevNode = prevNode;
|
||||
this.modelNode = this;
|
||||
this.icon = FSBComponentProvider.getFSIcon(fsRef.getFilesystem(), prevNode == null,
|
||||
FSBIcons.getInstance());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -69,6 +76,11 @@ public class FSBRootNode extends FSBNode {
|
||||
setChildren(generateChildren(monitor));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIcon(boolean expanded) {
|
||||
return icon;
|
||||
}
|
||||
|
||||
public void setCryptoStatusUpdated(boolean cryptoStatusUpdated) {
|
||||
this.cryptoStatusUpdated = cryptoStatusUpdated;
|
||||
}
|
||||
@@ -118,13 +130,6 @@ public class FSBRootNode extends FSBNode {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return modelNode.fsRef != null && !modelNode.fsRef.isClosed()
|
||||
? modelNode.fsRef.getFilesystem().getName()
|
||||
: " Missing ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToolTip() {
|
||||
return getName();
|
||||
@@ -178,10 +183,6 @@ public class FSBRootNode extends FSBNode {
|
||||
: null;
|
||||
}
|
||||
|
||||
public String getContainerName() {
|
||||
return prevNode != null ? prevNode.getName() : "/";
|
||||
}
|
||||
|
||||
private List<GFile> splitGFilePath(GFile f) {
|
||||
List<GFile> result = new ArrayList<>();
|
||||
while (f != null) {
|
||||
|
||||
+1
@@ -157,6 +157,7 @@ public class FileSystemBrowserPlugin extends Plugin
|
||||
currentBrowsers.put(fsFSRL, provider);
|
||||
getTool().addComponentProvider(provider, false);
|
||||
provider.afterAddedToTool();
|
||||
provider.contextChanged();
|
||||
}
|
||||
|
||||
if (show) {
|
||||
|
||||
+19
-4
@@ -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.
|
||||
@@ -19,10 +19,13 @@ import java.util.List;
|
||||
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.builder.ActionBuilder;
|
||||
import ghidra.formats.gfilesystem.FileSystemRef;
|
||||
import ghidra.formats.gfilesystem.FileSystemService;
|
||||
import ghidra.plugins.fsbrowser.*;
|
||||
|
||||
public class OpenFsFSBFileHandler implements FSBFileHandler {
|
||||
|
||||
private static final String FSB_OPEN_ROOT_FS = "FSB Open My Computer";
|
||||
public static final String FSB_OPEN_FILE_SYSTEM_CHOOSER = "FSB Open File System Chooser";
|
||||
public static final String FSB_OPEN_FILE_SYSTEM_IN_NEW_WINDOW =
|
||||
"FSB Open File System In New Window";
|
||||
@@ -62,10 +65,22 @@ public class OpenFsFSBFileHandler implements FSBFileHandler {
|
||||
ac -> ac.getComponentProvider().openFileSystem(ac.getSelectedNode(), false))
|
||||
.build(),
|
||||
|
||||
new ActionBuilder(FSB_OPEN_ROOT_FS, context.plugin().getName())
|
||||
.description("Show the 'My Computer' location")
|
||||
.enabledWhen(ac -> !context.fsbComponent().getGTree().isBusy())
|
||||
.toolBarIcon(FSBIcons.MY_COMPUTER)
|
||||
.toolBarGroup("B")
|
||||
.onAction(ac -> {
|
||||
FileSystemService fsService = context.fsService();
|
||||
FileSystemRef fsRef =
|
||||
fsService.getMountedFilesystem(fsService.getLocalFS().getFSRL());
|
||||
context.plugin().createNewFileSystemBrowser(fsRef, true);
|
||||
})
|
||||
.build(),
|
||||
|
||||
new ActionBuilder(FSB_OPEN_FILE_SYSTEM_CHOOSER, context.plugin().getName())
|
||||
.description("Open File System Chooser")
|
||||
.withContext(FSBActionContext.class)
|
||||
.enabledWhen(FSBActionContext::notBusy)
|
||||
.enabledWhen(ac -> !context.fsbComponent().getGTree().isBusy())
|
||||
.toolBarIcon(FSBIcons.OPEN_FILE_SYSTEM)
|
||||
.toolBarGroup("B")
|
||||
.onAction(ac -> context.plugin().openFileSystem())
|
||||
|
||||
@@ -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.
|
||||
@@ -65,10 +65,11 @@ public class FSRLTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDOSPaths() throws MalformedURLException {
|
||||
FSRL fsrl = FSRL.fromString("fsrl://a:\\dir\\filename.txt");
|
||||
public void testPathsWithBackslashes() throws MalformedURLException {
|
||||
FSRL fsrl = FSRL.fromString("fsrl:///dir/filename\\with\\backslashes");
|
||||
assertEquals("fsrl", fsrl.getFS().getProtocol());
|
||||
assertEquals("a:/dir/filename.txt", fsrl.getPath());
|
||||
assertEquals("/dir/filename\\with\\backslashes", fsrl.getPath());
|
||||
assertEquals("filename\\with\\backslashes", fsrl.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user