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