1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 // Mask for cffi purpose.
17 #![allow(non_camel_case_types)]
18 
19 pub(crate) mod basic_rust_types;
20 pub(crate) mod cloud_ext_types;
21 pub(crate) mod cloud_extension;
22 
23 use basic_rust_types::*;
24 use cloud_ext_types::*;
25 
26 use std::ffi::{c_int, c_uchar, c_uint, c_void};
27 use std::ptr::slice_from_raw_parts;
28 
29 /// Errno of success.
30 pub const ERRNO_SUCCESS: c_int = 0;
31 /// Errno of null pointer.
32 pub const ERRNO_NULLPTR: c_int = 1;
33 /// Errno of wrong type.
34 pub const ERRNO_WRONG_TYPE: c_int = 2;
35 /// Errno of invalid input type.
36 pub const ERRNO_INVALID_INPUT_TYPE: c_int = 3;
37 /// Errno of asset download failure.
38 pub const ERRNO_ASSET_DOWNLOAD_FAILURE: c_int = 4;
39 /// Errno of asset upload failure.
40 pub const ERRNO_ASSET_UPLOAD_FAILURE: c_int = 5;
41 /// Errno of unsupported feature.
42 pub const ERRNO_UNSUPPORTED: c_int = 6;
43 /// Errno of network error.
44 pub const ERRNO_NETWORK_ERROR: c_int = 7;
45 /// Errno of lock conflict.
46 pub const ERRNO_LOCKED_BY_OTHERS: c_int = 8;
47 /// Errno of locking action on unlocked cloud database.
48 pub const ERRNO_UNLOCKED: c_int = 9;
49 /// Errno of record limit exceeding.
50 pub const ERRNO_RECORD_LIMIT_EXCEEDED: c_int = 10;
51 /// Errno of no space for assets.
52 pub const ERRNO_NO_SPACE_FOR_ASSET: c_int = 11;
53 /// Errno of ipc read / write parcel error.
54 pub const ERRNO_IPC_RW_ERROR: c_int = 12;
55 /// Errno of IPC connection error.
56 pub const ERRNO_IPC_CONN_ERROR: c_int = 13;
57 /// Errno of batch of ipc errors.
58 pub const ERRNO_IPC_ERRORS: c_int = 14;
59 /// Errno of other io error.
60 pub const ERRNO_OTHER_IO_ERROR: c_int = 15;
61 /// Errno of array out of range.
62 pub const ERRNO_OUT_OF_RANGE: c_int = 16;
63 /// Errno of no target table in source database.
64 pub const ERRNO_NO_SUCH_TABLE_IN_DB: c_int = 17;
65 /// Errno of invalid status of the cloud
66 pub const ERRNO_CLOUD_INVALID_STATUS: c_int = 18;
67 /// Errno of unknown error.
68 pub const ERRNO_UNKNOWN: c_int = 19;
69 /// Errno of cloud disabling
70 pub const ERRNO_CLOUD_DISABLE: c_int = 20;
71 /// Errno of invalid key
72 pub const ERRNO_INVALID_KEY: c_int = 21;
73 
74 #[derive(Copy, Clone)]
75 pub(crate) enum SafetyCheckId {
76     // Arbitrarily defined id, used for type safety check
77     Vector = 32_isize,
78     HashMap = 33,
79     Value = 34,
80     CloudAsset = 35,
81     Database = 36,
82     CloudInfo = 37,
83     AppInfo = 38,
84     Table = 39,
85     Field = 40,
86     SchemaMeta = 41,
87     RelationSet = 42,
88     CloudDbData = 43,
89     ValueBucket = 44,
90     CloudAssetLoader = 45,
91     CloudDatabase = 46,
92     CloudSync = 47,
93 }
94 
95 impl SafetyCheckId {
as_usize(&self) -> usize96     pub(crate) fn as_usize(&self) -> usize {
97         *self as usize
98     }
99 }
100 
type_safety_check(ptr: *const c_void, tar_type: SafetyCheckId) -> bool101 pub(crate) unsafe fn type_safety_check(ptr: *const c_void, tar_type: SafetyCheckId) -> bool {
102     if ptr.is_null() {
103         return false;
104     }
105     // Read the id, if possible
106     let src = &*(ptr as *const usize);
107     *src == tar_type.as_usize()
108 }
109 
110 /// Wrapper of Rust struct. Add id for safety requirements, pointers passed in will be checked
111 /// according to this id.
112 #[repr(C)]
113 pub struct SafeCffiWrapper<T> {
114     id: usize,
115     inner: T,
116 }
117 
118 impl<T> SafeCffiWrapper<T> {
new(inner: T, tar_type: SafetyCheckId) -> SafeCffiWrapper<T>119     pub(crate) fn new(inner: T, tar_type: SafetyCheckId) -> SafeCffiWrapper<T> {
120         SafeCffiWrapper {
121             id: tar_type.as_usize(),
122             inner,
123         }
124     }
125 
into_ptr(self) -> *mut SafeCffiWrapper<T>126     pub(crate) fn into_ptr(self) -> *mut SafeCffiWrapper<T> {
127         Box::into_raw(Box::new(self))
128     }
129 
from_ptr( src: *mut SafeCffiWrapper<T>, typ: SafetyCheckId, ) -> Option<SafeCffiWrapper<T>>130     pub(crate) unsafe fn from_ptr(
131         src: *mut SafeCffiWrapper<T>,
132         typ: SafetyCheckId,
133     ) -> Option<SafeCffiWrapper<T>> {
134         src.as_mut().map(|obj| {
135             type_safety_check(obj as *const _ as *const c_void, typ)
136                 .then_some(*Box::from_raw(obj as *mut SafeCffiWrapper<T>))
137         })?
138     }
139 
get_inner_ref( src: *const SafeCffiWrapper<T>, typ: SafetyCheckId, ) -> Option<&'static T>140     pub(crate) unsafe fn get_inner_ref(
141         src: *const SafeCffiWrapper<T>,
142         typ: SafetyCheckId,
143     ) -> Option<&'static T> {
144         if let Some(obj) = src.as_ref() {
145             if type_safety_check(obj as *const _ as *const c_void, typ) {
146                 let wrapper = &*src;
147                 return Some(&wrapper.inner);
148             }
149         }
150         None
151     }
152 
get_inner_mut( src: *mut SafeCffiWrapper<T>, typ: SafetyCheckId, ) -> Option<&'static mut T>153     pub(crate) unsafe fn get_inner_mut(
154         src: *mut SafeCffiWrapper<T>,
155         typ: SafetyCheckId,
156     ) -> Option<&'static mut T> {
157         if let Some(obj) = src.as_mut() {
158             if type_safety_check(obj as *const _ as *const c_void, typ) {
159                 let wrapper = &mut *src;
160                 return Some(&mut wrapper.inner);
161             }
162         }
163         None
164     }
165 
get_inner(src: *mut SafeCffiWrapper<T>, typ: SafetyCheckId) -> Option<T>166     pub(crate) unsafe fn get_inner(src: *mut SafeCffiWrapper<T>, typ: SafetyCheckId) -> Option<T> {
167         SafeCffiWrapper::<T>::from_ptr(src, typ).map(|x| x.inner)
168     }
169 }
170 
171 /// Transform a pointer of c char array and its length to a String.
172 ///
173 /// # Safety
174 /// Users should guarantee that String doesn't contain non-UTF8 literals, and the length passed
175 /// in is valid to avoid memory issues and undefined behaviors.
char_ptr_to_string(ptr: *const c_uchar, len: c_uint) -> String176 pub(crate) unsafe fn char_ptr_to_string(ptr: *const c_uchar, len: c_uint) -> String {
177     if ptr.is_null() {
178         return String::default();
179     }
180     let slice = &(*slice_from_raw_parts(ptr, len as usize));
181     String::from_utf8_unchecked(slice.to_vec())
182 }
183 
184 #[cfg(test)]
185 mod test {
186     use crate::c_adapter::*;
187     use std::collections::HashMap;
188 
189     /// UT test for type wrapper.
190     ///
191     /// # Title
192     /// ut_wrapper
193     ///
194     /// # Brief
195     /// 1. Pass in type with wrong id.
196     /// 2. Process should not panic, but return Option successfully.
197     #[test]
ut_wrapper()198     fn ut_wrapper() {
199         unsafe {
200             let mut src = 3;
201             let mut wrong_typ = 1_usize;
202             assert_eq!(
203                 OhCloudExtVectorPush(
204                     &mut wrong_typ as *mut _ as *mut OhCloudExtVector,
205                     &mut src as *mut _ as *mut c_void,
206                     0
207                 ),
208                 ERRNO_WRONG_TYPE
209             );
210 
211             let map = HashMapCffi::U32(HashMap::new());
212             let mut wrong_map = OhCloudExtHashMap::new(map, SafetyCheckId::HashMap);
213             assert_eq!(
214                 OhCloudExtVectorPush(
215                     &mut wrong_map as *mut _ as *mut OhCloudExtVector,
216                     &mut src as *mut _ as *mut c_void,
217                     0
218                 ),
219                 ERRNO_WRONG_TYPE
220             );
221 
222             let vec = OhCloudExtVectorNew(OhCloudExtRustType::I32);
223             assert!(!vec.is_null());
224             assert_eq!(
225                 OhCloudExtVectorPush(vec, &mut src as *mut _ as *mut c_void, 0),
226                 ERRNO_SUCCESS
227             );
228             OhCloudExtVectorFree(vec);
229         }
230     }
231 }
232