1use core::fmt::Debug;
2use core::ops::Deref;
3
4use super::meta::MetaFileDirectory;
5use crate::error::{Error, InputError, OperationError};
6use crate::file::{FileOptions, TouchOptions};
7use crate::fs::SectorIndex;
8use crate::io::{self, Block, Wrap};
9use crate::region::data::entryset::primary::DateTime;
10
11#[derive(Copy, Clone, Debug, PartialEq, Eq)]
12pub enum SeekFrom {
13 Start(u64),
14 End(i64),
15 Current(i64),
16}
17
18pub struct File<B: Deref<Target = [Block]>, E: Debug, IO>
19where
20 IO: io::IO<Block<'static> = B, Error = E>,
21{
22 pub(crate) meta: MetaFileDirectory<IO>,
23 pub(crate) sector_index: SectorIndex,
24 pub(crate) size: u64,
25 cursor: u64,
26 dirty: bool,
27 #[cfg(feature = "async")]
28 closed: bool,
29}
30
31impl<B: Deref<Target = [Block]>, E: Debug, IO> File<B, E, IO>
32where
33 IO: io::IO<Block<'static> = B, Error = E>,
34{
35 pub(crate) fn new(meta: MetaFileDirectory<IO>, sector_index: SectorIndex) -> Self {
36 let size = meta.metadata.length();
37 match () {
38 #[cfg(not(feature = "async"))]
39 () => Self { meta, sector_index, size, cursor: 0, dirty: false },
40 #[cfg(feature = "async")]
41 () => Self { meta, sector_index, size, cursor: 0, dirty: false, closed: false },
42 }
43 }
44
45 pub fn change_options(&mut self, f: impl Fn(&mut FileOptions)) {
46 f(&mut self.meta.options)
47 }
48}
49
50#[cfg_attr(not(feature = "async"), maybe_async::must_be_sync)]
51impl<B: Deref<Target = [Block]>, E: Debug, IO> File<B, E, IO>
52where
53 IO: io::IO<Block<'static> = B, Error = E>,
54{
55 pub fn size(&self) -> u64 {
56 self.size
57 }
58
59 pub async fn touch(&mut self, datetime: DateTime, opts: TouchOptions) -> Result<(), Error<E>> {
61 self.meta.touch(datetime, opts).await?;
62 self.meta.io.acquire().await.wrap().flush().await
63 }
64
65 pub async fn read(&mut self, mut buf: &mut [u8]) -> Result<usize, Error<E>> {
70 if self.cursor == self.size {
71 return Err(OperationError::EOF.into());
72 }
73 if buf.len() > (self.size - self.cursor) as usize {
74 buf = &mut buf[..(self.size - self.cursor) as usize];
75 }
76 let sector_size = self.meta.fs.sector_size() as usize;
77 let offset = self.cursor as usize % sector_size;
78 let sector_id = self.sector_index.id(&self.meta.fs);
79 let sector_remain = sector_size - offset;
80 let mut io = self.meta.io.acquire().await.wrap();
81 let sector = io.read(sector_id).await?;
82 let bytes = crate::io::flatten(&*sector);
83 if buf.len() <= sector_remain {
84 buf.copy_from_slice(&bytes[offset..offset + buf.len()]);
85 drop(io);
86 if buf.len() == sector_remain {
87 self.sector_index = self.meta.next(self.sector_index).await?;
88 }
89 self.cursor += buf.len() as u64;
90 return Ok(buf.len());
91 }
92 buf[..sector_remain].copy_from_slice(&bytes[offset..]);
93 drop(io);
94 let mut remain = &mut buf[sector_remain..];
95 self.sector_index = self.meta.next(self.sector_index).await?;
96 for _ in 0..remain.len() / sector_size {
97 let mut io = self.meta.io.acquire().await.wrap();
98 let sector = io.read(sector_id).await?;
99 let bytes = crate::io::flatten(&*sector);
100 remain[..sector_size].copy_from_slice(bytes);
101 drop(io);
102 self.sector_index = self.meta.next(self.sector_index).await?;
103 remain = &mut remain[sector_size..];
104 }
105 let mut io = self.meta.io.acquire().await.wrap();
106 let sector = io.read(sector_id).await?;
107 let bytes = crate::io::flatten(&*sector);
108 remain.copy_from_slice(&bytes[..remain.len()]);
109 self.cursor += buf.len() as u64;
110 Ok(buf.len())
111 }
112
113 pub async fn write(&mut self, bytes: &[u8]) -> Result<usize, Error<E>> {
121 if bytes.len() == 0 {
122 return Ok(0);
123 }
124 self.dirty = true;
125 let sector_size = self.meta.fs.sector_size() as usize;
126 let mut capacity = self.meta.metadata.capacity();
127 let sector_remain = (capacity - self.cursor) as usize % sector_size;
128 if sector_remain > 0 {
129 let length = core::cmp::min(bytes.len(), sector_remain);
130 let chunk = &bytes[..length];
131 trace!("Write to sector-ref {}", self.sector_index);
132 let sector_id = self.sector_index.id(&self.meta.fs);
133 let mut io = self.meta.io.acquire().await.wrap();
134 io.write(sector_id, self.cursor as usize % sector_size, chunk).await?;
135 drop(io);
136 self.cursor += length as u64;
137 self.size = core::cmp::max(self.cursor, self.size);
138 if length == sector_remain && self.cursor < capacity {
139 self.sector_index = self.meta.next(self.sector_index).await?;
140 }
141 return Ok(sector_remain);
142 }
143 if self.cursor >= capacity {
144 let cluster_id = self.meta.allocate(self.sector_index.cluster_id).await?;
145 self.sector_index = SectorIndex::new(cluster_id, 0);
146 capacity = self.meta.metadata.capacity();
147 }
148 trace!("Write to sector-ref {}", self.sector_index);
149 let sector_id = self.sector_index.id(&self.meta.fs);
150 let length = core::cmp::min(bytes.len(), sector_size);
151 let chunk = &bytes[..length];
152 self.meta.io.acquire().await.wrap().write(sector_id, 0, chunk).await?;
153 self.cursor += length as u64;
154 self.size = core::cmp::max(self.cursor, self.size);
155 if length == sector_size && self.cursor < capacity {
156 self.sector_index = self.meta.next(self.sector_index).await?;
157 }
158 self.meta.metadata.set_length(self.size);
159 Ok(length)
160 }
161
162 pub async fn write_all(&mut self, bytes: &[u8]) -> Result<(), Error<E>> {
163 let written = self.write(bytes).await?; for chunk in bytes[written..].chunks(self.meta.fs.sector_size() as usize) {
165 self.write(chunk).await?;
166 }
167 Ok(())
168 }
169
170 pub async fn sync_data(&mut self) -> Result<(), Error<E>> {
172 if self.dirty {
173 self.meta.io.acquire().await.wrap().flush().await?;
174 self.dirty = false;
175 }
176 Ok(())
177 }
178
179 pub async fn sync_all(&mut self) -> Result<(), Error<E>> {
181 self.sync_data().await?;
182 self.meta.sync().await
183 }
184
185 pub async fn flush(&mut self) -> Result<(), Error<E>> {
187 self.sync_all().await
188 }
189
190 pub async fn seek(&mut self, seek_from: SeekFrom) -> Result<u64, Error<E>> {
192 let option = match seek_from {
193 SeekFrom::Start(cursor) => i64::try_from(cursor).ok(),
194 SeekFrom::End(offset) => Some((self.cursor as i64) + offset),
195 SeekFrom::Current(offset) => (self.cursor as i64).checked_add(offset),
196 };
197 let cursor = option.ok_or(Error::Input(InputError::SeekPosition))?;
198 if cursor < 0 || cursor >= self.size as i64 {
199 return Err(InputError::SeekPosition.into());
200 }
201 let cursor = cursor as u64;
202 let sector_size = self.meta.fs.sector_size() as u64;
203 let num_sectors = match () {
204 _ if cursor > self.cursor => (cursor - self.cursor + sector_size - 1) / sector_size,
205 _ if cursor < self.cursor => {
206 self.sector_index = self.meta.sector_index;
207 (cursor + sector_size - 1) / sector_size
208 }
209 _ => 0,
210 };
211 for _ in 0..num_sectors {
212 self.sector_index = self.meta.next(self.sector_index).await?;
213 }
214 self.cursor = cursor;
215 Ok(cursor)
216 }
217
218 pub async fn truncate(&mut self, size: u64) -> Result<(), Error<E>> {
220 if size > self.size {
221 return Err(InputError::Size.into());
222 }
223 if self.cursor > size {
224 self.cursor = size;
225 self.seek(SeekFrom::Start(size)).await?;
226 }
227 self.meta.metadata.set_length(size);
228 self.size = size;
229 Ok(())
230 }
231
232 #[cfg(all(feature = "async", not(feature = "std")))]
233 pub async fn close(mut self) -> Result<(), Error<E>> {
235 self.closed = true;
236 self.flush().await.and(self.meta.close().await)
237 }
238}
239
240#[cfg(any(not(feature = "async"), feature = "std"))]
241impl<B: Deref<Target = [Block]>, E: Debug, IO> Drop for File<B, E, IO>
242where
243 IO: io::IO<Block<'static> = B, Error = E>,
244{
245 fn drop(&mut self) {
246 #[cfg(feature = "async")]
247 if !self.closed {
248 panic!("Close must be explicitly called")
249 }
250 #[cfg(not(feature = "async"))]
251 self.flush().and(self.meta.close()).unwrap();
252 }
253}