summaryrefslogtreecommitdiff
path: root/rust
diff options
context:
space:
mode:
authorMason Reed <mason@vector35.com>2026-02-11 17:56:26 -0800
committerMason Reed <35282038+emesare@users.noreply.github.com>2026-02-23 00:09:44 -0800
commitc1dbea197a6ba7e3d008e01c8169f5c3702151ea (patch)
treec4dc5e203e7c04bd7ba1b105bd065073f05774a5 /rust
parentd61826e8fbe3580c762f7f317f69201bce3710ad (diff)
[Rust] Refactor `FileMetadata` file information
- Rename and retype `FileMetadata::filename` and make the assignment required to happen at time of construction. - Add `FileMetadata::display_name` which is only to be used for presentation purposes. - Add `FileMetadata::virtual_path` for containers. - Rename `FileMetadata::modified` to `FileMetadata::is_modified` to be more consistent across codebase. - Add some missing documentation. - Add `BinaryView::from_metadata` with accompanying documentation.
Diffstat (limited to 'rust')
-rw-r--r--rust/examples/decompile.rs2
-rw-r--r--rust/examples/disassemble.rs2
-rw-r--r--rust/examples/high_level_il.rs2
-rw-r--r--rust/examples/medium_level_il.rs2
-rw-r--r--rust/src/binary_view.rs19
-rw-r--r--rust/src/file_metadata.rs128
6 files changed, 138 insertions, 17 deletions
diff --git a/rust/examples/decompile.rs b/rust/examples/decompile.rs
index 6ba9cbf4..155de81c 100644
--- a/rust/examples/decompile.rs
+++ b/rust/examples/decompile.rs
@@ -42,7 +42,7 @@ pub fn main() {
.load(&filename)
.expect("Couldn't open file!");
- tracing::info!("Filename: `{}`", bv.file().filename());
+ tracing::info!("File: `{}`", bv.file());
tracing::info!("File size: `{:#x}`", bv.len());
tracing::info!("Function count: {}", bv.functions().len());
diff --git a/rust/examples/disassemble.rs b/rust/examples/disassemble.rs
index ce3ff765..df33aade 100644
--- a/rust/examples/disassemble.rs
+++ b/rust/examples/disassemble.rs
@@ -39,7 +39,7 @@ pub fn main() {
.load(&filename)
.expect("Couldn't open file!");
- tracing::info!("Filename: `{}`", bv.file().filename());
+ tracing::info!("File: `{}`", bv.file());
tracing::info!("File size: `{:#x}`", bv.len());
tracing::info!("Function count: {}", bv.functions().len());
diff --git a/rust/examples/high_level_il.rs b/rust/examples/high_level_il.rs
index a099437a..57b735e9 100644
--- a/rust/examples/high_level_il.rs
+++ b/rust/examples/high_level_il.rs
@@ -14,7 +14,7 @@ fn main() {
.load("/bin/cat")
.expect("Couldn't open `/bin/cat`");
- tracing::info!("Filename: `{}`", bv.file().filename());
+ tracing::info!("File: `{}`", bv.file());
tracing::info!("File size: `{:#x}`", bv.len());
tracing::info!("Function count: {}", bv.functions().len());
diff --git a/rust/examples/medium_level_il.rs b/rust/examples/medium_level_il.rs
index c9412d08..e2c0edee 100644
--- a/rust/examples/medium_level_il.rs
+++ b/rust/examples/medium_level_il.rs
@@ -14,7 +14,7 @@ fn main() {
.load("/bin/cat")
.expect("Couldn't open `/bin/cat`");
- tracing::info!("Filename: `{}`", bv.file().filename());
+ tracing::info!("File: `{}`", bv.file());
tracing::info!("File size: `{:#x}`", bv.len());
tracing::info!("Function count: {}", bv.functions().len());
diff --git a/rust/src/binary_view.rs b/rust/src/binary_view.rs
index 478b8265..4e35dc8c 100644
--- a/rust/src/binary_view.rs
+++ b/rust/src/binary_view.rs
@@ -2476,8 +2476,14 @@ impl BinaryView {
Ref::new(Self { handle })
}
- pub fn from_path(meta: &mut FileMetadata, file_path: impl AsRef<Path>) -> Result<Ref<Self>> {
- let file = file_path.as_ref().to_cstr();
+ /// Construct the raw binary view from the given metadata. Before calling this make sure you have
+ /// a valid file path set for the [`FileMetadata`]. It is required that the [`FileMetadata::file_path`]
+ /// exist on the local filesystem.
+ pub fn from_metadata(meta: &FileMetadata) -> Result<Ref<Self>> {
+ if !meta.file_path().exists() {
+ return Err(());
+ }
+ let file = meta.file_path().to_cstr();
let handle =
unsafe { BNCreateBinaryDataViewFromFilename(meta.handle, file.as_ptr() as *mut _) };
@@ -2488,6 +2494,15 @@ impl BinaryView {
unsafe { Ok(Ref::new(Self { handle })) }
}
+ /// Construct the raw binary view from the given `file_path` and metadata.
+ ///
+ /// This will implicitly set the metadata file path and then construct the view. If the metadata
+ /// already has the desired file path, use [`BinaryView::from_metadata`] instead.
+ pub fn from_path(meta: &FileMetadata, file_path: impl AsRef<Path>) -> Result<Ref<Self>> {
+ meta.set_file_path(file_path.as_ref());
+ Self::from_metadata(meta)
+ }
+
pub fn from_accessor<A: Accessor>(
meta: &FileMetadata,
file: &mut FileAccessor<A>,
diff --git a/rust/src/file_metadata.rs b/rust/src/file_metadata.rs
index 27ceb4af..f6427750 100644
--- a/rust/src/file_metadata.rs
+++ b/rust/src/file_metadata.rs
@@ -20,7 +20,7 @@ use binaryninjacore_sys::*;
use binaryninjacore_sys::{BNCreateDatabaseWithProgress, BNOpenExistingDatabaseWithProgress};
use std::ffi::c_void;
use std::fmt::{Debug, Display, Formatter};
-use std::path::Path;
+use std::path::{Path, PathBuf};
use crate::progress::ProgressCallback;
use crate::project::file::ProjectFile;
@@ -46,12 +46,15 @@ impl FileMetadata {
Self::ref_from_raw(unsafe { BNCreateFileMetadata() })
}
- pub fn with_filename(name: &str) -> Ref<Self> {
+ /// Build a [`FileMetadata`] with the given `path`, this is uncommon as you are likely to want to
+ /// open a [`BinaryView`]
+ pub fn with_file_path(path: &Path) -> Ref<Self> {
let ret = FileMetadata::new();
- ret.set_filename(name);
+ ret.set_file_path(path);
ret
}
+ /// Closes the [`FileMetadata`] allowing any [`BinaryView`] parented to it to be freed.
pub fn close(&self) {
unsafe {
BNCloseFile(self.handle);
@@ -63,22 +66,124 @@ impl FileMetadata {
SessionId(raw)
}
- pub fn filename(&self) -> String {
+ /// The path to the [`FileMetadata`] on disk.
+ ///
+ /// This will not point to the original file on disk, in the event that the file was saved
+ /// as a BNDB. When a BNDB is opened, the FileMetadata will contain the file path to the database.
+ ///
+ /// If you need the original binary file path, use [`FileMetadata::original_file_path`] instead.
+ ///
+ /// If you just want a name to present to the user, use [`FileMetadata::display_name`].
+ pub fn file_path(&self) -> PathBuf {
unsafe {
let raw = BNGetFilename(self.handle);
- BnString::into_string(raw)
+ PathBuf::from(BnString::into_string(raw))
}
}
- pub fn set_filename(&self, name: &str) {
+ // TODO: To prevent issues we will not allow users to set the file path as it really should be
+ // TODO: derived at construction and not modified later.
+ /// Set the files path on disk.
+ ///
+ /// This should always be a valid path.
+ pub(crate) fn set_file_path(&self, name: &Path) {
let name = name.to_cstr();
-
unsafe {
BNSetFilename(self.handle, name.as_ptr());
}
}
- pub fn modified(&self) -> bool {
+ /// The display name of the file. Useful for presenting to the user. Can differ from the original
+ /// name of the file and can be overridden with [`FileMetadata::set_display_name`].
+ pub fn display_name(&self) -> String {
+ let raw_name = unsafe {
+ let raw = BNGetDisplayName(self.handle);
+ BnString::into_string(raw)
+ };
+ // Sometimes this display name may return a full path, which is not the intended purpose.
+ raw_name
+ .split('/')
+ .next_back()
+ .unwrap_or(&raw_name)
+ .to_string()
+ }
+
+ /// Set the display name of the file.
+ ///
+ /// This can be anything and will not be used for any purpose other than presentation.
+ pub fn set_display_name(&self, name: &str) {
+ let name = name.to_cstr();
+ unsafe {
+ BNSetDisplayName(self.handle, name.as_ptr());
+ }
+ }
+
+ /// The path to the original file on disk, if any.
+ ///
+ /// It may not be present if the BNDB was saved without it or cleared via [`FileMetadata::clear_original_file_path`].
+ ///
+ /// Only prefer this over [`FileMetadata::file_path`] if you require the original binary location.
+ pub fn original_file_path(&self) -> Option<PathBuf> {
+ let raw_name = unsafe {
+ let raw = BNGetOriginalFilename(self.handle);
+ PathBuf::from(BnString::into_string(raw))
+ };
+ // If the original file path is empty, or the original file path is pointing to the same file
+ // as the database itself, we know the original file path does not exist.
+ if raw_name.as_os_str().is_empty()
+ || self.is_database_backed() && raw_name == self.file_path()
+ {
+ None
+ } else {
+ Some(raw_name)
+ }
+ }
+
+ /// Set the original file path inside the database. Useful if it has since been cleared from the
+ /// database, or you have moved the original file.
+ pub fn set_original_file_path(&self, path: &Path) {
+ let name = path.to_cstr();
+ unsafe {
+ BNSetOriginalFilename(self.handle, name.as_ptr());
+ }
+ }
+
+ /// Clear the original file path inside the database. This is useful since the original file path
+ /// may be sensitive information you wish to not share with others.
+ pub fn clear_original_file_path(&self) {
+ unsafe {
+ BNSetOriginalFilename(self.handle, std::ptr::null());
+ }
+ }
+
+ /// The non-filesystem path that describes how this file was derived from the container
+ /// transform system, detailing the sequence of transform steps and selection names.
+ ///
+ /// NOTE: Returns `None` if this [`FileMetadata`] was not processed by the transform system and
+ /// does not differ from that of the "physical" file path reported by [`FileMetadata::file_path`].
+ pub fn virtual_path(&self) -> Option<String> {
+ unsafe {
+ let raw = BNGetVirtualPath(self.handle);
+ let path = BnString::into_string(raw);
+ // For whatever reason the core may report there being a virtual path as the file path.
+ // In the case where that occurs, we wish not to report there being one to the user.
+ match path.is_empty() || path == self.file_path() {
+ true => None,
+ false => Some(path),
+ }
+ }
+ }
+
+ /// Sets the non-filesystem path that describes how this file was derived from the container
+ /// transform system.
+ pub fn set_virtual_path(&self, path: &str) {
+ let path = path.to_cstr();
+ unsafe {
+ BNSetVirtualPath(self.handle, path.as_ptr());
+ }
+ }
+
+ pub fn is_modified(&self) -> bool {
unsafe { BNIsFileModified(self.handle) }
}
@@ -372,9 +477,10 @@ impl FileMetadata {
impl Debug for FileMetadata {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FileMetadata")
- .field("filename", &self.filename())
+ .field("file_path", &self.file_path())
+ .field("display_name", &self.display_name())
.field("session_id", &self.session_id())
- .field("modified", &self.modified())
+ .field("is_modified", &self.is_modified())
.field("is_analysis_changed", &self.is_analysis_changed())
.field("current_view_type", &self.current_view())
.field("current_offset", &self.current_offset())
@@ -385,7 +491,7 @@ impl Debug for FileMetadata {
impl Display for FileMetadata {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
- f.write_str(&self.filename())
+ f.write_str(&self.display_name())
}
}