From eb24c51b51bfdbc5bde812045a8fab608d59f35f Mon Sep 17 00:00:00 2001 From: dev747368 <48332326+dev747368@users.noreply.github.com> Date: Mon, 4 Oct 2021 13:45:32 -0400 Subject: [PATCH] GP-1024 fix "Extract and Import" to not produce tmp files with bad names Temp files were named using memory block name and string rep of the min and max address, which would cause problems if address representation contained a ":" (seg:offset) and the user was on a windows platform. --- .../app/util/bin/MemoryByteProvider.java | 3 ++ .../gfilesystem/FileSystemService.java | 21 ++++++++++- .../formats/gfilesystem/LocalFileSystem.java | 2 +- .../plugin/importer/ImporterPlugin.java | 36 +++++++++++++------ .../java/ghidra/program/model/mem/Memory.java | 4 +-- 5 files changed, 52 insertions(+), 14 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/MemoryByteProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/MemoryByteProvider.java index c1fe10fcc3..6421a9bca1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/MemoryByteProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/MemoryByteProvider.java @@ -125,6 +125,9 @@ public class MemoryByteProvider implements ByteProvider { } return bytes; } + catch (IOException e) { + throw e; + } catch (Exception e) { throw new IOException(e.getMessage()); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/FileSystemService.java b/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/FileSystemService.java index 5a05e9bbf7..a7b3ed51d8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/FileSystemService.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/FileSystemService.java @@ -226,7 +226,7 @@ public class FileSystemService { * @return true if local, false if the path points to an embedded file in a container. */ public boolean isLocal(FSRL fsrl) { - return fsrl.getFS().hasContainer() == false; + return localFS.isSameFS(fsrl); } /** @@ -519,6 +519,25 @@ public class FileSystemService { return fileCache.createCacheEntryBuilder(sizeHint); } + /** + * Returns a {@link ByteProvider} for the specified {@link FileCacheEntry}, using the + * specified filename. + *
+ * The returned ByteProvider's FSRL will be decorative and does not allow returning to + * the same ByteProvider at a later time. + * + * @param tempFileCacheEntry {@link FileCacheEntry} (returned by {@link #createTempFile(long)}) + * @param name desired name + * @return new {@link ByteProvider} with decorative {@link FSRL} + * @throws IOException if io error + */ + public ByteProvider getNamedTempFile(FileCacheEntry tempFileCacheEntry, String name) + throws IOException { + FSRL resultFSRL = FSRLRoot.makeRoot("tmp") + .withPathMD5(FSUtilities.appendPath("/", name), tempFileCacheEntry.getMD5()); + return tempFileCacheEntry.asByteProvider(resultFSRL); + } + /** * Allows the resources used by caching the specified file to be released. * diff --git a/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/LocalFileSystem.java b/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/LocalFileSystem.java index 313f407ec7..253e4f3e0c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/LocalFileSystem.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/LocalFileSystem.java @@ -65,7 +65,7 @@ public class LocalFileSystem implements GFileSystem, GFileHashProvider { this.fsFSRL = fsrl; } - private boolean isSameFS(FSRL fsrl) { + boolean isSameFS(FSRL fsrl) { return fsFSRL.equals(fsrl.getFS()); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterPlugin.java index a5b5c70c22..071babbb16 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterPlugin.java @@ -17,7 +17,8 @@ package ghidra.plugin.importer; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; -import java.io.*; +import java.io.File; +import java.io.IOException; import java.util.*; import docking.ActionContext; @@ -29,8 +30,13 @@ import ghidra.app.context.ListingActionContext; import ghidra.app.events.ProgramActivatedPluginEvent; import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.services.*; +import ghidra.app.util.bin.ByteProvider; import ghidra.app.util.importer.LibrarySearchPathManager; +import ghidra.app.util.opinion.LoaderMap; +import ghidra.app.util.opinion.LoaderService; import ghidra.formats.gfilesystem.FSRL; +import ghidra.formats.gfilesystem.FileCache.FileCacheEntry; +import ghidra.formats.gfilesystem.FileCache.FileCacheEntryBuilder; import ghidra.formats.gfilesystem.FileSystemService; import ghidra.framework.main.*; import ghidra.framework.main.datatree.DomainFolderNode; @@ -385,20 +391,30 @@ public class ImporterPlugin extends Plugin return; } - Memory memory = program.getMemory(); - MemoryBlock block = memory.getBlock(range.getMinAddress()); - String tempFileName = - block.getName() + "_[" + range.getMinAddress() + "," + range.getMaxAddress() + "]_"; try { - File tempFile = File.createTempFile(tempFileName, ".tmp"); - try (OutputStream outputStream = new FileOutputStream(tempFile)) { + Memory memory = program.getMemory(); + FileSystemService fsService = FileSystemService.getInstance(); + + // create a tmp ByteProvider that contains the bytes from the selected region + FileCacheEntry tmpFile; + try (FileCacheEntryBuilder tmpFileBuilder = + fsService.createTempFile(range.getLength())) { byte[] bytes = new byte[(int) range.getLength()]; memory.getBytes(range.getMinAddress(), bytes); - outputStream.write(bytes); + tmpFileBuilder.write(bytes); + tmpFile = tmpFileBuilder.finish(); } - DomainFolder folder = AppInfo.getActiveProject().getProjectData().getRootFolder(); - importFile(folder, tempFile); + MemoryBlock block = memory.getBlock(range.getMinAddress()); + String rangeName = + block.getName() + "[" + range.getMinAddress() + "," + range.getMaxAddress() + "]"; + ByteProvider bp = + fsService.getNamedTempFile(tmpFile, program.getName() + " " + rangeName); + LoaderMap loaderMap = LoaderService.getAllSupportedLoadSpecs(bp); + + ImporterDialog importerDialog = + new ImporterDialog(tool, programManager, loaderMap, bp, null); + tool.showDialog(importerDialog); } catch (IOException e) { Msg.showError(this, null, "I/O Error Occurred", e.getMessage(), e); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/Memory.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/Memory.java index 65bcee3784..31a28ac370 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/Memory.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/Memory.java @@ -462,9 +462,9 @@ public interface Memory extends AddressSetView { * @param destIndex the offset into dest to place the bytes. * @param size the number of bytes to get. * @return the number of bytes put into dest. May be less than - * size if the requested number extends beyond available memory. + * size if the requested number extends beyond initialized / available memory. * @throws MemoryAccessException if the starting address is - * not contained in any memory block. + * not contained in any memory block or is an uninitialized location. */ public int getBytes(Address addr, byte[] dest, int destIndex, int size) throws MemoryAccessException;