Browse Source

Add dup,dup2 (#224)

* dup,dup2

* fix: sys_dup2语义与posix不一致的问题

---------

Co-authored-by: longjin <[email protected]>
Gou Ngai 1 year ago
parent
commit
2b771e32f5

+ 4 - 3
kernel/src/filesystem/vfs/core.rs

@@ -16,9 +16,10 @@ use crate::{
         ramfs::RamFS,
         vfs::{file::File, mount::MountFS, FileSystem, FileType},
     },
-    include::bindings::bindings::{PAGE_4K_SIZE},
+    include::bindings::bindings::PAGE_4K_SIZE,
     io::SeekFrom,
-    kerror, kinfo, syscall::SystemError,
+    kerror, kinfo,
+    syscall::SystemError,
 };
 
 use super::{file::FileMode, utils::rsplit_path, IndexNode, InodeId};
@@ -237,7 +238,7 @@ pub fn do_open(path: &str, mode: FileMode) -> Result<i32, SystemError> {
     }
 
     // 把文件对象存入pcb
-    return current_pcb().alloc_fd(file);
+    return current_pcb().alloc_fd(file, None);
 }
 
 /// @brief 根据文件描述符,读取文件数据。尝试读取的数据长度与buf的长度相同。

+ 3 - 8
kernel/src/filesystem/vfs/file.rs

@@ -3,14 +3,9 @@ use core::mem::MaybeUninit;
 use alloc::{boxed::Box, string::String, sync::Arc, vec::Vec};
 
 use crate::{
-    arch::asm::current::current_pcb,
-    driver::tty::TtyFilePrivateData,
-    filesystem::procfs::ProcfsFilePrivateData,
-    include::bindings::bindings::{
-        process_control_block,
-    },
-    io::SeekFrom,
-    kerror, syscall::SystemError,
+    arch::asm::current::current_pcb, driver::tty::TtyFilePrivateData,
+    filesystem::procfs::ProcfsFilePrivateData, include::bindings::bindings::process_control_block,
+    io::SeekFrom, kerror, syscall::SystemError,
 };
 
 use super::{Dirent, FileType, IndexNode, Metadata};

+ 93 - 2
kernel/src/filesystem/vfs/syscall.rs

@@ -4,11 +4,14 @@ use alloc::{boxed::Box, string::ToString};
 
 use crate::{
     arch::asm::{current::current_pcb, ptrace::user_mode},
+    filesystem::vfs::file::FileDescriptorVec,
     include::bindings::bindings::{
-        pt_regs, verify_area, AT_REMOVEDIR, PAGE_2M_SIZE, PAGE_4K_SIZE, PROC_MAX_FD_NUM, SEEK_CUR, SEEK_END, SEEK_MAX, SEEK_SET,
+        pt_regs, verify_area, AT_REMOVEDIR, PAGE_2M_SIZE, PAGE_4K_SIZE, PROC_MAX_FD_NUM, SEEK_CUR,
+        SEEK_END, SEEK_MAX, SEEK_SET,
     },
     io::SeekFrom,
-    kerror, syscall::SystemError,
+    kerror,
+    syscall::SystemError,
 };
 
 use super::{
@@ -344,3 +347,91 @@ pub extern "C" fn sys_unlink_at(regs: &pt_regs) -> u64 {
         }
     }
 }
