1mod error;
13pub mod filesystem;
14pub mod format;
15
16use crate::filesystem::BlockConnector;
17use fidl_fuchsia_fs_startup::{FormatOptions, StartOptions};
18use std::sync::Arc;
19
20pub use error::{QueryError, ShutdownError};
22
23pub const BLOBFS_TYPE_GUID: [u8; 16] = [
24 0x0e, 0x38, 0x67, 0x29, 0x4c, 0x13, 0xbb, 0x4c, 0xb6, 0xda, 0x17, 0xe7, 0xce, 0x1c, 0xa4, 0x5d,
25];
26pub const DATA_TYPE_GUID: [u8; 16] = [
27 0x0c, 0x5f, 0x18, 0x08, 0x2d, 0x89, 0x8a, 0x42, 0xa7, 0x89, 0xdb, 0xee, 0xc8, 0xf5, 0x5e, 0x6a,
28];
29pub const FVM_TYPE_GUID: [u8; 16] = [
30 0xb8, 0x7c, 0xfd, 0x49, 0x15, 0xdf, 0x73, 0x4e, 0xb9, 0xd9, 0x99, 0x20, 0x70, 0x12, 0x7f, 0x0f,
31];
32
33pub const FVM_TYPE_GUID_STR: &str = "49fd7cb8-df15-4e73-b9d9-992070127f0f";
34
35pub const FS_COLLECTION_NAME: &'static str = "fs-collection";
36
37#[derive(Clone)]
38pub enum ComponentType {
39 StaticChild,
42
43 DynamicChild { collection_name: String },
46}
47
48impl Default for ComponentType {
49 fn default() -> Self {
50 ComponentType::DynamicChild { collection_name: "fs-collection".to_string() }
51 }
52}
53
54pub struct Options<'a> {
55 pub component_name: &'a str,
61
62 pub reuse_component_after_serving: bool,
65
66 pub format_options: FormatOptions,
68
69 pub start_options: StartOptions,
71
72 pub component_type: ComponentType,
74}
75
76pub trait FSConfig: Send + Sync + 'static {
78 fn options(&self) -> Options<'_>;
80
81 fn is_multi_volume(&self) -> bool {
83 false
84 }
85
86 fn disk_format(&self) -> format::DiskFormat {
87 format::DiskFormat::Unknown
88 }
89}
90
91#[derive(Clone)]
97pub enum BlobLayout {
98 DeprecatedPadded,
101
102 Compact,
104}
105
106#[derive(Clone, Default)]
109pub struct Blobfs {
110 pub verbose: bool,
112 pub deprecated_padded_blobfs_format: bool,
113 pub num_inodes: u64,
114 pub readonly: bool,
116 pub component_type: ComponentType,
117}
118
119impl Blobfs {
120 pub fn new<B: BlockConnector + 'static>(block_connector: B) -> filesystem::Filesystem {
122 filesystem::Filesystem::new(block_connector, Self::default())
123 }
124
125 pub fn dynamic_child() -> Self {
127 Self {
128 component_type: ComponentType::DynamicChild {
129 collection_name: FS_COLLECTION_NAME.to_string(),
130 },
131 ..Default::default()
132 }
133 }
134}
135
136impl FSConfig for Blobfs {
137 fn options(&self) -> Options<'_> {
138 Options {
139 component_name: "blobfs",
140 reuse_component_after_serving: false,
141 format_options: FormatOptions {
142 verbose: Some(self.verbose),
143 deprecated_padded_blobfs_format: Some(self.deprecated_padded_blobfs_format),
144 num_inodes: if self.num_inodes > 0 { Some(self.num_inodes) } else { None },
145 ..Default::default()
146 },
147 start_options: {
148 StartOptions {
149 read_only: Some(self.readonly),
150 verbose: Some(self.verbose),
151 ..Default::default()
152 }
153 },
154 component_type: self.component_type.clone(),
155 }
156 }
157
158 fn disk_format(&self) -> format::DiskFormat {
159 format::DiskFormat::Blobfs
160 }
161}
162
163#[derive(Clone, Default)]
166pub struct Minfs {
167 pub verbose: bool,
170 pub fvm_data_slices: u32,
171 pub readonly: bool,
173 pub fsck_after_every_transaction: bool,
174 pub component_type: ComponentType,
175}
176
177impl Minfs {
178 pub fn new<B: BlockConnector + 'static>(block_connector: B) -> filesystem::Filesystem {
180 filesystem::Filesystem::new(block_connector, Self::default())
181 }
182
183 pub fn dynamic_child() -> Self {
185 Self {
186 component_type: ComponentType::DynamicChild {
187 collection_name: FS_COLLECTION_NAME.to_string(),
188 },
189 ..Default::default()
190 }
191 }
192}
193
194impl FSConfig for Minfs {
195 fn options(&self) -> Options<'_> {
196 Options {
197 component_name: "minfs",
198 reuse_component_after_serving: false,
199 format_options: FormatOptions {
200 verbose: Some(self.verbose),
201 fvm_data_slices: Some(self.fvm_data_slices),
202 ..Default::default()
203 },
204 start_options: StartOptions {
205 read_only: Some(self.readonly),
206 verbose: Some(self.verbose),
207 fsck_after_every_transaction: Some(self.fsck_after_every_transaction),
208 ..Default::default()
209 },
210 component_type: self.component_type.clone(),
211 }
212 }
213
214 fn disk_format(&self) -> format::DiskFormat {
215 format::DiskFormat::Minfs
216 }
217}
218
219pub type CryptClientFn = Arc<dyn Fn() -> zx::Channel + Send + Sync>;
220
221#[derive(Clone)]
223pub struct Fxfs {
224 pub readonly: bool,
226 pub fsck_after_every_transaction: bool,
227 pub component_type: ComponentType,
228 pub startup_profiling_seconds: Option<u32>,
229 pub inline_crypto_enabled: bool,
230 pub barriers_enabled: bool,
231 pub allow_type3_blobs: bool,
232}
233
234impl Default for Fxfs {
235 fn default() -> Self {
236 Self {
237 readonly: false,
238 fsck_after_every_transaction: false,
239 component_type: Default::default(),
240 startup_profiling_seconds: None,
241 inline_crypto_enabled: false,
242 barriers_enabled: false,
243 allow_type3_blobs: false,
244 }
245 }
246}
247
248impl Fxfs {
249 pub fn new<B: BlockConnector + 'static>(block_connector: B) -> filesystem::Filesystem {
251 filesystem::Filesystem::new(block_connector, Self::default())
252 }
253
254 pub fn dynamic_child() -> Self {
256 Self {
257 component_type: ComponentType::DynamicChild {
258 collection_name: FS_COLLECTION_NAME.to_string(),
259 },
260 ..Default::default()
261 }
262 }
263}
264
265impl FSConfig for Fxfs {
266 fn options(&self) -> Options<'_> {
267 Options {
268 component_name: "fxfs",
269 reuse_component_after_serving: true,
270 format_options: FormatOptions { verbose: Some(false), ..Default::default() },
271 start_options: StartOptions {
272 read_only: Some(self.readonly),
273 fsck_after_every_transaction: Some(self.fsck_after_every_transaction),
274 startup_profiling_seconds: Some(self.startup_profiling_seconds.unwrap_or(0)),
275 inline_crypto_enabled: Some(self.inline_crypto_enabled),
276 barriers_enabled: Some(self.barriers_enabled),
277 allow_type3_blobs: Some(self.allow_type3_blobs),
278 ..Default::default()
279 },
280 component_type: self.component_type.clone(),
281 }
282 }
283
284 fn is_multi_volume(&self) -> bool {
285 true
286 }
287
288 fn disk_format(&self) -> format::DiskFormat {
289 format::DiskFormat::Fxfs
290 }
291}
292
293#[derive(Clone, Default)]
296pub struct F2fs {
297 pub component_type: ComponentType,
298}
299
300impl F2fs {
301 pub fn new<B: BlockConnector + 'static>(block_connector: B) -> filesystem::Filesystem {
303 filesystem::Filesystem::new(block_connector, Self::default())
304 }
305
306 pub fn dynamic_child() -> Self {
308 Self {
309 component_type: ComponentType::DynamicChild {
310 collection_name: FS_COLLECTION_NAME.to_string(),
311 },
312 ..Default::default()
313 }
314 }
315}
316
317impl FSConfig for F2fs {
318 fn options(&self) -> Options<'_> {
319 Options {
320 component_name: "f2fs",
321 reuse_component_after_serving: false,
322 format_options: FormatOptions::default(),
323 start_options: StartOptions {
324 read_only: Some(false),
325 verbose: Some(false),
326 fsck_after_every_transaction: Some(false),
327 ..Default::default()
328 },
329 component_type: self.component_type.clone(),
330 }
331 }
332 fn is_multi_volume(&self) -> bool {
333 false
334 }
335
336 fn disk_format(&self) -> format::DiskFormat {
337 format::DiskFormat::F2fs
338 }
339}
340
341#[derive(Clone, Default)]
343pub struct Fvm {
344 pub component_type: ComponentType,
345 pub slice_size: u64,
346}
347
348impl Fvm {
349 pub fn new<B: BlockConnector + 'static>(block_connector: B) -> filesystem::Filesystem {
351 filesystem::Filesystem::new(block_connector, Self::default())
352 }
353
354 pub fn dynamic_child() -> Self {
356 Self {
357 component_type: ComponentType::DynamicChild {
358 collection_name: FS_COLLECTION_NAME.to_string(),
359 },
360 ..Default::default()
361 }
362 }
363}
364
365impl FSConfig for Fvm {
366 fn options(&self) -> Options<'_> {
367 Options {
368 component_name: "fvm2",
369 reuse_component_after_serving: true,
370 format_options: FormatOptions {
371 fvm_slice_size: if self.slice_size > 0 { Some(self.slice_size) } else { None },
372 ..FormatOptions::default()
373 },
374 start_options: StartOptions::default(),
375 component_type: self.component_type.clone(),
376 }
377 }
378
379 fn is_multi_volume(&self) -> bool {
380 true
381 }
382
383 fn disk_format(&self) -> format::DiskFormat {
384 format::DiskFormat::Fvm
385 }
386}
387
388#[derive(Clone)]
390pub struct Gpt {
391 pub component_type: ComponentType,
392 pub merge_super_and_userdata: bool,
393}
394
395impl Default for Gpt {
396 fn default() -> Self {
397 Self { component_type: Default::default(), merge_super_and_userdata: false }
398 }
399}
400
401impl Gpt {
402 pub fn new<B: BlockConnector + 'static>(block_connector: B) -> filesystem::Filesystem {
404 filesystem::Filesystem::new(block_connector, Self::default())
405 }
406
407 pub fn dynamic_child() -> Self {
409 Self {
410 component_type: ComponentType::DynamicChild {
411 collection_name: FS_COLLECTION_NAME.to_string(),
412 },
413 ..Default::default()
414 }
415 }
416}
417
418impl FSConfig for Gpt {
419 fn options(&self) -> Options<'_> {
420 Options {
421 component_name: "gpt2",
422 reuse_component_after_serving: true,
423 format_options: FormatOptions::default(),
424 start_options: StartOptions {
425 merge_super_and_userdata: Some(self.merge_super_and_userdata),
426 ..Default::default()
427 },
428 component_type: self.component_type.clone(),
429 }
430 }
431
432 fn is_multi_volume(&self) -> bool {
433 true
434 }
435
436 fn disk_format(&self) -> format::DiskFormat {
437 format::DiskFormat::Gpt
438 }
439}
440
441#[cfg(test)]
442mod tests {
443 use super::*;
444
445 struct PlaceholderFsConfig;
446 impl FSConfig for PlaceholderFsConfig {
447 fn options(&self) -> Options<'_> {
448 Options {
449 component_name: "placeholder",
450 reuse_component_after_serving: false,
451 format_options: FormatOptions::default(),
452 start_options: StartOptions::default(),
453 component_type: ComponentType::StaticChild,
454 }
455 }
456 }
457
458 #[fuchsia::test]
459 fn test_fs_config_defaults_and_options() {
460 let placeholder = PlaceholderFsConfig;
461 assert_eq!(placeholder.options().component_name, "placeholder");
462 assert!(!placeholder.is_multi_volume());
463 assert_eq!(placeholder.disk_format(), format::DiskFormat::Unknown);
464
465 let mut blobfs = Blobfs::dynamic_child();
466 assert_eq!(blobfs.options().format_options.num_inodes, None);
467 blobfs.num_inodes = 2048;
468 blobfs.verbose = true;
469 blobfs.readonly = true;
470 let blobfs_opts = blobfs.options();
471 assert_eq!(blobfs_opts.component_name, "blobfs");
472 assert!(!blobfs_opts.reuse_component_after_serving);
473 assert_eq!(blobfs_opts.format_options.num_inodes, Some(2048));
474 assert_eq!(blobfs_opts.start_options.read_only, Some(true));
475 assert!(!blobfs.is_multi_volume());
476 assert_eq!(blobfs.disk_format(), format::DiskFormat::Blobfs);
477
478 let mut minfs = Minfs::dynamic_child();
479 minfs.fvm_data_slices = 4;
480 minfs.fsck_after_every_transaction = true;
481 let minfs_opts = minfs.options();
482 assert_eq!(minfs_opts.component_name, "minfs");
483 assert_eq!(minfs_opts.format_options.fvm_data_slices, Some(4));
484 assert_eq!(minfs_opts.start_options.fsck_after_every_transaction, Some(true));
485 assert!(!minfs.is_multi_volume());
486 assert_eq!(minfs.disk_format(), format::DiskFormat::Minfs);
487
488 let mut fxfs = Fxfs::dynamic_child();
489 assert_eq!(fxfs.options().start_options.startup_profiling_seconds, Some(0));
490 fxfs.startup_profiling_seconds = Some(30);
491 fxfs.inline_crypto_enabled = true;
492 fxfs.barriers_enabled = true;
493 fxfs.allow_type3_blobs = true;
494 let fxfs_opts = fxfs.options();
495 assert_eq!(fxfs_opts.component_name, "fxfs");
496 assert!(fxfs_opts.reuse_component_after_serving);
497 assert_eq!(fxfs_opts.start_options.startup_profiling_seconds, Some(30));
498 assert_eq!(fxfs_opts.start_options.inline_crypto_enabled, Some(true));
499 assert_eq!(fxfs_opts.start_options.barriers_enabled, Some(true));
500 assert_eq!(fxfs_opts.start_options.allow_type3_blobs, Some(true));
501 assert!(fxfs.is_multi_volume());
502 assert_eq!(fxfs.disk_format(), format::DiskFormat::Fxfs);
503
504 let f2fs = F2fs::dynamic_child();
505 let f2fs_opts = f2fs.options();
506 assert_eq!(f2fs_opts.component_name, "f2fs");
507 assert!(!f2fs_opts.reuse_component_after_serving);
508 assert!(!f2fs.is_multi_volume());
509 assert_eq!(f2fs.disk_format(), format::DiskFormat::F2fs);
510
511 let mut fvm = Fvm::dynamic_child();
512 assert_eq!(fvm.options().format_options.fvm_slice_size, None);
513 fvm.slice_size = 32768;
514 let fvm_opts = fvm.options();
515 assert_eq!(fvm_opts.component_name, "fvm2");
516 assert!(fvm_opts.reuse_component_after_serving);
517 assert_eq!(fvm_opts.format_options.fvm_slice_size, Some(32768));
518 assert!(fvm.is_multi_volume());
519 assert_eq!(fvm.disk_format(), format::DiskFormat::Fvm);
520
521 let mut gpt = Gpt::dynamic_child();
522 gpt.merge_super_and_userdata = true;
523 let gpt_opts = gpt.options();
524 assert_eq!(gpt_opts.component_name, "gpt2");
525 assert!(gpt_opts.reuse_component_after_serving);
526 assert_eq!(gpt_opts.start_options.merge_super_and_userdata, Some(true));
527 assert!(gpt.is_multi_volume());
528 assert_eq!(gpt.disk_format(), format::DiskFormat::Gpt);
529 }
530}