1use super::*;
2
3pub enum Node {
5 File(File),
6 Dir(Dir),
7}
8
9impl Node {
10 pub fn open<R: ReadBlock>(block_ref: &BlockRef, block_reader: &mut R) -> Result<Self, Error> {
11 let mut reader = NodeReader::new(block_ref, block_reader)?;
12 let node = match reader.file().main_block().kind() {
13 NodeKind::File => {
14 let file = reader.into_file();
15 Self::File(file)
16 },
17 NodeKind::Dir => {
18 let dir = Dir::decode(&mut reader).map_err(|_| Error::Io)?;
19 Self::Dir(dir)
20 },
21 };
22 Ok(node)
23 }
24}
25
26#[derive(Encode, Decode, Debug)]
34pub struct Dir(pub VecMap<FileName, BlockRef>);
35
36impl Dir {
37 pub fn open<R: ReadBlock>(block_ref: &BlockRef, block_reader: &mut R) -> Result<Self, Error> {
38 let mut reader = NodeReader::new(block_ref, block_reader)?;
39 if reader.file().main_block().kind() != NodeKind::Dir {
40 return Err(Error::Node);
41 }
42 let dir = Self::decode(&mut reader).map_err(|_| Error::Io)?;
43 Ok(dir)
44 }
45}
46
47pub struct File {
51 main_block: MainBlock,
52 current_block: Option<(usize, FileBlock)>,
53 position: u64,
54}
55
56impl File {
57 pub fn main_block(&self) -> &MainBlock {
58 &self.main_block
59 }
60
61 pub fn position(&self) -> u64 {
62 self.position
63 }
64
65 pub fn seek(&mut self, position: u64) -> Result<(), Error> {
66 if position > self.main_block.file_size {
67 return Err(Error::Io);
68 }
69 self.position = position;
70 Ok(())
71 }
72
73 pub fn open<R: ReadBlock>(main_block_ref: &BlockRef, reader: &mut R) -> Result<Self, Error> {
74 let block = reader.read_block(main_block_ref)?;
75 let main_block = MainBlock::decode(block)?;
76 Ok(Self { main_block, current_block: None, position: 0 })
77 }
78
79 pub fn from_main_block(main_block: MainBlock) -> Self {
80 Self { main_block, current_block: None, position: 0 }
81 }
82
83 pub fn read<R: ReadBlock>(&mut self, buf: &mut [u8], reader: &mut R) -> Result<usize, Error> {
84 let n = (buf.len() as u64).min(self.main_block.file_size - self.position);
85 if n == 0 {
86 return Ok(0);
87 }
88 let next_position = self.position + n;
89 let n = n as usize;
90 let first_block_size = self.main_block.first_block.len() as u64;
91 let mut i = self.get_block_index(self.position);
92 let mut buf_position = 0;
93 if i == usize::MAX {
94 let a = self.position as usize;
96 let b = next_position.min(first_block_size) as usize;
97 let m = b - a;
98 buf[..m].copy_from_slice(&self.main_block.first_block.0[a..b]);
99 self.position += m as u64;
100 buf_position += m;
101 i = 0;
102 }
103 while self.position != next_position {
105 let block = match &mut self.current_block {
106 Some((block_index, block)) if *block_index == i => block,
107 block => {
108 let data = reader.read_block(&self.main_block.block_refs[i])?;
109 let new_block = FileBlock::new(data)?;
110 &mut block.insert((i, new_block)).1
111 },
112 };
113 let a = (self.position - first_block_size - i as u64 * MAX_BLOCK_SIZE as u64) as usize;
114 let m = ((next_position - self.position) as usize).min(block.len() - a);
115 buf[buf_position..buf_position + m].copy_from_slice(&block.0[a..a + m]);
116 self.position += m as u64;
117 buf_position += m;
118 i += 1;
119 }
120 Ok(n)
121 }
122
123 pub fn read_exact<R: ReadBlock>(
124 &mut self,
125 buf: &mut [u8],
126 reader: &mut R,
127 ) -> Result<(), Error> {
128 let n = self.read(buf, reader)?;
129 if n != buf.len() {
130 return Err(Error::Io);
131 }
132 Ok(())
133 }
134
135 pub fn read_to_end<R: ReadBlock>(
136 &mut self,
137 buf: &mut Vec<u8>,
138 reader: &mut R,
139 ) -> Result<usize, Error> {
140 let remaining = (self.main_block.file_size - self.position) as usize;
141 let old_len = buf.len();
142 buf.resize(old_len + remaining, 0_u8);
143 self.read_exact(&mut buf[old_len..], reader)?;
144 Ok(remaining)
145 }
146
147 fn get_block_index(&self, mut position: u64) -> usize {
148 debug_assert!(position < self.main_block.file_size);
149 let first_block_size = self.main_block.first_block.len() as u64;
150 if position < first_block_size {
151 return usize::MAX;
152 }
153 position -= first_block_size;
154 (position / self.main_block.block_size) as usize
155 }
156}
157
158pub struct NodeReader<R: ReadBlock> {
160 reader: R,
161 file: File,
162}
163
164impl<R: ReadBlock> NodeReader<R> {
165 pub fn new(main_block_ref: &BlockRef, mut reader: R) -> Result<Self, Error> {
166 let file = File::open(main_block_ref, &mut reader)?;
167 Ok(Self { reader, file })
168 }
169
170 pub fn from_main_block(main_block: MainBlock, reader: R) -> Self {
171 let file = File::from_main_block(main_block);
172 Self { reader, file }
173 }
174
175 pub fn file(&self) -> &File {
176 &self.file
177 }
178
179 pub fn into_file(self) -> File {
180 self.file
181 }
182
183 pub fn into_inner(self) -> R {
184 self.reader
185 }
186
187 pub fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
188 self.file.read(buf, &mut self.reader)
189 }
190
191 pub fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Error> {
192 self.file.read_exact(buf, &mut self.reader)
193 }
194
195 pub fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize, Error> {
196 self.file.read_to_end(buf, &mut self.reader)
197 }
198
199 pub fn seek(&mut self, position: u64) -> Result<(), Error> {
200 self.file.seek(position)
201 }
202}
203
204impl<R: ReadBlock> codec::Input for NodeReader<R> {
205 fn remaining_len(&mut self) -> Result<Option<usize>, codec::Error> {
206 let remaining = self.file.main_block().file_size() - self.file.position();
207 Ok(remaining.try_into().ok())
208 }
209
210 fn read(&mut self, into: &mut [u8]) -> Result<(), codec::Error> {
211 self.read_exact(into).map_err(|_| "I/o error")?;
212 Ok(())
213 }
214}
215
216pub struct NodeWriter<W: WriteBlock> {
218 writer: W,
219 buf: Vec<u8>,
220 kind: NodeKind,
221 file_size: u64,
222 block_size: usize,
223 first_block_size: usize,
224 position: u64,
225 block_refs: Vec<BlockRef>,
226 first_block: Vec<u8>,
227 service_id: ServiceId,
228}
229
230impl<W: WriteBlock> NodeWriter<W> {
231 pub fn new(
232 service_id: ServiceId,
233 writer: W,
234 file_size: u64,
235 block_size: usize,
236 ) -> Result<Self, Error> {
237 Self::do_new(service_id, writer, NodeKind::File, file_size, block_size)
238 }
239
240 pub fn new_dir(
241 service_id: ServiceId,
242 writer: W,
243 file_size: u64,
244 block_size: usize,
245 ) -> Result<Self, Error> {
246 Self::do_new(service_id, writer, NodeKind::Dir, file_size, block_size)
247 }
248
249 fn do_new(
250 service_id: ServiceId,
251 writer: W,
252 kind: NodeKind,
253 file_size: u64,
254 block_size: usize,
255 ) -> Result<Self, Error> {
256 let first_block_size = {
257 let mut num_blocks = file_size.div_ceil(block_size as u64) as usize;
258 let mut first_block_size = MAX_BLOCK_SIZE as u64;
259 for _ in 0..2 {
261 let metadata_len =
262 main_block_metadata_encoded_len(file_size, block_size as u64, num_blocks)
263 .ok_or(Error::Block)? as u64;
264 first_block_size = (MAX_BLOCK_SIZE as u64)
265 .checked_sub(metadata_len)
266 .ok_or(Error::Block)?
267 .min(file_size);
268 let new_num_blocks =
269 (file_size - first_block_size).div_ceil(block_size as u64) as usize;
270 if num_blocks == new_num_blocks {
271 break;
272 }
273 num_blocks = new_num_blocks;
274 }
275 first_block_size as usize
276 };
277 let buf_capacity = (block_size as u64).min(file_size) as usize;
278 Ok(Self {
279 writer,
280 kind,
281 file_size,
282 block_size,
283 first_block_size,
284 position: 0,
285 buf: Vec::with_capacity(buf_capacity.max(first_block_size)),
286 block_refs: Vec::new(),
287 first_block: Vec::new(),
288 service_id,
289 })
290 }
291
292 pub fn write_all(&mut self, data: &[u8]) -> Result<(), Error> {
293 let next_position = self.position + data.len() as u64;
294 if next_position > self.file_size {
295 return Err(Error::Io);
296 }
297 let mut slice = data;
298 while !slice.is_empty() {
299 let max_block_size =
300 if self.first_block.is_empty() { self.first_block_size } else { self.block_size };
301 let n = slice.len().min(max_block_size - self.buf.len());
302 let (chunk, rest) = slice.split_at(n);
303 self.buf.extend_from_slice(chunk);
304 if self.buf.len() == max_block_size {
305 self.write_block()?;
306 }
307 slice = rest;
308 }
309 self.position = next_position;
310 Ok(())
311 }
312
313 pub fn read_from<R: HostFileRead>(&mut self, reader: &mut R) -> Result<(), Error> {
314 let mut remaining = reader.remaining_len()?;
315 let next_position = self.position.checked_add(remaining).ok_or(Error::Io)?;
316 if next_position > self.file_size {
317 return Err(Error::Io);
318 }
319 while remaining != 0 {
320 let max_block_size =
321 if self.first_block.is_empty() { self.first_block_size } else { MAX_BLOCK_SIZE };
322 let old_len = self.buf.len();
323 let n = remaining.min(max_block_size as u64 - old_len as u64) as usize;
324 self.buf.resize(old_len + n, 0_u8);
325 reader.read_exact(&mut self.buf[old_len..])?;
326 if self.buf.len() == max_block_size {
327 self.write_block()?;
328 }
329 remaining -= n as u64;
330 }
331 self.position = next_position;
332 Ok(())
333 }
334
335 pub fn finish(mut self) -> Result<(BlockRef, W), Error> {
339 if !self.buf.is_empty() {
340 self.write_block()?;
341 }
342 if self.position != self.file_size {
343 return Err(Error::Io);
344 }
345 let main_block = MainBlock {
347 kind: self.kind,
348 file_size: self.file_size,
349 block_size: self.block_size as u64,
350 block_refs: core::mem::take(&mut self.block_refs),
351 first_block: FileBlock(core::mem::take(&mut self.first_block).into()),
352 };
353 debug_assert!(validate_main_block(
354 main_block.file_size,
355 main_block.block_size,
356 &main_block.block_refs,
357 &main_block.first_block
358 )
359 .is_ok());
360 self.buf.clear();
361 main_block.encode_to(&mut self.buf);
362 self.writer.write_block(self.service_id, &self.buf[..])?;
363 let main_block_ref =
364 BlockRef { service_id: self.service_id, hash: Hash::digest(&self.buf[..]) };
365 Ok((main_block_ref, self.writer))
366 }
367
368 fn write_block(&mut self) -> Result<(), Error> {
369 if self.first_block.is_empty() {
370 self.first_block = core::mem::take(&mut self.buf);
371 self.buf = Vec::with_capacity((self.block_size as u64).min(self.file_size) as usize);
372 } else {
373 self.block_refs
374 .push(BlockRef { service_id: self.service_id, hash: Hash::digest(&self.buf[..]) });
375 self.writer.write_block(self.service_id, &self.buf[..])?;
376 self.buf.clear();
377 }
378 Ok(())
379 }
380}
381
382struct FallibleOutput<'a, W: WriteBlock> {
384 writer: &'a mut NodeWriter<W>,
385 error: Option<Error>,
386}
387
388impl<W: WriteBlock> codec::Output for FallibleOutput<'_, W> {
389 fn write(&mut self, bytes: &[u8]) {
390 if self.error.is_some() {
391 return;
392 }
393 if let Err(e) = self.writer.write_all(bytes) {
394 self.error = Some(e);
395 }
396 }
397}
398
399pub fn copy_file_in<R: HostFileRead, W: WriteBlock>(
401 host_file_reader: &mut R,
402 service_id: ServiceId,
403 block_writer: &mut W,
404 block_size: usize,
405) -> Result<BlockRef, Error> {
406 let file_size = host_file_reader.remaining_len()?;
407 let mut writer = NodeWriter::new(service_id, block_writer, file_size, block_size)?;
408 writer.read_from(host_file_reader)?;
409 let (main_block_ref, _writer) = writer.finish()?;
410 Ok(main_block_ref)
411}
412
413pub fn copy_file_out<R: ReadBlock, W: HostFileWrite + ?Sized>(
415 main_block_ref: &BlockRef,
416 block_reader: &mut R,
417 host_file_writer: &mut W,
418) -> Result<(), Error> {
419 let mut reader = NodeReader::new(main_block_ref, block_reader)?;
420 if reader.file.main_block.kind != NodeKind::File {
421 return Err(Error::Node);
423 }
424 do_copy_file_out(&mut reader, host_file_writer)?;
425 Ok(())
426}
427
428fn do_copy_file_out<R: ReadBlock, W: HostFileWrite + ?Sized>(
429 reader: &mut NodeReader<R>,
430 writer: &mut W,
431) -> Result<(), Error> {
432 let mut buf = vec![0_u8; MAX_BLOCK_SIZE];
433 loop {
434 let n = reader.read(&mut buf[..])?;
435 if n == 0 {
436 break;
437 }
438 writer.write_all(&buf[..n])?;
439 }
440 Ok(())
441}
442
443pub fn create_dir<W: WriteBlock>(
445 dir: &Dir,
446 service_id: ServiceId,
447 block_writer: &mut W,
448 block_size: usize,
449) -> Result<BlockRef, Error> {
450 let file_size = dir.encoded_size() as u64;
451 let mut writer = NodeWriter::new_dir(service_id, block_writer, file_size, block_size)?;
452 let mut output = FallibleOutput { writer: &mut writer, error: None };
453 dir.encode_to(&mut output);
454 if let Some(e) = output.error {
455 return Err(e);
456 }
457 let (main_block_ref, _writer) = writer.finish()?;
458 Ok(main_block_ref)
459}
460
461pub fn copy_dir_in<F: HostFileRead, R: HostDirRead<F>, W: WriteBlock>(
465 host_dir_reader: R,
466 service_id: ServiceId,
467 block_writer: &mut W,
468 block_size: usize,
469) -> Result<BlockRef, Error> {
470 let mut dir_stack = Vec::new();
471 let mut queue = VecDeque::new();
472 let mut last_dir_ref = BlockRef { service_id: 0, hash: Hash::default() };
473 let mut visited_dirs = VecSet::new();
474 queue.push_back((host_dir_reader, FileName(Default::default()), usize::MAX));
475 while let Some((mut host_dir_reader, dir_name, parent_dir_index)) = queue.pop_front() {
476 let mut files = VecMap::new();
477 let mut subdirs = false;
478 while let Some(entry) = host_dir_reader.next_entry() {
479 let entry = entry?;
480 match entry.kind {
481 NodeKind::File => {
482 let mut file = host_dir_reader.open_file(&entry.file_name)?;
483 let block_ref = copy_file_in(&mut file, service_id, block_writer, block_size)?;
484 files.insert(entry.file_name, block_ref);
485 },
486 NodeKind::Dir => {
487 let (another_dir_reader, dir_id) =
488 host_dir_reader.open_dir(&entry.file_name)?;
489 let visited = match dir_id {
490 Some(dir_id) => !visited_dirs.insert(dir_id),
491 None => false,
492 };
493 if visited {
494 return Err(Error::Loop);
495 }
496 queue.push_back((another_dir_reader, entry.file_name, dir_stack.len()));
497 subdirs = true;
498 },
499 }
500 }
501 if subdirs {
502 dir_stack.push((files, dir_name, parent_dir_index));
503 continue;
504 }
505 let dir = Dir(files);
507 last_dir_ref = create_dir(&dir, service_id, block_writer, block_size)?;
508 if parent_dir_index == usize::MAX {
509 continue;
510 }
511 dir_stack[parent_dir_index].0.insert(dir_name, last_dir_ref);
512 }
513 while let Some((files, dir_name, parent_dir_index)) = dir_stack.pop() {
514 let dir = Dir(files);
515 last_dir_ref = create_dir(&dir, service_id, block_writer, block_size)?;
516 if parent_dir_index == usize::MAX {
517 continue;
518 }
519 dir_stack[parent_dir_index].0.insert(dir_name, last_dir_ref);
520 }
521 Ok(last_dir_ref)
522}
523
524pub fn copy_dir_out<R: ReadBlock, W: HostDirWrite>(
527 main_block_ref: &BlockRef,
528 block_reader: &mut R,
529 host_dir_writer: W,
530) -> Result<(), Error> {
531 let reader = NodeReader::new(main_block_ref, &mut *block_reader)?;
532 if reader.file.main_block.kind != NodeKind::Dir {
533 return Err(Error::Node);
535 }
536 do_copy_dir_out(reader, host_dir_writer)
537}
538
539fn do_copy_dir_out<R: ReadBlock, W: HostDirWrite>(
540 mut node_reader: NodeReader<R>,
541 host_dir_writer: W,
542) -> Result<(), Error> {
543 let mut queue = VecDeque::new();
544 let dir = Dir::decode(&mut node_reader).map_err(|_| Error::Io)?;
545 let mut block_reader = node_reader.into_inner();
546 queue.push_back((dir, host_dir_writer));
547 while let Some((dir, mut host_dir_writer)) = queue.pop_front() {
548 for (file_name, hash) in dir.0.iter() {
549 let mut reader = NodeReader::new(hash, &mut block_reader)?;
550 match reader.file.main_block.kind {
551 NodeKind::File => {
552 let mut file = host_dir_writer.create_file(file_name)?;
553 do_copy_file_out(&mut reader, &mut file)?;
554 },
555 NodeKind::Dir => {
556 let another_dir = Dir::decode(&mut reader).map_err(|_| Error::Io)?;
557 let another_dir_writer = host_dir_writer.create_dir(file_name)?;
558 queue.push_back((another_dir, another_dir_writer));
559 },
560 }
561 }
562 }
563 Ok(())
564}
565
566pub struct NodeIter<R: ReadBlock> {
568 queue: VecDeque<BlockRef>,
569 reader: R,
570}
571
572impl<R: ReadBlock> NodeIter<R> {
573 pub fn new(main_block_ref: BlockRef, reader: R) -> Self {
574 let mut queue = VecDeque::new();
575 queue.push_back(main_block_ref);
576 Self { queue, reader }
577 }
578}
579
580impl<R: ReadBlock> Iterator for NodeIter<R> {
581 type Item = Result<(BlockRef, File), Error>;
582
583 fn next(&mut self) -> Option<Self::Item> {
584 macro_rules! check {
585 ($body: expr) => {
586 match $body {
587 Ok(ret) => ret,
588 Err(e) => return Some(Err(e)),
589 }
590 };
591 }
592 let hash = self.queue.pop_front()?;
593 let mut reader = check!(NodeReader::new(&hash, &mut self.reader));
594 match reader.file.main_block.kind {
595 NodeKind::File => Some(Ok((hash, reader.into_file()))),
596 NodeKind::Dir => {
597 let dir = check!(Dir::decode(&mut reader).map_err(|_| Error::Io));
598 for (_name, hash) in dir.0.into_iter() {
599 self.queue.push_back(hash);
600 }
601 check!(reader.seek(0));
602 Some(Ok((hash, reader.into_file())))
603 },
604 }
605 }
606}
607
608pub fn copy_out<R: ReadBlock, W: HostWrite>(
611 main_block_ref: &BlockRef,
612 block_reader: &mut R,
613 host_writer: W,
614) -> Result<(), Error> {
615 let mut reader = NodeReader::new(main_block_ref, block_reader)?;
616 match reader.file.main_block.kind {
617 NodeKind::File => {
618 let mut file_writer = host_writer.into_file_writer()?;
619 do_copy_file_out(&mut reader, &mut file_writer)?
620 },
621 NodeKind::Dir => do_copy_dir_out(reader, host_writer.into_dir_writer()?)?,
622 }
623 Ok(())
624}
625
626pub fn read<R: ReadBlock>(
628 main_block_ref: &BlockRef,
629 block_reader: &mut R,
630) -> Result<Vec<u8>, Error> {
631 let mut reader = NodeReader::new(main_block_ref, block_reader)?;
632 let mut buf = Vec::with_capacity(reader.file().main_block().file_size() as usize);
633 reader.read_to_end(&mut buf)?;
634 Ok(buf)
635}
636
637pub fn resolve_path<R: ReadBlock>(
642 root_dir_ref: BlockRef,
643 current_dir: &CStr,
644 path: &CStr,
645 block_reader: &mut R,
646) -> Result<BlockRef, Error> {
647 assert!(
648 current_dir.to_bytes().is_empty() || matches!(current_dir.to_bytes(), [b'/', ..]),
649 "Current directory path must be absolute: {current_dir:?}"
650 );
651 let mut dir_stack = Vec::new();
652 let mut pending_ref = root_dir_ref;
653 let cwd_components = match path.to_bytes() {
654 [b'/', ..] => c"",
655 _ => current_dir,
656 }
657 .to_bytes()
658 .split(|b| *b == b'/');
659 let path_components = path.to_bytes().split(|b| *b == b'/');
660 for component in cwd_components.chain(path_components) {
661 match component {
662 b"." | b"" => {},
663 b".." =>
664 if let Some(dir_ref) = dir_stack.pop() {
665 pending_ref = dir_ref;
666 },
667 name => {
668 let dir_ref = pending_ref;
669 let dir = Dir::open(&dir_ref, block_reader)?;
670 pending_ref = dir.0.get(name).cloned().ok_or(Error::Path)?;
671 dir_stack.push(dir_ref);
672 },
673 }
674 }
675 Ok(pending_ref)
676}