+
+fn do_dup(oldfd: i32) -> Result<i32, SystemError> {
+    if let Some(fds) = FileDescriptorVec::from_pcb(current_pcb()) {
+        // 获得当前文件描述符数组
+        // 确认oldfd是否有效
+        if FileDescriptorVec::validate_fd(oldfd) {
+            if let Some(file) = &fds.fds[oldfd as usize] {
+                // 尝试获取对应的文件结构体
+                let file_cp = (file).try_clone();
+                if file_cp.is_none() {
+                    return Err(SystemError::EBADF);
+                }
+                let res = current_pcb().alloc_fd(*file_cp.unwrap(), None);
+                // 申请文件描述符,并把文件对象存入其中
+                return res;
+            }
+            // oldfd对应的文件不存在
+            return Err(SystemError::EBADF);
+        }
+        return Err(SystemError::EBADF);
+    } else {
+        return Err(SystemError::EMFILE);
+    }
+}
+
+#[no_mangle]
+/// @brief 根据提供的文件描述符的fd,复制对应的文件结构体,并返回新复制的文件结构体对应的fd
+pub extern "C" fn sys_dup(regs: &pt_regs) -> u64 {
+    let fd: i32 = regs.r8 as i32;
+    let r = do_dup(fd);
+    if r.is_ok() {
+        return r.unwrap() as u64;
+    } else {
+        return r.unwrap_err().to_posix_errno() as u64;
+    }
+}
+
+fn do_dup2(oldfd: i32, newfd: i32) -> Result<i32, SystemError> {
+    if let Some(fds) = FileDescriptorVec::from_pcb(current_pcb()) {
+        // 获得当前文件描述符数组
+        if FileDescriptorVec::validate_fd(oldfd) && FileDescriptorVec::validate_fd(newfd) {
+            //确认oldfd, newid是否有效
+            if oldfd == newfd {
+                // 若oldfd与newfd相等
+                return Ok(newfd);
+            }
+
+            if let Some(file) = &fds.fds[oldfd as usize] {
+                if fds.fds[newfd as usize].is_some() {
+                    // close newfd
+                    if let Err(_) = current_pcb().drop_fd(newfd) {
+                        // An I/O error occurred while attempting to close fildes2.
+                        return Err(SystemError::EIO);
+                    }
+                }
+
+                // 尝试获取对应的文件结构体
+                let file_cp = file.try_clone();
+                if file_cp.is_none() {
+                    return Err(SystemError::EBADF);
+                }
+                // 申请文件描述符,并把文件对象存入其中
+                let res = current_pcb().alloc_fd(*file_cp.unwrap(), Some(newfd));
+
+                return res;
+            }
+            return Err(SystemError::EBADF);
+        } else {
+            return Err(SystemError::EBADF);
+        }
+    }
+    // 从pcb获取文件描述符数组失败
+    return Err(SystemError::EMFILE);
+}
+
+#[no_mangle]
+/// @brief 根据提供的文件描述符的fd,和指定新fd,复制对应的文件结构体,
+/// 并返回新复制的文件结构体对应的fd
+pub extern "C" fn sys_dup2(regs: &pt_regs) -> u64 {
+    let ofd = regs.r8 as i32;
+    let nfd = regs.r9 as i32;
+    let r = do_dup2(ofd, nfd);
+    if r.is_ok() {
+        return r.unwrap() as u64;
+    } else {
+        return r.unwrap_err().to_posix_errno() as u64;
+    }
+}

+ 1 - 2
kernel/src/lib.rs

@@ -50,7 +50,7 @@ use mm::allocator::KernelAllocator;
 // <3>
 use crate::{
     arch::asm::current::current_pcb,
-    include::bindings::bindings::{process_do_exit, BLACK, GREEN}, filesystem::vfs::ROOT_INODE,
+    include::bindings::bindings::{process_do_exit, BLACK, GREEN},
 };
 
 // 声明全局的slab分配器
