file_system/
file_system.rs

1//! Core file system trait and abstractions.
2//!
3//! This module defines the primary [`File_system_traits`] trait that all file system
4//! implementations must implement. It provides a comprehensive POSIX-like interface
5//! for file and directory operations with support for multi-user environments,
6//! task isolation, and concurrent access.
7
8use alloc::collections::BTreeMap;
9
10use crate::{
11    Entry, FileIdentifier, Inode, LocalFileIdentifier, Metadata, Mode, Statistics_type, Time,
12};
13
14use super::{Error, Flags, Path, Position, Result, Size};
15
16use task::TaskIdentifier;
17use users::{GroupIdentifier, UserIdentifier};
18
19/// Convenience macro for creating file system instances.
20///
21/// This macro wraps file system implementations in a `Box` for dynamic dispatch
22/// and easy registration with the virtual file system.
23///
24/// # Examples
25///
26/// ```rust
27/// # extern crate alloc;
28/// # use file_system::*;
29///
30/// // Create a file system instance (assuming MyFileSystem implements File_system_traits)
31/// // let fs = Create_file_system!(MyFileSystem::new());
32/// ```
33#[macro_export]
34macro_rules! create_file_system {
35    ($file_system:expr) => {
36        alloc::boxed::Box::new($file_system)
37    };
38    () => {};
39}
40
41/// Core trait for all file system implementations.
42///
43/// This trait defines the complete interface that file systems must implement to integrate
44/// with the Xila operating system. It provides a POSIX-like API with additional features
45/// for multi-user environments, task isolation, and modern file system operations.
46///
47/// ## Design Principles
48///
49/// ### Task Isolation
50/// All file operations are associated with a [`TaskIdentifier`] to ensure proper
51/// isolation between processes. File descriptors are local to each task.
52///
53/// ### User Security
54/// Operations include user and group identifiers for permission checking, ensuring
55/// secure multi-user operation.
56///
57/// ### Concurrent Access
58/// Implementations must handle concurrent access safely. The trait requires `Send + Sync`
59/// and implementations should use appropriate synchronization primitives like `RwLock` or `Mutex`.
60///
61/// ### Non-blocking Operations
62/// All operations should avoid blocking indefinitely. If an operation would block,
63/// implementations should return [`Error::RessourceBusy`].
64///
65/// ## File Operations
66///
67/// The trait supports standard file operations including:
68/// - Opening and closing files with various flags
69/// - Reading and writing data
70/// - Seeking to specific positions
71/// - File and directory creation/deletion
72/// - Metadata operations
73///
74/// ## Directory Operations
75///
76/// Directory operations include:
77/// - Creating and removing directories
78/// - Opening directories for iteration
79/// - Reading directory entries
80/// - Position management for directory iteration
81///
82/// ## Example Implementation Pattern
83///
84/// ```rust
85/// # extern crate alloc;
86/// # use file_system::*;
87/// # use alloc::collections::BTreeMap;
88/// # use task::TaskIdentifier;
89/// # use users::{User_identifier_type, Group_identifier_type};
90/// # use synchronization::rwlock::RwLock;
91/// # use synchronization::blocking_mutex::raw::CriticalSectionRawMutex;
92///
93/// struct MyFileSystem {
94///     // Use RwLock for thread safety
95///     files: RwLock<CriticalSectionRawMutex, BTreeMap<Local_file_identifier_type, u32>>,
96///     // ... other fields
97/// }
98///
99/// impl File_system_traits for MyFileSystem {
100///     fn Open(&self, task: TaskIdentifier, path: &Path_type, flags: Flags_type,
101///             time: Time_type, user: User_identifier_type, group: Group_identifier_type)
102///             -> Result<Local_file_identifier_type> {
103///         todo!()
104///     }
105///     // ... other methods would be implemented here
106/// #    fn Close(&self, _: Local_file_identifier_type) -> Result<()> { todo!() }
107/// #    fn Close_all(&self, _: TaskIdentifier) -> Result<()> { todo!() }
108/// #    fn Duplicate(&self, _: Local_file_identifier_type) -> Result<Local_file_identifier_type> { todo!() }
109/// #    fn Transfert(&self, _: TaskIdentifier, _: Local_file_identifier_type, _: Option<File_identifier_type>) -> Result<Local_file_identifier_type> { todo!() }
110/// #    fn Remove(&self, _: &Path_type) -> Result<()> { todo!() }
111/// #    fn Read(&self, _: Local_file_identifier_type, _: &mut [u8], _: Time_type) -> Result<Size> { todo!() }
112/// #    fn Write(&self, _: Local_file_identifier_type, _: &[u8], _: Time_type) -> Result<Size> { todo!() }
113/// #    fn Rename(&self, _: &Path_type, _: &Path_type) -> Result<()> { todo!() }
114/// #    fn Set_position(&self, _: Local_file_identifier_type, _: &Position_type) -> Result<Size> { todo!() }
115/// #    fn Flush(&self, _: Local_file_identifier_type) -> Result<()> { todo!() }
116/// #    fn Create_directory(&self, _: &Path_type, _: Time_type, _: User_identifier_type, _: Group_identifier_type) -> Result<()> { todo!() }
117/// #    fn Open_directory(&self, _: &Path_type, _: TaskIdentifier) -> Result<Local_file_identifier_type> { todo!() }
118/// #    fn Read_directory(&self, _: Local_file_identifier_type) -> Result<Option<Entry_type>> { todo!() }
119/// #    fn Set_position_directory(&self, _: Local_file_identifier_type, _: Size) -> Result<()> { todo!() }
120/// #    fn get_position_directory(&self, _: Local_file_identifier_type) -> Result<Size> { todo!() }
121/// #    fn Rewind_directory(&self, _: Local_file_identifier_type) -> Result<()> { todo!() }
122/// #    fn Close_directory(&self, _: Local_file_identifier_type) -> Result<()> { todo!() }
123/// #    fn get_metadata(&self, _: Local_file_identifier_type) -> Result<Metadata_type> { todo!() }
124/// #    fn Set_metadata_from_path(&self, _: &Path_type, _: &Metadata_type) -> Result<()> { todo!() }
125/// #    fn get_metadata_from_path(&self, _: &Path_type) -> Result<Metadata_type> { todo!() }
126/// #    fn get_statistics(&self, _: Local_file_identifier_type) -> Result<Statistics_type> { todo!() }
127/// #    fn get_mode(&self, _: Local_file_identifier_type) -> Result<Mode_type> { todo!() }
128/// }
129/// ```
130pub trait FileSystemTraits: Send + Sync {
131    // - Status
132    // - Manipulation
133    // - - Open/close/delete
134
135    /// Open a file for I/O operations.
136    ///
137    /// Opens a file at the specified path with the given flags and associates it with
138    /// the specified task. The operation is subject to permission checking based on
139    /// the provided user and group identifiers.
140    ///
141    /// # Arguments
142    ///
143    /// * `Task` - Task identifier for file descriptor ownership
144    /// * `Path` - Path to the file to open
145    /// * `Flags` - Open flags (read, write, create, etc.)
146    /// * `Time` - Current time for metadata updates
147    /// * `User` - User identifier for permission checking
148    /// * `Group` - Group identifier for permission checking
149    ///
150    /// # Returns
151    ///
152    /// * `Ok(Local_file_identifier_type)` - File descriptor for the opened file
153    /// * `Err(Error)` - Error if file cannot be opened
154    ///
155    /// # Errors
156    ///
157    /// * [`Error::NotFound`] - File doesn't exist and create flag not set
158    /// * [`Error::PermissionDenied`] - Insufficient permissions
159    /// * [`Error::AlreadyExists`] - File exists and exclusive create flag set
160    /// * [`Error::TooManyOpenFiles`] - File descriptor limit reached
161    fn open(
162        &self,
163        task: TaskIdentifier,
164        path: &Path,
165        flags: Flags,
166        time: Time,
167        user: UserIdentifier,
168        group: GroupIdentifier,
169    ) -> Result<LocalFileIdentifier>;
170
171    /// Close a file and release its resources.
172    ///
173    /// Closes the file associated with the given file identifier and releases any
174    /// resources associated with it. After calling this method, the file identifier
175    /// becomes invalid for the task.
176    ///
177    /// # Arguments
178    ///
179    /// * `file` - File identifier to close
180    ///
181    /// # Returns
182    ///
183    /// * `Ok(())` - File successfully closed
184    /// * `Err(Error)` - Error closing file
185    ///
186    /// # Errors
187    ///
188    /// * [`Error::InvalidIdentifier`] - File identifier is invalid
189    /// * [`Error::InputOutput`] - I/O error during close operation
190    fn close(&self, file: LocalFileIdentifier) -> Result<()>;
191
192    /// Close all files opened by a specific task.
193    ///
194    /// This is typically called during task cleanup to ensure all file descriptors
195    /// are properly released when a task terminates.
196    ///
197    /// # Arguments
198    ///
199    /// * `task` - Task identifier whose files should be closed
200    ///
201    /// # Returns
202    ///
203    /// * `Ok(())` - All files successfully closed
204    /// * `Err(Error)` - Error during cleanup
205    fn close_all(&self, task: TaskIdentifier) -> Result<()>;
206
207    /// Create a duplicate file identifier for the same file.
208    ///
209    /// Creates a new file identifier that refers to the same open file. This is
210    /// similar to the `dup()` system call in Unix systems. Both identifiers
211    /// can be used independently and must be closed separately.
212    ///
213    /// # Arguments
214    ///
215    /// * `File` - File identifier to duplicate
216    ///
217    /// # Returns
218    ///
219    /// * `Ok(Local_file_identifier_type)` - New file identifier for the same file
220    /// * `Err(Error)` - Error creating duplicate
221    ///
222    /// # Errors
223    ///
224    /// * [`Error::InvalidIdentifier`] - Original file identifier is invalid
225    /// * [`Error::TooManyOpenFiles`] - File descriptor limit reached
226    fn duplicate(&self, file: LocalFileIdentifier) -> Result<LocalFileIdentifier>;
227
228    /// Transfer a file identifier from one task to another.
229    ///
230    /// Moves ownership of a file identifier from the current task to another task.
231    /// This is useful for inter-process communication and file descriptor passing.
232    ///
233    /// # Arguments
234    ///
235    /// * `New_task` - Task to transfer the file to
236    /// * `File` - File identifier to transfer
237    /// * `New_file` - Optional specific identifier to use in the new task
238    ///
239    /// # Returns
240    ///
241    /// * `Ok(Local_file_identifier_type)` - File identifier in the new task
242    /// * `Err(Error)` - Error during transfer
243    ///
244    /// # Errors
245    ///
246    /// * [`Error::InvalidIdentifier`] - File identifier is invalid
247    /// * [`Error::FailedToGetTaskInformations`] - Target task is invalid
248    fn transfert(
249        &self,
250        new_task: TaskIdentifier,
251        file: LocalFileIdentifier,
252        new_file: Option<FileIdentifier>,
253    ) -> Result<LocalFileIdentifier>;
254
255    /// Remove a file or directory from the file system.
256    ///
257    /// Permanently deletes the specified file or directory. For directories,
258    /// they must be empty before they can be removed.
259    ///
260    /// # Arguments
261    ///
262    /// * `path` - Path to the file or directory to remove
263    ///
264    /// # Returns
265    ///
266    /// * `Ok(())` - File or directory successfully removed
267    /// * `Err(Error)` - Error during removal
268    ///
269    /// # Errors
270    ///
271    /// * [`Error::NotFound`] - File or directory doesn't exist
272    /// * [`Error::PermissionDenied`] - Insufficient permissions
273    /// * [`Error::DirectoryNotEmpty`] - Directory contains files
274    /// * [`Error::RessourceBusy`] - File is currently in use
275    fn remove(&self, path: &Path) -> Result<()>;
276    // - - File operations
277
278    /// Read data from an open file.
279    ///
280    /// Reads data from the file at its current position into the provided buffer.
281    /// The file position is advanced by the number of bytes read.
282    ///
283    /// # Arguments
284    ///
285    /// * `File` - File identifier to read from
286    /// * `Buffer` - Buffer to read data into
287    /// * `Time_type` - Current time for access time updates
288    ///
289    /// # Returns
290    ///
291    /// * `Ok(Size)` - Number of bytes actually read
292    /// * `Err(Error)` - Error during read operation
293    ///
294    /// # Errors
295    ///
296    /// * [`Error::InvalidIdentifier`] - File identifier is invalid
297    /// * [`Error::PermissionDenied`] - File not opened for reading
298    /// * [`Error::InputOutput`] - I/O error during read
299    fn read(&self, file: LocalFileIdentifier, buffer: &mut [u8], time_type: Time) -> Result<Size>;
300
301    /// Write data to an open file.
302    ///
303    /// Writes data from the buffer to the file at its current position.
304    /// The file position is advanced by the number of bytes written.
305    ///
306    /// # Arguments
307    ///
308    /// * `File` - File identifier to write to
309    /// * `Buffer` - Buffer containing data to write
310    /// * `Time_type` - Current time for modification time updates
311    ///
312    /// # Returns
313    ///
314    /// * `Ok(Size)` - Number of bytes actually written
315    /// * `Err(Error)` - Error during write operation
316    ///
317    /// # Errors
318    ///
319    /// * [`Error::InvalidIdentifier`] - File identifier is invalid
320    /// * [`Error::PermissionDenied`] - File not opened for writing
321    /// * [`Error::NoSpaceLeft`] - Insufficient storage space
322    /// * [`Error::InputOutput`] - I/O error during write
323    fn write(&self, file: LocalFileIdentifier, buffer: &[u8], time_type: Time) -> Result<Size>;
324
325    /// Rename or move a file or directory.
326    ///
327    /// Changes the name or location of a file or directory. This can be used
328    /// for both renaming within the same directory and moving between directories.
329    ///
330    /// # Arguments
331    ///
332    /// * `source` - Current path of the file or directory
333    /// * `destination` - New path for the file or directory
334    ///
335    /// # Returns
336    ///
337    /// * `Ok(())` - File or directory successfully renamed/moved
338    /// * `Err(Error)` - Error during rename operation
339    ///
340    /// # Errors
341    ///
342    /// * [`Error::NotFound`] - Source file doesn't exist
343    /// * [`Error::AlreadyExists`] - Destination already exists
344    /// * [`Error::PermissionDenied`] - Insufficient permissions
345    fn rename(&self, source: &Path, destination: &Path) -> Result<()>;
346
347    /// Set the position of the file.
348    ///
349    /// # Errors
350    /// - If the file is not opened (invalid file identifier).
351    fn set_position(&self, file: LocalFileIdentifier, position: &Position) -> Result<Size>;
352
353    fn flush(&self, file: LocalFileIdentifier) -> Result<()>;
354
355    // - Directory
356
357    fn create_directory(
358        &self,
359        path: &Path,
360        time: Time,
361        user: UserIdentifier,
362        group: GroupIdentifier,
363    ) -> Result<()>;
364
365    fn open_directory(&self, path: &Path, task: TaskIdentifier) -> Result<LocalFileIdentifier>;
366
367    fn read_directory(&self, file: LocalFileIdentifier) -> Result<Option<Entry>>;
368
369    fn set_position_directory(&self, file: LocalFileIdentifier, position: Size) -> Result<()>;
370
371    fn get_position_directory(&self, file: LocalFileIdentifier) -> Result<Size>;
372
373    fn rewind_directory(&self, file: LocalFileIdentifier) -> Result<()>;
374
375    fn close_directory(&self, file: LocalFileIdentifier) -> Result<()>;
376
377    // - Metadata
378
379    fn get_metadata(&self, file: LocalFileIdentifier) -> Result<Metadata>;
380
381    fn set_metadata_from_path(&self, path: &Path, metadata: &Metadata) -> Result<()>;
382
383    fn get_metadata_from_path(&self, path: &Path) -> Result<Metadata>;
384
385    fn get_statistics(&self, file: LocalFileIdentifier) -> Result<Statistics_type>;
386
387    fn get_mode(&self, file: LocalFileIdentifier) -> Result<Mode>;
388}
389
390pub fn get_new_file_identifier<T>(
391    task: TaskIdentifier,
392    start: Option<FileIdentifier>,
393    end: Option<FileIdentifier>,
394    map: &BTreeMap<LocalFileIdentifier, T>,
395) -> Result<LocalFileIdentifier> {
396    let start = start.unwrap_or(FileIdentifier::MINIMUM);
397    let mut start = LocalFileIdentifier::new(task, start);
398
399    let end_value = end.unwrap_or(FileIdentifier::MAXIMUM);
400    let end = LocalFileIdentifier::new(task, end_value);
401
402    while start < end {
403        if !map.contains_key(&start) {
404            return Ok(start);
405        }
406
407        start += 1;
408    }
409
410    Err(Error::TooManyOpenFiles)
411}
412
413pub fn get_new_inode<T>(map: &BTreeMap<Inode, T>) -> Result<Inode> {
414    let mut inode = Inode::from(0);
415
416    while map.contains_key(&inode) {
417        inode += 1;
418    }
419
420    Ok(inode)
421}
422
423pub mod tests {
424
425    use crate::{Kind, Open, PathOwned, Time};
426
427    use alloc::{borrow::ToOwned, format};
428
429    use super::*;
430
431    pub fn get_test_path() -> PathOwned {
432        Path::ROOT.to_owned()
433    }
434
435    pub async fn test_open_close_delete(file_system: impl FileSystemTraits) {
436        let task = task::get_instance().get_current_task_identifier().await;
437
438        let path = get_test_path().append("Test_open_close_delete").unwrap();
439
440        let flags = Flags::new(Mode::READ_WRITE, Some(Open::CREATE_ONLY), None);
441
442        // - Open
443        let file = file_system
444            .open(
445                task,
446                &path,
447                flags,
448                Time::new(123),
449                UserIdentifier::ROOT,
450                GroupIdentifier::ROOT,
451            )
452            .unwrap();
453
454        // - Close
455        file_system.close(file).unwrap();
456
457        // - Delete
458        file_system.remove(&path).unwrap();
459    }
460
461    pub async fn test_read_write(file_system: impl FileSystemTraits) {
462        let task = task::get_instance().get_current_task_identifier().await;
463
464        let path = get_test_path().append("Test_read_write").unwrap();
465
466        let flags = Flags::new(Mode::READ_WRITE, Some(Open::CREATE_ONLY), None);
467
468        // - Open
469        let file = file_system
470            .open(
471                task,
472                &path,
473                flags,
474                Time::new(123),
475                UserIdentifier::ROOT,
476                GroupIdentifier::ROOT,
477            )
478            .unwrap();
479
480        // - Write
481        let buffer = [0x01, 0x02, 0x03];
482        let size = file_system.write(file, &buffer, Time::new(123)).unwrap();
483
484        assert_eq!(size, Size::from(buffer.len()));
485        file_system.set_position(file, &Position::Start(0)).unwrap();
486
487        // - Read
488        let mut buffer_read = [0; 3];
489        let size = file_system
490            .read(file, &mut buffer_read, Time::new(123))
491            .unwrap();
492        assert_eq!(buffer, buffer_read);
493        assert_eq!(size, Size::from(buffer.len()));
494
495        // - Close
496        file_system.close(file).unwrap();
497
498        // - Delete
499        file_system.remove(&path).unwrap();
500    }
501
502    pub async fn test_move(file_system: impl FileSystemTraits) {
503        let task = task::get_instance().get_current_task_identifier().await;
504
505        let path = get_test_path().append("Test_move").unwrap();
506        let path_destination = get_test_path().append("Test_move_destination").unwrap();
507
508        let flags = Flags::new(Mode::READ_WRITE, Some(Open::CREATE_ONLY), None);
509
510        // - Open
511        let file = file_system
512            .open(
513                task,
514                &path,
515                flags,
516                Time::new(123),
517                UserIdentifier::ROOT,
518                GroupIdentifier::ROOT,
519            )
520            .unwrap();
521
522        // - Write
523        let buffer = [0x01, 0x02, 0x03];
524        let size = file_system.write(file, &buffer, Time::new(123)).unwrap();
525        assert_eq!(size, Size::from(buffer.len()));
526
527        file_system.close(file).unwrap();
528
529        // - Move
530        file_system.rename(&path, &path_destination).unwrap();
531
532        // - Open
533        let file = file_system
534            .open(
535                task,
536                &path_destination,
537                Mode::READ_ONLY.into(),
538                Time::new(123),
539                UserIdentifier::ROOT,
540                GroupIdentifier::ROOT,
541            )
542            .unwrap();
543
544        // - Read
545        let mut buffer_read = [0; 3];
546        let size = file_system
547            .read(file, &mut buffer_read, Time::new(123))
548            .unwrap();
549        assert_eq!(size, Size::from(buffer.len()));
550        assert_eq!(buffer, buffer_read);
551
552        // - Close
553        file_system.close(file).unwrap();
554
555        // - Delete
556        file_system.remove(&path_destination).unwrap();
557    }
558
559    pub async fn test_set_position(file_system: impl FileSystemTraits) {
560        let task = task::get_instance().get_current_task_identifier().await;
561
562        let path = get_test_path().append("Test_set_position").unwrap();
563
564        let flags = Flags::new(Mode::READ_WRITE, Some(Open::CREATE_ONLY), None);
565
566        // - Open
567        let file = file_system
568            .open(
569                task,
570                &path,
571                flags,
572                Time::new(123),
573                UserIdentifier::ROOT,
574                GroupIdentifier::ROOT,
575            )
576            .unwrap();
577
578        // - Write
579        let buffer = [0x01, 0x02, 0x03];
580        let size = file_system.write(file, &buffer, Time::new(123)).unwrap();
581        assert_eq!(buffer.len(), size.into());
582
583        // - Set position
584        let position = Position::Start(0);
585        let size = file_system.set_position(file, &position).unwrap();
586        assert_eq!(
587            size,
588            file_system
589                .set_position(file, &Position::Current(0))
590                .unwrap()
591        );
592
593        // - Read
594        let mut buffer_read = [0; 3];
595        let size = file_system
596            .read(file, &mut buffer_read, Time::new(123))
597            .unwrap();
598        assert_eq!(buffer, buffer_read);
599        assert_eq!(buffer.len(), size.into());
600
601        // - Close
602        file_system.close(file).unwrap();
603
604        // - Delete
605        file_system.remove(&path).unwrap();
606    }
607
608    pub async fn test_flush(file_system: impl FileSystemTraits) {
609        let task = task::get_instance().get_current_task_identifier().await;
610
611        let path = get_test_path().append("Test_flush").unwrap();
612
613        let flags = Flags::new(Mode::READ_WRITE, Some(Open::CREATE_ONLY), None);
614
615        let file = file_system
616            .open(
617                task,
618                &path,
619                flags,
620                Time::new(123),
621                UserIdentifier::ROOT,
622                GroupIdentifier::ROOT,
623            )
624            .unwrap();
625
626        let buffer = [0x01, 0x02, 0x03];
627        let size = file_system.write(file, &buffer, Time::new(123)).unwrap();
628        assert_eq!(size, Size::from(buffer.len()));
629
630        file_system.flush(file).unwrap();
631
632        file_system.close(file).unwrap();
633
634        file_system.remove(&path).unwrap();
635    }
636
637    pub async fn test_set_get_metadata(file_system: impl FileSystemTraits) {
638        let task = task::get_instance().get_current_task_identifier().await;
639
640        let path = get_test_path().append("Test_set_owner").unwrap();
641
642        let flags = Flags::new(Mode::READ_WRITE, Some(Open::CREATE_ONLY), None);
643
644        let file = file_system
645            .open(
646                task,
647                &path,
648                flags,
649                Time::new(123),
650                UserIdentifier::ROOT,
651                GroupIdentifier::ROOT,
652            )
653            .unwrap();
654
655        let time = Time::new(123);
656
657        let metadata = Metadata::get_default(
658            Kind::File,
659            time,
660            UserIdentifier::ROOT,
661            GroupIdentifier::ROOT,
662        )
663        .unwrap();
664
665        file_system
666            .set_metadata_from_path(&path, &metadata)
667            .unwrap();
668
669        let metadata_read = file_system.get_metadata_from_path(&path).unwrap();
670
671        assert_eq!(metadata, metadata_read);
672
673        file_system.close(file).unwrap();
674
675        file_system.remove(&path).unwrap();
676    }
677
678    pub async fn test_read_directory(file_system: impl FileSystemTraits) {
679        let task = task::get_instance().get_current_task_identifier().await;
680
681        // Create multiple files
682        for i in 0..10 {
683            let flags = Flags::new(Mode::WRITE_ONLY, Some(Open::CREATE_ONLY), None);
684            let file = file_system
685                .open(
686                    task,
687                    Path::from_str(&format!("/Test{i}")),
688                    flags,
689                    Time::new(123),
690                    UserIdentifier::ROOT,
691                    GroupIdentifier::ROOT,
692                )
693                .unwrap();
694            file_system.close(file).unwrap();
695        }
696
697        let path = Path::from_str("/");
698        let directory = file_system.open_directory(path, task).unwrap();
699
700        let current_directory = file_system.read_directory(directory).unwrap().unwrap();
701        assert_eq!(*current_directory.get_name(), ".");
702        assert_eq!(current_directory.get_type(), Kind::Directory);
703
704        let parent_directory = file_system.read_directory(directory).unwrap().unwrap();
705        assert_eq!(*parent_directory.get_name(), "..");
706        assert_eq!(parent_directory.get_type(), Kind::Directory);
707
708        for i in 0..10 {
709            let entry = file_system.read_directory(directory).unwrap().unwrap();
710
711            assert_eq!(*entry.get_name(), format!("Test{i}"));
712            assert_eq!(entry.get_type(), Kind::File);
713        }
714
715        file_system.close_directory(directory).unwrap();
716    }
717
718    pub async fn test_set_position_directory(file_system: impl FileSystemTraits) {
719        let task = task::get_instance().get_current_task_identifier().await;
720
721        // Create multiple files
722        for i in 0..10 {
723            let flags = Flags::new(Mode::WRITE_ONLY, Some(Open::CREATE_ONLY), None);
724            let file = file_system
725                .open(
726                    task,
727                    Path::from_str(&format!("/Test{i}")),
728                    flags,
729                    Time::new(123),
730                    UserIdentifier::ROOT,
731                    GroupIdentifier::ROOT,
732                )
733                .unwrap();
734            file_system.close(file).unwrap();
735        }
736
737        let directory = file_system.open_directory(Path::ROOT, task).unwrap();
738
739        let current_directory = file_system.read_directory(directory).unwrap().unwrap();
740        assert_eq!(*current_directory.get_name(), ".");
741        assert_eq!(current_directory.get_type(), Kind::Directory);
742
743        let parent_directory = file_system.read_directory(directory).unwrap().unwrap();
744        assert_eq!(*parent_directory.get_name(), "..");
745        assert_eq!(parent_directory.get_type(), Kind::Directory);
746
747        let position = file_system.get_position_directory(directory).unwrap();
748
749        for i in 0..10 {
750            let entry = file_system.read_directory(directory).unwrap().unwrap();
751
752            assert_eq!(*entry.get_name(), format!("Test{i}"));
753            assert_eq!(entry.get_type(), Kind::File);
754        }
755
756        file_system
757            .set_position_directory(directory, position)
758            .unwrap();
759
760        for i in 0..10 {
761            let entry = file_system.read_directory(directory).unwrap().unwrap();
762
763            assert_eq!(*entry.get_name(), format!("Test{i}"));
764            assert_eq!(entry.get_type(), Kind::File);
765        }
766    }
767
768    pub async fn test_rewind_directory(file_system: impl FileSystemTraits) {
769        let task = task::get_instance().get_current_task_identifier().await;
770
771        // Create multiple files
772        for i in 0..10 {
773            let flags = Flags::new(Mode::WRITE_ONLY, Some(Open::CREATE_ONLY), None);
774            let file = file_system
775                .open(
776                    task,
777                    Path::from_str(&format!("/Test{i}")),
778                    flags,
779                    Time::new(123),
780                    UserIdentifier::ROOT,
781                    GroupIdentifier::ROOT,
782                )
783                .unwrap();
784            file_system.close(file).unwrap();
785        }
786
787        let directory = file_system.open_directory(Path::ROOT, task).unwrap();
788
789        let current_directory = file_system.read_directory(directory).unwrap().unwrap();
790        assert_eq!(*current_directory.get_name(), ".");
791        assert_eq!(current_directory.get_type(), Kind::Directory);
792
793        let parent_directory = file_system.read_directory(directory).unwrap().unwrap();
794        assert_eq!(*parent_directory.get_name(), "..");
795        assert_eq!(parent_directory.get_type(), Kind::Directory);
796
797        for i in 0..10 {
798            let entry = file_system.read_directory(directory).unwrap().unwrap();
799
800            assert_eq!(*entry.get_name(), format!("Test{i}"));
801            assert_eq!(entry.get_type(), Kind::File);
802        }
803
804        file_system.rewind_directory(directory).unwrap();
805
806        let current_directory = file_system.read_directory(directory).unwrap().unwrap();
807        assert_eq!(*current_directory.get_name(), ".");
808        assert_eq!(current_directory.get_type(), Kind::Directory);
809
810        let parent_directory = file_system.read_directory(directory).unwrap().unwrap();
811        assert_eq!(*parent_directory.get_name(), "..");
812        assert_eq!(parent_directory.get_type(), Kind::Directory);
813
814        for i in 0..10 {
815            let entry = file_system.read_directory(directory).unwrap().unwrap();
816
817            assert_eq!(*entry.get_name(), format!("Test{i}"));
818            assert_eq!(entry.get_type(), Kind::File);
819        }
820
821        file_system.close_directory(directory).unwrap();
822    }
823
824    pub async fn test_create_remove_directory(file_system: impl FileSystemTraits) {
825        let task = task::get_instance().get_current_task_identifier().await;
826
827        let path = get_test_path().append("Test_create_directory").unwrap();
828
829        file_system
830            .create_directory(
831                &path,
832                Time::new(123),
833                UserIdentifier::ROOT,
834                GroupIdentifier::ROOT,
835            )
836            .unwrap();
837
838        {
839            let root_directory = file_system.open_directory(Path::ROOT, task).unwrap();
840
841            let current_directory = file_system.read_directory(root_directory).unwrap().unwrap();
842            assert_eq!(*current_directory.get_name(), ".");
843            assert_eq!(current_directory.get_type(), Kind::Directory);
844
845            let parent_directory = file_system.read_directory(root_directory).unwrap().unwrap();
846            assert_eq!(*parent_directory.get_name(), "..");
847            assert_eq!(parent_directory.get_type(), Kind::Directory);
848
849            let directory = file_system.read_directory(root_directory).unwrap().unwrap();
850            assert_eq!(*directory.get_name(), "Test_create_directory");
851            assert_eq!(directory.get_type(), Kind::Directory);
852
853            file_system.close_directory(root_directory).unwrap();
854        }
855
856        {
857            let directory = file_system.open_directory(&path, task).unwrap();
858
859            let current_directory = file_system.read_directory(directory).unwrap().unwrap();
860
861            assert_eq!(*current_directory.get_name(), ".");
862            assert_eq!(current_directory.get_type(), Kind::Directory);
863
864            let parent_directory = file_system.read_directory(directory).unwrap().unwrap();
865            assert_eq!(*parent_directory.get_name(), "..");
866            assert_eq!(parent_directory.get_type(), Kind::Directory);
867
868            file_system.close_directory(directory).unwrap();
869        }
870        file_system.remove(&path).unwrap();
871    }
872}