nix_compat/nar/
copy.rs

1use std::io;
2
3use super::reader;
4use super::reader::Reader;
5use super::writer;
6
7/// Reads through the entire NAR, and writes it back to a writer.
8/// This verifies its syntactical correctness.
9pub fn copy<W>(r: &mut Reader<'_>, w: &mut W) -> io::Result<()>
10where
11    W: std::io::Write,
12{
13    let node_r = reader::open(r)?;
14    let node_w = writer::open(w)?;
15
16    copy_node(node_r, node_w)
17}
18
19fn copy_node<W>(node_r: reader::Node<'_, '_>, node_w: writer::Node<'_, W>) -> io::Result<()>
20where
21    W: std::io::Write,
22{
23    match node_r {
24        reader::Node::Symlink { target } => node_w.symlink(&target)?,
25        reader::Node::File { executable, reader } => node_w.file(
26            executable,
27            reader.len(),
28            &mut std::io::BufReader::new(reader),
29        )?,
30        reader::Node::Directory(mut dir_reader) => {
31            let mut directory_w = node_w.directory()?;
32            while let Some(entry) = dir_reader.next()? {
33                let node_w = directory_w.entry(entry.name)?;
34                copy_node(entry.node, node_w)?;
35            }
36
37            directory_w.close()?;
38        }
39    }
40
41    Ok(())
42}
43
44#[cfg(test)]
45mod tests {
46    use rstest::rstest;
47    use std::path::PathBuf;
48
49    #[rstest]
50    fn roundtrip(#[files("src/nar/tests/*.nar")] path: PathBuf) {
51        let nar_src = std::fs::read(path).expect("must succeed");
52
53        let mut out_buf = Vec::new();
54
55        assert!(super::copy(&mut std::io::Cursor::new(&nar_src), &mut out_buf).is_ok());
56        assert_eq!(nar_src, out_buf, "must roundtrip");
57    }
58}