binaryninja/
file_accessor.rs1use binaryninjacore_sys::BNFileAccessor;
16use std::io::{ErrorKind, Read, Seek, SeekFrom, Write};
17use std::marker::PhantomData;
18use std::slice;
19
20pub trait Accessor: Read + Write + Seek + Sized {}
21
22impl<T: Read + Write + Seek + Sized> Accessor for T {}
23
24pub struct FileAccessor<A: Accessor> {
25 pub(crate) raw: BNFileAccessor,
26 accessor: PhantomData<A>,
27}
28
29impl<A: Accessor> FileAccessor<A> {
30 pub fn new(accessor: A) -> Self {
31 use std::os::raw::c_void;
32
33 extern "C" fn cb_get_length<A: Accessor>(ctxt: *mut c_void) -> u64 {
34 let f = unsafe { &mut *(ctxt as *mut A) };
35
36 f.seek(SeekFrom::End(0)).unwrap_or(0)
37 }
38
39 extern "C" fn cb_read<A: Accessor>(
40 ctxt: *mut c_void,
41 dest: *mut c_void,
42 offset: u64,
43 len: usize,
44 ) -> usize {
45 let f = unsafe { &mut *(ctxt as *mut A) };
46 let dest = unsafe { slice::from_raw_parts_mut(dest as *mut u8, len) };
47
48 if f.seek(SeekFrom::Start(offset)).is_err() {
49 0
50 } else {
51 f.read(dest).unwrap_or(0)
52 }
53 }
54
55 extern "C" fn cb_write<A: Accessor>(
56 ctxt: *mut c_void,
57 offset: u64,
58 src: *const c_void,
59 len: usize,
60 ) -> usize {
61 let f = unsafe { &mut *(ctxt as *mut A) };
62 let src = unsafe { slice::from_raw_parts(src as *const u8, len) };
63
64 if f.seek(SeekFrom::Start(offset)).is_err() {
65 0
66 } else {
67 f.write(src).unwrap_or(0)
68 }
69 }
70
71 let boxed_accessor = Box::new(accessor);
72 let leaked_accessor = Box::leak(boxed_accessor);
73
74 Self {
75 raw: BNFileAccessor {
76 context: leaked_accessor as *mut A as *mut _,
77 getLength: Some(cb_get_length::<A>),
78 read: Some(cb_read::<A>),
79 write: Some(cb_write::<A>),
80 },
81 accessor: PhantomData,
82 }
83 }
84
85 pub fn read(&self, addr: u64, len: usize) -> Result<Vec<u8>, ErrorKind> {
86 let cb_read = self.raw.read.unwrap();
87 let mut buf = vec![0; len];
88 let read_len = unsafe { cb_read(self.raw.context, buf.as_mut_ptr() as *mut _, addr, len) };
89 if read_len != len {
90 return Err(ErrorKind::UnexpectedEof);
91 }
92 Ok(buf)
93 }
94
95 pub fn write(&self, addr: u64, data: &[u8]) -> usize {
96 let cb_write = self.raw.write.unwrap();
97 unsafe {
98 cb_write(
99 self.raw.context,
100 addr,
101 data.as_ptr() as *const _,
102 data.len(),
103 )
104 }
105 }
106
107 pub fn length(&self) -> u64 {
108 let cb_get_length = self.raw.getLength.unwrap();
109 unsafe { cb_get_length(self.raw.context) }
110 }
111}
112
113impl<A: Accessor> Drop for FileAccessor<A> {
114 fn drop(&mut self) {
115 unsafe {
116 let _ = Box::from_raw(self.raw.context as *mut A);
117 }
118 }
119}
120
121pub struct BorrowedFileAccessor<'a> {
128 pub(crate) raw: &'a mut BNFileAccessor,
129}
130
131impl<'a> BorrowedFileAccessor<'a> {
132 pub(crate) unsafe fn from_raw(raw: *mut BNFileAccessor) -> Self {
133 debug_assert!(!raw.is_null());
134 Self {
135 raw: unsafe { &mut *raw },
136 }
137 }
138
139 pub fn read(&self, addr: u64, len: usize) -> Result<Vec<u8>, ErrorKind> {
140 let cb_read = self.raw.read.unwrap();
141 let mut buf = vec![0; len];
142 let read_len = unsafe { cb_read(self.raw.context, buf.as_mut_ptr() as *mut _, addr, len) };
143 if read_len != len {
144 return Err(ErrorKind::UnexpectedEof);
145 }
146 Ok(buf)
147 }
148
149 pub fn write(&self, addr: u64, data: &[u8]) -> usize {
150 let cb_write = self.raw.write.unwrap();
151 unsafe {
152 cb_write(
153 self.raw.context,
154 addr,
155 data.as_ptr() as *const _,
156 data.len(),
157 )
158 }
159 }
160
161 pub fn length(&self) -> u64 {
162 let cb_get_length = self.raw.getLength.unwrap();
163 unsafe { cb_get_length(self.raw.context) }
164 }
165}
166
167mod private {
169 use binaryninjacore_sys::BNFileAccessor;
170
171 pub trait Sealed {
172 fn raw_mut(&mut self) -> &mut BNFileAccessor;
173 }
174}
175
176#[allow(private_bounds)]
180pub trait FileAccessorHandle: private::Sealed {}
181
182impl<T: private::Sealed + ?Sized> FileAccessorHandle for T {}
183
184impl<A: Accessor> private::Sealed for FileAccessor<A> {
185 fn raw_mut(&mut self) -> &mut BNFileAccessor {
186 &mut self.raw
187 }
188}
189
190impl private::Sealed for BorrowedFileAccessor<'_> {
191 fn raw_mut(&mut self) -> &mut BNFileAccessor {
192 self.raw
193 }
194}
195
196pub(crate) fn raw_mut<T: FileAccessorHandle + ?Sized>(accessor: &mut T) -> &mut BNFileAccessor {
197 private::Sealed::raw_mut(accessor)
198}