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