Skip to main content

fs_management/
lib.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Library for filesystem management in rust.
6//!
7//! This library is analogous to the fs-management library in zircon. It provides support for
8//! formatting, mounting, unmounting, and fsck-ing. It is implemented in a similar way to the C++
9//! version.  For components v2, add `/svc/fuchsia.process.Launcher` to `use` and add the
10//! binaries as dependencies to your component.
11
12mod error;
13pub mod filesystem;
14pub mod format;
15pub mod partition;
16
17use crate::filesystem::BlockConnector;
18use fidl_fuchsia_fs_startup::{FormatOptions, StartOptions};
19use std::sync::Arc;
20
21// Re-export errors as public.
22pub use error::{QueryError, ShutdownError};
23
24pub const BLOBFS_TYPE_GUID: [u8; 16] = [
25    0x0e, 0x38, 0x67, 0x29, 0x4c, 0x13, 0xbb, 0x4c, 0xb6, 0xda, 0x17, 0xe7, 0xce, 0x1c, 0xa4, 0x5d,
26];
27pub const DATA_TYPE_GUID: [u8; 16] = [
28    0x0c, 0x5f, 0x18, 0x08, 0x2d, 0x89, 0x8a, 0x42, 0xa7, 0x89, 0xdb, 0xee, 0xc8, 0xf5, 0x5e, 0x6a,
29];
30pub const FVM_TYPE_GUID: [u8; 16] = [
31    0xb8, 0x7c, 0xfd, 0x49, 0x15, 0xdf, 0x73, 0x4e, 0xb9, 0xd9, 0x99, 0x20, 0x70, 0x12, 0x7f, 0x0f,
32];
33
34pub const FVM_TYPE_GUID_STR: &str = "49fd7cb8-df15-4e73-b9d9-992070127f0f";
35
36pub const FS_COLLECTION_NAME: &'static str = "fs-collection";
37
38#[derive(Clone)]
39pub enum ComponentType {
40    /// Launch the filesystem as a static child, using the configured name in the options as the
41    /// child name. If the child doesn't exist, this will fail.
42    StaticChild,
43
44    /// Launch the filesystem as a dynamic child, in the configured collection. By default, the
45    /// collection is "fs-collection".
46    DynamicChild { collection_name: String },
47}
48
49impl Default for ComponentType {
50    fn default() -> Self {
51        ComponentType::DynamicChild { collection_name: "fs-collection".to_string() }
52    }
53}
54
55pub struct Options<'a> {
56    /// For static children, the name specifies the name of the child.  For dynamic children, the
57    /// component URL is "fuchsia-boot:///{component-name}#meta/{component-name}.cm" or
58    /// "#meta/{component-name}.cm".  The library will attempt to connect to a static child first,
59    /// and if that fails, it will launch the filesystem within a collection. It will try to
60    /// create a child component via the absolute URL and then fallback to the relative URL.
61    pub component_name: &'a str,
62
63    /// It should be possible to reuse components after serving them, but it's not universally
64    /// supported.
65    pub reuse_component_after_serving: bool,
66
67    /// Format options as defined by the startup protocol
68    pub format_options: FormatOptions,
69
70    /// Start options as defined by the startup protocol
71    pub start_options: StartOptions,
72
73    /// Whether to launch this filesystem as a dynamic or static child.
74    pub component_type: ComponentType,
75}
76
77/// Describes the configuration for a particular filesystem.
78pub trait FSConfig: Send + Sync + 'static {
79    /// Returns the options specifying how to run this filesystem.
80    fn options(&self) -> Options<'_>;
81
82    /// Whether the filesystem supports multiple volumes.
83    fn is_multi_volume(&self) -> bool {
84        false
85    }
86
87    fn disk_format(&self) -> format::DiskFormat {
88        format::DiskFormat::Unknown
89    }
90}
91
92///
93/// FILESYSTEMS
94///
95
96/// Layout of blobs in blobfs
97#[derive(Clone)]
98pub enum BlobLayout {
99    /// Merkle tree is stored in a separate block. This is deprecated and used only on Astro
100    /// devices (it takes more space).
101    DeprecatedPadded,
102
103    /// Merkle tree is appended to the last block of data
104    Compact,
105}
106
107/// Blobfs Filesystem Configuration
108/// If fields are None or false, they will not be set in arguments.
109#[derive(Clone, Default)]
110pub struct Blobfs {
111    // Format options
112    pub verbose: bool,
113    pub deprecated_padded_blobfs_format: bool,
114    pub num_inodes: u64,
115    // Start Options
116    pub readonly: bool,
117    pub component_type: ComponentType,
118}
119
120impl Blobfs {
121    /// Manages a block device using the default configuration.
122    pub fn new<B: BlockConnector + 'static>(block_connector: B) -> filesystem::Filesystem {
123        filesystem::Filesystem::new(block_connector, Self::default())
124    }
125
126    /// Launch blobfs, with the default configuration, as a dynamic child in the fs-collection.
127    pub fn dynamic_child() -> Self {
128        Self {
129            component_type: ComponentType::DynamicChild {
130                collection_name: FS_COLLECTION_NAME.to_string(),
131            },
132            ..Default::default()
133        }
134    }
135}
136
137impl FSConfig for Blobfs {
138    fn options(&self) -> Options<'_> {
139        Options {
140            component_name: "blobfs",
141            reuse_component_after_serving: false,
142            format_options: FormatOptions {
143                verbose: Some(self.verbose),
144                deprecated_padded_blobfs_format: Some(self.deprecated_padded_blobfs_format),
145                num_inodes: if self.num_inodes > 0 { Some(self.num_inodes) } else { None },
146                ..Default::default()
147            },
148            start_options: {
149                StartOptions {
150                    read_only: Some(self.readonly),
151                    verbose: Some(self.verbose),
152                    ..Default::default()
153                }
154            },
155            component_type: self.component_type.clone(),
156        }
157    }
158
159    fn disk_format(&self) -> format::DiskFormat {
160        format::DiskFormat::Blobfs
161    }
162}
163
164/// Minfs Filesystem Configuration
165/// If fields are None or false, they will not be set in arguments.
166#[derive(Clone, Default)]
167pub struct Minfs {
168    // TODO(xbhatnag): Add support for fvm_data_slices
169    // Format options
170    pub verbose: bool,
171    pub fvm_data_slices: u32,
172    // Start Options
173    pub readonly: bool,
174    pub fsck_after_every_transaction: bool,
175    pub component_type: ComponentType,
176}
177
178impl Minfs {
179    /// Manages a block device using the default configuration.
180    pub fn new<B: BlockConnector + 'static>(block_connector: B) -> filesystem::Filesystem {
181        filesystem::Filesystem::new(block_connector, Self::default())
182    }
183
184    /// Launch minfs, with the default configuration, as a dynamic child in the fs-collection.
185    pub fn dynamic_child() -> Self {
186        Self {
187            component_type: ComponentType::DynamicChild {
188                collection_name: FS_COLLECTION_NAME.to_string(),
189            },
190            ..Default::default()
191        }
192    }
193}
194
195impl FSConfig for Minfs {
196    fn options(&self) -> Options<'_> {
197        Options {
198            component_name: "minfs",
199            reuse_component_after_serving: false,
200            format_options: FormatOptions {
201                verbose: Some(self.verbose),
202                fvm_data_slices: Some(self.fvm_data_slices),
203                ..Default::default()
204            },
205            start_options: StartOptions {
206                read_only: Some(self.readonly),
207                verbose: Some(self.verbose),
208                fsck_after_every_transaction: Some(self.fsck_after_every_transaction),
209                ..Default::default()
210            },
211            component_type: self.component_type.clone(),
212        }
213    }
214
215    fn disk_format(&self) -> format::DiskFormat {
216        format::DiskFormat::Minfs
217    }
218}
219
220pub type CryptClientFn = Arc<dyn Fn() -> zx::Channel + Send + Sync>;
221
222/// Fxfs Filesystem Configuration
223#[derive(Clone)]
224pub struct Fxfs {
225    // Start Options
226    pub readonly: bool,
227    pub fsck_after_every_transaction: bool,
228    pub component_type: ComponentType,
229    pub startup_profiling_seconds: Option<u32>,
230    pub inline_crypto_enabled: bool,
231    pub barriers_enabled: bool,
232    pub allow_type3_blobs: bool,
233}
234
235impl Default for Fxfs {
236    fn default() -> Self {
237        Self {
238            readonly: false,
239            fsck_after_every_transaction: false,
240            component_type: Default::default(),
241            startup_profiling_seconds: None,
242            inline_crypto_enabled: false,
243            barriers_enabled: false,
244            allow_type3_blobs: false,
245        }
246    }
247}
248
249impl Fxfs {
250    /// Manages a block device using the default configuration.
251    pub fn new<B: BlockConnector + 'static>(block_connector: B) -> filesystem::Filesystem {
252        filesystem::Filesystem::new(block_connector, Self::default())
253    }
254
255    /// Launch Fxfs, with the default configuration, as a dynamic child in the fs-collection.
256    pub fn dynamic_child() -> Self {
257        Self {
258            component_type: ComponentType::DynamicChild {
259                collection_name: FS_COLLECTION_NAME.to_string(),
260            },
261            ..Default::default()
262        }
263    }
264}
265
266impl FSConfig for Fxfs {
267    fn options(&self) -> Options<'_> {
268        Options {
269            component_name: "fxfs",
270            reuse_component_after_serving: true,
271            format_options: FormatOptions { verbose: Some(false), ..Default::default() },
272            start_options: StartOptions {
273                read_only: Some(self.readonly),
274                fsck_after_every_transaction: Some(self.fsck_after_every_transaction),
275                startup_profiling_seconds: Some(self.startup_profiling_seconds.unwrap_or(0)),
276                inline_crypto_enabled: Some(self.inline_crypto_enabled),
277                barriers_enabled: Some(self.barriers_enabled),
278                allow_type3_blobs: Some(self.allow_type3_blobs),
279                ..Default::default()
280            },
281            component_type: self.component_type.clone(),
282        }
283    }
284
285    fn is_multi_volume(&self) -> bool {
286        true
287    }
288
289    fn disk_format(&self) -> format::DiskFormat {
290        format::DiskFormat::Fxfs
291    }
292}
293
294/// F2fs Filesystem Configuration
295/// If fields are None or false, they will not be set in arguments.
296#[derive(Clone, Default)]
297pub struct F2fs {
298    pub component_type: ComponentType,
299}
300
301impl F2fs {
302    /// Manages a block device using the default configuration.
303    pub fn new<B: BlockConnector + 'static>(block_connector: B) -> filesystem::Filesystem {
304        filesystem::Filesystem::new(block_connector, Self::default())
305    }
306
307    /// Launch f2fs, with the default configuration, as a dynamic child in the fs-collection.
308    pub fn dynamic_child() -> Self {
309        Self {
310            component_type: ComponentType::DynamicChild {
311                collection_name: FS_COLLECTION_NAME.to_string(),
312            },
313            ..Default::default()
314        }
315    }
316}
317
318impl FSConfig for F2fs {
319    fn options(&self) -> Options<'_> {
320        Options {
321            component_name: "f2fs",
322            reuse_component_after_serving: false,
323            format_options: FormatOptions::default(),
324            start_options: StartOptions {
325                read_only: Some(false),
326                verbose: Some(false),
327                fsck_after_every_transaction: Some(false),
328                ..Default::default()
329            },
330            component_type: self.component_type.clone(),
331        }
332    }
333    fn is_multi_volume(&self) -> bool {
334        false
335    }
336
337    fn disk_format(&self) -> format::DiskFormat {
338        format::DiskFormat::F2fs
339    }
340}
341
342/// FvmFilesystem Configuration
343#[derive(Clone, Default)]
344pub struct Fvm {
345    pub component_type: ComponentType,
346    pub slice_size: u64,
347}
348
349impl Fvm {
350    /// Manages a block device using the default configuration.
351    pub fn new<B: BlockConnector + 'static>(block_connector: B) -> filesystem::Filesystem {
352        filesystem::Filesystem::new(block_connector, Self::default())
353    }
354
355    /// Launch Fvm, with the default configuration, as a dynamic child in the fs-collection.
356    pub fn dynamic_child() -> Self {
357        Self {
358            component_type: ComponentType::DynamicChild {
359                collection_name: FS_COLLECTION_NAME.to_string(),
360            },
361            ..Default::default()
362        }
363    }
364}
365
366impl FSConfig for Fvm {
367    fn options(&self) -> Options<'_> {
368        Options {
369            component_name: "fvm2",
370            reuse_component_after_serving: true,
371            format_options: FormatOptions {
372                fvm_slice_size: if self.slice_size > 0 { Some(self.slice_size) } else { None },
373                ..FormatOptions::default()
374            },
375            start_options: StartOptions::default(),
376            component_type: self.component_type.clone(),
377        }
378    }
379
380    fn is_multi_volume(&self) -> bool {
381        true
382    }
383
384    fn disk_format(&self) -> format::DiskFormat {
385        format::DiskFormat::Fvm
386    }
387}
388
389/// Gpt Configuration
390#[derive(Clone)]
391pub struct Gpt {
392    pub component_type: ComponentType,
393    pub merge_super_and_userdata: bool,
394}
395
396impl Default for Gpt {
397    fn default() -> Self {
398        Self { component_type: Default::default(), merge_super_and_userdata: false }
399    }
400}
401
402impl Gpt {
403    /// Manages a block device using the default configuration.
404    pub fn new<B: BlockConnector + 'static>(block_connector: B) -> filesystem::Filesystem {
405        filesystem::Filesystem::new(block_connector, Self::default())
406    }
407
408    /// Launch Gpt, with the default configuration, as a dynamic child in the fs-collection.
409    pub fn dynamic_child() -> Self {
410        Self {
411            component_type: ComponentType::DynamicChild {
412                collection_name: FS_COLLECTION_NAME.to_string(),
413            },
414            ..Default::default()
415        }
416    }
417}
418
419impl FSConfig for Gpt {
420    fn options(&self) -> Options<'_> {
421        Options {
422            component_name: "gpt2",
423            reuse_component_after_serving: true,
424            format_options: FormatOptions::default(),
425            start_options: StartOptions {
426                merge_super_and_userdata: Some(self.merge_super_and_userdata),
427                ..Default::default()
428            },
429            component_type: self.component_type.clone(),
430        }
431    }
432
433    fn is_multi_volume(&self) -> bool {
434        true
435    }
436
437    fn disk_format(&self) -> format::DiskFormat {
438        format::DiskFormat::Gpt
439    }
440}