OXYGENHUB
# 5c4016b9c5eb oxygenflow / crates / flow / src / cpio.rs
1.7 KiB · Rust · last changed OxygenFlow M0: pipeline parser and canonical job graph, receipts, the runner API types, flow-init, the Firecracker tier, flow check, run, rootfs import and runner 1 month ago source blame history raw
1
//! A minimal `newc` cpio writer for the per-job initramfs: regular files
2
//! at the archive root, owned by root.
3
4
pub struct Entry<'a> {
5
    pub name: &'a str,
6
    pub mode: u32,
7
    pub data: &'a [u8],
8
}
9
10
fn header(out: &mut Vec<u8>, ino: u32, mode: u32, size: usize, name: &str) {
11
    let fields = [ino, mode, 0, 0, 1, 0, size as u32, 0, 0, 0, 0, (name.len() + 1) as u32, 0];
12
    out.extend_from_slice(b"070701");
13
    for f in fields {
14
        out.extend_from_slice(format!("{f:08X}").as_bytes());
15
    }
16
    out.extend_from_slice(name.as_bytes());
17
    out.push(0);
18
    pad(out);
19
}
20
21
fn pad(out: &mut Vec<u8>) {
22
    while !out.len().is_multiple_of(4) {
23
        out.push(0);
24
    }
25
}
26
27
pub fn newc(entries: &[Entry]) -> Vec<u8> {
28
    let mut out = Vec::new();
29
    for (i, e) in entries.iter().enumerate() {
30
        header(&mut out, i as u32 + 1, 0o100000 | e.mode, e.data.len(), e.name);
31
        out.extend_from_slice(e.data);
32
        pad(&mut out);
33
    }
34
    header(&mut out, 0, 0, 0, "TRAILER!!!");
35
    out
36
}
37
38
#[cfg(test)]
39
mod tests {
40
    use super::*;
41
42
    #[test]
43
    fn system_cpio_reads_it() {
44
        let dir = tempfile::tempdir().unwrap();
45
        let archive = newc(&[Entry { name: "init", mode: 0o755, data: b"#!x\n" }, Entry { name: "job.json", mode: 0o644, data: b"{}" }]);
46
        std::fs::write(dir.path().join("a.cpio"), &archive).unwrap();
47
        let listed = std::process::Command::new("cpio").args(["-it", "--quiet", "-F"]).arg(dir.path().join("a.cpio")).output();
48
        if let Ok(o) = listed {
49
            if o.status.success() {
50
                assert_eq!(String::from_utf8_lossy(&o.stdout), "init\njob.json\n");
51
            }
52
        }
53
        assert!(archive.len().is_multiple_of(4));
54
        assert!(archive.windows(10).any(|w| w == b"TRAILER!!!"));
55
    }
56
}