gc_gcm/
dir_listing.rs

1use core::fmt;
2use crate::{FsNode, FileSystem};
3
4#[cfg(feature = "no_std")]
5use crate::std::vec::Vec;
6
7impl FileSystem {
8    /// Iterates over the root of the filesystem
9    pub fn iter_root<'a>(&'a self) -> impl Iterator<Item = DirEntry<'a>> + 'a {
10        let files = &self.files;
11        let mut entries = Vec::new();
12
13        let mut entries_iter = self.files
14            .iter()
15            .enumerate()
16            .map(|(i, node)| DirEntry { node, files, index: i + 1 });
17
18        while let Some(entry) = entries_iter.next() {
19            recursive_remove(&entry, &mut entries_iter);
20
21            entries.push(entry);
22        }
23
24        entries.into_iter()
25    }
26
27    pub fn get_child(&self, child_name: &str) -> Option<DirEntry> {
28        self.iter_root()
29            .find(|entry| {
30                match entry.node {
31                    FsNode::Directory { name, .. } | FsNode::File { name, .. }
32                        if name == child_name => true,
33                    _ => false
34                }
35            })
36    }
37}
38
39/// An entry representing a directory within the image's filesystem
40#[derive(Clone, Copy)]
41pub struct DirEntry<'a> {
42    /// The `FsNode` of the current directory
43    node: &'a FsNode,
44
45    /// A backreference to all the files within the filesystem
46    files: &'a [FsNode],
47
48    /// The index of this directory's FsNode
49    index: usize,
50}
51
52impl<'a> fmt::Debug for DirEntry<'a> {
53    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54        fmt::Debug::fmt(&self.node, f)
55    }
56}
57
58fn recursive_remove<'a>(entry: &DirEntry, iter: &mut impl Iterator<Item = DirEntry<'a>>) {
59    match entry.node {
60        &FsNode::Directory { end_index, .. } => {
61            for _ in 1..(end_index as usize - entry.index) {
62                iter.next();
63            }
64        }
65        _ => {}
66    }
67}
68
69impl<'a> DirEntry<'a> {
70    pub fn is_dir(&self) -> bool {
71        match self.node {
72            FsNode::Directory { .. } => true,
73            FsNode::File { .. } => false,
74        }
75    } 
76
77    pub fn is_file(&self) -> bool {
78        match self.node {
79            FsNode::Directory { .. } => false,
80            FsNode::File { .. } => true,
81        }
82    }
83
84    pub fn entry_name(&self) -> &'a str {
85        match self.node {
86            FsNode::File { name, .. } | FsNode::Directory { name, .. } => &name,
87        }
88    }
89
90    pub fn iter_dir(&self) -> Option<impl Iterator<Item = DirEntry<'a>> + 'a> {
91        match self.node {
92            FsNode::Directory { end_index, .. } => {
93                let files = self.files;
94                let index = self.index;
95                let end_index = *end_index as usize;
96
97                let mut entries = Vec::new();
98                let mut entries_iter = 
99                    files[index..end_index - 1]
100                        .iter()
101                        .enumerate()
102                        .map(|(i, node)| DirEntry { node, files, index: index + i + 1 });
103
104                while let Some(entry) = entries_iter.next() {
105                    recursive_remove(&entry, &mut entries_iter);
106                    entries.push(entry);
107                }
108
109                Some(entries.into_iter())
110            },
111            FsNode::File { .. } => None,
112        }
113    }
114
115    pub fn get_child(&self, child_name: &str) -> Option<DirEntry<'a>> {
116        self.iter_dir()?
117            .find(|entry| {
118                match entry.node {
119                    FsNode::Directory { name, .. } | FsNode::File { name, .. }
120                        if name == child_name => true,
121                    _ => false
122                }
123            })
124    }
125
126    pub fn as_file(&self) -> Option<File> {
127        match self.node {
128            &FsNode::File { offset, size, .. } => Some(File { offset, size }),
129            FsNode::Directory { .. } => None
130        }
131    }
132}
133
134/// A file within the filesystem, representing the range of the data backing within the GCM image
135/// itself
136#[derive(Debug, Clone, Copy)]
137pub struct File {
138    pub offset: u32,
139    pub size: u32
140}