1+ use std:: borrow:: Cow ;
2+ use std:: collections:: HashMap ;
3+ use std:: fs;
4+ use std:: io:: Write ;
15use std:: os:: raw:: c_char;
26use std:: ptr:: copy_nonoverlapping;
37use std:: slice:: from_raw_parts;
4- use serde_json:: { Value } ;
5- use std:: collections:: HashMap ;
6- use tempfile:: NamedTempFile ;
7- use std:: io:: { Write } ;
8- use std:: fs;
98use std:: str;
109
10+ use serde_json:: Value ;
11+ use tempfile:: NamedTempFile ;
12+
1113const ERR_NONE : i32 = 0 ;
1214
1315//One of the provided pointers is NULL / nil / 0
@@ -42,14 +44,16 @@ static MAXIMUM_BUFFER_SIZE: i32 = i32::MAX;
4244
4345#[ cfg( feature = "cobhan_debug" ) ]
4446macro_rules! debug_print {
45- ( $( $args: expr ) ,* ) => { println!( $ ( $args ) ,* ) ; }
47+ ( $( $args: expr ) ,* ) => { println!( $ ( $args ) ,* ) ; } ;
4648}
4749
4850#[ cfg( not( feature = "cobhan_debug" ) ) ]
4951macro_rules! debug_print {
50- ( $( $args: expr ) ,* ) => { }
52+ ( $( $args: expr ) ,* ) => { } ;
5153}
5254
55+ /// ## Safety
56+ /// tbd
5357pub unsafe fn cbuffer_to_vector ( buffer : * const c_char ) -> Result < Vec < u8 > , i32 > {
5458 if buffer. is_null ( ) {
5559 debug_print ! ( "cbuffer_to_vector: buffer is NULL" ) ;
@@ -61,8 +65,12 @@ pub unsafe fn cbuffer_to_vector(buffer: *const c_char) -> Result<Vec<u8>, i32> {
6165 debug_print ! ( "cbuffer_to_vector: raw length field is {}" , length) ;
6266
6367 if length > MAXIMUM_BUFFER_SIZE {
64- debug_print ! ( "cbuffer_to_vector: length {} is larger than MAXIMUM_BUFFER_SIZE ({})" , length, MAXIMUM_BUFFER_SIZE ) ;
65- return Err ( ERR_BUFFER_TOO_LARGE )
68+ debug_print ! (
69+ "cbuffer_to_vector: length {} is larger than MAXIMUM_BUFFER_SIZE ({})" ,
70+ length,
71+ MAXIMUM_BUFFER_SIZE
72+ ) ;
73+ return Err ( ERR_BUFFER_TOO_LARGE ) ;
6674 }
6775 if length < 0 {
6876 debug_print ! ( "cbuffer_to_vector: calling temp_to_vector" ) ;
@@ -73,25 +81,8 @@ pub unsafe fn cbuffer_to_vector(buffer: *const c_char) -> Result<Vec<u8>, i32> {
7381 Ok ( from_raw_parts ( payload, length as usize ) . to_vec ( ) )
7482}
7583
76- unsafe fn temp_to_vector ( payload : * const u8 , length : i32 ) -> Result < Vec < u8 > , i32 > {
77- let file_name;
78- match str:: from_utf8 ( from_raw_parts ( payload, ( 0 - length) as usize ) ) {
79- Ok ( f) => file_name = f,
80- Err ( ..) => {
81- debug_print ! ( "temp_to_vector: temp file name is invalid utf-8 string (length = {})" , 0 - length) ;
82- return Err ( ERR_INVALID_UTF8 ) ;
83- }
84- }
85-
86- return match fs:: read ( file_name) {
87- Ok ( s) => Ok ( s) ,
88- Err ( _e) => {
89- debug_print ! ( "temp_to_vector: failed to read temporary file {}: {}" , file_name, _e) ;
90- Err ( ERR_READ_TEMP_FILE_FAILED )
91- }
92- }
93- }
94-
84+ /// ## Safety
85+ /// tbd
9586pub unsafe fn cbuffer_to_string ( buffer : * const c_char ) -> Result < String , i32 > {
9687 if buffer. is_null ( ) {
9788 debug_print ! ( "cbuffer_to_string: buffer is NULL" ) ;
@@ -103,49 +94,79 @@ pub unsafe fn cbuffer_to_string(buffer: *const c_char) -> Result<String, i32> {
10394 debug_print ! ( "cbuffer_to_string: raw length field is {}" , length) ;
10495
10596 if length > MAXIMUM_BUFFER_SIZE {
106- debug_print ! ( "cbuffer_to_string: length {} is larger than MAXIMUM_BUFFER_SIZE ({})" , length, MAXIMUM_BUFFER_SIZE ) ;
97+ debug_print ! (
98+ "cbuffer_to_string: length {} is larger than MAXIMUM_BUFFER_SIZE ({})" ,
99+ length,
100+ MAXIMUM_BUFFER_SIZE
101+ ) ;
107102 return Err ( ERR_BUFFER_TOO_LARGE ) ;
108103 }
109104
110105 debug_print ! ( "cbuffer_to_string: raw length field is {}" , length) ;
111106
112107 if length < 0 {
113108 debug_print ! ( "cbuffer_to_string: calling temp_to_string" ) ;
114- return temp_to_string ( payload, length)
109+ return temp_to_string ( payload, length) ;
115110 }
116111
117- //Allocation: to_vec() is a clone/copy
118- return match String :: from_utf8 ( from_raw_parts ( payload, length as usize ) . to_vec ( ) ) {
119- Ok ( input_str) => Ok ( input_str) ,
120- Err ( ..) => {
121- debug_print ! ( "cbuffer_to_string: payload is invalid utf-8 string (length = {})" , length) ;
122- Err ( ERR_INVALID_UTF8 )
123- }
124- }
112+ str:: from_utf8 ( from_raw_parts ( payload, length as usize ) )
113+ . map ( |s| s. to_owned ( ) )
114+ . map_err ( |_| {
115+ debug_print ! (
116+ "cbuffer_to_string: payload is invalid utf-8 string (length = {})" ,
117+ length
118+ ) ;
119+ ERR_INVALID_UTF8
120+ } )
125121}
126122
127123unsafe fn temp_to_string ( payload : * const u8 , length : i32 ) -> Result < String , i32 > {
128- let file_name;
129- match str:: from_utf8 ( from_raw_parts ( payload, ( 0 - length) as usize ) ) {
130- Ok ( f ) => file_name = f ,
131- Err ( .. ) => {
132- debug_print ! ( "temp_to_string: temp file name is invalid utf-8 string (length = {})" , 0 - length) ;
133- return Err ( ERR_INVALID_UTF8 ) ;
134- }
135- }
124+ let file_name =
125+ str:: from_utf8 ( from_raw_parts ( payload, ( 0 - length) as usize ) ) . map_err ( |_| {
126+ debug_print ! (
127+ "temp_to_string: temp file name is invalid utf-8 string (length = {})" ,
128+ 0 - length
129+ ) ;
130+ ERR_INVALID_UTF8
131+ } ) ? ;
136132
137133 debug_print ! ( "temp_to_string: reading temp file {}" , file_name) ;
138134
139- return match fs:: read_to_string ( file_name) {
140- Ok ( s) => Ok ( s) ,
141- Err ( _e) => {
142- debug_print ! ( "temp_to_string: Error reading temp file {}: {}" , file_name, _e) ;
143- Err ( ERR_READ_TEMP_FILE_FAILED )
144- }
145- }
135+ fs:: read_to_string ( file_name) . map_err ( |_e| {
136+ debug_print ! (
137+ "temp_to_string: Error reading temp file {}: {}" ,
138+ file_name,
139+ _e
140+ ) ;
141+ ERR_READ_TEMP_FILE_FAILED
142+ } )
143+ }
144+
145+ unsafe fn temp_to_vector ( payload : * const u8 , length : i32 ) -> Result < Vec < u8 > , i32 > {
146+ let file_name =
147+ str:: from_utf8 ( from_raw_parts ( payload, ( 0 - length) as usize ) ) . map_err ( |_| {
148+ debug_print ! (
149+ "temp_to_vector: temp file name is invalid utf-8 string (length = {})" ,
150+ 0 - length
151+ ) ;
152+ ERR_INVALID_UTF8
153+ } ) ?;
154+
155+ fs:: read ( file_name) . map_err ( |_e| {
156+ debug_print ! (
157+ "temp_to_vector: failed to read temporary file {}: {}" ,
158+ file_name,
159+ _e
160+ ) ;
161+ ERR_READ_TEMP_FILE_FAILED
162+ } )
146163}
147164
148- pub unsafe fn cbuffer_to_hashmap_json ( buffer : * const c_char ) -> Result < HashMap < String , Value > , i32 > {
165+ /// ## Safety
166+ /// tbd
167+ pub unsafe fn cbuffer_to_hashmap_json (
168+ buffer : * const c_char ,
169+ ) -> Result < HashMap < String , Value > , i32 > {
149170 if buffer. is_null ( ) {
150171 debug_print ! ( "cbuffer_to_hashmap_json: buffer is NULL" ) ;
151172 return Err ( ERR_NULL_PTR ) ;
@@ -155,56 +176,50 @@ pub unsafe fn cbuffer_to_hashmap_json(buffer: *const c_char) -> Result<HashMap<S
155176 let payload = buffer. offset ( BUFFER_HEADER_SIZE ) as * const u8 ;
156177 debug_print ! ( "cbuffer_to_hashmap_json: raw length field is {}" , length) ;
157178
158-
159179 if length > MAXIMUM_BUFFER_SIZE {
160- debug_print ! ( "cbuffer_to_hashmap_json: length {} is larger than MAXIMUM_BUFFER_SIZE ({})" , length, MAXIMUM_BUFFER_SIZE ) ;
180+ debug_print ! (
181+ "cbuffer_to_hashmap_json: length {} is larger than MAXIMUM_BUFFER_SIZE ({})" ,
182+ length,
183+ MAXIMUM_BUFFER_SIZE
184+ ) ;
161185 return Err ( ERR_BUFFER_TOO_LARGE ) ;
162186 }
163187
164188 debug_print ! ( "cbuffer_to_hashmap_json: raw length field is {}" , length) ;
165189
166- let json_str;
167- let temp_string_result;
168- if length >= 0 {
169- match str:: from_utf8 ( from_raw_parts ( payload, length as usize ) ) {
170- Ok ( input_str) => json_str = input_str,
171- Err ( ..) => {
172- debug_print ! ( "cbuffer_to_hashmap_json: payload is invalid utf-8 string (length = {})" , length) ;
173- return Err ( ERR_INVALID_UTF8 ) ;
174- }
175- }
190+ let json_bytes = if length >= 0 {
191+ Cow :: Borrowed ( from_raw_parts ( payload, length as usize ) )
176192 } else {
177- debug_print ! ( "cbuffer_to_hashmap_json: calling temp_to_string" ) ;
178- match temp_to_string ( payload, length) {
179- Ok ( string) => {
180- temp_string_result = string;
181- json_str = & temp_string_result;
182- } ,
183- Err ( e) => return Err ( e)
184- }
185- }
186-
187- return match serde_json:: from_str ( & json_str) {
188- Ok ( json) => Ok ( json) ,
189- Err ( _e) => {
190- debug_print ! ( "cbuffer_to_hashmap_json: serde_json::from_str / JSON decode failed {}" , _e) ;
191- Err ( ERR_JSON_DECODE_FAILED )
192- }
193- }
193+ debug_print ! ( "cbuffer_to_hashmap_json: calling temp_to_vector" ) ;
194+ Cow :: Owned ( temp_to_vector ( payload, length) ?)
195+ } ;
196+
197+ serde_json:: from_slice ( & json_bytes) . map_err ( |_e| {
198+ debug_print ! (
199+ "cbuffer_to_hashmap_json: serde_json::from_slice / JSON decode failed {}" ,
200+ _e
201+ ) ;
202+ ERR_JSON_DECODE_FAILED
203+ } )
194204}
195205
196- pub unsafe fn hashmap_json_to_cbuffer ( json : & HashMap < String , Value > , buffer : * mut c_char ) -> i32 {
197- //TODO: Use tovec?
198- return match serde_json:: to_string ( & json) {
199- Ok ( json_str) => string_to_cbuffer ( & json_str, buffer) ,
200- Err ( ..) => ERR_JSON_ENCODE_FAILED
206+ /// ## Safety
207+ /// tbd
208+ pub unsafe fn hashmap_json_to_cbuffer ( json : & HashMap < String , Value > , buffer : * mut c_char ) -> i32 {
209+ match serde_json:: to_vec ( & json) {
210+ Ok ( json_bytes) => bytes_to_cbuffer ( & json_bytes, buffer) ,
211+ Err ( _) => ERR_JSON_ENCODE_FAILED ,
201212 }
202213}
203214
215+ /// ## Safety
216+ /// tbd
204217pub unsafe fn string_to_cbuffer ( string : & str , buffer : * mut c_char ) -> i32 {
205218 bytes_to_cbuffer ( string. as_bytes ( ) , buffer)
206219}
207220
221+ /// ## Safety
222+ /// tbd
208223pub unsafe fn bytes_to_cbuffer ( bytes : & [ u8 ] , buffer : * mut c_char ) -> i32 {
209224 if buffer. is_null ( ) {
210225 debug_print ! ( "bytes_to_cbuffer: buffer is NULL" ) ;
@@ -239,64 +254,57 @@ pub unsafe fn bytes_to_cbuffer(bytes: &[u8], buffer: *mut c_char) -> i32 {
239254}
240255
241256unsafe fn bytes_to_temp ( bytes : & [ u8 ] , buffer : * mut c_char ) -> i32 {
242- let tmp_file_path;
243- match write_new_file ( bytes) {
244- Ok ( t) => tmp_file_path = t,
245- Err ( r) => return r
246- }
247- debug_print ! ( "bytes_to_temp: write_new_file wrote {} bytes to {}" , bytes. len( ) , tmp_file_path) ;
257+ // TODO: eventually replace this pattern with if-let once that is stable -jsenkpiel
258+ let tmp_file_path = match write_new_file ( bytes) {
259+ Ok ( t) => t,
260+ Err ( r) => return r,
261+ } ;
262+ debug_print ! (
263+ "bytes_to_temp: write_new_file wrote {} bytes to {}" ,
264+ bytes. len( ) ,
265+ tmp_file_path
266+ ) ;
248267
249268 let length = buffer as * mut i32 ;
250269 let tmp_file_path_len = tmp_file_path. len ( ) as i32 ;
251270
252271 //NOTE: We explicitly test this so we don't recursively attempt to create temp files with string_to_cbuffer()
253272 if * length < tmp_file_path_len {
254273 //Temp file path won't fit in output buffer, we're out of luck
255- debug_print ! ( "bytes_to_temp: temp file path {} is larger than buffer capacity {}" , tmp_file_path, * length) ;
274+ debug_print ! (
275+ "bytes_to_temp: temp file path {} is larger than buffer capacity {}" ,
276+ tmp_file_path,
277+ * length
278+ ) ;
256279 let _ = fs:: remove_file ( tmp_file_path) ;
257280 return ERR_BUFFER_TOO_SMALL ;
258281 }
259282
260283 let result = string_to_cbuffer ( & tmp_file_path, buffer) ;
261284 if result != ERR_NONE {
262- debug_print ! ( "bytes_to_temp: failed to store temp path {} in buffer" , tmp_file_path) ;
285+ debug_print ! (
286+ "bytes_to_temp: failed to store temp path {} in buffer" ,
287+ tmp_file_path
288+ ) ;
263289 let _ = fs:: remove_file ( tmp_file_path) ;
264290 return result;
265291 }
266292
267293 * length = 0 - tmp_file_path_len;
268- return result;
294+
295+ result
269296}
270297
271298unsafe fn write_new_file ( bytes : & [ u8 ] ) -> Result < String , i32 > {
272- let mut tmpfile;
273- match NamedTempFile :: new ( ) {
274- Ok ( f) => tmpfile = f,
275- Err ( ..) => return Err ( ERR_WRITE_TEMP_FILE_FAILED )
276- }
277- let bytes_len = bytes. len ( ) ;
278-
279- let bytes_written;
280- match tmpfile. write_all ( & bytes) {
281- Ok ( ..) => bytes_written = bytes_len as i32 ,
282- Err ( ..) => return Err ( ERR_WRITE_TEMP_FILE_FAILED )
283- }
299+ let mut tmpfile = NamedTempFile :: new ( ) . map_err ( |_| ERR_WRITE_TEMP_FILE_FAILED ) ?;
284300
285- if ( bytes_written as usize ) != bytes_len {
301+ if tmpfile . write_all ( bytes ) . is_err ( ) {
286302 return Err ( ERR_WRITE_TEMP_FILE_FAILED ) ;
287- }
303+ } ;
288304
289- let result;
290- match tmpfile. keep ( ) {
291- Ok ( r) => result = r,
292- Err ( ..) => return Err ( ERR_WRITE_TEMP_FILE_FAILED )
293- }
294- let ( _, path) = result;
305+ let ( _, path) = tmpfile. keep ( ) . map_err ( |_| ERR_WRITE_TEMP_FILE_FAILED ) ?;
295306
296- return match path. into_os_string ( ) . into_string ( ) {
297- Ok ( tmp_path) => Ok ( tmp_path) ,
298- Err ( ..) => {
299- Err ( ERR_WRITE_TEMP_FILE_FAILED )
300- }
301- }
307+ path. into_os_string ( )
308+ . into_string ( )
309+ . map_err ( |_| ERR_WRITE_TEMP_FILE_FAILED )
302310}
0 commit comments