Skip to main content

strate_fs_abstraction/
capabilities.rs

1//! Filesystem capability flags.
2//!
3//! This module defines the capabilities that a filesystem implementation
4//! can advertise, allowing the VFS layer to adapt its behavior accordingly.
5
6/// Filesystem capabilities.
7///
8/// These flags describe what features a filesystem supports.
9/// The VFS layer uses this information to:
10/// - Reject unsupported operations early
11/// - Adapt behavior (e.g., case sensitivity)
12/// - Provide accurate information to applications
13#[derive(Debug, Clone)]
14pub struct FsCapabilities {
15    // === Access Mode ===
16    /// Filesystem is read-only (no write operations allowed)
17    pub read_only: bool,
18
19    // === Naming ===
20    /// Filesystem is case-sensitive (Linux default)
21    pub case_sensitive: bool,
22
23    /// Filesystem preserves case even if not case-sensitive
24    pub case_preserving: bool,
25
26    /// Maximum filename length in bytes
27    pub max_filename_len: usize,
28
29    /// Maximum full path length in bytes
30    pub max_path_len: usize,
31
32    // === Links ===
33    /// Supports symbolic links
34    pub supports_symlinks: bool,
35
36    /// Supports hard links
37    pub supports_hardlinks: bool,
38
39    // === File Features ===
40    /// Supports sparse files (holes in files)
41    pub supports_sparse_files: bool,
42
43    /// Maximum file size in bytes
44    pub max_file_size: u64,
45
46    // === Extended Attributes ===
47    /// Supports extended attributes (xattr)
48    pub supports_xattr: bool,
49
50    /// Supports POSIX ACLs
51    pub supports_acl: bool,
52
53    // === Timestamps ===
54    /// Supports sub-second timestamp precision
55    pub supports_nanoseconds: bool,
56
57    /// Supports creation/birth time (crtime)
58    pub supports_crtime: bool,
59}
60
61impl FsCapabilities {
62    /// Exbibyte constant (2^60) for max_file_size declarations.
63    const EIB: u64 = 1 << 60;
64
65    /// Create capabilities for a typical read-only Linux filesystem.
66    pub const fn read_only_linux() -> Self {
67        Self {
68            read_only: true,
69            case_sensitive: true,
70            case_preserving: true,
71            max_filename_len: 255,
72            max_path_len: 4096,
73            supports_symlinks: true,
74            supports_hardlinks: true,
75            supports_sparse_files: true,
76            max_file_size: i64::MAX as u64,
77            supports_xattr: false,
78            supports_acl: false,
79            supports_nanoseconds: true,
80            supports_crtime: false,
81        }
82    }
83
84    /// Create capabilities for a writable Linux filesystem.
85    pub const fn writable_linux() -> Self {
86        Self {
87            read_only: false,
88            ..Self::read_only_linux()
89        }
90    }
91
92    /// Create default XFS capabilities.
93    pub const fn xfs() -> Self {
94        Self {
95            read_only: false,
96            case_sensitive: true,
97            case_preserving: true,
98            max_filename_len: 255,
99            max_path_len: 4096,
100            supports_symlinks: true,
101            supports_hardlinks: true,
102            supports_sparse_files: true,
103            // XFS max file size: 8 EiB on 64-bit systems (was wrongly
104            // computed as 8 PiB : the literal chain had only five 1024s).
105            max_file_size: 8 * Self::EIB,
106            supports_xattr: true,
107            supports_acl: true,
108            supports_nanoseconds: true,
109            supports_crtime: true, // XFS v5 has crtime
110        }
111    }
112
113    /// Create default ext4 capabilities.
114    pub const fn ext4() -> Self {
115        Self {
116            read_only: false,
117            case_sensitive: true,
118            case_preserving: true,
119            max_filename_len: 255,
120            max_path_len: 4096,
121            supports_symlinks: true,
122            supports_hardlinks: true,
123            supports_sparse_files: true,
124            max_file_size: 16 * 1024 * 1024 * 1024 * 1024, // 16 TiB
125            supports_xattr: true,
126            supports_acl: true,
127            supports_nanoseconds: true,
128            supports_crtime: true,
129        }
130    }
131
132    /// Create default btrfs capabilities.
133    pub const fn btrfs() -> Self {
134        Self {
135            read_only: false,
136            case_sensitive: true,
137            case_preserving: true,
138            max_filename_len: 255,
139            max_path_len: 4096,
140            supports_symlinks: true,
141            supports_hardlinks: true,
142            supports_sparse_files: true,
143            // btrfs theoretical max file size is 16 EiB, which does NOT fit
144            // in u64 (2^64). Clamp to u64::MAX like other metadata that
145            // saturates; callers treat it as "unbounded".
146            max_file_size: u64::MAX,
147            supports_xattr: true,
148            supports_acl: true,
149            supports_nanoseconds: true,
150            supports_crtime: true,
151        }
152    }
153
154    /// Check if write operations are allowed.
155    pub const fn can_write(&self) -> bool {
156        !self.read_only
157    }
158}
159
160impl Default for FsCapabilities {
161    /// Implements default.
162    fn default() -> Self {
163        Self::read_only_linux()
164    }
165}