1#![allow(dead_code)]
2use std::ffi::c_void;
3use std::time::{Duration, SystemTime, UNIX_EPOCH};
4
5use crate::progress::{NoProgressCallback, ProgressCallback};
6use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner};
7use crate::string::{raw_to_string, BnString, IntoCStr};
8use binaryninjacore_sys::*;
9
10pub type UpdateResult = BNUpdateResult;
11
12pub fn auto_updates_enabled() -> bool {
13 unsafe { BNAreAutoUpdatesEnabled() }
14}
15
16pub fn set_auto_updates_enabled(enabled: bool) {
17 unsafe { BNSetAutoUpdatesEnabled(enabled) }
18}
19
20pub fn time_since_last_update_check() -> Duration {
21 Duration::from_secs(unsafe { BNGetTimeSinceLastUpdateCheck() })
22}
23
24pub fn is_update_installation_pending() -> bool {
26 unsafe { BNIsUpdateInstallationPending() }
27}
28
29pub fn install_pending_update() -> Result<(), BnString> {
31 let mut errors = std::ptr::null_mut();
32 unsafe { BNInstallPendingUpdate(&mut errors) };
33 if !errors.is_null() {
34 Err(unsafe { BnString::from_raw(errors) })
35 } else {
36 Ok(())
37 }
38}
39
40pub fn updates_checked() {
41 unsafe { BNUpdatesChecked() }
42}
43
44#[derive(Clone, Debug)]
45pub struct UpdateChannel {
46 pub name: String,
47 pub description: String,
48 pub latest_version: String,
49}
50
51impl UpdateChannel {
52 pub(crate) fn from_raw(value: &BNUpdateChannel) -> Self {
53 Self {
54 name: raw_to_string(value.name as *mut _).unwrap(),
55 description: raw_to_string(value.description as *mut _).unwrap(),
56 latest_version: raw_to_string(value.latestVersion as *mut _).unwrap(),
57 }
58 }
59
60 pub(crate) fn from_owned_raw(value: BNUpdateChannel) -> Self {
61 let owned = Self::from_raw(&value);
62 Self::free_raw(value);
63 owned
64 }
65
66 pub(crate) fn into_raw(value: Self) -> BNUpdateChannel {
67 let bn_name = BnString::new(value.name);
68 let bn_description = BnString::new(value.description);
69 let bn_latest_version = BnString::new(value.latest_version);
70 BNUpdateChannel {
71 name: BnString::into_raw(bn_name),
72 description: BnString::into_raw(bn_description),
73 latestVersion: BnString::into_raw(bn_latest_version),
74 }
75 }
76
77 pub(crate) fn free_raw(value: BNUpdateChannel) {
78 unsafe { BnString::free_raw(value.name) };
79 unsafe { BnString::free_raw(value.description) };
80 unsafe { BnString::free_raw(value.latestVersion) };
81 }
82
83 pub fn all() -> Result<Array<UpdateChannel>, BnString> {
84 let mut count = 0;
85 let mut errors = std::ptr::null_mut();
86 let result = unsafe { BNGetUpdateChannels(&mut count, &mut errors) };
87 if !errors.is_null() {
88 Err(unsafe { BnString::from_raw(errors) })
89 } else {
90 assert!(!result.is_null());
91 Ok(unsafe { Array::new(result, count, ()) })
92 }
93 }
94
95 pub fn versions(&self) -> Result<Array<UpdateVersion>, BnString> {
97 let mut count = 0;
98 let mut errors = std::ptr::null_mut();
99 let name = self.name.clone().to_cstr();
100 let result = unsafe { BNGetUpdateChannelVersions(name.as_ptr(), &mut count, &mut errors) };
101 if !errors.is_null() {
102 Err(unsafe { BnString::from_raw(errors) })
103 } else {
104 assert!(!result.is_null());
105 Ok(unsafe { Array::new(result, count, ()) })
106 }
107 }
108
109 pub fn latest_version(&self) -> Result<UpdateVersion, BnString> {
111 let last_version = &self.latest_version;
112 let versions = self.versions()?;
113 for version in &versions {
114 if &version.version == last_version {
115 return Ok(version);
116 }
117 }
118 Err(BnString::new("Could not find latest version"))
119 }
120
121 pub fn updates_available(&self) -> Result<bool, BnString> {
123 let mut errors = std::ptr::null_mut();
124 let name = self.name.clone().to_cstr();
125 let result = unsafe {
126 BNAreUpdatesAvailable(
127 name.as_ptr(),
128 std::ptr::null_mut(),
129 std::ptr::null_mut(),
130 &mut errors,
131 )
132 };
133 if !errors.is_null() {
134 Err(unsafe { BnString::from_raw(errors) })
135 } else {
136 Ok(result)
137 }
138 }
139
140 pub fn update_to_latest(&self) -> Result<UpdateResult, BnString> {
141 self.update_to_latest_with_progress(NoProgressCallback)
142 }
143
144 pub fn update_to_latest_with_progress<P: ProgressCallback>(
145 &self,
146 mut progress: P,
147 ) -> Result<UpdateResult, BnString> {
148 let mut errors = std::ptr::null_mut();
149
150 let name = self.name.clone().to_cstr();
151 let result = unsafe {
152 BNUpdateToLatestVersion(
153 name.as_ptr(),
154 &mut errors,
155 Some(P::cb_progress_callback),
156 &mut progress as *mut P as *mut c_void,
157 )
158 };
159
160 if !errors.is_null() {
161 Err(unsafe { BnString::from_raw(errors) })
162 } else {
163 Ok(result)
164 }
165 }
166
167 pub fn update(&self, version: &UpdateVersion) -> Result<UpdateResult, BnString> {
168 self.update_with_progress(version, NoProgressCallback)
169 }
170
171 pub fn update_with_progress<P: ProgressCallback>(
172 &self,
173 version: &UpdateVersion,
174 mut progress: P,
175 ) -> Result<UpdateResult, BnString> {
176 let mut errors = std::ptr::null_mut();
177
178 let name = self.name.clone().to_cstr();
179 let version = version.version.clone().to_cstr();
180 let result = unsafe {
181 BNUpdateToVersion(
182 name.as_ptr(),
183 version.as_ptr(),
184 &mut errors,
185 Some(P::cb_progress_callback),
186 &mut progress as *mut P as *mut c_void,
187 )
188 };
189
190 if !errors.is_null() {
191 Err(unsafe { BnString::from_raw(errors) })
192 } else {
193 Ok(result)
194 }
195 }
196}
197
198impl CoreArrayProvider for UpdateChannel {
199 type Raw = BNUpdateChannel;
200 type Context = ();
201 type Wrapped<'a> = Self;
202}
203
204unsafe impl CoreArrayProviderInner for UpdateChannel {
205 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
206 BNFreeUpdateChannelList(raw, count)
207 }
208
209 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
210 UpdateChannel::from_raw(raw)
211 }
212}
213
214#[derive(Clone)]
215pub struct UpdateVersion {
216 pub version: String,
217 pub notes: String,
218 pub time: SystemTime,
219}
220
221impl UpdateVersion {
222 pub(crate) fn from_raw(value: &BNUpdateVersion) -> Self {
223 Self {
224 version: raw_to_string(value.version as *mut _).unwrap(),
225 notes: raw_to_string(value.notes as *mut _).unwrap(),
226 time: UNIX_EPOCH + Duration::from_secs(value.time),
227 }
228 }
229
230 pub(crate) fn from_owned_raw(value: BNUpdateVersion) -> Self {
231 let owned = Self::from_raw(&value);
232 Self::free_raw(value);
233 owned
234 }
235
236 pub(crate) fn into_raw(value: Self) -> BNUpdateVersion {
237 let bn_version = BnString::new(value.version);
238 let bn_notes = BnString::new(value.notes);
239 let epoch = value.time.duration_since(UNIX_EPOCH).unwrap();
240 BNUpdateVersion {
241 version: BnString::into_raw(bn_version),
242 notes: BnString::into_raw(bn_notes),
243 time: epoch.as_secs(),
244 }
245 }
246
247 pub(crate) fn free_raw(value: BNUpdateVersion) {
248 unsafe { BnString::free_raw(value.version) };
249 unsafe { BnString::free_raw(value.notes) };
250 }
251}
252
253impl CoreArrayProvider for UpdateVersion {
254 type Raw = BNUpdateVersion;
255 type Context = ();
256 type Wrapped<'a> = Self;
257}
258
259unsafe impl CoreArrayProviderInner for UpdateVersion {
260 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
261 BNFreeUpdateChannelVersionList(raw, count)
262 }
263
264 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
265 UpdateVersion::from_raw(raw)
266 }
267}