1mod fs;
2mod net;
3mod pipe;
4mod stdio;
5
6use core::{any::Any, ffi::c_int};
7
8use alloc::{sync::Arc, vec::Vec};
9use axerrno::{LinuxError, LinuxResult};
10use axio::PollState;
11use axns::{ResArc, def_resource};
12use flatten_objects::FlattenObjects;
13use linux_raw_sys::general::{stat, statx};
14use spin::RwLock;
15
16pub use self::{
17 fs::{Directory, File},
18 net::Socket,
19 pipe::Pipe,
20};
21
22pub const AX_FILE_LIMIT: usize = 1024;
23
24#[derive(Debug, Clone, Copy)]
25pub struct Kstat {
26 ino: u64,
27 nlink: u32,
28 uid: u32,
29 gid: u32,
30 mode: u32,
31 size: u64,
32 blocks: u64,
33 blksize: u32,
34}
35
36impl Default for Kstat {
37 fn default() -> Self {
38 Self {
39 ino: 1,
40 nlink: 1,
41 uid: 1,
42 gid: 1,
43 mode: 0,
44 size: 0,
45 blocks: 0,
46 blksize: 4096,
47 }
48 }
49}
50
51impl From<Kstat> for stat {
52 fn from(value: Kstat) -> Self {
53 let mut stat: stat = unsafe { core::mem::zeroed() };
55 stat.st_ino = value.ino as _;
56 stat.st_nlink = value.nlink as _;
57 stat.st_mode = value.mode as _;
58 stat.st_uid = value.uid as _;
59 stat.st_gid = value.gid as _;
60 stat.st_size = value.size as _;
61 stat.st_blksize = value.blksize as _;
62 stat.st_blocks = value.blocks as _;
63
64 stat
65 }
66}
67
68impl From<Kstat> for statx {
69 fn from(value: Kstat) -> Self {
70 let mut statx: statx = unsafe { core::mem::zeroed() };
72 statx.stx_blksize = value.blksize as _;
73 statx.stx_attributes = value.mode as _;
74 statx.stx_nlink = value.nlink as _;
75 statx.stx_uid = value.uid as _;
76 statx.stx_gid = value.gid as _;
77 statx.stx_mode = value.mode as _;
78 statx.stx_ino = value.ino as _;
79 statx.stx_size = value.size as _;
80 statx.stx_blocks = value.blocks as _;
81
82 statx
83 }
84}
85
86#[allow(dead_code)]
87pub trait FileLike: Send + Sync {
88 fn read(&self, buf: &mut [u8]) -> LinuxResult<usize>;
89 fn write(&self, buf: &[u8]) -> LinuxResult<usize>;
90 fn stat(&self) -> LinuxResult<Kstat>;
91 fn into_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
92 fn poll(&self) -> LinuxResult<PollState>;
93 fn set_nonblocking(&self, nonblocking: bool) -> LinuxResult;
94
95 fn from_fd(fd: c_int) -> LinuxResult<Arc<Self>>
96 where
97 Self: Sized + 'static,
98 {
99 get_file_like(fd)?
100 .into_any()
101 .downcast::<Self>()
102 .map_err(|_| LinuxError::EINVAL)
103 }
104
105 fn add_to_fd_table(self) -> LinuxResult<c_int>
106 where
107 Self: Sized + 'static,
108 {
109 add_file_like(Arc::new(self))
110 }
111}
112
113def_resource! {
114 pub static FD_TABLE: ResArc<RwLock<FlattenObjects<Arc<dyn FileLike>, AX_FILE_LIMIT>>> = ResArc::new();
115}
116
117impl FD_TABLE {
118 pub fn copy_inner(&self) -> RwLock<FlattenObjects<Arc<dyn FileLike>, AX_FILE_LIMIT>> {
120 let table = self.read();
121 let mut new_table = FlattenObjects::new();
122 for id in table.ids() {
123 let _ = new_table.add_at(id, table.get(id).unwrap().clone());
124 }
125 RwLock::new(new_table)
126 }
127
128 pub fn clear(&self) {
129 let mut table = self.write();
130 let ids = table.ids().collect::<Vec<_>>();
131 for id in ids {
132 let _ = table.remove(id);
133 }
134 }
135}
136
137pub fn get_file_like(fd: c_int) -> LinuxResult<Arc<dyn FileLike>> {
139 FD_TABLE
140 .read()
141 .get(fd as usize)
142 .cloned()
143 .ok_or(LinuxError::EBADF)
144}
145
146pub fn add_file_like(f: Arc<dyn FileLike>) -> LinuxResult<c_int> {
148 Ok(FD_TABLE.write().add(f).map_err(|_| LinuxError::EMFILE)? as c_int)
149}
150
151pub fn close_file_like(fd: c_int) -> LinuxResult {
153 let f = FD_TABLE
154 .write()
155 .remove(fd as usize)
156 .ok_or(LinuxError::EBADF)?;
157 debug!("close_file_like <= count: {}", Arc::strong_count(&f));
158 Ok(())
159}
160
161#[ctor_bare::register_ctor]
162fn init_stdio() {
163 let mut fd_table = flatten_objects::FlattenObjects::new();
164 fd_table
165 .add_at(0, Arc::new(stdio::stdin()) as _)
166 .unwrap_or_else(|_| panic!()); fd_table
168 .add_at(1, Arc::new(stdio::stdout()) as _)
169 .unwrap_or_else(|_| panic!()); fd_table
171 .add_at(2, Arc::new(stdio::stdout()) as _)
172 .unwrap_or_else(|_| panic!()); FD_TABLE.init_new(spin::RwLock::new(fd_table));
174}