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 Some(sz) = self.size {
71 *offset = sz;
72 } else if let Ok(sz) = self.scheme.size(self.file_id) {
73 *offset = sz;
74 }
75 }
78
79 let bytes_written = self.scheme.write(self.file_id, *offset, buf)?;
80 *offset += bytes_written as u64;
81 Ok(bytes_written)
82 }
83
84 pub fn pread(&self, offset: u64, buf: &mut [u8]) -> Result<usize, SyscallError> {
86 if !self.open_flags.contains(OpenFlags::READ) {
87 return Err(SyscallError::PermissionDenied);
88 }
89 self.scheme.read(self.file_id, offset, buf)
90 }
91
92 pub fn pwrite(&self, offset: u64, buf: &[u8]) -> Result<usize, SyscallError> {
94 if !self.open_flags.contains(OpenFlags::WRITE) {
95 return Err(SyscallError::PermissionDenied);
96 }
97 self.scheme.write(self.file_id, offset, buf)
98 }
99
100 pub fn seek(&self, new_offset: u64) -> Result<u64, SyscallError> {
102 let mut offset = self.offset.lock();
103 *offset = new_offset;
104 Ok(*offset)
105 }
106
107 pub fn lseek(&self, off: i64, whence: u32) -> Result<u64, SyscallError> {
109 let mut cur = self.offset.lock();
110 let new_pos: i64 = match whence {
111 0 => off,
112 1 => (*cur as i64)
113 .checked_add(off)
114 .ok_or(SyscallError::InvalidArgument)?,
115 2 => {
116 let sz = self.size().unwrap_or(0) as i64;
117 sz.checked_add(off).ok_or(SyscallError::InvalidArgument)?
118 }
119 _ => return Err(SyscallError::InvalidArgument),
120 };
121 if new_pos < 0 {
122 return Err(SyscallError::InvalidArgument);
123 }
124 *cur = new_pos as u64;
125 Ok(*cur)
126 }
127
128 pub fn tell(&self) -> u64 {
130 *self.offset.lock()
131 }
132
133 pub fn size(&self) -> Result<u64, SyscallError> {
135 if let Ok(sz) = self.scheme.size(self.file_id) {
136 Ok(sz)
137 } else if let Some(sz) = self.size {
138 Ok(sz)
139 } else {
140 Err(SyscallError::NotImplemented)
141 }
142 }
143
144 pub fn sync(&self) -> Result<(), SyscallError> {
146 self.scheme.sync(self.file_id)
147 }
148
149 pub fn close(&self) -> Result<(), SyscallError> {
155 Ok(())
156 }
157
158 pub fn flags(&self) -> FileFlags {
160 self.file_flags
161 }
162
163 pub fn open_flags(&self) -> OpenFlags {
165 self.open_flags
166 }
167
168 pub fn path(&self) -> &str {
170 &self.path
171 }
172
173 pub fn stat(&self) -> Result<FileStat, SyscallError> {
175 self.scheme.stat(self.file_id)
176 }
177
178 pub fn readdir(&self) -> Result<Vec<DirEntry>, SyscallError> {
180 if !self.file_flags.contains(FileFlags::DIRECTORY) {
181 return Err(SyscallError::InvalidArgument);
182 }
183 self.scheme.readdir(self.file_id)
184 }
185
186 pub fn file_id(&self) -> u64 {
188 self.file_id
189 }
190
191 pub fn scheme(&self) -> &DynScheme {
193 &self.scheme
194 }
195}
196
197impl Drop for OpenFile {
198 fn drop(&mut self) {
200 let _ = self.scheme.close(self.file_id);
202 }
203}