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}