file_system/
error.rs

1//! Error types and result handling for file system operations.
2//!
3//! This module defines all possible errors that can occur during file system operations,
4//! along with conversion traits and display implementations for comprehensive error reporting.
5
6use core::{fmt::Display, num::NonZeroU32};
7
8/// Standard result type for file system operations.
9///
10/// This is a convenience alias for `Result<T, Error>` used throughout the file system crate.
11/// All file system operations that can fail return this type.
12///
13/// # Examples
14///
15/// ```rust
16/// # extern crate alloc;
17/// use file_system::{Result, Error};
18///
19/// fn example_operation() -> Result<String> {
20///     Ok("Success".into())
21/// }
22///
23/// fn failing_operation() -> Result<()> {
24///     Err(Error::Permission_denied)
25/// }
26/// ```
27pub type Result<T> = core::result::Result<T, Error>;
28
29/// Comprehensive enumeration of all possible file system errors.
30///
31/// This enum covers errors that can occur at various levels of the file system stack,
32/// from low-level device operations to high-level file system operations. Each variant
33/// has a unique numeric discriminant for FFI compatibility.
34#[derive(Debug, PartialEq, Clone, Copy, Eq)]
35#[repr(C)]
36pub enum Error {
37    /// Failed to initialize the file system.
38    FailedToInitializeFileSystem = 1,
39    /// Permission denied for the requested operation.
40    PermissionDenied,
41    /// File, directory, or resource not found.
42    NotFound,
43    /// File or directory already exists.
44    AlreadyExists,
45    /// Directory already exists (more specific than Already_exists).
46    DirectoryAlreadyExists,
47    /// File system is full and cannot store more data.
48    FileSystemFull,
49    /// Generic file system error.
50    FileSystemError,
51    /// The provided path is invalid or malformed.
52    InvalidPath,
53    /// The file is corrupted or invalid.
54    InvalidFile,
55    /// The directory is corrupted or invalid.
56    InvalidDirectory,
57    /// The symbolic link is invalid or broken.
58    InvalidSymbolicLink,
59    /// Unknown or unspecified error.
60    Unknown,
61    /// File or task identifier is invalid.
62    InvalidIdentifier,
63    /// Failed to retrieve task information from task manager.
64    FailedToGetTaskInformations,
65    /// Failed to retrieve user information from user manager.
66    FailedToGetUsersInformations,
67    /// Maximum number of mounted file systems exceeded.
68    TooManyMountedFileSystems,
69    /// Maximum number of open files exceeded.
70    TooManyOpenFiles,
71    /// Internal implementation error.
72    InternalError,
73    /// Invalid access mode specified.
74    InvalidMode,
75    /// Operation is not supported by the device or file system.
76    UnsupportedOperation,
77    /// Resource is temporarily busy or unavailable.
78    RessourceBusy,
79    /// System or component is already initialized.
80    AlreadyInitialized,
81    /// System or component is not initialized.
82    NotInitialized,
83    /// Failed to get users manager instance.
84    FailedToGetUsersManagerInstance,
85    /// Failed to get task manager instance.
86    FailedToGetTaskManagerInstance,
87    /// Invalid parameter provided to function.
88    InvalidParameter,
89    /// Invalid flags specified for operation.
90    InvalidFlags,
91    /// Expected a directory but found a file.
92    NotDirectory,
93    /// Expected a file but found a directory.
94    IsDirectory,
95    /// Input/output error during operation.
96    InputOutput,
97    /// Directory is not empty and cannot be removed.
98    DirectoryNotEmpty,
99    /// File size exceeds maximum allowed size.
100    FileTooLarge,
101    /// Requested attribute does not exist.
102    NoAttribute,
103    /// File or directory name is too long.
104    NameTooLong,
105    /// Data corruption detected.
106    Corrupted,
107    /// Insufficient memory for operation.
108    NoMemory,
109    /// No space left on device.
110    NoSpaceLeft,
111    /// Error in timestamp or time-related operation.
112    TimeError,
113    /// Invalid inode reference.
114    InvalidInode,
115    /// Other unclassified error.
116    Other,
117}
118
119impl Error {
120    /// Get the numeric discriminant of the error as a non-zero u32.
121    ///
122    /// This is useful for FFI operations where errors need to be represented
123    /// as numeric codes.
124    ///
125    /// # Returns
126    ///
127    /// A `NonZeroU32` containing the error's discriminant value.
128    ///
129    /// # Examples
130    ///
131    /// ```rust
132    /// # extern crate alloc;
133    /// use file_system::Error;
134    ///
135    /// let error = Error::Permission_denied;
136    /// let code = error.get_discriminant();
137    /// assert_eq!(code.get(), 2); // Permission_denied has discriminant 2
138    /// ```
139    pub fn get_discriminant(&self) -> NonZeroU32 {
140        unsafe { NonZeroU32::new_unchecked(*self as u32) }
141    }
142}
143
144/// Convert Task module errors to file system errors.
145///
146/// This allows transparent handling of task-related errors in file system operations.
147impl From<task::Error> for Error {
148    fn from(_: task::Error) -> Self {
149        Error::FailedToGetTaskInformations
150    }
151}
152
153/// Convert Users module errors to file system errors.
154///
155/// This allows transparent handling of user-related errors in file system operations.
156impl From<users::Error> for Error {
157    fn from(_: users::Error) -> Self {
158        Error::FailedToGetUsersInformations
159    }
160}
161
162/// Convert file system errors to numeric discriminants.
163///
164/// This conversion is useful for FFI where errors need to be represented as numbers.
165impl From<Error> for NonZeroU32 {
166    fn from(error: Error) -> Self {
167        error.get_discriminant()
168    }
169}
170
171/// Display implementation for user-friendly error messages.
172///
173/// Provides human-readable descriptions of all error variants.
174impl Display for Error {
175    fn fmt(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
176        let string = match self {
177            Error::FailedToInitializeFileSystem => "Failed to initialize file system",
178            Error::PermissionDenied => "Permission denied",
179            Error::NotFound => "Not found",
180            Error::AlreadyExists => "Already exists",
181            Error::DirectoryAlreadyExists => "Directory already exists",
182            Error::FileSystemFull => "File system full",
183            Error::FileSystemError => "File system error",
184            Error::InvalidPath => "Invalid path",
185            Error::InvalidFile => "Invalid file",
186            Error::InvalidDirectory => "Invalid directory",
187            Error::InvalidSymbolicLink => "Invalid symbolic link",
188            Error::Unknown => "Unknown",
189            Error::InvalidIdentifier => "Invalid identifier",
190            Error::FailedToGetTaskInformations => "Failed to get task informations",
191            Error::FailedToGetUsersInformations => "Failed to get users informations",
192            Error::TooManyMountedFileSystems => "Too many mounted file systems",
193            Error::TooManyOpenFiles => "Too many open files",
194            Error::InternalError => "Internal error",
195            Error::InvalidMode => "Invalid mode",
196            Error::UnsupportedOperation => "Unsupported operation",
197            Error::RessourceBusy => "Ressource busy",
198            Error::AlreadyInitialized => "Already initialized",
199            Error::NotInitialized => "Not initialized",
200            Error::FailedToGetUsersManagerInstance => "Failed to get users manager instance",
201            Error::FailedToGetTaskManagerInstance => "Failed to get task manager instance",
202            Error::InvalidParameter => "Invalid parameter",
203            Error::InvalidFlags => "Invalid flags",
204            Error::NotDirectory => "Not directory",
205            Error::IsDirectory => "Is directory",
206            Error::InputOutput => "Input output",
207            Error::DirectoryNotEmpty => "Directory not empty",
208            Error::FileTooLarge => "File too large",
209            Error::NoAttribute => "No attribute",
210            Error::NameTooLong => "Name too long",
211            Error::Corrupted => "Corrupted",
212            Error::NoMemory => "No memory",
213            Error::NoSpaceLeft => "No space left",
214            Error::TimeError => "Time error",
215            Error::InvalidInode => "Invalid inode",
216            Error::Other => "Other",
217        };
218
219        write!(formatter, "{string}")
220    }
221}
222
223#[cfg(test)]
224mod tests {
225    use super::*;
226    use alloc::format;
227
228    #[test]
229    fn test_error_discriminants() {
230        // Test that each error has a unique discriminant
231        assert_eq!(
232            Error::FailedToInitializeFileSystem.get_discriminant().get(),
233            1
234        );
235        assert_eq!(Error::PermissionDenied.get_discriminant().get(), 2);
236        assert_eq!(Error::NotFound.get_discriminant().get(), 3);
237        assert_eq!(Error::AlreadyExists.get_discriminant().get(), 4);
238        assert_eq!(Error::DirectoryAlreadyExists.get_discriminant().get(), 5);
239
240        // Test a few more to ensure discriminants are sequential
241        assert_eq!(Error::FileSystemFull.get_discriminant().get(), 6);
242        assert_eq!(Error::FileSystemError.get_discriminant().get(), 7);
243        assert_eq!(Error::InvalidPath.get_discriminant().get(), 8);
244    }
245
246    #[test]
247    fn test_error_display() {
248        // Test display formatting for all error types
249        assert_eq!(
250            format!("{}", Error::FailedToInitializeFileSystem),
251            "Failed to initialize file system"
252        );
253        assert_eq!(format!("{}", Error::PermissionDenied), "Permission denied");
254        assert_eq!(format!("{}", Error::NotFound), "Not found");
255        assert_eq!(format!("{}", Error::AlreadyExists), "Already exists");
256        assert_eq!(
257            format!("{}", Error::DirectoryAlreadyExists),
258            "Directory already exists"
259        );
260        assert_eq!(format!("{}", Error::FileSystemFull), "File system full");
261        assert_eq!(format!("{}", Error::FileSystemError), "File system error");
262        assert_eq!(format!("{}", Error::InvalidPath), "Invalid path");
263        assert_eq!(format!("{}", Error::InvalidFile), "Invalid file");
264        assert_eq!(format!("{}", Error::InvalidDirectory), "Invalid directory");
265        assert_eq!(
266            format!("{}", Error::InvalidSymbolicLink),
267            "Invalid symbolic link"
268        );
269        assert_eq!(format!("{}", Error::Unknown), "Unknown");
270        assert_eq!(
271            format!("{}", Error::InvalidIdentifier),
272            "Invalid identifier"
273        );
274        assert_eq!(
275            format!("{}", Error::FailedToGetTaskInformations),
276            "Failed to get task informations"
277        );
278        assert_eq!(
279            format!("{}", Error::FailedToGetUsersInformations),
280            "Failed to get users informations"
281        );
282        assert_eq!(
283            format!("{}", Error::TooManyMountedFileSystems),
284            "Too many mounted file systems"
285        );
286        assert_eq!(
287            format!("{}", Error::TooManyOpenFiles),
288            "Too many open files"
289        );
290        assert_eq!(format!("{}", Error::InternalError), "Internal error");
291        assert_eq!(format!("{}", Error::InvalidMode), "Invalid mode");
292        assert_eq!(
293            format!("{}", Error::UnsupportedOperation),
294            "Unsupported operation"
295        );
296        assert_eq!(format!("{}", Error::RessourceBusy), "Ressource busy");
297        assert_eq!(
298            format!("{}", Error::AlreadyInitialized),
299            "Already initialized"
300        );
301        assert_eq!(format!("{}", Error::NotInitialized), "Not initialized");
302        assert_eq!(
303            format!("{}", Error::FailedToGetUsersManagerInstance),
304            "Failed to get users manager instance"
305        );
306        assert_eq!(
307            format!("{}", Error::FailedToGetTaskManagerInstance),
308            "Failed to get task manager instance"
309        );
310        assert_eq!(format!("{}", Error::InvalidParameter), "Invalid parameter");
311        assert_eq!(format!("{}", Error::InvalidFlags), "Invalid flags");
312        assert_eq!(format!("{}", Error::NotDirectory), "Not directory");
313        assert_eq!(format!("{}", Error::IsDirectory), "Is directory");
314        assert_eq!(format!("{}", Error::InputOutput), "Input output");
315        assert_eq!(
316            format!("{}", Error::DirectoryNotEmpty),
317            "Directory not empty"
318        );
319        assert_eq!(format!("{}", Error::FileTooLarge), "File too large");
320        assert_eq!(format!("{}", Error::NoAttribute), "No attribute");
321        assert_eq!(format!("{}", Error::NameTooLong), "Name too long");
322        assert_eq!(format!("{}", Error::Corrupted), "Corrupted");
323        assert_eq!(format!("{}", Error::NoMemory), "No memory");
324        assert_eq!(format!("{}", Error::NoSpaceLeft), "No space left");
325        assert_eq!(format!("{}", Error::TimeError), "Time error");
326        assert_eq!(format!("{}", Error::InvalidInode), "Invalid inode");
327        assert_eq!(format!("{}", Error::Other), "Other");
328    }
329
330    #[test]
331    fn test_error_debug() {
332        // Test debug formatting
333        let error = Error::PermissionDenied;
334        let debug_str = format!("{error:?}");
335        assert_eq!(debug_str, "Permission_denied");
336    }
337
338    #[test]
339    fn test_error_equality() {
340        // Test equality and cloning
341        let error1 = Error::NotFound;
342        let error2 = Error::NotFound;
343        let error3 = Error::PermissionDenied;
344
345        assert_eq!(error1, error2);
346        assert_ne!(error1, error3);
347
348        let cloned = error1;
349        assert_eq!(error1, cloned);
350    }
351
352    #[test]
353    fn test_error_conversions() {
354        // Test conversion to NonZeroU32
355        let error = Error::NotFound;
356        let discriminant: NonZeroU32 = error.into();
357        assert_eq!(discriminant.get(), 3);
358
359        // Test explicit discriminant access
360        assert_eq!(error.get_discriminant().get(), 3);
361    }
362
363    #[test]
364    fn test_result_type() {
365        // Test the Result alias
366        let success: Result<i32> = Ok(42);
367        let failure: Result<i32> = Err(Error::PermissionDenied);
368
369        assert_eq!(success, Ok(42));
370
371        assert_eq!(failure, Err(Error::PermissionDenied));
372    }
373
374    #[test]
375    fn test_error_categories() {
376        // Test that errors can be categorized by their discriminant ranges
377
378        // Initialization errors (1-3 range roughly)
379        assert!(matches!(
380            Error::FailedToInitializeFileSystem.get_discriminant().get(),
381            1
382        ));
383        assert!(matches!(
384            Error::AlreadyInitialized.get_discriminant().get(),
385            22
386        ));
387        assert!(matches!(Error::NotInitialized.get_discriminant().get(), 23));
388
389        // Permission errors
390        assert!(matches!(
391            Error::PermissionDenied.get_discriminant().get(),
392            2
393        ));
394        assert!(matches!(Error::InvalidMode.get_discriminant().get(), 19));
395
396        // File/Directory errors
397        assert!(matches!(Error::NotFound.get_discriminant().get(), 3));
398        assert!(matches!(Error::AlreadyExists.get_discriminant().get(), 4));
399        assert!(matches!(
400            Error::DirectoryAlreadyExists.get_discriminant().get(),
401            5
402        ));
403    }
404
405    #[test]
406    fn test_error_copy_semantics() {
407        // Test that Error implements Copy
408        let error = Error::FileSystemFull;
409        let copied = error; // This should work due to Copy trait
410
411        // Both should be usable
412        assert_eq!(error, Error::FileSystemFull);
413        assert_eq!(copied, Error::FileSystemFull);
414        assert_eq!(error, copied);
415    }
416
417    #[test]
418    fn test_error_size() {
419        // Ensure Error has a reasonable size for an enum
420        use core::mem::size_of;
421
422        // Should be small since it's a C-style enum
423        assert!(size_of::<Error>() <= 4); // Should be 4 bytes or less
424    }
425
426    #[test]
427    fn test_nonzero_conversion() {
428        // Test that all errors convert to valid NonZeroU32
429        let errors = [
430            Error::FailedToInitializeFileSystem,
431            Error::PermissionDenied,
432            Error::NotFound,
433            Error::AlreadyExists,
434            Error::DirectoryAlreadyExists,
435            Error::FileSystemFull,
436            Error::FileSystemError,
437            Error::InvalidPath,
438            Error::InvalidFile,
439            Error::InvalidDirectory,
440            Error::InvalidSymbolicLink,
441            Error::Unknown,
442            Error::InvalidIdentifier,
443            Error::FailedToGetTaskInformations,
444            Error::FailedToGetUsersInformations,
445            Error::TooManyMountedFileSystems,
446            Error::TooManyOpenFiles,
447            Error::InternalError,
448            Error::InvalidMode,
449            Error::UnsupportedOperation,
450            Error::RessourceBusy,
451            Error::AlreadyInitialized,
452            Error::NotInitialized,
453            Error::FailedToGetUsersManagerInstance,
454            Error::FailedToGetTaskManagerInstance,
455            Error::InvalidParameter,
456            Error::InvalidFlags,
457            Error::NotDirectory,
458            Error::IsDirectory,
459            Error::InputOutput,
460            Error::DirectoryNotEmpty,
461            Error::FileTooLarge,
462            Error::NoAttribute,
463            Error::NameTooLong,
464            Error::Corrupted,
465            Error::NoMemory,
466            Error::NoSpaceLeft,
467            Error::TimeError,
468            Error::InvalidInode,
469            Error::Other,
470        ];
471
472        for error in errors.iter() {
473            let discriminant = error.get_discriminant();
474            assert!(discriminant.get() > 0);
475
476            let converted: NonZeroU32 = (*error).into();
477            assert_eq!(discriminant, converted);
478        }
479    }
480}