blockless_car/utils/
ls.rs

1use std::collections::{HashMap, VecDeque};
2
3use cid::Cid;
4use ipld::raw::RawCodec;
5
6use crate::{
7    error::CarError,
8    reader::CarReader,
9    unixfs::{FileType, UnixFs},
10    Ipld,
11};
12
13/// walk the node and print the files in the directory.
14fn walk<F>(
15    vecq: &mut VecDeque<Cid>,
16    reader: &mut impl CarReader,
17    list_f: &F,
18) -> Result<(), CarError>
19where
20    F: Fn(&Cid, &str),
21{
22    let mut cache: HashMap<Cid, String> = HashMap::new();
23    let raw_code: u64 = RawCodec.into();
24    while let Some(file_cid) = vecq.pop_front() {
25        let codec = file_cid.codec();
26        let file_n = cache
27            .get(&file_cid)
28            .map_or(file_cid.to_string(), |c| c.to_string());
29        list_f(&file_cid, &file_n);
30        // if the codec is RawCodec, the block is the file content block,
31        // it don't conatian the file info. we don't need walk continue.
32        if codec == raw_code {
33            continue;
34        }
35        let file_ipld: Ipld = reader.ipld(&file_cid)?;
36        if let m @ Ipld::Map(_) = file_ipld {
37            let unixfs: UnixFs = m.try_into()?;
38            match unixfs.file_type() {
39                FileType::Directory => {}
40                _ => continue,
41            }
42            for n in unixfs.links().into_iter() {
43                let cid = n.hash;
44                cache.insert(cid, file_n.clone() + "/" + &n.name);
45                vecq.push_back(cid);
46            }
47        }
48    }
49    Ok(())
50}
51
52/// the list file_name from car file  by reader.
53pub fn list(reader: &mut impl CarReader) -> Result<(), CarError> {
54    list_call(reader, |_, file_n| println!("{file_n}"))
55}
56
57/// the list_cid file_name from car file  by reader.
58pub fn list_cid(reader: &mut impl CarReader) -> Result<(), CarError> {
59    list_call(reader, |cid, _| println!("{cid}"))
60}
61
62/// the list car file  by reader.
63/// `reader` is the CarReader
64/// `list_f` is the list call function, first parameter is cid, the second is cid path.
65pub fn list_call<F>(reader: &mut impl CarReader, list_f: F) -> Result<(), CarError>
66where
67    F: Fn(&Cid, &str),
68{
69    let roots = reader.header().roots();
70    let mut queue: VecDeque<Cid> = VecDeque::new();
71    for r in roots.iter() {
72        queue.push_front(*r);
73        walk(&mut queue, reader, &list_f)?;
74    }
75    Ok(())
76}