binaryninja/collaboration/
folder.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
use super::{Remote, RemoteProject};
use binaryninjacore_sys::*;
use std::ffi::c_char;
use std::ptr::NonNull;

use crate::project::folder::ProjectFolder;
use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable};
use crate::string::{BnStrCompatible, BnString};

#[repr(transparent)]
pub struct RemoteFolder {
    pub(crate) handle: NonNull<BNRemoteFolder>,
}

impl RemoteFolder {
    pub(crate) unsafe fn from_raw(handle: NonNull<BNRemoteFolder>) -> Self {
        Self { handle }
    }

    pub(crate) unsafe fn ref_from_raw(handle: NonNull<BNRemoteFolder>) -> Ref<Self> {
        Ref::new(Self { handle })
    }

    // TODO: Rename to local folder?
    // TODO: Bump this to an option
    /// Get the core folder associated with this remote folder.
    pub fn core_folder(&self) -> Result<Ref<ProjectFolder>, ()> {
        let result = unsafe { BNRemoteFolderGetCoreFolder(self.handle.as_ptr()) };
        NonNull::new(result)
            .map(|handle| unsafe { ProjectFolder::ref_from_raw(handle) })
            .ok_or(())
    }

    // TODO: Bump this to an option
    /// Get the owning project of this folder.
    pub fn project(&self) -> Result<Ref<RemoteProject>, ()> {
        let result = unsafe { BNRemoteFolderGetProject(self.handle.as_ptr()) };
        NonNull::new(result)
            .map(|handle| unsafe { RemoteProject::ref_from_raw(handle) })
            .ok_or(())
    }

    // TODO: Bump this to an option
    /// Get the owning remote of this folder.
    pub fn remote(&self) -> Result<Ref<Remote>, ()> {
        let result = unsafe { BNRemoteFolderGetRemote(self.handle.as_ptr()) };
        NonNull::new(result)
            .map(|handle| unsafe { Remote::ref_from_raw(handle) })
            .ok_or(())
    }

    // TODO: Should this pull folders?
    // TODO: If it does we keep the result?
    /// Get the parent folder, if available.
    pub fn parent(&self) -> Result<Option<Ref<RemoteFolder>>, ()> {
        let project = self.project()?;
        // TODO: This sync should be removed?
        if !project.has_pulled_folders() {
            project.pull_folders()?;
        }
        let mut parent_handle = std::ptr::null_mut();
        let success = unsafe { BNRemoteFolderGetParent(self.handle.as_ptr(), &mut parent_handle) };
        success
            .then(|| {
                NonNull::new(parent_handle)
                    .map(|handle| unsafe { RemoteFolder::ref_from_raw(handle) })
            })
            .ok_or(())
    }

    /// Set the parent folder. You will need to push the folder to update the remote version.
    pub fn set_parent(&self, parent: Option<&RemoteFolder>) -> Result<(), ()> {
        let parent_handle = parent.map_or(std::ptr::null_mut(), |p| p.handle.as_ptr());
        let success = unsafe { BNRemoteFolderSetParent(self.handle.as_ptr(), parent_handle) };
        success.then_some(()).ok_or(())
    }

    /// Get web API endpoint URL.
    pub fn url(&self) -> BnString {
        let result = unsafe { BNRemoteFolderGetUrl(self.handle.as_ptr()) };
        assert!(!result.is_null());
        unsafe { BnString::from_raw(result) }
    }

    /// Get unique ID.
    pub fn id(&self) -> BnString {
        let result = unsafe { BNRemoteFolderGetId(self.handle.as_ptr()) };
        assert!(!result.is_null());
        unsafe { BnString::from_raw(result) }
    }

    /// Unique id of parent folder, if there is a parent. None, otherwise
    pub fn parent_id(&self) -> Option<BnString> {
        let mut parent_id = std::ptr::null_mut();
        let have = unsafe { BNRemoteFolderGetParentId(self.handle.as_ptr(), &mut parent_id) };
        have.then(|| unsafe { BnString::from_raw(parent_id) })
    }

    /// Displayed name of folder
    pub fn name(&self) -> BnString {
        let result = unsafe { BNRemoteFolderGetName(self.handle.as_ptr()) };
        assert!(!result.is_null());
        unsafe { BnString::from_raw(result) }
    }

    /// Set the display name of the folder. You will need to push the folder to update the remote version.
    pub fn set_name<S: BnStrCompatible>(&self, name: S) -> Result<(), ()> {
        let name = name.into_bytes_with_nul();
        let success = unsafe {
            BNRemoteFolderSetName(
                self.handle.as_ptr(),
                name.as_ref().as_ptr() as *const c_char,
            )
        };
        success.then_some(()).ok_or(())
    }

    /// Description of the folder
    pub fn description(&self) -> BnString {
        let result = unsafe { BNRemoteFolderGetDescription(self.handle.as_ptr()) };
        assert!(!result.is_null());
        unsafe { BnString::from_raw(result) }
    }

    /// Set the description of the folder. You will need to push the folder to update the remote version.
    pub fn set_description<S: BnStrCompatible>(&self, description: S) -> Result<(), ()> {
        let description = description.into_bytes_with_nul();
        let success = unsafe {
            BNRemoteFolderSetDescription(
                self.handle.as_ptr(),
                description.as_ref().as_ptr() as *const c_char,
            )
        };
        success.then_some(()).ok_or(())
    }
}

impl PartialEq for RemoteFolder {
    fn eq(&self, other: &Self) -> bool {
        self.id() == other.id()
    }
}
impl Eq for RemoteFolder {}

impl ToOwned for RemoteFolder {
    type Owned = Ref<Self>;

    fn to_owned(&self) -> Self::Owned {
        unsafe { RefCountable::inc_ref(self) }
    }
}

unsafe impl RefCountable for RemoteFolder {
    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
        Ref::new(Self {
            handle: NonNull::new(BNNewRemoteFolderReference(handle.handle.as_ptr())).unwrap(),
        })
    }

    unsafe fn dec_ref(handle: &Self) {
        BNFreeRemoteFolder(handle.handle.as_ptr());
    }
}

impl CoreArrayProvider for RemoteFolder {
    type Raw = *mut BNRemoteFolder;
    type Context = ();
    type Wrapped<'a> = Guard<'a, Self>;
}

unsafe impl CoreArrayProviderInner for RemoteFolder {
    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
        BNFreeRemoteFolderList(raw, count)
    }

    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
        let raw_ptr = NonNull::new(*raw).unwrap();
        Guard::new(Self::from_raw(raw_ptr), context)
    }
}