rust_car/utils/
ls.rs

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