      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110

    use crate::fs::{make_pipe, open_file, OpenFlags};
    use crate::mm::{translated_byte_buffer, translated_refmut, translated_str, UserBuffer};
    use crate::task::{current_process, current_user_token};
    use alloc::sync::Arc;

    pub fn sys_write(fd: usize, buf: *const u8, len: usize) -> isize {
        if fd!=1 && fd!=2 {
            kprintln!("[KERN] syscall::fs::sys_write(fd: {}) begin", fd);
           }
        let token = current_user_token();
        let process = current_process();
        let inner = process.inner_exclusive_access();
        if fd >= inner.fd_table.len() {
            return -1;
        }
        if let Some(file) = &inner.fd_table[fd] {
            if !file.writable() {
                return -1;
            }
            let file = file.clone();
            // release current task TCB manually to avoid multi-borrow
            drop(inner);
            file.write(UserBuffer::new(translated_byte_buffer(token, buf, len))) as isize
        } else {
            -1
        }
    }

    pub fn sys_read(fd: usize, buf: *const u8, len: usize) -> isize {
        if fd!=0 {
         kprintln!("[KERN] syscall::fs::sys_read(fd: {}) begin", fd);
        }
        let token = current_user_token();
        let process = current_process();
        let inner = process.inner_exclusive_access();
        if fd >= inner.fd_table.len() {
            return -1;
        }
        if let Some(file) = &inner.fd_table[fd] {
            let file = file.clone();
            if !file.readable() {
                return -1;
            }
            // release current task TCB manually to avoid multi-borrow
            drop(inner);
            file.read(UserBuffer::new(translated_byte_buffer(token, buf, len))) as isize
        } else {
            -1
        }
    }

    pub fn sys_open(path: *const u8, flags: u32) -> isize {
        kprintln!("[KERN] syscall::fs::sys_open() begin");
        let process = current_process();
        let token = current_user_token();
        let path = translated_str(token, path);
        if let Some(inode) = open_file(path.as_str(), OpenFlags::from_bits(flags).unwrap()) {
            let mut inner = process.inner_exclusive_access();
            let fd = inner.alloc_fd();
            inner.fd_table[fd] = Some(inode);
            kprintln!("[KERN] syscall::fs::sys_open() return fd {}, end",fd);
            fd as isize
        } else {
            -1
        }
    }

    pub fn sys_close(fd: usize) -> isize {
        kprintln!("[KERN] syscall::fs::sys_close(fd: {}) begin",fd);
        let process = current_process();
        let mut inner = process.inner_exclusive_access();
        if fd >= inner.fd_table.len() {
            return -1;
        }
        if inner.fd_table[fd].is_none() {
            return -1;
        }
        inner.fd_table[fd].take();
        0
    }

    pub fn sys_pipe(pipe: *mut usize) -> isize {
        kprintln!("[KERN] syscall::fs::sys_pipe() begin");
        let process = current_process();
        let token = current_user_token();
        let mut inner = process.inner_exclusive_access();
        let (pipe_read, pipe_write) = make_pipe();
        let read_fd = inner.alloc_fd();
        inner.fd_table[read_fd] = Some(pipe_read);
        let write_fd = inner.alloc_fd();
        inner.fd_table[write_fd] = Some(pipe_write);
        *translated_refmut(token, pipe) = read_fd;
        *translated_refmut(token, unsafe { pipe.add(1) }) = write_fd;
        0
    }

    pub fn sys_dup(fd: usize) -> isize {
        kprintln!("[KERN] syscall::fs::sys_dup(fd: {}) begin", fd);
        let process = current_process();
        let mut inner = process.inner_exclusive_access();
        if fd >= inner.fd_table.len() {
            return -1;
        }
        if inner.fd_table[fd].is_none() {
            return -1;
        }
        let new_fd = inner.alloc_fd();
        inner.fd_table[new_fd] = Some(Arc::clone(inner.fd_table[fd].as_ref().unwrap()));
        new_fd as isize
    }