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}