keos_project5/
advanced_file_structs.rs

1//! # Extension of the [`FileStruct`].
2//!
3//! Up to this point, you have implemented a fully functional file system.
4//! Now you will extend the basic [`FileStruct`] interface to provide
5//! higher-level functionality. The [`AdvancedFileStructs`] trait builds on
6//! the existing interface by introducing additional operations that are
7//! essential for a complete and usable file system. These include support
8//! for creating and removing files (`create`, `unlink`), managing directories
9//! (`mkdir`, `chdir`), enumerating directory entries (`readdir`), retrieving
10//! file metadata (`stat`), and ensuring persistence with `fsync`.
11//!
12//! ## Implementation Requirements
13//! You need to implement the followings:
14//! - [`AdvancedFileStructs::create`]
15//! - [`AdvancedFileStructs::mkdir`]
16//! - [`AdvancedFileStructs::unlink`]
17//! - [`AdvancedFileStructs::chdir`]
18//! - [`AdvancedFileStructs::readdir`]
19//! - [`AdvancedFileStructs::stat`]
20//! - [`AdvancedFileStructs::fsync`]
21//!
22//! # Final Remarks
23//! 🎉 Congratulations! By completing this section, you have successfully
24//! finished the entire **KeOS** project. You have built, from the ground up, a
25//! **minimal yet fully functional operating system** capable of running
26//! multi-threaded user processes, managing virtual memory, and supporting a
27//! journaling file system.
28//!
29//! Through this journey, you've gained hands-on experience with core OS
30//! subsystems - process scheduling, memory protection, system calls, page
31//! tables, file abstraction, and crash-consistent storage. This experience
32//! provides deep insight into the **“invisible” responsibilities** of the
33//! operating system to support software. Whatever you work with software
34//! engineering or pursue low-level engineering, the knowledge and skills you’ve
35//! developed here form a strong foundation to understand how your program works
36//! on the computer.
37
38use keos::{KernelError, fs::File};
39use keos_project1::{file_struct::FileStruct, syscall::SyscallAbi};
40
41/// Represents a directory entry as visible to user-space programs.
42///
43/// This struct contains the basic information about a directory entry
44/// that user programs can observe, including the inode number and name of the
45/// record.
46#[derive(Clone, Copy)]
47#[repr(C)]
48pub struct Dentry {
49    /// The inode number corresponding to the file or directory.
50    pub ino: u64,
51    /// The name of entry in null-terminated string.
52    pub name: [u8; 256],
53}
54
55/// Represents the basic metadata of a file or directory exposed to user-space.
56///
57/// This struct is typically returned by `stat()` to provide information about a
58/// file.
59#[derive(Clone, Copy)]
60#[repr(C)]
61pub struct Stat {
62    /// The inode number of the file or directory.
63    pub inode: u64,
64    /// The type of the file:
65    /// - `0` = regular file
66    /// - `1` = directory
67    pub ty: u32,
68    /// The size of the file in bytes.
69    pub size: u64,
70    #[doc(hidden)]
71    pub __must_be_zero: u32,
72}
73
74impl Stat {
75    /// Create a [`Stat`] struct for the file.
76    pub fn new(file: &File) -> Self {
77        Self {
78            inode: file.ino().into_u32() as u64,
79            ty: if matches!(file, File::RegularFile(_)) {
80                0
81            } else {
82                1
83            },
84            size: file.size(),
85            __must_be_zero: 0,
86        }
87    }
88}
89
90/// A trait for extending file operation functionality.
91///
92/// This trait provides implementations for file system-related system calls
93/// that operate on files and directories. Each method corresponds to a
94/// specific system call, handling user-space arguments via [`SyscallAbi`]
95/// and returning either success or a [`KernelError`] on failure.
96pub trait AdvancedFileStructs {
97    /// Creates a new empty file in the current directory.
98    ///
99    /// # Syscall API
100    /// ```c
101    /// int create(const char *pathname);
102    /// ```
103    /// - `pathname`: Path of the new file to create.
104    ///
105    /// Returns `0` on success.
106    fn create(&mut self, abi: &SyscallAbi) -> Result<usize, KernelError>;
107
108    /// Creates a new directory in the current working directory.
109    ///
110    /// # Syscall API
111    /// ```c
112    /// int mkdir(const char *pathname);
113    /// ```
114    /// - `pathname`: Path of the new directory to create.
115    ///
116    /// Returns `0` on success.
117    fn mkdir(&mut self, abi: &SyscallAbi) -> Result<usize, KernelError>;
118
119    /// Removes a file from the file system.
120    ///
121    /// # Syscall API
122    /// ```c
123    /// int unlink(const char *pathname);
124    /// ```
125    /// - `pathname`: Path of the file to remove.
126    ///
127    /// Returns `0` on success.
128    fn unlink(&mut self, abi: &SyscallAbi) -> Result<usize, KernelError>;
129
130    /// Changes the current working directory.
131    ///
132    /// # Syscall API
133    /// ```c
134    /// int chdir(const char *pathname);
135    /// ```
136    /// - `pathname`: Path of the directory to change to.
137    ///
138    /// Returns `0` on success.
139    fn chdir(&mut self, abi: &SyscallAbi) -> Result<usize, KernelError>;
140
141    /// Reads directory entries from the current directory.
142    ///
143    /// # Syscall API
144    /// ```c
145    /// ssize_t readdir(int fd, struct dentry *buf, size_t count);
146    /// ```
147    /// - `fd`: File descriptor of the directory to read from.
148    /// - `buf`: a pointer to the array of the dentries.
149    /// - `count`: the number of entries in the array.
150    ///
151    /// Returns the number of entries read into the buffer.
152    fn readdir(&mut self, abi: &SyscallAbi) -> Result<usize, KernelError>;
153
154    /// Retrieves file metadata.
155    ///
156    /// # Syscall API
157    /// ```c
158    /// int stat(const char *pathname, struct stat *buf);
159    /// ```
160    /// - `pathname`: Path of the file or directory.
161    /// - `buf`: Buffer to store the metadata.
162    ///
163    /// Returns `0` on success.
164    fn stat(&mut self, abi: &SyscallAbi) -> Result<usize, KernelError>;
165
166    /// Synchronizes in-memory file contents to disk.
167    ///
168    /// # Syscall API
169    /// ```c
170    /// int fsync(int fd);
171    /// ```
172    /// - `fd`: File descriptor of the file to synchronize.
173    ///
174    /// Returns `0` on success.
175    fn fsync(&mut self, abi: &SyscallAbi) -> Result<usize, KernelError>;
176}
177
178impl AdvancedFileStructs for FileStruct {
179    /// Creates a new empty file in the current directory.
180    ///
181    /// # Syscall API
182    /// ```c
183    /// int create(const char *pathname);
184    /// ```
185    /// - `pathname`: Path of the new file to create.
186    ///
187    /// Returns `0` on success.
188    fn create(&mut self, abi: &SyscallAbi) -> Result<usize, KernelError> {
189        todo!()
190    }
191
192    /// Creates a new directory in the current working directory.
193    ///
194    /// # Syscall API
195    /// ```c
196    /// int mkdir(const char *pathname);
197    /// ```
198    /// - `pathname`: Path of the new directory to create.
199    ///
200    /// Returns `0` on success.
201    fn mkdir(&mut self, abi: &SyscallAbi) -> Result<usize, KernelError> {
202        todo!()
203    }
204
205    /// Removes a file from the file system.
206    ///
207    /// # Syscall API
208    /// ```c
209    /// int unlink(const char *pathname);
210    /// ```
211    /// - `pathname`: Path of the file to remove.
212    ///
213    /// Returns `0` on success.
214    fn unlink(&mut self, abi: &SyscallAbi) -> Result<usize, KernelError> {
215        todo!()
216    }
217
218    /// Changes the current working directory.
219    ///
220    /// # Syscall API
221    /// ```c
222    /// int chdir(const char *pathname);
223    /// ```
224    /// - `pathname`: Path of the directory to change to.
225    ///
226    /// Returns `0` on success.
227    fn chdir(&mut self, abi: &SyscallAbi) -> Result<usize, KernelError> {
228        todo!()
229    }
230
231    /// Reads directory entries from the current directory.
232    ///
233    /// # Syscall API
234    /// ```c
235    /// ssize_t readdir(int fd, struct dentry *buf, size_t count);
236    /// ```
237    /// - `fd`: File descriptor of the directory to read from.
238    /// - `buf`: a pointer to the array of the dentries.
239    /// - `count`: the number of entries in the array.
240    ///
241    /// Returns the number of entries read into the buffer.
242    fn readdir(&mut self, abi: &SyscallAbi) -> Result<usize, KernelError> {
243        todo!()
244    }
245
246    /// Retrieves file metadata.
247    ///
248    /// # Syscall API
249    /// ```c
250    /// int stat(const char *pathname, struct stat *buf);
251    /// ```
252    /// - `pathname`: Path of the file or directory.
253    /// - `buf`: Buffer to store the metadata.
254    ///
255    /// Returns `0` on success.
256    fn stat(&mut self, abi: &SyscallAbi) -> Result<usize, KernelError> {
257        todo!()
258    }
259
260    /// Synchronizes in-memory file contents to disk.
261    ///
262    /// # Syscall API
263    /// ```c
264    /// int fsync(int fd);
265    /// ```
266    /// - `fd`: File descriptor of the file to synchronize.
267    ///
268    /// Returns `0` on success.
269    fn fsync(&mut self, abi: &SyscallAbi) -> Result<usize, KernelError> {
270        todo!()
271    }
272}