Skip to main content

arcbox_virtio_fs/
request.rs

1//! FUSE request/response wire types — read by the device, parsed by handlers.
2
3/// FUSE request from guest.
4#[derive(Debug)]
5pub struct FuseRequest<'a> {
6    /// Raw request data.
7    data: &'a [u8],
8}
9
10impl<'a> FuseRequest<'a> {
11    /// Creates a new FUSE request from raw bytes.
12    #[must_use]
13    pub const fn new(data: &'a [u8]) -> Self {
14        Self { data }
15    }
16
17    /// Returns the raw request data.
18    #[must_use]
19    pub const fn data(&self) -> &[u8] {
20        self.data
21    }
22
23    /// Returns the request length.
24    #[must_use]
25    pub const fn len(&self) -> usize {
26        self.data.len()
27    }
28
29    /// Returns true if the request is empty.
30    #[must_use]
31    pub const fn is_empty(&self) -> bool {
32        self.data.is_empty()
33    }
34
35    /// Parses the opcode from the request header.
36    ///
37    /// Returns None if the request is too small.
38    #[must_use]
39    pub fn opcode(&self) -> Option<u32> {
40        if self.data.len() < 8 {
41            return None;
42        }
43        Some(u32::from_le_bytes([
44            self.data[4],
45            self.data[5],
46            self.data[6],
47            self.data[7],
48        ]))
49    }
50
51    /// Parses the unique ID from the request header.
52    #[must_use]
53    pub fn unique(&self) -> Option<u64> {
54        if self.data.len() < 16 {
55            return None;
56        }
57        Some(u64::from_le_bytes([
58            self.data[8],
59            self.data[9],
60            self.data[10],
61            self.data[11],
62            self.data[12],
63            self.data[13],
64            self.data[14],
65            self.data[15],
66        ]))
67    }
68}
69
70/// FUSE response to guest.
71#[derive(Debug)]
72pub struct FuseResponse {
73    /// Response data.
74    data: Vec<u8>,
75}
76
77impl FuseResponse {
78    /// Creates a new FUSE response.
79    #[must_use]
80    pub fn new(unique: u64, payload: Vec<u8>) -> Self {
81        let len = (16 + payload.len()) as u32;
82        let mut data = Vec::with_capacity(len as usize);
83
84        // Response header
85        data.extend_from_slice(&len.to_le_bytes());
86        data.extend_from_slice(&0i32.to_le_bytes()); // error = 0
87        data.extend_from_slice(&unique.to_le_bytes());
88
89        data.extend_from_slice(&payload);
90
91        Self { data }
92    }
93
94    /// Creates an error response.
95    #[must_use]
96    pub fn error(unique: u64, errno: i32) -> Self {
97        let len = 16u32;
98        let mut data = Vec::with_capacity(len as usize);
99
100        data.extend_from_slice(&len.to_le_bytes());
101        data.extend_from_slice(&(-errno).to_le_bytes());
102        data.extend_from_slice(&unique.to_le_bytes());
103
104        Self { data }
105    }
106
107    /// Returns the response data.
108    #[must_use]
109    pub fn data(&self) -> &[u8] {
110        &self.data
111    }
112
113    /// Consumes the response and returns the data.
114    #[must_use]
115    pub fn into_data(self) -> Vec<u8> {
116        self.data
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123
124    #[test]
125    fn test_fuse_request_new() {
126        let data = vec![0u8; 64];
127        let request = FuseRequest::new(&data);
128        assert_eq!(request.len(), 64);
129        assert!(!request.is_empty());
130    }
131
132    #[test]
133    fn test_fuse_request_empty() {
134        let data = vec![];
135        let request = FuseRequest::new(&data);
136        assert!(request.is_empty());
137    }
138
139    #[test]
140    fn test_fuse_request_opcode() {
141        let mut data = vec![0u8; 16];
142        data[4..8].copy_from_slice(&42u32.to_le_bytes());
143
144        let request = FuseRequest::new(&data);
145        assert_eq!(request.opcode(), Some(42));
146    }
147
148    #[test]
149    fn test_fuse_request_opcode_too_small() {
150        let data = vec![0u8; 4];
151        let request = FuseRequest::new(&data);
152        assert!(request.opcode().is_none());
153    }
154
155    #[test]
156    fn test_fuse_request_unique() {
157        let mut data = vec![0u8; 16];
158        data[8..16].copy_from_slice(&12345u64.to_le_bytes());
159
160        let request = FuseRequest::new(&data);
161        assert_eq!(request.unique(), Some(12345));
162    }
163
164    #[test]
165    fn test_fuse_response_new() {
166        let response = FuseResponse::new(123, vec![1, 2, 3, 4]);
167
168        let data = response.data();
169        assert_eq!(data.len(), 20); // 16 header + 4 payload
170
171        let len = u32::from_le_bytes([data[0], data[1], data[2], data[3]]);
172        let error = i32::from_le_bytes([data[4], data[5], data[6], data[7]]);
173        let unique = u64::from_le_bytes([
174            data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15],
175        ]);
176
177        assert_eq!(len, 20);
178        assert_eq!(error, 0);
179        assert_eq!(unique, 123);
180        assert_eq!(&data[16..], &[1, 2, 3, 4]);
181    }
182
183    #[test]
184    fn test_fuse_response_error() {
185        let response = FuseResponse::error(456, libc::ENOENT);
186
187        let data = response.data();
188        assert_eq!(data.len(), 16);
189
190        let len = u32::from_le_bytes([data[0], data[1], data[2], data[3]]);
191        let error = i32::from_le_bytes([data[4], data[5], data[6], data[7]]);
192        let unique = u64::from_le_bytes([
193            data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15],
194        ]);
195
196        assert_eq!(len, 16);
197        assert_eq!(error, -libc::ENOENT);
198        assert_eq!(unique, 456);
199    }
200
201    #[test]
202    fn test_fuse_response_into_data() {
203        let response = FuseResponse::new(1, vec![]);
204        let data = response.into_data();
205        assert_eq!(data.len(), 16);
206    }
207}