binaryninja/
update.rs

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
24/// Whether an update has been downloaded and is waiting installation
25pub fn is_update_installation_pending() -> bool {
26    unsafe { BNIsUpdateInstallationPending() }
27}
28
29/// Installs any pending updates
30pub 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    /// List of versions
96    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    /// Latest version
110    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    /// Whether updates are available
122    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}