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