nix_compat/nar/writer/
async.rs1use crate::nar::wire;
34use std::{
35 io::{
36 self,
37 ErrorKind::{InvalidInput, UnexpectedEof},
38 },
39 pin::Pin,
40};
41use tokio::io::{AsyncBufRead, AsyncBufReadExt, AsyncWrite, AsyncWriteExt};
42
43pub type Writer<'a> = dyn AsyncWrite + Unpin + Send + 'a;
45
46pub async fn open<'a, 'w: 'a>(writer: &'a mut Writer<'w>) -> io::Result<Node<'a, 'w>> {
48 let mut node = Node { writer };
49 node.write(&wire::TOK_NAR).await?;
50 Ok(node)
51}
52
53pub struct Node<'a, 'w: 'a> {
58 writer: &'a mut Writer<'w>,
59}
60
61impl<'a, 'w> Node<'a, 'w> {
62 async fn write(&mut self, data: &[u8]) -> io::Result<()> {
63 self.writer.write_all(data).await
64 }
65
66 async fn pad(&mut self, n: u64) -> io::Result<()> {
67 match (n & 7) as usize {
68 0 => Ok(()),
69 n => self.write(&[0; 8][n..]).await,
70 }
71 }
72
73 pub async fn symlink(mut self, target: &[u8]) -> io::Result<()> {
75 debug_assert!(
76 target.len() <= wire::MAX_TARGET_LEN,
77 "target.len() > {}",
78 wire::MAX_TARGET_LEN
79 );
80 debug_assert!(!target.is_empty(), "target is empty");
81 debug_assert!(!target.contains(&0), "target contains null byte");
82
83 self.write(&wire::TOK_SYM).await?;
84 self.write(&target.len().to_le_bytes()).await?;
85 self.write(target).await?;
86 self.pad(target.len() as u64).await?;
87 self.write(&wire::TOK_PAR).await?;
88 Ok(())
89 }
90
91 pub async fn file(
93 mut self,
94 executable: bool,
95 size: u64,
96 reader: &mut (dyn AsyncBufRead + Unpin + Send),
97 ) -> io::Result<()> {
98 self.write(if executable {
99 &wire::TOK_EXE
100 } else {
101 &wire::TOK_REG
102 })
103 .await?;
104
105 self.write(&size.to_le_bytes()).await?;
106
107 let mut need = size;
108 while need != 0 {
109 let data = reader.fill_buf().await?;
110
111 if data.is_empty() {
112 return Err(UnexpectedEof.into());
113 }
114
115 let n = need.min(data.len() as u64) as usize;
116 self.write(&data[..n]).await?;
117
118 need -= n as u64;
119 Pin::new(&mut *reader).consume(n);
120 }
121
122 if reader.fill_buf().await.map(|b| !b.is_empty())? {
125 return Err(io::Error::new(
126 InvalidInput,
127 "reader contained more data than specified size",
128 ));
129 }
130
131 self.pad(size).await?;
132 self.write(&wire::TOK_PAR).await?;
133
134 Ok(())
135 }
136
137 pub async fn directory(mut self) -> io::Result<Directory<'a, 'w>> {
143 self.write(&wire::TOK_DIR).await?;
144 Ok(Directory::new(self))
145 }
146}
147
148#[cfg(debug_assertions)]
149type Name = Vec<u8>;
150#[cfg(not(debug_assertions))]
151type Name = ();
152
153fn into_name(_name: &[u8]) -> Name {
154 #[cfg(debug_assertions)]
155 _name.to_owned()
156}
157
158pub struct Directory<'a, 'w> {
160 node: Node<'a, 'w>,
161 prev_name: Option<Name>,
162}
163
164impl<'a, 'w> Directory<'a, 'w> {
165 fn new(node: Node<'a, 'w>) -> Self {
166 Self {
167 node,
168 prev_name: None,
169 }
170 }
171
172 pub async fn entry(&mut self, name: &[u8]) -> io::Result<Node<'_, 'w>> {
181 debug_assert!(
182 name.len() <= wire::MAX_NAME_LEN,
183 "name.len() > {}",
184 wire::MAX_NAME_LEN
185 );
186 debug_assert!(!name.is_empty(), "name is empty");
187 debug_assert!(!name.contains(&0), "name contains null byte");
188 debug_assert!(!name.contains(&b'/'), "name contains {:?}", '/');
189 debug_assert!(name != b".", "name == {:?}", ".");
190 debug_assert!(name != b"..", "name == {:?}", "..");
191
192 match self.prev_name {
193 None => {
194 self.prev_name = Some(into_name(name));
195 }
196 Some(ref mut _prev_name) => {
197 #[cfg(debug_assertions)]
198 {
199 use bstr::ByteSlice;
200 assert!(
201 &**_prev_name < name,
202 "misordered names: {:?} >= {:?}",
203 _prev_name.as_bstr(),
204 name.as_bstr()
205 );
206 name.clone_into(_prev_name);
207 }
208 self.node.write(&wire::TOK_PAR).await?;
209 }
210 }
211
212 self.node.write(&wire::TOK_ENT).await?;
213 self.node.write(&name.len().to_le_bytes()).await?;
214 self.node.write(name).await?;
215 self.node.pad(name.len() as u64).await?;
216 self.node.write(&wire::TOK_NOD).await?;
217
218 Ok(Node {
219 writer: &mut *self.node.writer,
220 })
221 }
222
223 pub async fn close(mut self) -> io::Result<()> {
228 if self.prev_name.is_some() {
229 self.node.write(&wire::TOK_PAR).await?;
230 }
231
232 self.node.write(&wire::TOK_PAR).await?;
233 Ok(())
234 }
235}