1use crate::task::CurrentTask;
6use crate::vfs::buffers::{InputBuffer, OutputBuffer};
7use crate::vfs::pseudo::simple_file::SimpleFileNode;
8use crate::vfs::{
9 Buffer, FileObject, FileOps, FsNodeOps, OutputBufferCallback, PeekBufferSegmentsCallback,
10 SeekTarget, default_seek, fileops_impl_noop_sync,
11};
12use starnix_sync::{DynamicFileStateLock, LockDepMutex};
13use starnix_uapi::errors::Errno;
14use starnix_uapi::{errno, error, off_t};
15use std::collections::VecDeque;
16
17unsafe extern "C" {
18 fn undefined_symbol_to_prevent_compilation();
22}
23
24pub trait SequenceFileSource: Send + Sync + 'static {
25 type Cursor: Default + Send;
26 fn next(
27 &self,
28 _current_task: &CurrentTask,
29 _cursor: Self::Cursor,
30 _sink: &mut DynamicFileBuf,
31 ) -> Result<Option<Self::Cursor>, Errno> {
32 unsafe {
34 undefined_symbol_to_prevent_compilation();
35 }
36 panic!("Either next or next_locked must be implemented");
37 }
38 fn next_locked(
39 &self,
40 current_task: &CurrentTask,
41 cursor: Self::Cursor,
42 sink: &mut DynamicFileBuf,
43 ) -> Result<Option<Self::Cursor>, Errno> {
44 self.next(current_task, cursor, sink)
45 }
46 fn write(
47 &self,
48 _current_task: &CurrentTask,
49 _offset: usize,
50 _data: &mut dyn InputBuffer,
51 ) -> Result<usize, Errno> {
52 error!(ENOSYS)
53 }
54}
55
56pub trait DynamicFileSource: Send + Sync + 'static {
57 fn generate(
58 &self,
59 _current_task: &CurrentTask,
60 _sink: &mut DynamicFileBuf,
61 ) -> Result<(), Errno> {
62 unsafe {
64 undefined_symbol_to_prevent_compilation();
65 }
66 panic!("Either generate or generate_locked must be implemented");
67 }
68 fn generate_locked(
69 &self,
70 current_task: &CurrentTask,
71 sink: &mut DynamicFileBuf,
72 ) -> Result<(), Errno> {
73 self.generate(current_task, sink)
74 }
75 fn write(
76 &self,
77 _current_task: &CurrentTask,
78 _offset: usize,
79 _data: &mut dyn InputBuffer,
80 ) -> Result<usize, Errno> {
81 error!(ENOSYS)
82 }
83}
84
85impl<T> SequenceFileSource for T
86where
87 T: DynamicFileSource,
88{
89 type Cursor = ();
90 fn next_locked(
91 &self,
92 current_task: &CurrentTask,
93 _cursor: (),
94 sink: &mut DynamicFileBuf,
95 ) -> Result<Option<()>, Errno> {
96 self.generate_locked(current_task, sink).map(|_| None)
97 }
98 fn write(
99 &self,
100 current_task: &CurrentTask,
101 offset: usize,
102 data: &mut dyn InputBuffer,
103 ) -> Result<usize, Errno> {
104 DynamicFileSource::write(self, current_task, offset, data)
105 }
106}
107
108pub struct DynamicFile<Source: SequenceFileSource> {
181 state: LockDepMutex<DynamicFileState<Source>, DynamicFileStateLock>,
182}
183
184impl<Source: SequenceFileSource> DynamicFile<Source> {
185 pub fn new(source: Source) -> Self {
186 DynamicFile { state: DynamicFileState::new(source).into() }
187 }
188}
189
190impl<Source: SequenceFileSource + Clone> DynamicFile<Source> {
191 pub fn new_node(source: Source) -> impl FsNodeOps {
192 SimpleFileNode::new(move |_| Ok(DynamicFile::new(source.clone())))
193 }
194}
195
196impl<Source: SequenceFileSource> DynamicFile<Source> {
197 fn read_internal(
198 &self,
199 current_task: &CurrentTask,
200 offset: usize,
201 data: &mut dyn OutputBuffer,
202 ) -> Result<usize, Errno> {
203 self.state.lock().read(current_task, offset, data)
204 }
205 fn write_internal(
206 &self,
207 current_task: &CurrentTask,
208 offset: usize,
209 data: &mut dyn InputBuffer,
210 ) -> Result<usize, Errno> {
211 self.state.lock().write(current_task, offset, data)
212 }
213}
214
215impl<Source: SequenceFileSource> FileOps for DynamicFile<Source> {
216 fileops_impl_noop_sync!();
217
218 fn is_seekable(&self) -> bool {
219 true
220 }
221
222 fn read(
223 &self,
224 _file: &FileObject,
225 current_task: &CurrentTask,
226 offset: usize,
227 data: &mut dyn OutputBuffer,
228 ) -> Result<usize, Errno> {
229 self.read_internal(current_task, offset, data)
230 }
231
232 fn write(
233 &self,
234 _file: &FileObject,
235 current_task: &CurrentTask,
236 offset: usize,
237 data: &mut dyn InputBuffer,
238 ) -> Result<usize, Errno> {
239 self.write_internal(current_task, offset, data)
240 }
241
242 fn seek(
243 &self,
244 _file: &FileObject,
245 _current_task: &CurrentTask,
246 current_offset: off_t,
247 target: SeekTarget,
248 ) -> Result<off_t, Errno> {
249 default_seek(current_offset, target, || error!(EINVAL))
250 }
251}
252
253struct DynamicFileState<Source: SequenceFileSource> {
255 source: Source,
257
258 cursor: Option<Source::Cursor>,
261
262 buf: DynamicFileBuf,
265
266 byte_offset: usize,
273}
274
275impl<Source: SequenceFileSource> DynamicFileState<Source> {
276 fn new(source: Source) -> Self {
277 Self {
278 source,
279 cursor: Some(Source::Cursor::default()),
280 buf: DynamicFileBuf::default(),
281 byte_offset: 0,
282 }
283 }
284}
285
286impl<Source: SequenceFileSource> DynamicFileState<Source> {
287 fn reset(&mut self) {
288 self.cursor = Some(Source::Cursor::default());
289 self.buf = DynamicFileBuf::default();
290 self.byte_offset = 0;
291 }
292
293 fn read(
294 &mut self,
295 current_task: &CurrentTask,
296 offset: usize,
297 data: &mut dyn OutputBuffer,
298 ) -> Result<usize, Errno> {
299 if offset != self.byte_offset {
300 self.reset();
301 }
302 let read_size = data.available();
303
304 while self.byte_offset + self.buf.0.len() < offset + read_size {
306 let cursor = if let Some(cursor) = std::mem::take(&mut self.cursor) {
307 cursor
308 } else {
309 break;
310 };
311 let mut buf = std::mem::take(&mut self.buf);
312 self.cursor = self.source.next_locked(current_task, cursor, &mut buf).map_err(|e| {
313 self.reset();
315 e
316 })?;
317 self.buf = buf;
318
319 let to_drain = std::cmp::min(offset - self.byte_offset, self.buf.0.len());
322 self.buf.0.drain(..to_drain);
323 self.byte_offset += to_drain;
324 }
325
326 let (slice1, slice2) = self.buf.0.as_slices();
329 let mut written = data.write(slice1)?;
330 if written == slice1.len() && !slice2.is_empty() {
331 written += data.write(slice2)?;
332 }
333
334 self.buf.0.drain(..written);
336 self.byte_offset += written;
337 Ok(written)
338 }
339
340 fn write(
341 &mut self,
342 current_task: &CurrentTask,
343 offset: usize,
344 data: &mut dyn InputBuffer,
345 ) -> Result<usize, Errno> {
346 self.source.write(current_task, offset, data)
347 }
348}
349
350#[derive(Debug, Default)]
351pub struct DynamicFileBuf(VecDeque<u8>);
352impl DynamicFileBuf {
353 pub fn write(&mut self, data: &[u8]) {
354 self.0.extend(data);
355 }
356 pub fn write_iter<I>(&mut self, data: I)
357 where
358 I: IntoIterator<Item = u8>,
359 {
360 self.0.extend(data);
361 }
362 pub fn write_fmt(&mut self, args: std::fmt::Arguments<'_>) -> Result<usize, Errno> {
363 let start_size = self.0.len();
364 std::io::Write::write_fmt(&mut self.0, args).map_err(|_| errno!(EINVAL))?;
365 let end_size = self.0.len();
366 Ok(end_size - start_size)
367 }
368}
369
370#[cfg(test)]
371impl From<DynamicFileBuf> for Vec<u8> {
372 fn from(buf: DynamicFileBuf) -> Self {
373 buf.0.into()
374 }
375}
376
377impl Buffer for DynamicFileBuf {
378 fn segments_count(&self) -> Result<usize, Errno> {
379 std::unimplemented!();
380 }
381
382 fn peek_each_segment(
383 &mut self,
384 _callback: &mut PeekBufferSegmentsCallback<'_>,
385 ) -> Result<(), Errno> {
386 std::unimplemented!();
387 }
388}
389
390impl OutputBuffer for DynamicFileBuf {
391 fn available(&self) -> usize {
392 std::unimplemented!();
393 }
394
395 fn bytes_written(&self) -> usize {
396 std::unimplemented!();
397 }
398
399 fn zero(&mut self) -> Result<usize, Errno> {
400 std::unimplemented!();
401 }
402
403 fn write_each(&mut self, _callback: &mut OutputBufferCallback<'_>) -> Result<usize, Errno> {
404 std::unimplemented!();
405 }
406
407 fn write_all(&mut self, buffer: &[u8]) -> Result<usize, Errno> {
408 self.write(buffer);
409 Ok(buffer.len())
410 }
411
412 unsafe fn advance(&mut self, _length: usize) -> Result<(), Errno> {
413 std::unimplemented!();
414 }
415}
416
417pub struct ConstFile {
419 data: Vec<u8>,
420}
421
422impl DynamicFileSource for ConstFile {
423 fn generate(
424 &self,
425 _current_task: &CurrentTask,
426 sink: &mut DynamicFileBuf,
427 ) -> Result<(), Errno> {
428 sink.write(&self.data);
429 Ok(())
430 }
431
432 fn write(
433 &self,
434 _current_task: &CurrentTask,
435 _offset: usize,
436 data: &mut dyn InputBuffer,
437 ) -> Result<usize, Errno> {
438 Ok(data.drain())
439 }
440}
441
442impl ConstFile {
443 pub fn new_node(data: Vec<u8>) -> impl FsNodeOps {
445 SimpleFileNode::new(move |_| Ok(DynamicFile::new(ConstFile { data: data.clone() })))
446 }
447}
448
449#[cfg(test)]
450mod tests {
451 use crate::task::CurrentTask;
452 use crate::testing::{anon_test_file, spawn_kernel_and_run};
453 use crate::vfs::pseudo::dynamic_file::{
454 DynamicFile, DynamicFileBuf, DynamicFileSource, SequenceFileSource,
455 };
456 use crate::vfs::{SeekTarget, VecOutputBuffer};
457 use starnix_sync::Mutex;
458 use starnix_uapi::errors::Errno;
459 use starnix_uapi::open_flags::OpenFlags;
460 use std::sync::Arc;
461
462 struct Counter {
463 value: Mutex<u8>,
464 }
465
466 struct TestSequenceFileSource;
467
468 impl SequenceFileSource for TestSequenceFileSource {
469 type Cursor = u8;
470 fn next(
471 &self,
472 _current_task: &CurrentTask,
473 i: u8,
474 sink: &mut DynamicFileBuf,
475 ) -> Result<Option<u8>, Errno> {
476 sink.write(&[i]);
477 Ok(if i == u8::MAX { None } else { Some(i + 1) })
478 }
479 }
480
481 #[fuchsia::test]
482 async fn test_sequence() {
483 spawn_kernel_and_run(async |current_task| {
484 let file = anon_test_file(
485 ¤t_task,
486 Box::new(DynamicFile::new(TestSequenceFileSource {})),
487 OpenFlags::RDONLY,
488 );
489
490 let read_at = |offset: usize, length: usize| -> Result<Vec<u8>, Errno> {
491 let mut buffer = VecOutputBuffer::new(length);
492 file.read_at(¤t_task, offset, &mut buffer)?;
493 Ok(buffer.data().to_vec())
494 };
495
496 assert_eq!(read_at(0, 2).unwrap(), &[0, 1]);
497 assert_eq!(read_at(2, 2).unwrap(), &[2, 3]);
498 assert_eq!(read_at(4, 4).unwrap(), &[4, 5, 6, 7]);
499 assert_eq!(read_at(0, 2).unwrap(), &[0, 1]);
500 assert_eq!(read_at(4, 2).unwrap(), &[4, 5]);
501 })
502 .await;
503 }
504
505 struct TestFileSource {
506 counter: Arc<Counter>,
507 }
508
509 impl DynamicFileSource for TestFileSource {
510 fn generate(
511 &self,
512 _current_task: &CurrentTask,
513 sink: &mut DynamicFileBuf,
514 ) -> Result<(), Errno> {
515 let mut counter = self.counter.value.lock();
516 let base = *counter;
517 let data = (0..10).map(|i| base + i).collect::<Vec<u8>>();
519 sink.write(&data);
520 *counter += 1;
521 Ok(())
522 }
523 }
524
525 #[fuchsia::test]
526 async fn test_read() {
527 let counter = Arc::new(Counter { value: Mutex::new(0) });
528 spawn_kernel_and_run(async move |current_task| {
529 let file = anon_test_file(
530 ¤t_task,
531 Box::new(DynamicFile::new(TestFileSource { counter: counter.clone() })),
532 OpenFlags::RDONLY,
533 );
534 let read_at = |offset: usize, length: usize| -> Result<Vec<u8>, Errno> {
535 let mut buffer = VecOutputBuffer::new(length);
536 let bytes_read = file.read_at(¤t_task, offset, &mut buffer)?;
537 Ok(buffer.data()[0..bytes_read].to_vec())
538 };
539
540 assert_eq!(read_at(0, 20).unwrap(), (0..10).collect::<Vec<u8>>());
542
543 assert_eq!(read_at(0, 2).unwrap(), [1, 2]);
545
546 assert_eq!(read_at(2, 2).unwrap(), [3, 4]);
548
549 assert_eq!(read_at(5, 2).unwrap(), [7, 8]);
551 })
552 .await;
553 }
554
555 #[fuchsia::test]
556 async fn test_read_and_seek() {
557 let counter = Arc::new(Counter { value: Mutex::new(0) });
558 spawn_kernel_and_run(async move |current_task| {
559 let file = anon_test_file(
560 ¤t_task,
561 Box::new(DynamicFile::new(TestFileSource { counter: counter.clone() })),
562 OpenFlags::RDONLY,
563 );
564 let read = |length: usize| -> Result<Vec<u8>, Errno> {
565 let mut buffer = VecOutputBuffer::new(length);
566 let bytes_read = file.read(¤t_task, &mut buffer)?;
567 Ok(buffer.data()[0..bytes_read].to_vec())
568 };
569
570 assert_eq!(read(1).unwrap(), [0]);
572 assert_eq!(read(2).unwrap(), [1, 2]);
573 assert_eq!(read(20).unwrap(), (3..10).collect::<Vec<u8>>());
574
575 file.seek(¤t_task, SeekTarget::Set(0)).unwrap();
577 assert_eq!(*counter.value.lock(), 1);
578 assert_eq!(read(2).unwrap(), [1, 2]);
579 assert_eq!(*counter.value.lock(), 2);
580
581 file.seek(¤t_task, SeekTarget::Set(1)).unwrap();
583 assert_eq!(*counter.value.lock(), 2);
584
585 assert_eq!(read(1).unwrap(), [3]);
587 assert_eq!(*counter.value.lock(), 3);
588 })
589 .await;
590 }
591}