running_process_platform_internal/platform_linux/
raw_write.rs1use std::io;
4use std::os::fd::RawFd;
5
6use crate::platform::fs::RawDescriptor;
7
8impl From<RawFd> for RawDescriptor {
9 fn from(fd: RawFd) -> Self {
10 RawDescriptor::from_value(fd as usize)
11 }
12}
13
14pub fn write_all_to_descriptor(descriptor: RawDescriptor, mut bytes: &[u8]) -> io::Result<()> {
22 let fd = descriptor.value() as RawFd;
23 while !bytes.is_empty() {
24 let written = unsafe { libc::write(fd, bytes.as_ptr().cast(), bytes.len()) };
27 if written < 0 {
28 let error = io::Error::last_os_error();
29 if error.kind() == io::ErrorKind::Interrupted {
30 continue;
31 }
32 return Err(error);
33 }
34 if written == 0 {
35 return Err(io::Error::new(
36 io::ErrorKind::WriteZero,
37 "raw descriptor write returned zero",
38 ));
39 }
40 bytes = &bytes[written as usize..];
41 }
42 Ok(())
43}
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48 use std::io::Read as _;
49 use std::os::fd::AsRawFd as _;
50
51 #[test]
53 fn every_byte_is_written() {
54 let file = tempfile::NamedTempFile::new().expect("temp file");
55 let payload = vec![b'x'; 300_000];
56
57 write_all_to_descriptor(RawDescriptor::from(file.as_file().as_raw_fd()), &payload)
58 .expect("write");
59
60 let mut readback = Vec::new();
61 std::fs::File::open(file.path())
62 .expect("reopen")
63 .read_to_end(&mut readback)
64 .expect("read");
65 assert_eq!(readback.len(), payload.len());
66 assert!(readback.iter().all(|b| *b == b'x'));
67 }
68
69 #[test]
71 fn an_empty_write_is_not_an_error() {
72 write_all_to_descriptor(RawDescriptor::from(-1), &[]).expect("empty write");
73 }
74
75 #[test]
77 fn a_closed_descriptor_reports_the_host_error() {
78 let error = write_all_to_descriptor(RawDescriptor::from(-1), b"x").expect_err("bad fd");
79 assert_eq!(error.raw_os_error(), Some(libc::EBADF));
80 }
81}