starnix_core/vfs/pseudo/
simple_file.rs1use crate::task::{CurrentTask, Kernel};
6use crate::vfs::buffers::{InputBuffer, OutputBuffer};
7use crate::vfs::{
8 AppendLockWriteGuard, FileObject, FileOps, FsNode, FsNodeOps, fileops_impl_seekable,
9 fs_node_impl_not_dir,
10};
11
12use crate::vfs::fileops_impl_noop_sync;
13
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(&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(&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(&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 _node: &FsNode,
50 current_task: &CurrentTask,
51 _flags: OpenFlags,
52 ) -> Result<Box<dyn FileOps>, Errno> {
53 Ok(Box::new((self.create_file_ops)(current_task)?))
54 }
55
56 fn truncate(
57 &self,
58 _guard: &AppendLockWriteGuard<'_>,
59 _node: &FsNode,
60 _current_task: &CurrentTask,
61 _length: u64,
62 ) -> Result<(), Errno> {
63 Ok(())
65 }
66}
67
68pub fn parse_unsigned_file<T: Into<u64> + std::str::FromStr>(buf: &[u8]) -> Result<T, Errno> {
69 let i = buf.iter().position(|c| !char::from(*c).is_ascii_digit()).unwrap_or(buf.len());
70 std::str::from_utf8(&buf[..i]).unwrap().parse::<T>().map_err(|_| errno!(EINVAL))
71}
72
73pub fn parse_i32_file(buf: &[u8]) -> Result<i32, Errno> {
74 let i = buf
75 .iter()
76 .position(|c| {
77 let ch = char::from(*c);
78 !(ch.is_ascii_digit() || ch == '-')
79 })
80 .unwrap_or(buf.len());
81 std::str::from_utf8(&buf[..i]).unwrap().parse::<i32>().map_err(|_| errno!(EINVAL))
82}
83
84pub fn serialize_for_file<T: Display>(value: T) -> Vec<u8> {
85 let string = format!("{}\n", value);
86 string.into_bytes()
87}
88
89pub struct BytesFile<Ops>(Arc<Ops>);
90
91impl<Ops: BytesFileOps> BytesFile<Ops> {
92 pub fn new(data: Ops) -> Self {
93 Self(Arc::new(data))
94 }
95
96 pub fn new_node(data: Ops) -> impl FsNodeOps {
97 let data = Arc::new(data);
98 SimpleFileNode::new(move |_| Ok(BytesFile(Arc::clone(&data))))
99 }
100}
101
102impl<Ops> std::clone::Clone for BytesFile<Ops> {
104 fn clone(&self) -> Self {
105 Self(self.0.clone())
106 }
107}
108
109impl<Ops: BytesFileOps> FileOps for BytesFile<Ops> {
110 fileops_impl_seekable!();
111 fileops_impl_noop_sync!();
112
113 fn open(&self, file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
114 self.0.open(file, current_task)
115 }
116
117 fn read(
118 &self,
119 _file: &FileObject,
120 current_task: &CurrentTask,
121 offset: usize,
122 data: &mut dyn OutputBuffer,
123 ) -> Result<usize, Errno> {
124 let content = self.0.read(current_task)?;
125 if offset >= content.len() {
126 return Ok(0);
127 }
128 data.write(&content[offset..])
129 }
130
131 fn write(
132 &self,
133 _file: &FileObject,
134 current_task: &CurrentTask,
135 _offset: usize,
136 data: &mut dyn InputBuffer,
137 ) -> Result<usize, Errno> {
138 let data = data.read_all()?;
139 let len = data.len();
140 self.0.write(current_task, data)?;
141 Ok(len)
142 }
143}
144
145pub trait BytesFileOps: Send + Sync + AsAny + 'static {
146 fn write(&self, _current_task: &CurrentTask, _data: Vec<u8>) -> Result<(), Errno> {
147 error!(ENOSYS)
148 }
149 fn read(&self, _current_task: &CurrentTask) -> Result<Cow<'_, [u8]>, Errno> {
150 error!(ENOSYS)
151 }
152 fn open(&self, _file: &FileObject, _current_task: &CurrentTask) -> Result<(), Errno> {
153 Ok(())
154 }
155}
156
157impl BytesFileOps for Vec<u8> {
158 fn read(&self, _current_task: &CurrentTask) -> Result<Cow<'_, [u8]>, Errno> {
159 Ok(self.into())
160 }
161}
162
163impl<T> BytesFileOps for T
164where
165 T: Fn() -> Result<String, Errno> + Send + Sync + 'static,
166{
167 fn read(&self, _current_task: &CurrentTask) -> Result<Cow<'_, [u8]>, Errno> {
168 let data = self()?;
169 Ok(data.into_bytes().into())
170 }
171}
172
173pub fn create_bytes_file_with_handler<F>(kernel: Weak<Kernel>, kernel_handler: F) -> impl FsNodeOps
174where
175 F: Fn(Arc<Kernel>) -> String + Send + Sync + 'static,
176{
177 BytesFile::new_node(move || {
178 if let Some(kernel) = kernel.upgrade() {
179 Ok(kernel_handler(kernel) + "\n")
180 } else {
181 error!(ENOENT)
182 }
183 })
184}