1 use core::ffi::{c_char, CStr};
2
3 use alloc::{boxed::Box, string::ToString};
4
5 use crate::{
6 arch::asm::{current::current_pcb, ptrace::user_mode},
7 include::bindings::bindings::{
8 pt_regs, verify_area, AT_REMOVEDIR, EBADF, EFAULT, EINVAL, ENAMETOOLONG, ENOENT, ENOTDIR,
9 EPERM, PAGE_2M_SIZE, PAGE_4K_SIZE, PROC_MAX_FD_NUM, SEEK_CUR, SEEK_END, SEEK_MAX, SEEK_SET,
10 },
11 io::SeekFrom,
12 kerror,
13 };
14
15 use super::{
16 core::{do_lseek, do_mkdir, do_open, do_read, do_remove_dir, do_unlink_at, do_write},
17 file::{File, FileMode},
18 Dirent, FileType, ROOT_INODE,
19 };
20
21 /// @brief 打开文件
22 ///
23 /// @param regs->r8 path 文件路径
24 /// @param regs->r9 o_flags 打开文件的标志位
25 ///
26 /// @return u64 文件描述符编号,或者是错误码
27 #[no_mangle]
sys_open(regs: &pt_regs) -> u6428 pub extern "C" fn sys_open(regs: &pt_regs) -> u64 {
29 let path: &CStr = unsafe { CStr::from_ptr(regs.r8 as usize as *const c_char) };
30 let path: Result<&str, core::str::Utf8Error> = path.to_str();
31 if path.is_err() {
32 return (-(EINVAL as i32)) as u64;
33 }
34 let path: &str = path.unwrap();
35 let flags = regs.r9;
36 let open_flags: FileMode = FileMode::from_bits_truncate(flags as u32);
37 let r: Result<i32, i32> = do_open(path, open_flags);
38
39 if r.is_ok() {
40 return r.unwrap() as u64;
41 } else {
42 return r.unwrap_err() as u64;
43 }
44 }
45
46 /// @brief 关闭文件的系统调用函数
47 ///
48 /// @param regs->r8 fd:文件描述符编号
49 #[no_mangle]
sys_close(regs: &pt_regs) -> u6450 pub extern "C" fn sys_close(regs: &pt_regs) -> u64 {
51 let fd = regs.r8 as i32;
52 let r: Result<(), i32> = current_pcb().drop_fd(fd);
53
54 if r.is_ok() {
55 return 0;
56 } else {
57 return r.unwrap_err() as u64;
58 }
59 }
60
61 /// @brief 读取文件的系统调用函数
62 ///
63 /// @param regs->r8 文件描述符编号
64 /// @param regs->r9 输出缓冲区
65 /// @param regs->r10 要读取的长度
66 #[no_mangle]
sys_read(regs: &pt_regs) -> u6467 pub extern "C" fn sys_read(regs: &pt_regs) -> u64 {
68 let fd = regs.r8 as i32;
69 let buf_vaddr = regs.r9 as usize;
70 let len = regs.r10 as usize;
71
72 // 判断缓冲区是否来自用户态,进行权限校验
73 if user_mode(regs) && unsafe { !verify_area(buf_vaddr as u64, len as u64) } {
74 // 来自用户态,而buffer在内核态,这样的操作不被允许
75 return (-(EPERM as i32)) as u64;
76 }
77
78 let buf: &mut [u8] =
79 unsafe { core::slice::from_raw_parts_mut::<'static, u8>(buf_vaddr as *mut u8, len) };
80
81 let r: Result<usize, i32> = do_read(fd, buf);
82
83 if r.is_ok() {
84 return r.unwrap() as u64;
85 } else {
86 return r.unwrap_err() as u64;
87 }
88 }
89
90 /// @brief 向文件写入数据的系统调用函数
91 ///
92 /// @param regs->r8 文件描述符编号
93 /// @param regs->r9 输入缓冲区
94 /// @param regs->r10 要写入的长度
95 #[no_mangle]
sys_write(regs: &pt_regs) -> u6496 pub extern "C" fn sys_write(regs: &pt_regs) -> u64 {
97 let fd = regs.r8 as i32;
98 let buf_vaddr = regs.r9 as usize;
99 let len = regs.r10 as usize;
100
101 // 判断缓冲区是否来自用户态,进行权限校验
102 if user_mode(regs) && unsafe { !verify_area(buf_vaddr as u64, len as u64) } {
103 // 来自用户态,而buffer在内核态,这样的操作不被允许
104 return (-(EPERM as i32)) as u64;
105 }
106
107 let buf: &[u8] =
108 unsafe { core::slice::from_raw_parts::<'static, u8>(buf_vaddr as *mut u8, len) };
109
110 let r: Result<usize, i32> = do_write(fd, buf);
111
112 if r.is_ok() {
113 return r.unwrap() as u64;
114 } else {
115 return r.unwrap_err() as u64;
116 }
117 }
118
119 /// @brief 调整文件访问指针位置的系统调用函数
120 ///
121 /// @param regs->r8 文件描述符编号
122 /// @param regs->r9 调整偏移量
123 /// @param regs->r10 调整的模式
124 #[no_mangle]
sys_lseek(regs: &pt_regs) -> u64125 pub extern "C" fn sys_lseek(regs: &pt_regs) -> u64 {
126 let fd = regs.r8 as i32;
127 let offset = regs.r9 as i64;
128 let whence = regs.r10 as u32;
129
130 let w: SeekFrom = match whence {
131 SEEK_SET => SeekFrom::SeekSet(offset),
132 SEEK_CUR => SeekFrom::SeekCurrent(offset),
133 SEEK_END => SeekFrom::SeekEnd(offset),
134 SEEK_MAX => SeekFrom::SeekEnd(0),
135 _ => return (-(EINVAL as i32)) as u64,
136 };
137
138 let r: Result<usize, i32> = do_lseek(fd, w);
139 if r.is_ok() {
140 return r.unwrap() as u64;
141 } else {
142 return r.unwrap_err() as u64;
143 }
144 }
145
146 /// @brief 切换工作目录
147 ///
148 /// @param dest_path 目标路径
149 ///
150 /// @return 返回码 描述
151 /// 0 | 成功
152 ///
153 /// EACCESS | 权限不足
154 ///
155 /// ELOOP | 解析path时遇到路径循环
156 ///
157 /// ENAMETOOLONG | 路径名过长
158 ///
159 /// ENOENT | 目标文件或目录不存在
160 ///
161 /// ENODIR | 检索期间发现非目录项
162 ///
163 /// ENOMEM | 系统内存不足
164 ///
165 /// EFAULT | 错误的地址
166 ///
167 /// ENAMETOOLONG | 路径过长
168 #[no_mangle]
sys_chdir(regs: &pt_regs) -> u64169 pub extern "C" fn sys_chdir(regs: &pt_regs) -> u64 {
170 if regs.r8 == 0 {
171 return -(EFAULT as i32) as u64;
172 }
173 let ptr = regs.r8 as usize as *const c_char;
174 // 权限校验
175 if ptr.is_null()
176 || (user_mode(regs) && unsafe { !verify_area(ptr as u64, PAGE_2M_SIZE as u64) })
177 {
178 return -(EINVAL as i32) as u64;
179 }
180
181 let dest_path: &CStr = unsafe { CStr::from_ptr(ptr) };
182 let dest_path: Result<&str, core::str::Utf8Error> = dest_path.to_str();
183
184 if dest_path.is_err() {
185 return (-(EINVAL as i32)) as u64;
186 }
187
188 let dest_path: &str = dest_path.unwrap();
189
190 if dest_path.len() == 0 {
191 return (-(EINVAL as i32)) as u64;
192 } else if dest_path.len() >= PAGE_4K_SIZE as usize {
193 return (-(ENAMETOOLONG as i32)) as u64;
194 }
195
196 let path = Box::new(dest_path.clone());
197 let inode = match ROOT_INODE().lookup(&path) {
198 Err(e) => {
199 kerror!("Change Directory Failed, Error = {}", e);
200 return (-(ENOENT as i32)) as u64;
201 }
202 Ok(i) => i,
203 };
204
205 match inode.metadata() {
206 Err(e) => {
207 kerror!("INode Get MetaData Failed, Error = {}", e);
208 return (-(ENOENT as i32)) as u64;
209 }
210 Ok(i) => {
211 if let FileType::Dir = i.file_type {
212 return 0;
213 } else {
214 return (-(ENOTDIR as i32)) as u64;
215 }
216 }
217 }
218 }
219
220 /// @brief 获取目录中的数据
221 ///
222 /// @param fd 文件描述符号
223 /// @return uint64_t dirent的总大小
224 #[no_mangle]
sys_getdents(regs: &pt_regs) -> u64225 pub extern "C" fn sys_getdents(regs: &pt_regs) -> u64 {
226 let fd = regs.r8 as i32;
227 let count = regs.r10 as i64;
228 let dirent = match unsafe { (regs.r9 as usize as *mut Dirent).as_mut() } {
229 None => {
230 return 0;
231 }
232 Some(dirent) => dirent,
233 };
234
235 if fd < 0 || fd as u32 > PROC_MAX_FD_NUM {
236 return (-(EBADF as i32)) as u64;
237 }
238
239 if count < 0 {
240 return (-(EINVAL as i32)) as u64;
241 }
242
243 // 获取fd
244 let file: &mut File = match current_pcb().get_file_mut_by_fd(fd) {
245 None => {
246 return (-(EBADF as i32)) as u64;
247 }
248 Some(file) => file,
249 };
250 // kdebug!("file={file:?}");
251
252 return match file.readdir(dirent) {
253 Err(_) => 0,
254 Ok(len) => len,
255 };
256 }
257
258 /// @brief 创建文件夹
259 ///
260 /// @param path(r8) 路径 / mode(r9) 模式
261 ///
262 /// @return uint64_t 负数错误码 / 0表示成功
263 #[no_mangle]
sys_mkdir(regs: &pt_regs) -> u64264 pub extern "C" fn sys_mkdir(regs: &pt_regs) -> u64 {
265 let ptr = regs.r8 as usize as *const c_char;
266 if ptr.is_null()
267 || (user_mode(regs) && unsafe { !verify_area(ptr as u64, PAGE_2M_SIZE as u64) })
268 {
269 return -(EINVAL as i32) as u64;
270 }
271 let path: &CStr = unsafe { CStr::from_ptr(ptr) };
272 let path: Result<&str, core::str::Utf8Error> = path.to_str();
273 let mode = regs.r9;
274
275 if path.is_err() {
276 return (-(EINVAL as i32)) as u64;
277 }
278
279 let path = &path.unwrap().to_string();
280 if path.trim() == "" {
281 return (-(EINVAL as i32)) as u64;
282 }
283
284 return match do_mkdir(&path.trim(), FileMode::from_bits_truncate(mode as u32)) {
285 Err(err) => {
286 kerror!("Failed in do_mkdir, Error Code = {}", err);
287 err as u64
288 }
289 Ok(_) => 0,
290 };
291 }
292
293 ///@brief 删除文件夹、取消文件的链接、删除文件的系统调用
294 ///
295 ///@param regs->r8 dfd 进程相对路径基准目录的文件描述符(见fcntl.h)
296 ///
297 ///@param regs->r9 路径名称字符串
298 ///
299 ///@param regs->r10 flag 预留的标志位,暂时未使用,请置为0。
300 ///
301 ///@return uint64_t 错误码
302 #[no_mangle]
sys_unlink_at(regs: &pt_regs) -> u64303 pub extern "C" fn sys_unlink_at(regs: &pt_regs) -> u64 {
304 let _dfd = regs.r8;
305 let ptr = regs.r9 as usize as *const c_char;
306 if ptr.is_null()
307 || (user_mode(regs) && unsafe { !verify_area(ptr as u64, PAGE_2M_SIZE as u64) })
308 {
309 return -(EINVAL as i32) as u64;
310 }
311 let path: &CStr = unsafe { CStr::from_ptr(ptr) };
312 let path: Result<&str, core::str::Utf8Error> = path.to_str();
313 let flag = regs.r10;
314 if path.is_err() {
315 return (-(EINVAL as i32)) as u64;
316 }
317
318 let path = &path.unwrap().to_string();
319 // kdebug!("sys_unlink_at={path:?}");
320 if (flag & (!(AT_REMOVEDIR as u64))) != 0_u64 {
321 return (-(EINVAL as i32)) as u64;
322 }
323
324 if (flag & (AT_REMOVEDIR as u64)) > 0 {
325 // kdebug!("rmdir");
326 match do_remove_dir(&path) {
327 Err(err) => {
328 kerror!("Failed to Remove Directory, Error Code = {}", err);
329 return err as u64;
330 }
331 Ok(_) => {
332 return 0;
333 }
334 }
335 }
336
337 // kdebug!("rm");
338 match do_unlink_at(&path, FileMode::from_bits_truncate(flag as u32)) {
339 Err(err) => {
340 kerror!("Failed to Remove Directory, Error Code = {}", err);
341 return err as u64;
342 }
343 Ok(_) => {
344 return 0;
345 }
346 }
347 }
348