1use crate::{
7 ipc::{message::IpcMessage, port::PortId},
8 memory::{UserSliceRead, UserSliceWrite},
9 sync::SpinLock,
10 syscall::error::SyscallError,
11};
12use alloc::{
13 collections::BTreeMap,
14 string::{String, ToString},
15 sync::Arc,
16 vec::Vec,
17};
18
19pub use strat9_abi::data::{
20 FileStat, DT_BLK, DT_CHR, DT_DIR, DT_FIFO, DT_LNK, DT_REG, DT_SOCK, DT_UNKNOWN,
21 IPC_FILE_FLAG_APPEND, IPC_FILE_FLAG_CHUNK_READ, IPC_FILE_FLAG_CHUNK_WRITE,
22 IPC_FILE_FLAG_DEVICE, IPC_FILE_FLAG_DIRECTORY, IPC_FILE_FLAG_PIPE,
23};
24
25#[derive(Debug, Clone)]
27pub struct DirEntry {
28 pub ino: u64,
29 pub file_type: u8,
30 pub name: String,
31}
32
33#[derive(Debug, Clone)]
35pub struct OpenResult {
36 pub file_id: u64,
38 pub size: Option<u64>,
40 pub flags: FileFlags,
42}
43
44bitflags::bitflags! {
45 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
47 pub struct FileFlags: u32 {
48 const DIRECTORY = IPC_FILE_FLAG_DIRECTORY;
49 const DEVICE = IPC_FILE_FLAG_DEVICE;
50 const PIPE = IPC_FILE_FLAG_PIPE;
51 const APPEND = IPC_FILE_FLAG_APPEND;
52 const CHUNK_READ = IPC_FILE_FLAG_CHUNK_READ;
53 const CHUNK_WRITE = IPC_FILE_FLAG_CHUNK_WRITE;
54 }
55}
56
57pub use strat9_abi::flag::OpenFlags;
58
59pub trait Scheme: Send + Sync {
61 fn open(&self, path: &str, flags: OpenFlags) -> Result<OpenResult, SyscallError>;
66
67 fn read(&self, file_id: u64, offset: u64, buf: &mut [u8]) -> Result<usize, SyscallError>;
69
70 fn write(&self, file_id: u64, offset: u64, buf: &[u8]) -> Result<usize, SyscallError>;
72
73 fn async_read(
79 &self,
80 file_id: u64,
81 offset: u64,
82 user_buf_vaddr: u64,
83 len: usize,
84 _ring_id: u64,
85 _user_data: u64,
86 ) -> Result<AsyncSubmitResult, SyscallError> {
87 const MAX_SYNC_FALLBACK_LEN: usize = 4 * 1024 * 1024; if len > MAX_SYNC_FALLBACK_LEN {
91 return Err(SyscallError::InvalidArgument);
92 }
93 let user_buf = UserSliceWrite::new(user_buf_vaddr, len)?;
94 let mut kernel_buf = alloc::vec![0u8; len];
95 let n = self.read(file_id, offset, &mut kernel_buf)?;
96 user_buf.copy_from(&kernel_buf[..n]);
97 Ok(AsyncSubmitResult::Completed(n as i32))
98 }
99
100 fn async_write(
105 &self,
106 file_id: u64,
107 offset: u64,
108 user_buf_vaddr: u64,
109 len: usize,
110 _ring_id: u64,
111 _user_data: u64,
112 ) -> Result<AsyncSubmitResult, SyscallError> {
113 const MAX_SYNC_FALLBACK_LEN: usize = 4 * 1024 * 1024; if len > MAX_SYNC_FALLBACK_LEN {
116 return Err(SyscallError::InvalidArgument);
117 }
118 let user_buf = UserSliceRead::new(user_buf_vaddr, len)?;
119 let kernel_buf = user_buf.read_to_vec();
120 let n = self.write(file_id, offset, &kernel_buf)?;
121 Ok(AsyncSubmitResult::Completed(n as i32))
122 }
123
124 fn close(&self, file_id: u64) -> Result<(), SyscallError>;
126
127 fn size(&self, file_id: u64) -> Result<u64, SyscallError> {
129 let _ = file_id;
130 Err(SyscallError::NotImplemented)
131 }
132
133 fn truncate(&self, file_id: u64, new_size: u64) -> Result<(), SyscallError> {
135 let _ = (file_id, new_size);
136 Err(SyscallError::NotImplemented)
137 }
138
139 fn truncate_by_path(&self, _path: &str, _new_size: u64) -> Result<(), SyscallError> {
144 Err(SyscallError::NotImplemented)
145 }
146
147 fn sync(&self, file_id: u64) -> Result<(), SyscallError> {
149 let _ = file_id;
150 Ok(()) }
152
153 fn create_file(&self, path: &str, mode: u32) -> Result<OpenResult, SyscallError> {
155 let _ = (path, mode);
156 Err(SyscallError::NotImplemented)
157 }
158
159 fn create_directory(&self, path: &str, mode: u32) -> Result<OpenResult, SyscallError> {
161 let _ = (path, mode);
162 Err(SyscallError::NotImplemented)
163 }
164
165 fn unlink(&self, path: &str) -> Result<(), SyscallError> {
167 let _ = path;
168 Err(SyscallError::NotImplemented)
169 }
170
171 fn stat(&self, file_id: u64) -> Result<FileStat, SyscallError> {
173 let _ = file_id;
174 Err(SyscallError::NotImplemented)
175 }
176
177 fn readdir(&self, file_id: u64) -> Result<Vec<DirEntry>, SyscallError> {
179 let _ = file_id;
180 Err(SyscallError::NotImplemented)
181 }
182
183 fn rename(&self, old_path: &str, new_path: &str) -> Result<(), SyscallError> {
185 let _ = (old_path, new_path);
186 Err(SyscallError::NotImplemented)
187 }
188
189 fn chmod(&self, path: &str, mode: u32) -> Result<(), SyscallError> {
191 let _ = (path, mode);
192 Err(SyscallError::NotImplemented)
193 }
194
195 fn fchmod(&self, file_id: u64, mode: u32) -> Result<(), SyscallError> {
197 let _ = (file_id, mode);
198 Err(SyscallError::NotImplemented)
199 }
200
201 fn link(&self, old_path: &str, new_path: &str) -> Result<(), SyscallError> {
203 let _ = (old_path, new_path);
204 Err(SyscallError::NotImplemented)
205 }
206
207 fn symlink(&self, target: &str, link_path: &str) -> Result<(), SyscallError> {
209 let _ = (target, link_path);
210 Err(SyscallError::NotImplemented)
211 }
212
213 fn readlink(&self, path: &str) -> Result<String, SyscallError> {
215 let _ = path;
216 Err(SyscallError::NotImplemented)
217 }
218}
219
220pub type DynScheme = Arc<dyn Scheme>;
222
223#[derive(Debug, Clone, Copy, PartialEq, Eq)]
224pub enum AsyncSubmitResult {
225 Completed(i32),
226 InFlight,
227}
228
229pub const DEV_RAMFS: u64 = 1;
230pub const DEV_SYSFS: u64 = 2;
231pub const DEV_PROCFS: u64 = 3;
232pub const DEV_DEVFS: u64 = 4;
233pub const DEV_CONSOLE: u64 = 5;
234pub const DEV_PIPEFS: u64 = 6;
235pub const DEV_IPCFS: u64 = 7;
236pub const DEV_NETFS: u64 = 8;
237pub const DEV_CHAR_FS: u64 = 9;
238pub const DEV_INPUT: u64 = 10;
239
240pub fn finalize_pseudo_stat(mut st: FileStat, st_dev: u64, st_rdev: u64) -> FileStat {
243 let now = strat9_abi::data::TimeSpec::from_nanos(crate::syscall::time::current_time_ns());
244 st.st_dev = st_dev;
245 st.st_rdev = st_rdev;
246 st.st_atime = now;
247 st.st_mtime = now;
248 st.st_ctime = now;
249 st
250}
251
252pub struct IpcScheme {
258 port_id: PortId,
259 open_file_flags: SpinLock<BTreeMap<u64, FileFlags>>,
260}
261
262impl IpcScheme {
263 pub fn new(port_id: PortId) -> Self {
265 IpcScheme {
266 port_id,
267 open_file_flags: SpinLock::new(BTreeMap::new()),
268 }
269 }
270
271 fn remember_open_flags(&self, file_id: u64, flags: FileFlags) {
272 self.open_file_flags.lock().insert(file_id, flags);
273 }
274
275 fn take_open_flags(&self, file_id: u64) {
276 self.open_file_flags.lock().remove(&file_id);
277 }
278
279 fn open_flags_for(&self, file_id: u64) -> FileFlags {
280 self.open_file_flags
281 .lock()
282 .get(&file_id)
283 .copied()
284 .unwrap_or_else(FileFlags::empty)
285 }
286
287 fn build_open_msg(path: &str, flags: OpenFlags) -> Result<IpcMessage, SyscallError> {
289 const OPCODE_OPEN: u32 = 0x01;
290 let mut msg = IpcMessage::new(OPCODE_OPEN);
291
292 if path.len() > IpcMessage::OPEN_INLINE_CAPACITY {
294 return Err(SyscallError::InvalidArgument); }
296
297 msg.payload[0..4].copy_from_slice(&flags.bits().to_le_bytes());
298 msg.payload[4..6].copy_from_slice(&(path.len() as u16).to_le_bytes());
299 msg.payload[6..6 + path.len()].copy_from_slice(path.as_bytes());
300 Ok(msg)
301 }
302
303 fn build_read_msg(file_id: u64, offset: u64, count: u32) -> IpcMessage {
305 const OPCODE_READ: u32 = 0x02;
306 let mut msg = IpcMessage::new(OPCODE_READ);
307 msg.payload[0..8].copy_from_slice(&file_id.to_le_bytes());
308 msg.payload[8..16].copy_from_slice(&offset.to_le_bytes());
309 msg.payload[16..20].copy_from_slice(&count.to_le_bytes());
310 msg
311 }
312
313 fn build_write_msg(file_id: u64, offset: u64, data: &[u8]) -> (IpcMessage, usize) {
317 const OPCODE_WRITE: u32 = 0x03;
318 let mut msg = IpcMessage::new(OPCODE_WRITE);
319 msg.payload[0..8].copy_from_slice(&file_id.to_le_bytes());
320 msg.payload[8..16].copy_from_slice(&offset.to_le_bytes());
321
322 let packed = core::cmp::min(data.len(), IpcMessage::WRITE_INLINE_CAPACITY);
323 msg.payload[16..18].copy_from_slice(&(packed as u16).to_le_bytes());
324 msg.payload[18..18 + packed].copy_from_slice(&data[..packed]);
325 (msg, packed)
326 }
327
328 fn build_close_msg(file_id: u64) -> IpcMessage {
330 const OPCODE_CLOSE: u32 = 0x04;
331 let mut msg = IpcMessage::new(OPCODE_CLOSE);
332 msg.payload[0..8].copy_from_slice(&file_id.to_le_bytes());
333 msg
334 }
335
336 fn build_readdir_msg(file_id: u64, cursor: u16) -> IpcMessage {
338 const OPCODE_READDIR: u32 = 0x08;
339 let mut msg = IpcMessage::new(OPCODE_READDIR);
340 msg.payload[0..8].copy_from_slice(&file_id.to_le_bytes());
341 msg.payload[8..10].copy_from_slice(&cursor.to_le_bytes());
342 msg
343 }
344
345 fn parse_status(reply: &IpcMessage) -> Result<(), SyscallError> {
347 if reply.msg_type != 0x80 {
348 return Err(SyscallError::IoError);
349 }
350
351 let status = u32::from_le_bytes([
352 reply.payload[0],
353 reply.payload[1],
354 reply.payload[2],
355 reply.payload[3],
356 ]);
357 if status == 0 {
358 return Ok(());
359 }
360
361 let signed = status as i32;
365 let code = if signed < 0 {
366 signed as i64
367 } else {
368 -(signed as i64)
369 };
370 Err(SyscallError::from_code(code))
371 }
372}
373
374impl IpcScheme {
375 fn call(&self, mut msg: IpcMessage) -> Result<IpcMessage, SyscallError> {
380 let task_id = crate::process::current_task_id().ok_or(SyscallError::PermissionDenied)?;
381
382 msg.sender = task_id.as_u64();
384
385 let port = crate::ipc::port::get_port(self.port_id).ok_or(SyscallError::BadHandle)?;
386 let port_owner = port.owner;
387 port.send(msg).map_err(|_| SyscallError::BadHandle)?;
388 drop(port);
391
392 Ok(crate::ipc::reply::wait_for_reply(task_id, port_owner))
393 }
394}
395
396impl Scheme for IpcScheme {
397 fn open(&self, path: &str, flags: OpenFlags) -> Result<OpenResult, SyscallError> {
399 let msg = Self::build_open_msg(path, flags)?;
400 let reply = self.call(msg)?;
401
402 Self::parse_status(&reply)?;
404
405 let file_id = u64::from_le_bytes([
406 reply.payload[4],
407 reply.payload[5],
408 reply.payload[6],
409 reply.payload[7],
410 reply.payload[8],
411 reply.payload[9],
412 reply.payload[10],
413 reply.payload[11],
414 ]);
415
416 let size = u64::from_le_bytes([
417 reply.payload[12],
418 reply.payload[13],
419 reply.payload[14],
420 reply.payload[15],
421 reply.payload[16],
422 reply.payload[17],
423 reply.payload[18],
424 reply.payload[19],
425 ]);
426
427 let file_flags = u32::from_le_bytes([
428 reply.payload[20],
429 reply.payload[21],
430 reply.payload[22],
431 reply.payload[23],
432 ]);
433 let flags = FileFlags::from_bits_truncate(file_flags);
434 self.remember_open_flags(file_id, flags);
435
436 Ok(OpenResult {
437 file_id,
438 size: if size == u64::MAX { None } else { Some(size) },
439 flags,
440 })
441 }
442
443 fn read(&self, file_id: u64, offset: u64, buf: &mut [u8]) -> Result<usize, SyscallError> {
445 let flags = self.open_flags_for(file_id);
446 let chunked = flags.contains(FileFlags::CHUNK_READ);
447 let chunk_size = if chunked {
448 IpcMessage::READ_INLINE_CAPACITY
449 } else {
450 buf.len()
451 };
452
453 let mut total = 0usize;
454 let mut current_offset = offset;
455 while total < buf.len() {
456 let request_len = core::cmp::min(buf.len() - total, chunk_size);
457 let msg = Self::build_read_msg(file_id, current_offset, request_len as u32);
458 let reply = self.call(msg)?;
459
460 Self::parse_status(&reply)?;
461
462 let bytes_read = u32::from_le_bytes([
463 reply.payload[4],
464 reply.payload[5],
465 reply.payload[6],
466 reply.payload[7],
467 ]) as usize;
468
469 let available = core::cmp::min(bytes_read, reply.payload.len() - 8);
470 let to_copy = core::cmp::min(available, request_len);
471 buf[total..total + to_copy].copy_from_slice(&reply.payload[8..8 + to_copy]);
472
473 total += to_copy;
474 current_offset += to_copy as u64;
475
476 if !chunked || to_copy < request_len {
477 break;
478 }
479 }
480
481 Ok(total)
482 }
483
484 fn write(&self, file_id: u64, offset: u64, buf: &[u8]) -> Result<usize, SyscallError> {
486 let flags = self.open_flags_for(file_id);
487 let chunked = flags.contains(FileFlags::CHUNK_WRITE);
488 if !chunked && buf.len() > IpcMessage::WRITE_INLINE_CAPACITY {
491 return Err(SyscallError::MessageSize);
492 }
493 let chunk_size = if chunked {
494 IpcMessage::WRITE_INLINE_CAPACITY
495 } else {
496 buf.len()
497 };
498
499 let mut total = 0usize;
500 let mut current_offset = offset;
501 while total < buf.len() {
502 let request_len = core::cmp::min(buf.len() - total, chunk_size);
503 let (msg, packed) =
504 Self::build_write_msg(file_id, current_offset, &buf[total..total + request_len]);
505 let reply = self.call(msg)?;
506
507 Self::parse_status(&reply)?;
508
509 let bytes_written = u32::from_le_bytes([
510 reply.payload[4],
511 reply.payload[5],
512 reply.payload[6],
513 reply.payload[7],
514 ]) as usize;
515
516 let chunk_written = bytes_written.min(packed);
517 total += chunk_written;
518 current_offset += chunk_written as u64;
519
520 if !chunked || chunk_written < packed {
521 break;
522 }
523 }
524
525 Ok(total)
526 }
527
528 fn close(&self, file_id: u64) -> Result<(), SyscallError> {
530 let msg = Self::build_close_msg(file_id);
531 let reply = self.call(msg);
532 self.take_open_flags(file_id);
533 let reply = reply?;
534
535 Self::parse_status(&reply)?;
536
537 Ok(())
538 }
539
540 fn create_file(&self, path: &str, mode: u32) -> Result<OpenResult, SyscallError> {
542 const OPCODE_CREATE_FILE: u32 = 0x05;
543 self.handle_create_op(OPCODE_CREATE_FILE, path, mode)
544 }
545
546 fn create_directory(&self, path: &str, mode: u32) -> Result<OpenResult, SyscallError> {
548 const OPCODE_CREATE_DIR: u32 = 0x06;
549 self.handle_create_op(OPCODE_CREATE_DIR, path, mode)
550 }
551
552 fn unlink(&self, path: &str) -> Result<(), SyscallError> {
554 const OPCODE_UNLINK: u32 = 0x07;
555 let mut msg = IpcMessage::new(OPCODE_UNLINK);
556
557 if path.len() > IpcMessage::UNLINK_INLINE_CAPACITY {
558 return Err(SyscallError::InvalidArgument);
559 }
560
561 msg.payload[0..2].copy_from_slice(&(path.len() as u16).to_le_bytes());
562 msg.payload[2..2 + path.len()].copy_from_slice(path.as_bytes());
563
564 let reply = self.call(msg)?;
565 Self::parse_status(&reply)?;
566
567 Ok(())
568 }
569
570 fn readdir(&self, file_id: u64) -> Result<Vec<DirEntry>, SyscallError> {
572 let mut cursor: u16 = 0;
573 let mut entries = Vec::new();
574
575 loop {
576 let msg = Self::build_readdir_msg(file_id, cursor);
577 let reply = self.call(msg)?;
578 Self::parse_status(&reply)?;
579
580 let next_cursor = u16::from_le_bytes([reply.payload[4], reply.payload[5]]);
581 let entry_count = reply.payload[6] as usize;
582 let used_bytes = reply.payload[7] as usize;
583 if used_bytes > reply.payload.len() - 8 {
584 return Err(SyscallError::IoError);
585 }
586
587 let mut offset = 8usize;
588 for _ in 0..entry_count {
589 if offset + 10 > 8 + used_bytes {
590 return Err(SyscallError::IoError);
591 }
592
593 let ino = u64::from_le_bytes([
594 reply.payload[offset],
595 reply.payload[offset + 1],
596 reply.payload[offset + 2],
597 reply.payload[offset + 3],
598 reply.payload[offset + 4],
599 reply.payload[offset + 5],
600 reply.payload[offset + 6],
601 reply.payload[offset + 7],
602 ]);
603 let file_type = reply.payload[offset + 8];
604 let name_len = reply.payload[offset + 9] as usize;
605 if offset + 10 + name_len > 8 + used_bytes {
606 return Err(SyscallError::IoError);
607 }
608 let name_bytes = &reply.payload[offset + 10..offset + 10 + name_len];
609 let name = core::str::from_utf8(name_bytes)
610 .map_err(|_| SyscallError::IoError)?
611 .to_string();
612
613 entries.push(DirEntry {
614 ino,
615 file_type,
616 name,
617 });
618 offset += 10 + name_len;
619 }
620
621 if next_cursor == u16::MAX {
622 break;
623 }
624 if next_cursor <= cursor {
625 return Err(SyscallError::IoError);
626 }
627 cursor = next_cursor;
628 }
629
630 Ok(entries)
631 }
632}
633
634impl IpcScheme {
635 fn handle_create_op(
637 &self,
638 opcode: u32,
639 path: &str,
640 mode: u32,
641 ) -> Result<OpenResult, SyscallError> {
642 let mut msg = IpcMessage::new(opcode);
643
644 if path.len() > IpcMessage::OPEN_INLINE_CAPACITY {
645 return Err(SyscallError::InvalidArgument);
646 }
647
648 msg.payload[0..4].copy_from_slice(&mode.to_le_bytes());
649 msg.payload[4..6].copy_from_slice(&(path.len() as u16).to_le_bytes());
650 msg.payload[6..6 + path.len()].copy_from_slice(path.as_bytes());
651
652 let reply = self.call(msg)?;
653
654 Self::parse_status(&reply)?;
655
656 let file_id = u64::from_le_bytes([
657 reply.payload[4],
658 reply.payload[5],
659 reply.payload[6],
660 reply.payload[7],
661 reply.payload[8],
662 reply.payload[9],
663 reply.payload[10],
664 reply.payload[11],
665 ]);
666
667 Ok(OpenResult {
668 file_id,
669 size: Some(0),
670 flags: FileFlags::empty(),
671 })
672 }
673}
674
675pub struct KernelScheme {
680 files: SpinLock<BTreeMap<String, (u64, *const u8, usize)>>,
682 by_id: SpinLock<BTreeMap<u64, String>>,
684}
685
686unsafe impl Send for KernelScheme {}
689unsafe impl Sync for KernelScheme {}
690
691impl KernelScheme {
692 pub fn new() -> Self {
694 KernelScheme {
695 files: SpinLock::new(BTreeMap::new()),
696 by_id: SpinLock::new(BTreeMap::new()),
697 }
698 }
699
700 pub fn register(&self, path: &str, base: *const u8, len: usize) {
702 static NEXT_ID: core::sync::atomic::AtomicU64 = core::sync::atomic::AtomicU64::new(1);
703 let id = NEXT_ID.fetch_add(1, core::sync::atomic::Ordering::SeqCst);
704 self.files
705 .lock()
706 .insert(String::from(path), (id, base, len));
707 self.by_id.lock().insert(id, String::from(path));
708 }
709
710 fn get_by_id(&self, file_id: u64) -> Option<(u64, *const u8, usize)> {
712 let name = self.by_id.lock().get(&file_id)?.clone();
713 let entry = self.files.lock().get(&name).cloned()?;
714 Some(entry)
715 }
716
717 pub fn lookup_bytes(&self, path: &str) -> Option<&'static [u8]> {
719 let (_, base, len) = self.files.lock().get(path).cloned()?;
720 Some(unsafe { core::slice::from_raw_parts(base, len) })
723 }
724}
725
726impl Scheme for KernelScheme {
727 fn open(&self, path: &str, _flags: OpenFlags) -> Result<OpenResult, SyscallError> {
729 if path.is_empty() || path == "/" {
730 return Ok(OpenResult {
731 file_id: 0, size: None,
733 flags: FileFlags::DIRECTORY,
734 });
735 }
736
737 let files = self.files.lock();
738 let (id, _, len) = files.get(path).ok_or(SyscallError::BadHandle)?;
739 Ok(OpenResult {
740 file_id: *id,
741 size: Some(*len as u64),
742 flags: FileFlags::empty(),
743 })
744 }
745
746 fn read(&self, file_id: u64, offset: u64, buf: &mut [u8]) -> Result<usize, SyscallError> {
748 if file_id == 0 {
749 let mut list = String::new();
751 let files = self.files.lock();
752 for name in files.keys() {
753 list.push_str(name);
754 list.push('\n');
755 }
756
757 if offset >= list.len() as u64 {
758 return Ok(0);
759 }
760
761 let start = offset as usize;
762 let end = core::cmp::min(start + buf.len(), list.len());
763 let to_copy = end - start;
764 buf[..to_copy].copy_from_slice(&list.as_bytes()[start..end]);
765 return Ok(to_copy);
766 }
767
768 let (_, base, len) = self.get_by_id(file_id).ok_or(SyscallError::BadHandle)?;
769
770 if offset >= len as u64 {
771 return Ok(0);
772 }
773
774 let remaining = len - offset as usize;
775 let to_copy = core::cmp::min(remaining, buf.len());
776
777 unsafe {
779 let src = base.add(offset as usize);
780 core::ptr::copy_nonoverlapping(src, buf.as_mut_ptr(), to_copy);
781 }
782
783 Ok(to_copy)
784 }
785
786 fn write(&self, _file_id: u64, _offset: u64, _buf: &[u8]) -> Result<usize, SyscallError> {
788 Err(SyscallError::PermissionDenied) }
790
791 fn close(&self, _file_id: u64) -> Result<(), SyscallError> {
793 Ok(()) }
795
796 fn size(&self, file_id: u64) -> Result<u64, SyscallError> {
798 let (_, _, len) = self.get_by_id(file_id).ok_or(SyscallError::BadHandle)?;
799 Ok(len as u64)
800 }
801
802 fn stat(&self, file_id: u64) -> Result<FileStat, SyscallError> {
804 if file_id == 0 {
805 return Ok(finalize_pseudo_stat(
806 FileStat {
807 st_ino: 0,
808 st_mode: 0o040555,
809 st_nlink: 2,
810 st_size: 0,
811 st_blksize: 512,
812 st_blocks: 0,
813 ..FileStat::zeroed()
814 },
815 DEV_SYSFS,
816 0,
817 ));
818 }
819 let (_, _, len) = self.get_by_id(file_id).ok_or(SyscallError::BadHandle)?;
820 Ok(finalize_pseudo_stat(
821 FileStat {
822 st_ino: file_id,
823 st_mode: 0o100444,
824 st_nlink: 1,
825 st_size: len as u64,
826 st_blksize: 512,
827 st_blocks: ((len as u64) + 511) / 512,
828 ..FileStat::zeroed()
829 },
830 DEV_SYSFS,
831 0,
832 ))
833 }
834
835 fn readdir(&self, file_id: u64) -> Result<Vec<DirEntry>, SyscallError> {
837 if file_id != 0 {
838 return Err(SyscallError::InvalidArgument);
839 }
840 let files = self.files.lock();
841 let mut entries = Vec::new();
842 for (name, (id, _, _)) in files.iter() {
843 entries.push(DirEntry {
844 ino: *id,
845 file_type: DT_REG,
846 name: name.clone(),
847 });
848 }
849 Ok(entries)
850 }
851}