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