1use crate::security;
6use crate::task::{CurrentTask, Kernel};
7use crate::vfs::buffers::{InputBuffer, OutputBuffer};
8use crate::vfs::{
9 AppendLockGuard, CheckAccessReason, FileObject, FileOps, FsNode, FsNodeInfo, FsNodeOps,
10 fileops_impl_seekable, fs_node_impl_not_dir,
11};
12
13use crate::vfs::fileops_impl_noop_sync;
14use starnix_sync::{FileOpsCore, Locked, RwLock};
15use starnix_uapi::as_any::AsAny;
16use starnix_uapi::auth::Capabilities;
17use starnix_uapi::errors::Errno;
18use starnix_uapi::open_flags::OpenFlags;
19use starnix_uapi::{errno, error};
20use std::borrow::Cow;
21use std::fmt::Display;
22use std::sync::{Arc, Weak};
23
24pub struct SimpleFileNode<F, O>
25where
26 F: Fn() -> Result<O, Errno>,
27 O: FileOps,
28{
29 create_file_ops: F,
30
31 capabilities: Capabilities,
33}
34
35impl<F, O> SimpleFileNode<F, O>
36where
37 F: Fn() -> Result<O, Errno> + Send + Sync,
38 O: FileOps,
39{
40 pub fn new(create_file_ops: F) -> SimpleFileNode<F, O> {
41 SimpleFileNode { create_file_ops, capabilities: Capabilities::empty() }
42 }
43
44 pub fn new_with_capabilities(
45 create_file_ops: F,
46 capabilities: Capabilities,
47 ) -> SimpleFileNode<F, O> {
48 SimpleFileNode { create_file_ops, capabilities }
49 }
50}
51
52impl<F, O> FsNodeOps for SimpleFileNode<F, O>
53where
54 F: Fn() -> Result<O, Errno> + Send + Sync + 'static,
55 O: FileOps,
56{
57 fs_node_impl_not_dir!();
58
59 fn check_access(
60 &self,
61 _locked: &mut Locked<FileOpsCore>,
62 node: &FsNode,
63 current_task: &CurrentTask,
64 permission_flags: security::PermissionFlags,
65 info: &RwLock<FsNodeInfo>,
66 reason: CheckAccessReason,
67 audit_context: security::Auditable<'_>,
68 ) -> Result<(), Errno> {
69 if self.capabilities != Capabilities::empty()
70 && security::is_task_capable_noaudit(current_task, self.capabilities)
71 {
72 Ok(())
73 } else {
74 node.default_check_access_impl(
75 current_task,
76 permission_flags,
77 reason,
78 info.read(),
79 audit_context,
80 )
81 }
82 }
83
84 fn create_file_ops(
85 &self,
86 _locked: &mut Locked<FileOpsCore>,
87 _node: &FsNode,
88 _current_task: &CurrentTask,
89 _flags: OpenFlags,
90 ) -> Result<Box<dyn FileOps>, Errno> {
91 Ok(Box::new((self.create_file_ops)()?))
92 }
93
94 fn truncate(
95 &self,
96 _locked: &mut Locked<FileOpsCore>,
97 _guard: &AppendLockGuard<'_>,
98 _node: &FsNode,
99 _current_task: &CurrentTask,
100 _length: u64,
101 ) -> Result<(), Errno> {
102 Ok(())
104 }
105}
106
107pub fn parse_unsigned_file<T: Into<u64> + std::str::FromStr>(buf: &[u8]) -> Result<T, Errno> {
108 let i = buf.iter().position(|c| !char::from(*c).is_ascii_digit()).unwrap_or(buf.len());
109 std::str::from_utf8(&buf[..i]).unwrap().parse::<T>().map_err(|_| errno!(EINVAL))
110}
111
112pub fn parse_i32_file(buf: &[u8]) -> Result<i32, Errno> {
113 let i = buf
114 .iter()
115 .position(|c| {
116 let ch = char::from(*c);
117 !(ch.is_ascii_digit() || ch == '-')
118 })
119 .unwrap_or(buf.len());
120 std::str::from_utf8(&buf[..i]).unwrap().parse::<i32>().map_err(|_| errno!(EINVAL))
121}
122
123pub fn serialize_for_file<T: Display>(value: T) -> Vec<u8> {
124 let string = format!("{}\n", value);
125 string.into_bytes()
126}
127
128pub struct BytesFile<Ops>(Arc<Ops>);
129
130impl<Ops: BytesFileOps> BytesFile<Ops> {
131 pub fn new(data: Ops) -> Self {
132 Self(Arc::new(data))
133 }
134
135 pub fn new_node(data: Ops) -> impl FsNodeOps {
136 let data = Arc::new(data);
137 SimpleFileNode::new(move || Ok(BytesFile(Arc::clone(&data))))
138 }
139}
140
141impl<Ops> std::clone::Clone for BytesFile<Ops> {
143 fn clone(&self) -> Self {
144 Self(self.0.clone())
145 }
146}
147
148impl<Ops: BytesFileOps> FileOps for BytesFile<Ops> {
149 fileops_impl_seekable!();
150 fileops_impl_noop_sync!();
151
152 fn open(
153 &self,
154 locked: &mut Locked<FileOpsCore>,
155 file: &FileObject,
156 current_task: &CurrentTask,
157 ) -> Result<(), Errno> {
158 self.0.open(locked, file, current_task)
159 }
160
161 fn read(
162 &self,
163 locked: &mut Locked<FileOpsCore>,
164 _file: &FileObject,
165 current_task: &CurrentTask,
166 offset: usize,
167 data: &mut dyn OutputBuffer,
168 ) -> Result<usize, Errno> {
169 let content = self.0.read_locked(locked, current_task)?;
170 if offset >= content.len() {
171 return Ok(0);
172 }
173 data.write(&content[offset..])
174 }
175
176 fn write(
177 &self,
178 locked: &mut Locked<FileOpsCore>,
179 _file: &FileObject,
180 current_task: &CurrentTask,
181 _offset: usize,
182 data: &mut dyn InputBuffer,
183 ) -> Result<usize, Errno> {
184 let data = data.read_all()?;
185 let len = data.len();
186 self.0.write_locked(locked, current_task, data)?;
187 Ok(len)
188 }
189}
190
191pub trait BytesFileOps: Send + Sync + AsAny + 'static {
192 fn write(&self, _current_task: &CurrentTask, _data: Vec<u8>) -> Result<(), Errno> {
193 error!(ENOSYS)
194 }
195 fn write_locked(
196 &self,
197 _locked: &mut Locked<FileOpsCore>,
198 current_task: &CurrentTask,
199 data: Vec<u8>,
200 ) -> Result<(), Errno> {
201 self.write(current_task, data)
202 }
203 fn read(&self, _current_task: &CurrentTask) -> Result<Cow<'_, [u8]>, Errno> {
204 error!(ENOSYS)
205 }
206 fn read_locked(
207 &self,
208 _locked: &mut Locked<FileOpsCore>,
209 current_task: &CurrentTask,
210 ) -> Result<Cow<'_, [u8]>, Errno> {
211 self.read(current_task)
212 }
213 fn open(
214 &self,
215 _locked: &mut Locked<FileOpsCore>,
216 _file: &FileObject,
217 _current_task: &CurrentTask,
218 ) -> Result<(), Errno> {
219 Ok(())
220 }
221}
222
223impl BytesFileOps for Vec<u8> {
224 fn read(&self, _current_task: &CurrentTask) -> Result<Cow<'_, [u8]>, Errno> {
225 Ok(self.into())
226 }
227}
228
229impl<T> BytesFileOps for T
230where
231 T: Fn() -> Result<String, Errno> + Send + Sync + 'static,
232{
233 fn read(&self, _current_task: &CurrentTask) -> Result<Cow<'_, [u8]>, Errno> {
234 let data = self()?;
235 Ok(data.into_bytes().into())
236 }
237}
238
239pub fn create_bytes_file_with_handler<F>(kernel: Weak<Kernel>, kernel_handler: F) -> impl FsNodeOps
240where
241 F: Fn(Arc<Kernel>) -> String + Send + Sync + 'static,
242{
243 BytesFile::new_node(move || {
244 if let Some(kernel) = kernel.upgrade() {
245 Ok(kernel_handler(kernel) + "\n")
246 } else {
247 error!(ENOENT)
248 }
249 })
250}