Skip to content

Commit c2c9780

Browse files
committed
Implement ReadVolatile/WriteVolatile for Cursor
This is needed for some unittests in linux-loader. Signed-off-by: Patrick Roy <roypat@amazon.co.uk>
1 parent dcaa268 commit c2c9780

File tree

1 file changed

+113
-2
lines changed

1 file changed

+113
-2
lines changed

src/io.rs

Lines changed: 113 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
use crate::bitmap::BitmapSlice;
77
use crate::volatile_memory::copy_slice_impl::{copy_from_volatile_slice, copy_to_volatile_slice};
88
use crate::{VolatileMemoryError, VolatileSlice};
9-
use std::io::{ErrorKind, Stdout};
9+
use std::io::{Cursor, ErrorKind, Stdout};
1010
use std::os::fd::AsRawFd;
1111

1212
/// A version of the standard library's [`Read`] trait that operates on volatile memory instead of
@@ -280,11 +280,56 @@ impl ReadVolatile for &[u8] {
280280
}
281281
}
282282

283+
// ReadVolatile and WriteVolatile implementations for Cursor<T> is modelled after the standard
284+
// library's implementation (modulo having to inline `Cursor::remaining_slice`, as that's nightly only)
285+
impl<T> ReadVolatile for Cursor<T>
286+
where
287+
T: AsRef<[u8]>,
288+
{
289+
fn read_volatile<B: BitmapSlice>(
290+
&mut self,
291+
buf: &mut VolatileSlice<B>,
292+
) -> Result<usize, VolatileMemoryError> {
293+
let inner = self.get_ref().as_ref();
294+
let len = self.position().min(inner.len() as u64);
295+
let n = ReadVolatile::read_volatile(&mut &inner[(len as usize)..], buf)?;
296+
self.set_position(self.position() + n as u64);
297+
Ok(n)
298+
}
299+
300+
fn read_exact_volatile<B: BitmapSlice>(
301+
&mut self,
302+
buf: &mut VolatileSlice<B>,
303+
) -> Result<(), VolatileMemoryError> {
304+
let inner = self.get_ref().as_ref();
305+
let n = buf.len();
306+
let len = self.position().min(inner.len() as u64);
307+
ReadVolatile::read_exact_volatile(&mut &inner[(len as usize)..], buf)?;
308+
self.set_position(self.position() + n as u64);
309+
Ok(())
310+
}
311+
}
312+
313+
impl WriteVolatile for Cursor<&mut [u8]> {
314+
fn write_volatile<B: BitmapSlice>(
315+
&mut self,
316+
buf: &VolatileSlice<B>,
317+
) -> Result<usize, VolatileMemoryError> {
318+
let pos = self.position().min(self.get_ref().len() as u64);
319+
let n = WriteVolatile::write_volatile(&mut &mut self.get_mut()[(pos as usize)..], buf)?;
320+
self.set_position(self.position() + n as u64);
321+
Ok(n)
322+
}
323+
324+
// no write_all provided in standard library, since our default for write_all is based on the
325+
// standard library's write_all, omitting it here as well will correctly mimic stdlib behavior.
326+
}
327+
283328
#[cfg(test)]
284329
mod tests {
285330
use crate::io::{ReadVolatile, WriteVolatile};
286331
use crate::{VolatileMemoryError, VolatileSlice};
287-
use std::io::{ErrorKind, Read, Seek, Write};
332+
use std::io::{Cursor, ErrorKind, Read, Seek, Write};
288333
use vmm_sys_util::tempfile::TempFile;
289334

290335
// ---- Test ReadVolatile for &[u8] ----
@@ -450,4 +495,70 @@ mod tests {
450495
write_5_bytes_to_file(input);
451496
}
452497
}
498+
499+
#[test]
500+
fn test_read_volatile_for_cursor() {
501+
let read_buffer = [1, 2, 3, 4, 5, 6, 7];
502+
let mut output = vec![0u8; 5];
503+
504+
let mut cursor = Cursor::new(read_buffer);
505+
506+
// Read 4 bytes from cursor to volatile slice (amount read limited by volatile slice length)
507+
assert_eq!(
508+
cursor
509+
.read_volatile(&mut VolatileSlice::from(&mut output[..4]))
510+
.unwrap(),
511+
4
512+
);
513+
assert_eq!(output, vec![1, 2, 3, 4, 0]);
514+
515+
// Read next 3 bytes from cursor to volatile slice (amount read limited by length of remaining data in cursor)
516+
assert_eq!(
517+
cursor
518+
.read_volatile(&mut VolatileSlice::from(&mut output[..4]))
519+
.unwrap(),
520+
3
521+
);
522+
assert_eq!(output, vec![5, 6, 7, 4, 0]);
523+
524+
cursor.set_position(0);
525+
// Same as first test above, but with read_exact
526+
cursor
527+
.read_exact_volatile(&mut VolatileSlice::from(&mut output[..4]))
528+
.unwrap();
529+
assert_eq!(output, vec![1, 2, 3, 4, 0]);
530+
531+
// Same as above, but with read_exact. Should fail now, because we cannot fill a 4 byte buffer
532+
// with whats remaining in the cursor (3 bytes). Output should remain unchanged.
533+
assert!(cursor
534+
.read_exact_volatile(&mut VolatileSlice::from(&mut output[..4]))
535+
.is_err());
536+
assert_eq!(output, vec![1, 2, 3, 4, 0]);
537+
}
538+
539+
#[test]
540+
fn test_write_volatile_for_cursor() {
541+
let mut write_buffer = vec![0u8; 7];
542+
let mut input = [1, 2, 3, 4];
543+
544+
let mut cursor = Cursor::new(write_buffer.as_mut_slice());
545+
546+
// Write 4 bytes from volatile slice to cursor (amount written limited by volatile slice length)
547+
assert_eq!(
548+
cursor
549+
.write_volatile(&VolatileSlice::from(input.as_mut_slice()))
550+
.unwrap(),
551+
4
552+
);
553+
assert_eq!(cursor.get_ref(), &[1, 2, 3, 4, 0, 0, 0]);
554+
555+
// Write 3 bytes from volatile slice to cursor (amount written limited by remaining space in cursor)
556+
assert_eq!(
557+
cursor
558+
.write_volatile(&VolatileSlice::from(input.as_mut_slice()))
559+
.unwrap(),
560+
3
561+
);
562+
assert_eq!(cursor.get_ref(), &[1, 2, 3, 4, 1, 2, 3]);
563+
}
453564
}

0 commit comments

Comments
 (0)