1use alloc::string::String;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
10pub enum Error {
11 InvalidConfig,
12 OutOfBounds,
13 Corrupt,
14 NotFound,
15 AlreadyExists,
16 NotDir,
17 IsDir,
18 NotEmpty,
19 BadFileDescriptor,
20 InvalidPath,
21 NameTooLong,
22 FileTooLarge,
23 Unsupported,
24 NoSpace,
25 Utf8,
26 Io,
27}
28
29pub type Result<T> = core::result::Result<T, Error>;
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub struct Config {
37 pub block_size: usize,
38 pub block_count: usize,
39}
40
41impl Config {
42 pub const DEFAULT_CACHE_SIZE: usize = 256;
43
44 #[cfg(any(feature = "std", test))]
45 pub(crate) fn cache_size(self) -> usize {
46 core::cmp::min(self.block_size, Self::DEFAULT_CACHE_SIZE)
47 }
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq)]
60pub struct FilesystemOptions {
61 pub read_size: usize,
62 pub prog_size: usize,
63 pub cache_size: usize,
64 pub lookahead_size: usize,
65 pub block_cycles: Option<u32>,
66 pub name_max: u32,
67 pub file_max: u32,
68 pub attr_max: u32,
69 pub metadata_max: Option<usize>,
70 pub inline_max: InlineMax,
71}
72
73#[derive(Debug, Clone, Copy, PartialEq, Eq)]
80pub enum InlineMax {
81 Default,
83 Disabled,
85 Limit(usize),
87}
88
89impl Default for FilesystemOptions {
90 fn default() -> Self {
91 Self {
92 read_size: 16,
93 prog_size: 16,
94 cache_size: Config::DEFAULT_CACHE_SIZE,
95 lookahead_size: 64,
100 block_cycles: Some(128),
101 name_max: 255,
102 file_max: 2_147_483_647,
103 attr_max: 1_022,
104 metadata_max: None,
105 inline_max: InlineMax::Default,
106 }
107 }
108}
109
110impl FilesystemOptions {
111 pub(crate) fn validate(self, cfg: Config) -> Result<Self> {
112 if cfg.block_size == 0
113 || cfg.block_count < 2
114 || self.read_size == 0
115 || self.prog_size == 0
116 || self.cache_size == 0
117 || self.lookahead_size == 0
118 {
119 return Err(Error::InvalidConfig);
120 }
121
122 let cache_size = self.cache_size_for(cfg);
125 if cache_size % self.read_size != 0
126 || cache_size % self.prog_size != 0
127 || cfg.block_size % cache_size != 0
128 {
129 return Err(Error::InvalidConfig);
130 }
131 if !self.prog_size.is_power_of_two() {
132 return Err(Error::InvalidConfig);
133 }
134 if self.lookahead_size % 8 != 0 {
135 return Err(Error::InvalidConfig);
136 }
137 if matches!(self.block_cycles, Some(0)) {
138 return Err(Error::InvalidConfig);
139 }
140 if self.name_max == 0
141 || self.name_max > 1_022
142 || self.file_max == 0
143 || self.file_max > 2_147_483_647
144 || self.attr_max == 0
145 || self.attr_max > 1_022
146 {
147 return Err(Error::InvalidConfig);
148 }
149
150 if let Some(metadata_max) = self.metadata_max {
151 if metadata_max == 0
152 || metadata_max > cfg.block_size
153 || metadata_max % self.read_size != 0
154 || metadata_max % self.prog_size != 0
155 || cfg.block_size % metadata_max != 0
156 {
157 return Err(Error::InvalidConfig);
158 }
159 }
160
161 if let InlineMax::Limit(limit) = self.inline_max {
162 let metadata_limit = self.metadata_max.unwrap_or(cfg.block_size);
163 if limit > cache_size || limit > self.attr_max as usize || limit > metadata_limit / 8 {
164 return Err(Error::InvalidConfig);
165 }
166 }
167
168 Ok(self)
169 }
170
171 pub(crate) fn cache_size_for(self, cfg: Config) -> usize {
172 core::cmp::min(self.cache_size, cfg.block_size)
173 }
174
175 pub(crate) fn inline_threshold(self, cfg: Config, attr_max: u32) -> usize {
176 match self.inline_max {
177 InlineMax::Default => {
178 let metadata_limit = self.metadata_max.unwrap_or(cfg.block_size);
179 core::cmp::min(
180 self.cache_size_for(cfg),
181 core::cmp::min(attr_max as usize, metadata_limit / 8),
182 )
183 }
184 InlineMax::Disabled => 0,
185 InlineMax::Limit(limit) => core::cmp::min(limit, attr_max as usize),
186 }
187 }
188}
189
190#[derive(Debug, Clone, PartialEq, Eq)]
191pub struct FsInfo {
192 pub disk_version: u32,
193 pub block_size: u32,
194 pub block_count: u32,
195 pub name_max: u32,
196 pub file_max: u32,
197 pub attr_max: u32,
198}
199
200#[derive(Debug, Clone, PartialEq, Eq)]
201pub struct FilesystemLimits {
202 pub block_size: u32,
203 pub block_count: u32,
204 pub name_max: u32,
205 pub file_max: u32,
206 pub attr_max: u32,
207}
208
209#[derive(Debug, Clone, PartialEq, Eq)]
210pub struct DirectoryUsage {
211 pub entry_count: usize,
212 pub metadata_pair_count: usize,
213 pub is_split: bool,
214 pub append_bytes_used: usize,
215 pub append_bytes_remaining: usize,
216}
217
218#[derive(Debug, Clone, Copy, PartialEq, Eq)]
219pub enum FileType {
220 File,
221 Dir,
222}
223
224#[derive(Debug, Clone, PartialEq, Eq)]
225pub struct DirEntry {
226 pub name: String,
227 pub ty: FileType,
228 pub size: u32,
229}
230
231#[derive(Debug, Clone, PartialEq, Eq)]
232pub struct WalkEntry {
233 pub path: String,
234 pub entry: DirEntry,
235}