From 2be7b54b7bc7a0e46408b228ee55bbb4fe342e6c Mon Sep 17 00:00:00 2001 From: Alexander Khosrowshahi Date: Mon, 30 Jun 2025 14:56:41 -0400 Subject: [PATCH 1/3] Add GetPathInProject() to core API --- binaryninjaapi.h | 1 + binaryninjacore.h | 1 + examples/triage/fileinfo.cpp | 11 ++++++++++- project.cpp | 8 ++++++++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 66f40face0..0c86e02683 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -2878,6 +2878,7 @@ namespace BinaryNinja { Ref GetProject() const; std::string GetPathOnDisk() const; + std::string GetPathInProject() const; bool ExistsOnDisk() const; std::string GetName() const; std::string GetDescription() const; diff --git a/binaryninjacore.h b/binaryninjacore.h index 215cd6b236..e25b1b8fa9 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -4037,6 +4037,7 @@ extern "C" BINARYNINJACOREAPI void BNFreeProjectFile(BNProjectFile* file); BINARYNINJACOREAPI void BNFreeProjectFileList(BNProjectFile** files, size_t count); BINARYNINJACOREAPI char* BNProjectFileGetPathOnDisk(BNProjectFile* file); + BINARYNINJACOREAPI char* BNProjectFileGetPathInProject(BNProjectFile* file); BINARYNINJACOREAPI bool BNProjectFileExistsOnDisk(BNProjectFile* file); BINARYNINJACOREAPI char* BNProjectFileGetName(BNProjectFile* file); BINARYNINJACOREAPI bool BNProjectFileSetName(BNProjectFile* file, const char* name); diff --git a/examples/triage/fileinfo.cpp b/examples/triage/fileinfo.cpp index 3250feae6c..b521b8925f 100644 --- a/examples/triage/fileinfo.cpp +++ b/examples/triage/fileinfo.cpp @@ -72,9 +72,18 @@ FileInfoWidget::FileInfoWidget(QWidget* parent, BinaryViewRef bv) this->m_layout->setVerticalSpacing(1); const auto view = bv->GetParentView() ? bv->GetParentView() : bv; - const auto filePath = bv->GetFile()->GetOriginalFilename(); + + const auto file = bv->GetFile(); + const auto filePath = file->GetOriginalFilename(); this->addCopyableField("Path: ", filePath.c_str()); + // If triage view is opened from a project, show both actual filepath and path relative to project + if (const auto fileProjectRef = file->GetProjectFile()) + { + const auto projectFilePath = file->GetProjectFile()->GetPathInProject(); + this->addCopyableField("Path in project: ", projectFilePath.c_str()); + } + const auto fileSize = QString::number(view->GetLength(), 16).prepend("0x"); this->addCopyableField("Size: ", fileSize); diff --git a/project.cpp b/project.cpp index da4ee88d9e..6cb76a02e3 100644 --- a/project.cpp +++ b/project.cpp @@ -552,6 +552,14 @@ std::string ProjectFile::GetPathOnDisk() const return result; } +std::string ProjectFile::GetPathInProject() const +{ + char* path = BNProjectFileGetPathInProject(m_object); + std::string result = path; + BNFreeString(path); + return result; +} + bool ProjectFile::ExistsOnDisk() const { From dd5009bd17bc0d814c06d3a6962929084878f350 Mon Sep 17 00:00:00 2001 From: Alexander Khosrowshahi Date: Mon, 30 Jun 2025 15:05:08 -0400 Subject: [PATCH 2/3] Change 'Path' to 'Path on disk' in triage summary --- examples/triage/fileinfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/triage/fileinfo.cpp b/examples/triage/fileinfo.cpp index b521b8925f..5a9ba743a1 100644 --- a/examples/triage/fileinfo.cpp +++ b/examples/triage/fileinfo.cpp @@ -75,7 +75,7 @@ FileInfoWidget::FileInfoWidget(QWidget* parent, BinaryViewRef bv) const auto file = bv->GetFile(); const auto filePath = file->GetOriginalFilename(); - this->addCopyableField("Path: ", filePath.c_str()); + this->addCopyableField("Path on disk: ", filePath.c_str()); // If triage view is opened from a project, show both actual filepath and path relative to project if (const auto fileProjectRef = file->GetProjectFile()) From 533b8e546a00537d6945f5329decab4b74a5bf09 Mon Sep 17 00:00:00 2001 From: Alexander Khosrowshahi Date: Thu, 3 Jul 2025 13:53:40 -0400 Subject: [PATCH 3/3] Add get_files_by_path_in_project and get_path_in_project to C++ and python APIs --- binaryninjaapi.h | 3 ++- binaryninjacore.h | 3 ++- project.cpp | 21 +++++++++++++++- python/project.py | 53 +++++++++++++++++++++++++++++++++++++++ rust/tests/binary_view.rs | 3 ++- 5 files changed, 79 insertions(+), 4 deletions(-) diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 0c86e02683..2d21ef6d90 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -2938,7 +2938,8 @@ namespace BinaryNinja { Ref CreateFileUnsafe(const std::vector& contents, Ref folder, const std::string& name, const std::string& description, const std::string& id, int64_t creationTimestamp, const ProgressFunction& progressCallback = {}); std::vector> GetFiles() const; Ref GetFileById(const std::string& id) const; - Ref GetFileByPathOnDisk(const std::string& path); + Ref GetFileByPathOnDisk(const std::string& path) const; + std::vector> GetFilesByPathInProject(const std::string& path) const; void PushFile(Ref file); bool DeleteFile_(Ref file); diff --git a/binaryninjacore.h b/binaryninjacore.h index e25b1b8fa9..9e816a8a6b 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -4013,6 +4013,7 @@ extern "C" BINARYNINJACOREAPI BNProjectFile** BNProjectGetFiles(BNProject* project, size_t* count); BINARYNINJACOREAPI BNProjectFile* BNProjectGetFileById(BNProject* project, const char* id); BINARYNINJACOREAPI BNProjectFile* BNProjectGetFileByPathOnDisk(BNProject* project, const char* path); + BINARYNINJACOREAPI BNProjectFile** BNProjectGetFilesByPathInProject(BNProject* project, const char* path, size_t* count); BINARYNINJACOREAPI void BNProjectPushFile(BNProject* project, BNProjectFile* file); BINARYNINJACOREAPI bool BNProjectDeleteFile(BNProject* project, BNProjectFile* file); @@ -4037,7 +4038,7 @@ extern "C" BINARYNINJACOREAPI void BNFreeProjectFile(BNProjectFile* file); BINARYNINJACOREAPI void BNFreeProjectFileList(BNProjectFile** files, size_t count); BINARYNINJACOREAPI char* BNProjectFileGetPathOnDisk(BNProjectFile* file); - BINARYNINJACOREAPI char* BNProjectFileGetPathInProject(BNProjectFile* file); + BINARYNINJACOREAPI char* BNProjectFileGetPathInProject(const BNProjectFile* file); BINARYNINJACOREAPI bool BNProjectFileExistsOnDisk(BNProjectFile* file); BINARYNINJACOREAPI char* BNProjectFileGetName(BNProjectFile* file); BINARYNINJACOREAPI bool BNProjectFileSetName(BNProjectFile* file, const char* name); diff --git a/project.cpp b/project.cpp index 6cb76a02e3..e795db619f 100644 --- a/project.cpp +++ b/project.cpp @@ -477,7 +477,7 @@ Ref Project::GetFileById(const std::string& id) const } -Ref Project::GetFileByPathOnDisk(const std::string& path) +Ref Project::GetFileByPathOnDisk(const std::string& path) const { BNProjectFile* file = BNProjectGetFileByPathOnDisk(m_object, path.c_str()); if (file == nullptr) @@ -486,6 +486,25 @@ Ref Project::GetFileByPathOnDisk(const std::string& path) } +std::vector> Project::GetFilesByPathInProject( + const std::string& path +) const +{ + size_t count; + BNProjectFile** files = BNProjectGetFilesByPathInProject(m_object, path.c_str(), &count); + + std::vector> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + result.emplace_back(new ProjectFile(BNNewProjectFileReference(files[i]))); + } + + BNFreeProjectFileList(files, count); + return result; +} + + void Project::PushFile(Ref file) { BNProjectPushFile(m_object, file->m_object); diff --git a/python/project.py b/python/project.py index 4357f27683..c8f87d2f4c 100644 --- a/python/project.py +++ b/python/project.py @@ -190,6 +190,22 @@ def export(self, dest: AsPath) -> bool: """ return core.BNProjectFileExport(self._handle, str(dest)) + def get_path_on_disk(self) -> Optional[str]: + """ + Get this file's path on disk + + :return: The path on disk of the file or None + """ + return core.BNProjectFileGetPathOnDisk(self._handle) + + def get_path_in_project(self) -> Optional[str]: + """ + Get this file's path in its parent project + + :return: The path on disk of the file or None + """ + return core.BNProjectFileGetPathInProject(self._handle) + class ProjectFolder: """ @@ -650,6 +666,43 @@ def get_file_by_id(self, id: str) -> Optional[ProjectFile]: file = ProjectFile(handle) return file + def get_file_by_path_on_disk(self, path: str) -> Optional[ProjectFile]: + """ + Retrieve a file in the project by its path on disk + + :param path: Path of the file on the disk + :return: File with the requested path or None + """ + handle = core.BNProjectGetFileByPathOnDisk(self._handle, path) + if handle is None: + return None + file = ProjectFile(handle) + return file + + def get_files_by_path_in_project(self, path: str) -> List[ProjectFile]: + """ + Retrieve a file(s) by path in the project + Note that files in a project can share names and paths within the project + but are uniquely identified by a disk path or id. + + :param path: Path of the file(s) in the project, separate from their path on disk. + :return: List of files with the requested path + """ + count = ctypes.c_size_t() + value = core.BNProjectGetFilesByPathInProject(self._handle, path, count) + if value is None: + raise ProjectException("Failed to get list of project files by path in project") + result = [] + try: + for i in range(count.value): + file_handle = core.BNNewProjectFileReference(value[i]) + if file_handle is None: + raise ProjectException("core.BNNewProjectFileReference returned None") + result.append(ProjectFile(file_handle)) + return result + finally: + core.BNFreeProjectFileList(value, count.value) + def delete_file(self, file: ProjectFile) -> bool: """ Delete a file from the project diff --git a/rust/tests/binary_view.rs b/rust/tests/binary_view.rs index 2db96d6128..5e8206e062 100644 --- a/rust/tests/binary_view.rs +++ b/rust/tests/binary_view.rs @@ -106,7 +106,8 @@ fn test_binary_tags() { let view = binaryninja::load(out_dir.join("atox.obj")).expect("Failed to create view"); let tag_ty = view.create_tag_type("Test", ""); view.add_tag(0x0, &tag_ty, "t", false); - view.tag_type_by_name("Test").expect("Failed to get tag type"); + view.tag_type_by_name("Test") + .expect("Failed to get tag type"); } // These are the target files present in OUT_DIR