1- use core:: cmp;
1+ use core:: { cmp, mem :: MaybeUninit } ;
22use std:: { io, os:: fd:: IntoRawFd } ;
33
44use uhyve_interface:: {
@@ -76,42 +76,12 @@ pub(super) fn read(
7676) {
7777 sysread. ret = if let Some ( fdata) = file_map. fdmap . get_mut ( GuestFd ( sysread. fd . into_raw_fd ( ) ) ) {
7878 if let Ok ( host_address) = mem. host_address ( sysread. buf ) {
79- match fdata {
80- FdData :: Raw ( rfd) => {
81- let bytes_read = unsafe {
82- libc:: read (
83- * rfd,
84- host_address as * mut libc:: c_void ,
85- sysread. len as usize ,
86- )
87- } ;
88- if bytes_read < 0 {
89- -translate_last_errno ( ) . unwrap_or ( 1 ) as i64
90- } else {
91- bytes_read as i64
92- }
93- }
94- FdData :: Virtual { data, offset } => {
95- let remaining = {
96- let pos = cmp:: min ( * offset, data. len ( ) as u64 ) ;
97- & data[ pos as usize ..]
98- } ;
99- let amt = cmp:: min ( remaining. len ( ) as u64 , sysread. len ) as usize ;
100- assert ! ( amt <= isize :: MAX as usize ) ;
101-
102- // SAFETY: the input slices can't overlap, as `host_address` is owned by the guest
103- // and `data` is owned by the host.
104- unsafe {
105- core:: ptr:: copy_nonoverlapping (
106- remaining. as_ptr ( ) ,
107- host_address as * mut u8 ,
108- amt,
109- )
110- } ;
111- * offset += amt as u64 ;
112- amt as i64
113- }
114- FdData :: MappedDirectory { .. } => -EBADF as i64 ,
79+ if let Ok ( len) = sysread. len . try_into ( ) {
80+ read_internal ( fdata, unsafe {
81+ core:: slice:: from_raw_parts_mut ( host_address as * mut MaybeUninit < u8 > , len)
82+ } )
83+ } else {
84+ -EINVAL as i64
11585 }
11686 } else {
11787 warn ! ( "Unable to get host address for read buffer" ) ;
@@ -122,6 +92,41 @@ pub(super) fn read(
12292 } ;
12393}
12494
95+ fn read_internal ( fdata : & mut FdData , out_bytes : & mut [ MaybeUninit < u8 > ] ) -> i64 {
96+ match fdata {
97+ FdData :: Raw ( rfd) => {
98+ let bytes_read = unsafe {
99+ libc:: read (
100+ * rfd,
101+ out_bytes. as_mut_ptr ( ) . cast :: < libc:: c_void > ( ) ,
102+ out_bytes. len ( ) ,
103+ )
104+ } ;
105+ if bytes_read < 0 {
106+ -translate_last_errno ( ) . unwrap_or ( 1 ) as i64
107+ } else {
108+ bytes_read as i64
109+ }
110+ }
111+ FdData :: Virtual { data, offset } => {
112+ let remaining = {
113+ let pos = cmp:: min ( * offset, data. len ( ) as u64 ) ;
114+ & data[ pos as usize ..]
115+ } ;
116+ let amt = out_bytes
117+ . iter_mut ( )
118+ . zip ( remaining. iter ( ) )
119+ . map ( |( o, i) | {
120+ o. write ( * i) ;
121+ } )
122+ . count ( ) ;
123+ * offset += amt as u64 ;
124+ amt as i64
125+ }
126+ FdData :: MappedDirectory { .. } => -EBADF as i64 ,
127+ }
128+ }
129+
125130/// Handles a v1 write hypercall (for which a guest-provided guest virtual address must be
126131/// converted to a guest physical address by the host).
127132pub ( super ) fn write_v1 < N : NetworkBackend > (
@@ -288,3 +293,24 @@ pub(super) fn lseek(syslseek: &mut LseekParams, file_map: &mut UhyveFileMap) {
288293 }
289294 } ;
290295}
296+
297+ #[ cfg( test) ]
298+ mod tests {
299+ use std:: sync:: Arc ;
300+
301+ use super :: { FdData , MaybeUninit , read_internal} ;
302+
303+ #[ test]
304+ fn test_read_internal_on_virtual00 ( ) {
305+ let data: Arc < [ u8 ] > = Arc :: from ( b"Hello!" . to_vec ( ) . into_boxed_slice ( ) ) ;
306+ let len = data. len ( ) as u64 ;
307+ let mut fdata = FdData :: Virtual { data, offset : 0 } ;
308+ let mut out = [ MaybeUninit :: new ( 0u8 ) ; 20 ] ;
309+
310+ assert_eq ! ( read_internal( & mut fdata, & mut out) , len as i64 ) ;
311+ let FdData :: Virtual { offset, .. } = & fdata else {
312+ unreachable ! ( ) ;
313+ } ;
314+ assert_eq ! ( * offset, len) ;
315+ }
316+ }
0 commit comments