1#[cfg(test)]
24mod tests;
25
26use log::debug;
27use nuts_backend::Backend;
28use std::cmp;
29
30use crate::entry::mode::Mode;
31use crate::entry::{populate_mode_api, populate_tstamp_api, Inner};
32use crate::error::ArchiveResult;
33use crate::flush_header;
34use crate::header::Header;
35use crate::id::Id;
36use crate::pager::Pager;
37use crate::tree::Tree;
38
39macro_rules! impl_new {
40 ($type:ident, $mode:ident) => {
41 pub(crate) fn new(
42 pager: &'a mut Pager<B>,
43 header_id: &'a Id<B>,
44 header: &'a mut Header,
45 tree: &'a mut Tree<B>,
46 name: String,
47 ) -> $type<'a, B> {
48 $type(InnerBuilder::new(
49 pager,
50 header_id,
51 header,
52 tree,
53 name,
54 Mode::$mode(),
55 ))
56 }
57 };
58}
59
60pub struct FileBuilder<'a, B: Backend>(InnerBuilder<'a, B>);
66
67impl<'a, B: Backend> FileBuilder<'a, B> {
68 impl_new!(FileBuilder, file);
69
70 populate_mode_api!(mut);
71 populate_tstamp_api!(mut);
72
73 pub fn build(self) -> ArchiveResult<EntryMut<'a, B>, B> {
78 self.0.build()
79 }
80
81 fn inner(&self) -> &Inner {
82 &self.0.entry
83 }
84
85 fn inner_mut(&mut self) -> &mut Inner {
86 &mut self.0.entry
87 }
88}
89
90pub struct DirectoryBuilder<'a, B: Backend>(InnerBuilder<'a, B>);
97
98impl<'a, B: Backend> DirectoryBuilder<'a, B> {
99 impl_new!(DirectoryBuilder, directory);
100
101 populate_mode_api!(mut);
102 populate_tstamp_api!(mut);
103
104 pub fn build(self) -> ArchiveResult<(), B> {
106 self.0.build().map(|_| ())
107 }
108
109 fn inner(&self) -> &Inner {
110 &self.0.entry
111 }
112
113 fn inner_mut(&mut self) -> &mut Inner {
114 &mut self.0.entry
115 }
116}
117
118pub struct SymlinkBuilder<'a, B: Backend> {
125 builder: InnerBuilder<'a, B>,
126 target: String,
127}
128
129impl<'a, B: Backend> SymlinkBuilder<'a, B> {
130 pub(crate) fn new(
131 pager: &'a mut Pager<B>,
132 header_id: &'a Id<B>,
133 header: &'a mut Header,
134 tree: &'a mut Tree<B>,
135 name: String,
136 target: String,
137 ) -> SymlinkBuilder<'a, B> {
138 let builder = InnerBuilder::new(pager, header_id, header, tree, name, Mode::symlink());
139
140 SymlinkBuilder { builder, target }
141 }
142
143 populate_mode_api!(mut);
144 populate_tstamp_api!(mut);
145
146 pub fn build(self) -> ArchiveResult<(), B> {
148 let mut entry = self.builder.build()?;
149
150 entry.write_all(self.target.as_bytes())?;
151
152 Ok(())
153 }
154
155 fn inner(&self) -> &Inner {
156 &self.builder.entry
157 }
158
159 fn inner_mut(&mut self) -> &mut Inner {
160 &mut self.builder.entry
161 }
162}
163
164struct InnerBuilder<'a, B: Backend> {
165 pager: &'a mut Pager<B>,
166 header_id: &'a Id<B>,
167 header: &'a mut Header,
168 tree: &'a mut Tree<B>,
169 entry: Inner,
170}
171
172impl<'a, B: Backend> InnerBuilder<'a, B> {
173 fn new(
174 pager: &'a mut Pager<B>,
175 header_id: &'a Id<B>,
176 header: &'a mut Header,
177 tree: &'a mut Tree<B>,
178 name: String,
179 mode: Mode,
180 ) -> InnerBuilder<'a, B> {
181 InnerBuilder {
182 pager,
183 header_id,
184 header,
185 tree,
186 entry: Inner::new(name, mode),
187 }
188 }
189
190 fn build(self) -> ArchiveResult<EntryMut<'a, B>, B> {
191 let id = self.tree.aquire(self.pager)?.clone();
192
193 self.entry.flush(self.pager, &id)?;
194
195 self.header.inc_files();
196 flush_header(self.pager, self.header_id, self.header, self.tree)?;
197
198 Ok(EntryMut::new(
199 self.pager,
200 self.header_id,
201 self.header,
202 self.tree,
203 self.entry,
204 id,
205 ))
206 }
207}
208
209pub struct EntryMut<'a, B: Backend> {
214 pager: &'a mut Pager<B>,
215 header_id: &'a Id<B>,
216 header: &'a mut Header,
217 tree: &'a mut Tree<B>,
218 entry: Inner,
219 first: Id<B>,
220 last: Id<B>,
221 cache: Vec<u8>,
222}
223
224impl<'a, B: Backend> EntryMut<'a, B> {
225 fn new(
226 pager: &'a mut Pager<B>,
227 header_id: &'a Id<B>,
228 header: &'a mut Header,
229 tree: &'a mut Tree<B>,
230 entry: Inner,
231 id: Id<B>,
232 ) -> EntryMut<'a, B> {
233 EntryMut {
234 pager,
235 header_id,
236 header,
237 tree,
238 entry,
239 first: id.clone(),
240 last: id,
241 cache: vec![],
242 }
243 }
244
245 pub fn write(&mut self, buf: &[u8]) -> ArchiveResult<usize, B> {
250 let block_size = self.pager.block_size() as u64;
251 let pos = (self.entry.size % block_size) as usize;
252
253 let available = if pos == 0 {
254 self.last = self.tree.aquire(self.pager)?.clone();
255
256 debug!("block aquired: {}", self.last);
257
258 self.cache.clear();
259 self.cache.resize(block_size as usize, 0);
260
261 block_size as usize
262 } else {
263 assert_eq!(self.cache.len(), block_size as usize);
264
265 block_size as usize - pos
266 };
267
268 let nbytes = cmp::min(buf.len(), available as usize);
269
270 debug!(
271 "bsize={}, pos={}, available={}, nbytes={}",
272 block_size, pos, available, nbytes
273 );
274
275 self.cache[pos..pos + nbytes].copy_from_slice(&buf[..nbytes]);
276 self.pager.write(&self.last, &self.cache)?;
277
278 self.entry.size += nbytes as u64;
279 self.entry.flush(self.pager, &self.first)?;
280 flush_header(self.pager, self.header_id, self.header, self.tree)?;
281
282 Ok(nbytes)
283 }
284
285 pub fn write_all(&mut self, mut buf: &[u8]) -> ArchiveResult<(), B> {
286 while !buf.is_empty() {
287 let n = self.write(buf)?;
288
289 buf = &buf[n..]
290 }
291
292 Ok(())
293 }
294}