xref: /DragonOS/kernel/src/filesystem/vfs/syscall.rs (revision 36fd013004ee0bd5fc7cfb452ba22531a83a859c)
1 use alloc::{boxed::Box, sync::Arc, vec::Vec};
2 
3 use crate::{
4     arch::asm::current::current_pcb,
5     filesystem::vfs::file::FileDescriptorVec,
6     include::bindings::bindings::{verify_area, AT_REMOVEDIR, PAGE_4K_SIZE, PROC_MAX_FD_NUM},
7     io::SeekFrom,
8     kerror,
9     syscall::{Syscall, SystemError},
10 };
11 
12 use super::{
13     core::{do_mkdir, do_remove_dir, do_unlink_at},
14     file::{File, FileMode},
15     utils::rsplit_path,
16     Dirent, FileType, IndexNode, ROOT_INODE,
17 };
18 
19 pub const SEEK_SET: u32 = 0;
20 pub const SEEK_CUR: u32 = 1;
21 pub const SEEK_END: u32 = 2;
22 pub const SEEK_MAX: u32 = 3;
23 
24 impl Syscall {
25     /// @brief 为当前进程打开一个文件
26     ///
27     /// @param path 文件路径
28     /// @param o_flags 打开文件的标志位
29     ///
30     /// @return 文件描述符编号,或者是错误码
31     pub fn open(path: &str, mode: FileMode) -> Result<usize, SystemError> {
32         // 文件名过长
33         if path.len() > PAGE_4K_SIZE as usize {
34             return Err(SystemError::ENAMETOOLONG);
35         }
36 
37         let inode: Result<Arc<dyn IndexNode>, SystemError> = ROOT_INODE().lookup(path);
38 
39         let inode: Arc<dyn IndexNode> = if inode.is_err() {
40             let errno = inode.unwrap_err();
41             // 文件不存在,且需要创建
42             if mode.contains(FileMode::O_CREAT)
43                 && !mode.contains(FileMode::O_DIRECTORY)
44                 && errno == SystemError::ENOENT
45             {
46                 let (filename, parent_path) = rsplit_path(path);
47                 // 查找父目录
48                 let parent_inode: Arc<dyn IndexNode> =
49                     ROOT_INODE().lookup(parent_path.unwrap_or("/"))?;
50                 // 创建文件
51                 let inode: Arc<dyn IndexNode> =
52                     parent_inode.create(filename, FileType::File, 0o777)?;
53                 inode
54             } else {
55                 // 不需要创建文件,因此返回错误码
56                 return Err(errno);
57             }
58         } else {
59             inode.unwrap()
60         };
61 
62         let file_type: FileType = inode.metadata()?.file_type;
63         // 如果要打开的是文件夹,而目标不是文件夹
64         if mode.contains(FileMode::O_DIRECTORY) && file_type != FileType::Dir {
65             return Err(SystemError::ENOTDIR);
66         }
67 
68         // 如果O_TRUNC,并且,打开模式包含O_RDWR或O_WRONLY,清空文件
69         if mode.contains(FileMode::O_TRUNC)
70             && (mode.contains(FileMode::O_RDWR) || mode.contains(FileMode::O_WRONLY))
71             && file_type == FileType::File
72         {
73             inode.truncate(0)?;
74         }
75 
76         // 创建文件对象
77         let mut file: File = File::new(inode, mode)?;
78 
79         // 打开模式为“追加”
80         if mode.contains(FileMode::O_APPEND) {
81             file.lseek(SeekFrom::SeekEnd(0))?;
82         }
83 
84         // 把文件对象存入pcb
85         return current_pcb().alloc_fd(file, None).map(|fd| fd as usize);
86     }
87 
88     /// @brief 关闭文件
89     ///
90     /// @param fd 文件描述符编号
91     ///
92     /// @return 成功返回0,失败返回错误码
93     pub fn close(fd: usize) -> Result<usize, SystemError> {
94         return current_pcb().drop_fd(fd as i32).map(|_| 0);
95     }
96 
97     /// @brief 根据文件描述符,读取文件数据。尝试读取的数据长度与buf的长度相同。
98     ///
99     /// @param fd 文件描述符编号
100     /// @param buf 输出缓冲区。
101     ///
102     /// @return Ok(usize) 成功读取的数据的字节数
103     /// @return Err(SystemError) 读取失败,返回posix错误码
104     pub fn read(fd: i32, buf: &mut [u8]) -> Result<usize, SystemError> {
105         let file: Option<&mut File> = current_pcb().get_file_mut_by_fd(fd);
106         if file.is_none() {
107             return Err(SystemError::EBADF);
108         }
109         let file: &mut File = file.unwrap();
110 
111         return file.read(buf.len(), buf);
112     }
113 
114     /// @brief 根据文件描述符,向文件写入数据。尝试写入的数据长度与buf的长度相同。
115     ///
116     /// @param fd 文件描述符编号
117     /// @param buf 输入缓冲区。
118     ///
119     /// @return Ok(usize) 成功写入的数据的字节数
120     /// @return Err(SystemError) 写入失败,返回posix错误码
121     pub fn write(fd: i32, buf: &[u8]) -> Result<usize, SystemError> {
122         let file: Option<&mut File> = current_pcb().get_file_mut_by_fd(fd);
123         if file.is_none() {
124             return Err(SystemError::EBADF);
125         }
126         let file: &mut File = file.unwrap();
127 
128         return file.write(buf.len(), buf);
129     }
130 
131     /// @brief 调整文件操作指针的位置
132     ///
133     /// @param fd 文件描述符编号
134     /// @param seek 调整的方式
135     ///
136     /// @return Ok(usize) 调整后,文件访问指针相对于文件头部的偏移量
137     /// @return Err(SystemError) 调整失败,返回posix错误码
138     pub fn lseek(fd: i32, seek: SeekFrom) -> Result<usize, SystemError> {
139         let file: Option<&mut File> = current_pcb().get_file_mut_by_fd(fd);
140         if file.is_none() {
141             return Err(SystemError::EBADF);
142         }
143         let file: &mut File = file.unwrap();
144         return file.lseek(seek);
145     }
146 
147     /// @brief 切换工作目录
148     ///
149     /// @param dest_path 目标路径
150     ///
151     /// @return   返回码  描述
152     ///      0       |          成功
153     ///
154     ///   EACCESS    |        权限不足
155     ///
156     ///    ELOOP     | 解析path时遇到路径循环
157     ///
158     /// ENAMETOOLONG |       路径名过长
159     ///
160     ///    ENOENT    |  目标文件或目录不存在
161     ///
162     ///    ENODIR    |  检索期间发现非目录项
163     ///
164     ///    ENOMEM    |      系统内存不足
165     ///
166     ///    EFAULT    |       错误的地址
167     ///
168     /// ENAMETOOLONG |        路径过长
169     pub fn chdir(dest_path: &str) -> Result<usize, SystemError> {
170         // Copy path to kernel space to avoid some security issues
171         let path: Box<&str> = Box::new(dest_path);
172         let inode = match ROOT_INODE().lookup(&path) {
173             Err(e) => {
174                 kerror!("Change Directory Failed, Error = {:?}", e);
175                 return Err(SystemError::ENOENT);
176             }
177             Ok(i) => i,
178         };
179 
180         match inode.metadata() {
181             Err(e) => {
182                 kerror!("INode Get MetaData Failed, Error = {:?}", e);
183                 return Err(SystemError::ENOENT);
184             }
185             Ok(i) => {
186                 if let FileType::Dir = i.file_type {
187                     return Ok(0);
188                 } else {
189                     return Err(SystemError::ENOTDIR);
190                 }
191             }
192         }
193     }
194 
195     /// @brief 获取目录中的数据
196     ///
197     /// TODO: 这个函数的语义与Linux不一致,需要修改!!!
198     ///
199     /// @param fd 文件描述符号
200     /// @param buf 输出缓冲区
201     ///
202     /// @return 成功返回读取的字节数,失败返回错误码
203     pub fn getdents(fd: i32, buf: &mut [u8]) -> Result<usize, SystemError> {
204         let dirent =
205             unsafe { (buf.as_mut_ptr() as *mut Dirent).as_mut() }.ok_or(SystemError::EFAULT)?;
206 
207         if fd < 0 || fd as u32 > PROC_MAX_FD_NUM {
208             return Err(SystemError::EBADF);
209         }
210 
211         // 获取fd
212         let file: &mut File = match current_pcb().get_file_mut_by_fd(fd) {
213             None => {
214                 return Err(SystemError::EBADF);
215             }
216             Some(file) => file,
217         };
218         // kdebug!("file={file:?}");
219 
220         return file.readdir(dirent).map(|x| x as usize);
221     }
222 
223     /// @brief 创建文件夹
224     ///
225     /// @param path(r8) 路径 / mode(r9) 模式
226     ///
227     /// @return uint64_t 负数错误码 / 0表示成功
228     pub fn mkdir(path: &str, mode: usize) -> Result<usize, SystemError> {
229         return do_mkdir(path, FileMode::from_bits_truncate(mode as u32)).map(|x| x as usize);
230     }
231 
232     /// **删除文件夹、取消文件的链接、删除文件的系统调用**
233     ///
234     /// ## 参数
235     ///
236     /// - `dirfd`:文件夹的文件描述符.目前暂未实现
237     /// - `pathname`:文件夹的路径
238     /// - `flags`:标志位
239     ///
240     ///
241     pub fn unlinkat(_dirfd: i32, pathname: &str, flags: u32) -> Result<usize, SystemError> {
242         // kdebug!("sys_unlink_at={path:?}");
243         if (flags & (!AT_REMOVEDIR)) != 0 {
244             return Err(SystemError::EINVAL);
245         }
246 
247         if (flags & AT_REMOVEDIR) > 0 {
248             // kdebug!("rmdir");
249             match do_remove_dir(&pathname) {
250                 Err(err) => {
251                     kerror!("Failed to Remove Directory, Error Code = {:?}", err);
252                     return Err(err);
253                 }
254                 Ok(_) => {
255                     return Ok(0);
256                 }
257             }
258         }
259 
260         match do_unlink_at(&pathname, FileMode::from_bits_truncate(flags as u32)) {
261             Err(err) => {
262                 kerror!("Failed to Remove Directory, Error Code = {:?}", err);
263                 return Err(err);
264             }
265             Ok(_) => {
266                 return Ok(0);
267             }
268         }
269     }
270 
271     /// @brief 根据提供的文件描述符的fd,复制对应的文件结构体,并返回新复制的文件结构体对应的fd
272     pub fn dup(oldfd: i32) -> Result<usize, SystemError> {
273         if let Some(fds) = FileDescriptorVec::from_pcb(current_pcb()) {
274             // 获得当前文件描述符数组
275             // 确认oldfd是否有效
276             if FileDescriptorVec::validate_fd(oldfd) {
277                 if let Some(file) = &fds.fds[oldfd as usize] {
278                     // 尝试获取对应的文件结构体
279                     let file_cp: Box<File> = file.try_clone().ok_or(SystemError::EBADF)?;
280 
281                     // 申请文件描述符,并把文件对象存入其中
282                     let res = current_pcb().alloc_fd(*file_cp, None).map(|x| x as usize);
283                     return res;
284                 }
285                 // oldfd对应的文件不存在
286                 return Err(SystemError::EBADF);
287             }
288             return Err(SystemError::EBADF);
289         } else {
290             return Err(SystemError::EMFILE);
291         }
292     }
293 
294     /// 根据提供的文件描述符的fd,和指定新fd,复制对应的文件结构体,
295     /// 并返回新复制的文件结构体对应的fd.
296     /// 如果新fd已经打开,则会先关闭新fd.
297     ///
298     /// ## 参数
299     ///
300     /// - `oldfd`:旧文件描述符
301     /// - `newfd`:新文件描述符
302     ///
303     /// ## 返回值
304     ///
305     /// - 成功:新文件描述符
306     /// - 失败:错误码
307     pub fn dup2(oldfd: i32, newfd: i32) -> Result<usize, SystemError> {
308         if let Some(fds) = FileDescriptorVec::from_pcb(current_pcb()) {
309             // 获得当前文件描述符数组
310             if FileDescriptorVec::validate_fd(oldfd) && FileDescriptorVec::validate_fd(newfd) {
311                 //确认oldfd, newid是否有效
312                 if oldfd == newfd {
313                     // 若oldfd与newfd相等
314                     return Ok(newfd as usize);
315                 }
316 
317                 if let Some(file) = &fds.fds[oldfd as usize] {
318                     if fds.fds[newfd as usize].is_some() {
319                         // close newfd
320                         if let Err(_) = current_pcb().drop_fd(newfd) {
321                             // An I/O error occurred while attempting to close fildes2.
322                             return Err(SystemError::EIO);
323                         }
324                     }
325 
326                     // 尝试获取对应的文件结构体
327                     let file_cp = file.try_clone();
328                     if file_cp.is_none() {
329                         return Err(SystemError::EBADF);
330                     }
331                     // 申请文件描述符,并把文件对象存入其中
332                     let res = current_pcb()
333                         .alloc_fd(*file_cp.unwrap(), Some(newfd))
334                         .map(|x| x as usize);
335 
336                     return res;
337                 }
338                 return Err(SystemError::EBADF);
339             } else {
340                 return Err(SystemError::EBADF);
341             }
342         }
343         // 从pcb获取文件描述符数组失败
344         return Err(SystemError::EMFILE);
345     }
346 }
347 
348 #[repr(C)]
349 #[derive(Debug, Clone, Copy)]
350 pub struct IoVec {
351     /// 缓冲区的起始地址
352     pub iov_base: *mut u8,
353     /// 缓冲区的长度
354     pub iov_len: usize,
355 }
356 
357 /// 用于存储多个来自用户空间的IoVec
358 ///
359 /// 由于目前内核中的文件系统还不支持分散读写,所以暂时只支持将用户空间的IoVec聚合成一个缓冲区,然后进行操作。
360 /// TODO:支持分散读写
361 #[derive(Debug)]
362 pub struct IoVecs(Vec<&'static mut [u8]>);
363 
364 impl IoVecs {
365     /// 从用户空间的IoVec中构造IoVecs
366     ///
367     /// @param iov 用户空间的IoVec
368     /// @param iovcnt 用户空间的IoVec的数量
369     /// @param readv 是否为readv系统调用
370     ///
371     /// @return 构造成功返回IoVecs,否则返回错误码
372     pub unsafe fn from_user(
373         iov: *const IoVec,
374         iovcnt: usize,
375         _readv: bool,
376     ) -> Result<Self, SystemError> {
377         // 检查iov指针所在空间是否合法
378         if !verify_area(
379             iov as usize as u64,
380             (iovcnt * core::mem::size_of::<IoVec>()) as u64,
381         ) {
382             return Err(SystemError::EFAULT);
383         }
384 
385         // 将用户空间的IoVec转换为引用(注意:这里的引用是静态的,因为用户空间的IoVec不会被释放)
386         let iovs: &[IoVec] = core::slice::from_raw_parts(iov, iovcnt);
387 
388         let mut slices: Vec<&mut [u8]> = vec![];
389         slices.reserve(iovs.len());
390 
391         for iov in iovs.iter() {
392             if iov.iov_len == 0 {
393                 continue;
394             }
395 
396             if !verify_area(iov.iov_base as usize as u64, iov.iov_len as u64) {
397                 return Err(SystemError::EFAULT);
398             }
399 
400             slices.push(core::slice::from_raw_parts_mut(iov.iov_base, iov.iov_len));
401         }
402 
403         return Ok(Self(slices));
404     }
405 
406     /// @brief 将IoVecs中的数据聚合到一个缓冲区中
407     ///
408     /// @return 返回聚合后的缓冲区
409     pub fn gather(&self) -> Vec<u8> {
410         let mut buf = Vec::new();
411         for slice in self.0.iter() {
412             buf.extend_from_slice(slice);
413         }
414         return buf;
415     }
416 
417     /// @brief 将给定的数据分散写入到IoVecs中
418     pub fn scatter(&mut self, data: &[u8]) {
419         let mut data: &[u8] = data;
420         for slice in self.0.iter_mut() {
421             let len = core::cmp::min(slice.len(), data.len());
422             if len == 0 {
423                 continue;
424             }
425 
426             slice[..len].copy_from_slice(&data[..len]);
427             data = &data[len..];
428         }
429     }
430 
431     /// @brief 创建与IoVecs等长的缓冲区
432     ///
433     /// @param set_len 是否设置返回的Vec的len。
434     /// 如果为true,则返回的Vec的len为所有IoVec的长度之和;
435     /// 否则返回的Vec的len为0,capacity为所有IoVec的长度之和.
436     ///
437     /// @return 返回创建的缓冲区
438     pub fn new_buf(&self, set_len: bool) -> Vec<u8> {
439         let total_len: usize = self.0.iter().map(|slice| slice.len()).sum();
440         let mut buf: Vec<u8> = Vec::with_capacity(total_len);
441 
442         if set_len {
443             unsafe {
444                 buf.set_len(total_len);
445             }
446         }
447         return buf;
448     }
449 }
450