@@ -97,6 +97,5 @@ pub fn panic(info: &PanicInfo) -> ! {
 #[no_mangle]
 pub extern "C" fn __rust_demo_func() -> i32 {
     printk_color!(GREEN, BLACK, "__rust_demo_func()\n");
-
     return 0;
 }

+ 35 - 16
kernel/src/process/process.rs

@@ -7,13 +7,17 @@ use alloc::boxed::Box;
 
 use crate::{
     arch::{asm::current::current_pcb, fpu::FpState},
-    filesystem::vfs::{file::{File, FileDescriptorVec, FileMode}, ROOT_INODE},
+    filesystem::vfs::{
+        file::{File, FileDescriptorVec, FileMode},
+        ROOT_INODE,
+    },
     include::bindings::bindings::{
-        process_control_block, CLONE_FS, PROC_INTERRUPTIBLE,
-        PROC_RUNNING, PROC_STOPPED, PROC_UNINTERRUPTIBLE,
+        process_control_block, CLONE_FS, PROC_INTERRUPTIBLE, PROC_RUNNING, PROC_STOPPED,
+        PROC_UNINTERRUPTIBLE,
     },
     sched::core::{cpu_executing, sched_enqueue},
-    smp::core::{smp_get_processor_id, smp_send_reschedule}, syscall::SystemError,
+    smp::core::{smp_get_processor_id, smp_send_reschedule},
+    syscall::SystemError,
 };
 
 use super::preempt::{preempt_disable, preempt_enable};
@@ -173,9 +177,12 @@ impl process_control_block {
 
     /// @brief 申请文件描述符,并把文件对象存入其中。
     ///
+    /// @param file 要存放的文件对象
+    /// @param fd 如果为Some(i32),表示指定要申请这个文件描述符,如果这个文件描述符已经被使用,那么返回EBADF
+    ///
     /// @return Ok(i32) 申请到的文件描述符编号
     /// @return Err(SystemError) 申请失败,返回错误码,并且,file对象将被drop掉
-    pub fn alloc_fd(&mut self, file: File) -> Result<i32, SystemError> {
+    pub fn alloc_fd(&mut self, file: File, fd: Option<i32>) -> Result<i32, SystemError> {
         // 获取pcb的文件描述符数组的引用
         let fds: &mut FileDescriptorVec =
             if let Some(f) = FileDescriptorVec::from_pcb(current_pcb()) {
@@ -192,16 +199,28 @@ impl process_control_block {
                 r.unwrap()
             };
 
-        // 寻找空闲的文件描述符
-        let mut cnt = 0;
-        for x in fds.fds.iter_mut() {
+        if fd.is_some() {
+            // 指定了要申请的文件描述符编号
+            let new_fd = fd.unwrap();
+            let x = &mut fds.fds[new_fd as usize];
             if x.is_none() {
                 *x = Some(Box::new(file));
-                return Ok(cnt);
+                return Ok(new_fd);
+            } else {
+                return Err(SystemError::EBADF);
+            }
+        } else {
+            // 寻找空闲的文件描述符
+            let mut cnt = 0;
+            for x in fds.fds.iter_mut() {
+                if x.is_none() {
+                    *x = Some(Box::new(file));
+                    return Ok(cnt);
+                }
+                cnt += 1;
             }
-            cnt += 1;
+            return Err(SystemError::ENFILE);
         }
-        return Err(SystemError::ENFILE);
     }
 
     /// @brief 根据文件描述符序号,获取文件结构体的可变引用
@@ -377,10 +396,10 @@ pub fn init_stdio() -> Result<(), SystemError> {
         .expect("Init stdio: can't create stderr");
 
     /*
-        按照规定,进程的文件描述符数组的前三个位置,分别是stdin, stdout, stderr
-     */
-    assert_eq!(current_pcb().alloc_fd(stdin).unwrap(), 0);
-    assert_eq!(current_pcb().alloc_fd(stdout).unwrap(), 1);
-    assert_eq!(current_pcb().alloc_fd(stderr).unwrap(), 2);
+       按照规定,进程的文件描述符数组的前三个位置,分别是stdin, stdout, stderr
+    */
+    assert_eq!(current_pcb().alloc_fd(stdin, None).unwrap(), 0);
+    assert_eq!(current_pcb().alloc_fd(stdout, None).unwrap(), 1);
+    assert_eq!(current_pcb().alloc_fd(stderr, None).unwrap(), 2);
     return Ok(());
 }

+ 6 - 1
kernel/src/syscall/syscall.c

@@ -400,6 +400,9 @@ uint64_t sys_pipe(struct pt_regs *regs)
 
 extern uint64_t sys_mkdir(struct pt_regs *regs);
 
+extern int sys_dup(int oldfd);
+extern int sys_dup2(int oldfd, int newfd);
+
 system_call_t system_call_table[MAX_SYSTEM_CALL_NUM] = {
     [0] = system_call_not_exists,
     [1] = sys_put_string,
@@ -429,5 +432,7 @@ system_call_t system_call_table[MAX_SYSTEM_CALL_NUM] = {
     [25] = sys_rt_sigreturn,
     [26] = sys_getpid,
     [27] = sys_sched,
-    [28 ... 255] = system_call_not_exists,
+    [28] = sys_dup,
+    [29] = sys_dup2,
+    [30 ... 255] = system_call_not_exists,
 };

+ 2 - 0
kernel/src/syscall/syscall_num.h

@@ -39,5 +39,7 @@
 #define SYS_RT_SIGRETURN 25 // 从信号处理函数返回
 #define SYS_GETPID 26       // 获取当前进程的pid(进程标识符)
 #define SYS_SCHED 27        // 让系统立即运行调度器(该系统调用不能由运行在Ring3的程序发起)
+#define SYS_DUP 28
+#define SYS_DUP2 29
 
 #define SYS_AHCI_END_REQ 255 // AHCI DMA请求结束end_request的系统调用

+ 3 - 3
user/apps/about/about.c

@@ -1,10 +1,10 @@
-#include "sys_version.h"    // 这是系统的版本头文件,在编译过程中自动生成
+#include "sys_version.h" // 这是系统的版本头文件,在编译过程中自动生成
+#include <fcntl.h>
 #include <math.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <time.h>
 #include <unistd.h>
-
 void print_ascii_logo()
 {
     printf(" ____                                      ___   ____ \n");
@@ -36,7 +36,7 @@ void print_copyright()
 }
 
 int main()
-{   
+{
     print_ascii_logo();
     print_copyright();
 

+ 4 - 0
user/libs/libc/src/include/export/unistd.h

@@ -122,6 +122,10 @@ void swab(void *restrict src, void *restrict dest, ssize_t nbytes);
 
 pid_t getpid(void);
 
+int dup(int fd);
+
+int dup2(int ofd, int nfd);
+
 #if defined(__cplusplus) 
 }  /* extern "C" */ 
 #endif

+ 13 - 4
user/libs/libc/src/unistd.c

@@ -1,10 +1,10 @@
 #include <errno.h>
 #include <fcntl.h>
+#include <libsystem/syscall.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
-#include <libsystem/syscall.h>
 
 /**
  * @brief 关闭文件接口
@@ -88,7 +88,6 @@ pid_t vfork(void)
 uint64_t brk(uint64_t end_brk)
 {
     uint64_t x = (uint64_t)syscall_invoke(SYS_BRK, (uint64_t)end_brk, 0, 0, 0, 0, 0, 0, 0);
-    // printf("brk():  end_brk=%#018lx x=%#018lx", (uint64_t)end_brk, x);
     return x;
 }
 
@@ -197,10 +196,20 @@ void swab(void *restrict src, void *restrict dest, ssize_t nbytes)
 
 /**
  * @brief 获取当前进程的pid(进程标识符)
- * 
+ *
  * @return pid_t 当前进程的pid
  */
 pid_t getpid(void)
 {
-    syscall_invoke(SYS_GETPID, 0, 0, 0, 0, 0, 0, 0, 0);
+    return syscall_invoke(SYS_GETPID, 0, 0, 0, 0, 0, 0, 0, 0);
+}
+
+int dup(int fd)
+{
+    return syscall_invoke(SYS_DUP, fd, 0, 0, 0, 0, 0, 0, 0);    
+}
+
+int dup2(int ofd, int nfd)
+{
+    return syscall_invoke(SYS_DUP2, ofd, nfd, 0, 0, 0, 0, 0, 0);
 }

+ 2 - 0
user/libs/libsystem/syscall.h

@@ -32,6 +32,8 @@
 #define SYS_SIGACTION 24    // 设置进程的信号处理动作
 #define SYS_RT_SIGRETURN 25 // 从信号处理函数返回
 #define SYS_GETPID 26 // 获取当前进程的pid(进程标识符)
+#define SYS_DUP 28
+#define SYS_DUP2 29
 
 /**
  * @brief 用户态系统调用函数