summaryrefslogtreecommitdiff
path: root/rust/src/update.rs
diff options
context:
space:
mode:
authorRubens Brandao <git@rubens.io>2024-06-25 08:28:49 -0300
committerKyle Martin <krm504@nyu.edu>2024-07-09 18:52:38 -0400
commit1b22f189fc4b26fb383179f378b6d811e7c16083 (patch)
treeb6e43de70fcfd02ca6927a5e58e61c6f2b9f6614 /rust/src/update.rs
parent37ab27e142e43814669058dfc3d5845279c713d3 (diff)
implement rust Update
Diffstat (limited to 'rust/src/update.rs')
-rw-r--r--rust/src/update.rs272
1 files changed, 272 insertions, 0 deletions
diff --git a/rust/src/update.rs b/rust/src/update.rs
new file mode 100644
index 00000000..026316f5
--- /dev/null
+++ b/rust/src/update.rs
@@ -0,0 +1,272 @@
+use core::{ffi, mem, ptr};
+use std::time::{Duration, SystemTime, UNIX_EPOCH};
+
+use binaryninjacore_sys::*;
+
+use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner};
+use crate::string::BnString;
+
+pub type UpdateResult = BNUpdateResult;
+
+#[repr(C)]
+pub struct UpdateChannel {
+ pub name: BnString,
+ pub description: BnString,
+ pub latest_version: BnString,
+ // NOTE don't allow the user to create his own UpdateChannel
+ _lock: core::marker::PhantomData<()>,
+}
+
+impl UpdateChannel {
+ pub(crate) unsafe fn ref_from_raw(handle: &BNUpdateChannel) -> &Self {
+ mem::transmute(handle)
+ }
+
+ pub fn all() -> Result<Array<UpdateChannel>, BnString> {
+ let mut count = 0;
+ let mut errors = ptr::null_mut();
+ let result = unsafe { BNGetUpdateChannels(&mut count, &mut errors) };
+ if !errors.is_null() {
+ Err(unsafe { BnString::from_raw(errors) })
+ } else {
+ assert!(!result.is_null());
+ Ok(unsafe { Array::new(result, count, ()) })
+ }
+ }
+
+ /// List of versions
+ pub fn versions(&self) -> Result<Array<UpdateVersion>, BnString> {
+ let mut count = 0;
+ let mut errors = ptr::null_mut();
+ let result =
+ unsafe { BNGetUpdateChannelVersions(self.name.as_ptr(), &mut count, &mut errors) };
+ if !errors.is_null() {
+ Err(unsafe { BnString::from_raw(errors) })
+ } else {
+ assert!(!result.is_null());
+ Ok(unsafe { Array::new(result, count, ()) })
+ }
+ }
+
+ /// Latest version
+ pub fn latest_version(&self) -> Result<UpdateVersion, BnString> {
+ let last_version = &self.latest_version;
+ let versions = self.versions()?;
+ for version in &versions {
+ if &version.version == last_version {
+ return Ok(version.clone());
+ }
+ }
+ panic!();
+ }
+
+ /// Whether updates are available
+ pub fn updates_available(&self) -> Result<bool, BnString> {
+ let mut errors = ptr::null_mut();
+ let result = unsafe {
+ BNAreUpdatesAvailable(
+ self.name.as_ptr(),
+ ptr::null_mut(),
+ ptr::null_mut(),
+ &mut errors,
+ )
+ };
+ if !errors.is_null() {
+ Err(unsafe { BnString::from_raw(errors) })
+ } else {
+ Ok(result)
+ }
+ }
+
+ pub fn update_to_latest(&self) -> Result<UpdateResult, BnString> {
+ let mut errors = ptr::null_mut();
+ let result = unsafe {
+ BNUpdateToLatestVersion(
+ self.name.as_ptr(),
+ &mut errors,
+ Some(cb_progress_nop),
+ ptr::null_mut(),
+ )
+ };
+ if !errors.is_null() {
+ Err(unsafe { BnString::from_raw(errors) })
+ } else {
+ Ok(result)
+ }
+ }
+
+ pub fn update_to_latest_with_progress<F>(
+ &self,
+ mut progress: F,
+ ) -> Result<UpdateResult, BnString>
+ where
+ F: FnMut(u64, u64) -> bool,
+ {
+ let mut errors = ptr::null_mut();
+ let result = unsafe {
+ BNUpdateToLatestVersion(
+ self.name.as_ptr(),
+ &mut errors,
+ Some(cb_progress::<F>),
+ &mut progress as *mut _ as *mut ffi::c_void,
+ )
+ };
+ if !errors.is_null() {
+ Err(unsafe { BnString::from_raw(errors) })
+ } else {
+ Ok(result)
+ }
+ }
+
+ pub fn update(&self, version: &UpdateVersion) -> Result<UpdateResult, BnString> {
+ let mut errors = ptr::null_mut();
+ let result = unsafe {
+ BNUpdateToVersion(
+ self.name.as_ptr(),
+ version.version.as_ptr(),
+ &mut errors,
+ Some(cb_progress_nop),
+ ptr::null_mut(),
+ )
+ };
+ if !errors.is_null() {
+ Err(unsafe { BnString::from_raw(errors) })
+ } else {
+ Ok(result)
+ }
+ }
+
+ pub fn update_with_progress<F>(
+ &self,
+ version: &UpdateVersion,
+ mut progress: F,
+ ) -> Result<UpdateResult, BnString>
+ where
+ F: FnMut(u64, u64) -> bool,
+ {
+ let mut errors = ptr::null_mut();
+ let result = unsafe {
+ BNUpdateToVersion(
+ self.name.as_ptr(),
+ version.version.as_ptr(),
+ &mut errors,
+ Some(cb_progress::<F>),
+ &mut progress as *mut _ as *mut ffi::c_void,
+ )
+ };
+ if !errors.is_null() {
+ Err(unsafe { BnString::from_raw(errors) })
+ } else {
+ Ok(result)
+ }
+ }
+}
+
+impl CoreArrayProvider for UpdateChannel {
+ type Raw = BNUpdateChannel;
+ type Context = ();
+ type Wrapped<'a> = &'a Self;
+}
+
+unsafe impl CoreArrayProviderInner for UpdateChannel {
+ unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
+ BNFreeUpdateChannelList(raw, count)
+ }
+
+ unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
+ UpdateChannel::ref_from_raw(raw)
+ }
+}
+
+#[repr(C)]
+#[derive(Clone)]
+pub struct UpdateVersion {
+ pub version: BnString,
+ pub notes: BnString,
+ time: u64,
+ // NOTE don't allow the user to create his own UpdateVersion
+ _lock: core::marker::PhantomData<()>,
+}
+
+impl UpdateVersion {
+ pub(crate) unsafe fn ref_from_raw(handle: &BNUpdateVersion) -> &Self {
+ mem::transmute(handle)
+ }
+
+ pub fn time(&self) -> SystemTime {
+ UNIX_EPOCH + Duration::from_secs(self.time)
+ }
+
+ pub fn set_time(&mut self, time: SystemTime) {
+ let epoch = time.duration_since(UNIX_EPOCH).unwrap();
+ self.time = epoch.as_secs();
+ }
+}
+
+impl CoreArrayProvider for UpdateVersion {
+ type Raw = BNUpdateVersion;
+ type Context = ();
+ type Wrapped<'a> = &'a Self;
+}
+
+unsafe impl CoreArrayProviderInner for UpdateVersion {
+ unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
+ BNFreeUpdateChannelVersionList(raw, count)
+ }
+
+ unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
+ UpdateVersion::ref_from_raw(raw)
+ }
+}
+
+/// queries if auto updates are enabled.
+pub fn are_auto_updates_enabled() -> bool {
+ unsafe { BNAreAutoUpdatesEnabled() }
+}
+
+/// sets auto update enabled status.
+pub fn set_auto_updates_enabled(enabled: bool) {
+ unsafe { BNSetAutoUpdatesEnabled(enabled) }
+}
+
+/// returns the time stamp for the last time updates were checked.
+pub fn get_time_since_last_update_check() -> u64 {
+ unsafe { BNGetTimeSinceLastUpdateCheck() }
+}
+
+/// whether an update has been downloaded and is waiting installation
+pub fn is_update_installation_pending() -> bool {
+ unsafe { BNIsUpdateInstallationPending() }
+}
+
+/// installs any pending updates
+pub fn install_pending_update() -> Result<(), BnString> {
+ let mut errors = ptr::null_mut();
+ unsafe { BNInstallPendingUpdate(&mut errors) };
+ if !errors.is_null() {
+ Err(unsafe { BnString::from_raw(errors) })
+ } else {
+ Ok(())
+ }
+}
+
+pub fn updates_checked() {
+ unsafe { BNUpdatesChecked() }
+}
+
+unsafe extern "C" fn cb_progress_nop(
+ _ctxt: *mut ::std::os::raw::c_void,
+ _progress: u64,
+ _total: u64,
+) -> bool {
+ true
+}
+
+unsafe extern "C" fn cb_progress<F: FnMut(u64, u64) -> bool>(
+ ctxt: *mut ::std::os::raw::c_void,
+ progress: u64,
+ total: u64,
+) -> bool {
+ let ctxt: &mut F = &mut *(ctxt as *mut F);
+ ctxt(progress, total)
+}