Skip to main content

wireshift_fallback/ops/
write.rs

1use std::io::{Seek, SeekFrom, Write};
2
3use wireshift_core::buffer::{Buffer, Submitted};
4use wireshift_core::op::CompletionPayload;
5use wireshift_core::{Error, Result};
6
7use crate::ops::retry_eintr;
8
9/// Execute a positional write at `offset`, returning the buffer and the
10/// number of bytes written.
11pub fn execute_write(
12    mut file: std::fs::File,
13    offset: u64,
14    buffer: Buffer<Submitted>,
15) -> Result<CompletionPayload> {
16    if let Err(error) = file.seek(SeekFrom::Start(offset)) {
17        let is_espipe = error.raw_os_error() == Some(rustix::io::Errno::SPIPE.raw_os_error());
18        if !is_espipe || offset > 0 {
19            return Err(Error::io(
20                "write seek failed",
21                error,
22                "seek to a valid offset before writing",
23            ));
24        }
25    }
26    let data = &buffer.backend_ref()[..buffer.filled_len()];
27    let bytes = retry_eintr!(file.write(data)).map_err(|error| {
28        Error::io(
29            "write failed",
30            error,
31            "ensure the file descriptor is writable",
32        )
33    })?;
34    Ok(CompletionPayload::Bytes(bytes))
35}
36
37/// Execute a positional vectored write at `offset` over `buffers`,
38/// returning the completed buffers and the total number of bytes written.
39pub fn execute_write_vectored(
40    mut file: std::fs::File,
41    offset: u64,
42    buffers: Vec<Buffer<Submitted>>,
43) -> Result<CompletionPayload> {
44    if let Err(error) = file.seek(SeekFrom::Start(offset)) {
45        let is_espipe = error.raw_os_error() == Some(rustix::io::Errno::SPIPE.raw_os_error());
46        if !is_espipe || offset > 0 {
47            return Err(Error::io(
48                "writev seek failed",
49                error,
50                "seek to a valid offset before writing vectored data",
51            ));
52        }
53    }
54    let mut written = 0_usize;
55    for buffer in buffers {
56        let chunk = &buffer.backend_ref()[..buffer.filled_len()];
57        let bytes = retry_eintr!(file.write(chunk)).map_err(|error| {
58            Error::io(
59                "writev segment write failed",
60                error,
61                "ensure the file descriptor remains writable for all writev segments",
62            )
63        })?;
64        written += bytes;
65        if bytes < chunk.len() {
66            break;
67        }
68    }
69    Ok(CompletionPayload::Bytes(written))
70}