arceos_posix_api/imp/
fd_ops.rs1use alloc::sync::Arc;
2use core::ffi::c_int;
3
4use axerrno::{LinuxError, LinuxResult};
5use axio::PollState;
6use axns::{ResArc, def_resource};
7use flatten_objects::FlattenObjects;
8use spin::RwLock;
9
10use crate::ctypes;
11use crate::imp::stdio::{stdin, stdout};
12
13pub const AX_FILE_LIMIT: usize = 1024;
14
15#[allow(dead_code)]
16pub trait FileLike: Send + Sync {
17 fn read(&self, buf: &mut [u8]) -> LinuxResult<usize>;
18 fn write(&self, buf: &[u8]) -> LinuxResult<usize>;
19 fn stat(&self) -> LinuxResult<ctypes::stat>;
20 fn into_any(self: Arc<Self>) -> Arc<dyn core::any::Any + Send + Sync>;
21 fn poll(&self) -> LinuxResult<PollState>;
22 fn set_nonblocking(&self, nonblocking: bool) -> LinuxResult;
23}
24
25def_resource! {
26 pub(crate) static FD_TABLE: ResArc<RwLock<FlattenObjects<Arc<dyn FileLike>, AX_FILE_LIMIT>>> = ResArc::new();
27}
28
29pub fn get_file_like(fd: c_int) -> LinuxResult<Arc<dyn FileLike>> {
30 FD_TABLE
31 .read()
32 .get(fd as usize)
33 .cloned()
34 .ok_or(LinuxError::EBADF)
35}
36
37pub fn add_file_like(f: Arc<dyn FileLike>) -> LinuxResult<c_int> {
38 Ok(FD_TABLE.write().add(f).map_err(|_| LinuxError::EMFILE)? as c_int)
39}
40
41pub fn close_file_like(fd: c_int) -> LinuxResult {
42 let f = FD_TABLE
43 .write()
44 .remove(fd as usize)
45 .ok_or(LinuxError::EBADF)?;
46 drop(f);
47 Ok(())
48}
49
50pub fn sys_close(fd: c_int) -> c_int {
52 debug!("sys_close <= {}", fd);
53 if (0..=2).contains(&fd) {
54 return 0; }
56 syscall_body!(sys_close, close_file_like(fd).map(|_| 0))
57}
58
59fn dup_fd(old_fd: c_int) -> LinuxResult<c_int> {
60 let f = get_file_like(old_fd)?;
61 let new_fd = add_file_like(f)?;
62 Ok(new_fd)
63}
64
65pub fn sys_dup(old_fd: c_int) -> c_int {
67 debug!("sys_dup <= {}", old_fd);
68 syscall_body!(sys_dup, dup_fd(old_fd))
69}
70
71pub fn sys_dup2(old_fd: c_int, new_fd: c_int) -> c_int {
75 debug!("sys_dup2 <= old_fd: {}, new_fd: {}", old_fd, new_fd);
76 syscall_body!(sys_dup2, {
77 if old_fd == new_fd {
78 let r = sys_fcntl(old_fd, ctypes::F_GETFD as _, 0);
79 if r >= 0 {
80 return Ok(old_fd);
81 } else {
82 return Ok(r);
83 }
84 }
85 if new_fd as usize >= AX_FILE_LIMIT {
86 return Err(LinuxError::EBADF);
87 }
88
89 let f = get_file_like(old_fd)?;
90 FD_TABLE
91 .write()
92 .add_at(new_fd as usize, f)
93 .map_err(|_| LinuxError::EMFILE)?;
94
95 Ok(new_fd)
96 })
97}
98
99pub fn sys_fcntl(fd: c_int, cmd: c_int, arg: usize) -> c_int {
103 debug!("sys_fcntl <= fd: {} cmd: {} arg: {}", fd, cmd, arg);
104 syscall_body!(sys_fcntl, {
105 match cmd as u32 {
106 ctypes::F_DUPFD => dup_fd(fd),
107 ctypes::F_DUPFD_CLOEXEC => {
108 dup_fd(fd)
110 }
111 ctypes::F_SETFL => {
112 if fd == 0 || fd == 1 || fd == 2 {
113 return Ok(0);
114 }
115 get_file_like(fd)?.set_nonblocking(arg & (ctypes::O_NONBLOCK as usize) > 0)?;
116 Ok(0)
117 }
118 _ => {
119 warn!("unsupported fcntl parameters: cmd {}", cmd);
120 Ok(0)
121 }
122 }
123 })
124}
125
126#[ctor_bare::register_ctor]
127fn init_stdio() {
128 let mut fd_table = flatten_objects::FlattenObjects::new();
129 fd_table
130 .add_at(0, Arc::new(stdin()) as _)
131 .unwrap_or_else(|_| panic!()); fd_table
133 .add_at(1, Arc::new(stdout()) as _)
134 .unwrap_or_else(|_| panic!()); fd_table
136 .add_at(2, Arc::new(stdout()) as _)
137 .unwrap_or_else(|_| panic!()); FD_TABLE.init_new(spin::RwLock::new(fd_table));
139}