strat9_kernel/vfs/
file.rs1use super::scheme::{DirEntry, DynScheme, FileFlags, FileStat, OpenFlags};
6use crate::{sync::SpinLock, syscall::error::SyscallError};
7use alloc::{string::String, vec::Vec};
8
9pub struct OpenFile {
11 scheme: DynScheme,
13 file_id: u64,
15 path: String,
17 offset: SpinLock<u64>,
19 open_flags: OpenFlags,
21 file_flags: FileFlags,
23 size: Option<u64>,
25}
26
27impl OpenFile {
28 pub fn new(
30 scheme: DynScheme,
31 file_id: u64,
32 path: String,
33 open_flags: OpenFlags,
34 file_flags: FileFlags,
35 size: Option<u64>,
36 ) -> Self {
37 OpenFile {
38 scheme,
39 file_id,
40 path,
41 offset: SpinLock::new(0),
42 open_flags,
43 file_flags,
44 size,
45 }
46 }
47
48 pub fn read(&self, buf: &mut [u8]) -> Result<usize, SyscallError> {
50 if !self.open_flags.contains(OpenFlags::READ) {
51 return Err(SyscallError::PermissionDenied);
52 }
53
54 let mut offset = self.offset.lock();
55 let bytes_read = self.scheme.read(self.file_id, *offset, buf)?;
56 *offset += bytes_read as u64;
57 Ok(bytes_read)
58 }
59
60 pub fn write(&self, buf: &[u8]) -> Result<usize, SyscallError> {
62 if !self.open_flags.contains(OpenFlags::WRITE) {
63 return Err(SyscallError::PermissionDenied);
64 }
65
66 let mut offset = self.offset.lock();
67 if self.open_flags.contains(OpenFlags::APPEND) {
68 if let Ok(sz) = self.scheme.size(self.file_id) {
69 *offset = sz;
70 } else if let Some(sz) = self.size {
71 *offset = sz;
72 }
73 }
74
75 let bytes_written = self.scheme.write(self.file_id, *offset, buf)?;
76 *offset += bytes_written as u64;
77 Ok(bytes_written)
78 }
79
80 pub fn pread(&self, offset: u64, buf: &mut [u8]) -> Result<usize, SyscallError> {
82 if !self.open_flags.contains(OpenFlags::READ) {
83 return Err(SyscallError::PermissionDenied);
84 }
85 self.scheme.read(self.file_id, offset, buf)
86 }
87
88 pub fn pwrite(&self, offset: u64, buf: &[u8]) -> Result<usize, SyscallError> {
90 if !self.open_flags.contains(OpenFlags::WRITE) {
91 return Err(SyscallError::PermissionDenied);
92 }
93 self.scheme.write(self.file_id, offset, buf)
94 }
95
96 pub fn seek(&self, new_offset: u64) -> Result<u64, SyscallError> {
98 let mut offset = self.offset.lock();
99 *offset = new_offset;
100 Ok(*offset)
101 }
102
103 pub fn lseek(&self, off: i64, whence: u32) -> Result<u64, SyscallError> {
105 let mut cur = self.offset.lock();
106 let new_pos: i64 = match whence {
107 0 => off,
108 1 => (*cur as i64)
109 .checked_add(off)
110 .ok_or(SyscallError::InvalidArgument)?,
111 2 => {
112 let sz = self.size().unwrap_or(0) as i64;
113 sz.checked_add(off).ok_or(SyscallError::InvalidArgument)?
114 }
115 _ => return Err(SyscallError::InvalidArgument),
116 };
117 if new_pos < 0 {
118 return Err(SyscallError::InvalidArgument);
119 }
120 *cur = new_pos as u64;
121 Ok(*cur)
122 }
123
124 pub fn tell(&self) -> u64 {
126 *self.offset.lock()
127 }
128
129 pub fn size(&self) -> Result<u64, SyscallError> {
131 if let Ok(sz) = self.scheme.size(self.file_id) {
132 Ok(sz)
133 } else if let Some(sz) = self.size {
134 Ok(sz)
135 } else {
136 Err(SyscallError::NotImplemented)
137 }
138 }
139
140 pub fn sync(&self) -> Result<(), SyscallError> {
142 self.scheme.sync(self.file_id)
143 }
144
145 pub fn close(&self) -> Result<(), SyscallError> {
151 Ok(())
152 }
153
154 pub fn flags(&self) -> FileFlags {
156 self.file_flags
157 }
158
159 pub fn open_flags(&self) -> OpenFlags {
161 self.open_flags
162 }
163
164 pub fn path(&self) -> &str {
166 &self.path
167 }
168
169 pub fn stat(&self) -> Result<FileStat, SyscallError> {
171 self.scheme.stat(self.file_id)
172 }
173
174 pub fn readdir(&self) -> Result<Vec<DirEntry>, SyscallError> {
176 if !self.file_flags.contains(FileFlags::DIRECTORY) {
177 return Err(SyscallError::InvalidArgument);
178 }
179 self.scheme.readdir(self.file_id)
180 }
181
182 pub fn file_id(&self) -> u64 {
184 self.file_id
185 }
186
187 pub fn scheme(&self) -> &DynScheme {
189 &self.scheme
190 }
191}
192
193impl Drop for OpenFile {
194 fn drop(&mut self) {
196 let _ = self.scheme.close(self.file_id);
198 }
199}