1io_transform! {
4
5#[cfg(feature = "alloc")]
6use core::ops::DerefMut;
7
8#[cfg(feature = "alloc")]
9use alloc::vec::Vec;
10
11use crate::error::{Error, Result};
12#[cfg(feature = "write")]
13use crate::file::ShortFileName;
14use super::{
15 fs::FatVolume, dir::FileEntry,
16 io::{Cluster, ClusterLike, ErrorKind, Read, Seek, SeekFrom},
17};
18
19pub struct FileReader<'a, DATA: Read + Seek> {
35 fs: &'a FatVolume<DATA>,
36 first_cluster: Cluster<usize>,
38 cluster: Cluster<usize>,
39 offset_in_cluster: usize,
41 position: u64,
43 size: usize,
45 cluster_steps: u32,
49 #[cfg(feature = "alloc")]
51 cluster_buffer: Option<Vec<u8>>,
52 #[cfg(feature = "alloc")]
54 cached_chain: Option<Vec<u32>>,
55 #[cfg(feature = "alloc")]
57 chain_index: usize,
58 #[cfg(feature = "write")]
63 entry_parent: Cluster<usize>,
64 #[cfg(feature = "write")]
65 entry_offset: usize,
66 #[cfg(feature = "write")]
67 entry_short_name: ShortFileName,
68 #[cfg(feature = "write")]
70 entry_created: crate::time::FatDateTime,
71}
72
73impl<'a, DATA: Read + Seek> FileReader<'a, DATA> {
74 pub fn new(fs: &'a FatVolume<DATA>, entry: &FileEntry) -> Result<Self> {
78 if entry.is_directory() {
79 return Err(Error::NotAFile);
80 }
81
82 Ok(Self {
83 fs,
84 first_cluster: entry.cluster(),
85 cluster: entry.cluster(),
86 offset_in_cluster: 0,
87 position: 0,
88 size: entry.len() as usize,
89 cluster_steps: 0,
90 #[cfg(feature = "alloc")]
91 cluster_buffer: None,
92 #[cfg(feature = "alloc")]
93 cached_chain: None,
94 #[cfg(feature = "alloc")]
95 chain_index: 0,
96 #[cfg(feature = "write")]
97 entry_parent: entry.parent_clus,
98 #[cfg(feature = "write")]
99 entry_offset: entry.offset_within_cluster,
100 #[cfg(feature = "write")]
101 entry_short_name: entry.short_name,
102 #[cfg(feature = "write")]
103 entry_created: entry.created,
104 })
105 }
106
107 pub fn size(&self) -> usize {
109 self.size
110 }
111
112 pub fn position(&self) -> u64 {
114 self.position
115 }
116
117 pub fn remaining(&self) -> usize {
119 (self.size as u64).saturating_sub(self.position) as usize
120 }
121
122 #[cfg(feature = "alloc")]
130 pub fn with_buffer(mut self) -> Self {
131 self.cluster_buffer = Some(Vec::new());
132 self
133 }
134
135 #[cfg(feature = "alloc")]
144 pub async fn with_cached_chain(mut self) -> Result<Self> {
145 if self.first_cluster.0 < 2 {
146 self.cached_chain = Some(Vec::new());
148 return Ok(self);
149 }
150
151 let max_clusters = self.fs.info.max_cluster as usize;
152 let mut data = self.fs.data.lock();
153 let cluster_size = data.cluster_size;
154 let chain = self
155 .fs
156 .fat
157 .read_chain(
158 data.deref_mut(),
159 self.first_cluster.0 as u32,
160 max_clusters,
161 )
162 .await?;
163 drop(data);
164
165 if self.position < self.size as u64 {
166 let chain_index = self.position as usize / cluster_size;
167 let cluster = chain
168 .get(chain_index)
169 .copied()
170 .ok_or(Error::UnexpectedEndOfChain {
171 cluster: chain
172 .last()
173 .copied()
174 .unwrap_or(self.first_cluster.0 as u32),
175 })?;
176 self.cluster.0 = cluster as usize;
177 self.offset_in_cluster = self.position as usize % cluster_size;
178 self.chain_index = chain_index;
179 }
180 self.cached_chain = Some(chain);
181 Ok(self)
182 }
183
184 pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
193 let max = buf.len().min(self.remaining());
196 if max == 0 {
197 return Ok(0);
198 }
199 self.read_to_buf(&mut buf[..max]).await
200 }
201
202 async fn read_to_buf(&mut self, buf: &mut [u8]) -> Result<usize> {
211 let max = buf.len().min(self.remaining());
212 if max == 0 {
213 return Ok(0);
214 }
215 #[cfg(feature = "write")]
221 self.fs
222 .revalidate_slot(
223 self.entry_parent,
224 self.entry_offset,
225 &self.entry_short_name,
226 &self.entry_created,
227 )
228 .await?;
229 let buf = &mut buf[..max];
230
231 #[cfg(feature = "alloc")]
232 {
233 let mut data = self.fs.data.lock();
234 let cluster_size = data.cluster_size;
235 let data_start = self.fs.info.data_start;
236
237 if let Some(ref chain) = self.cached_chain {
239 let buf_len = buf.len();
240 let mut total = 0usize;
242 let mut chain_index = self.chain_index;
243 let mut offset_in_cluster = self.offset_in_cluster;
244
245 while total < buf_len && chain_index < chain.len() {
246 let first_cluster = chain[chain_index] as usize;
247 let mut run_len = 1usize;
249 while chain_index + run_len < chain.len()
250 && chain[chain_index + run_len] == chain[chain_index + run_len - 1] + 1
251 {
252 run_len += 1;
253 }
254
255 let bytes_from_first = cluster_size.saturating_sub(offset_in_cluster);
257 let bytes_from_run = bytes_from_first
258 .saturating_add(run_len.saturating_sub(1).saturating_mul(cluster_size));
259 let to_read = bytes_from_run.min(buf_len - total);
260
261 if to_read == 0 {
262 break;
263 }
264
265 let seek_pos = Cluster(first_cluster)
266 .to_bytes(data_start, cluster_size)
267 .saturating_add(offset_in_cluster);
268 data.seek(SeekFrom::Start(seek_pos as u64)).await?;
269 data.read_exact(&mut buf[total..total + to_read]).await?;
270
271 total += to_read;
272 self.position += to_read as u64;
273
274 let new_offset = offset_in_cluster + to_read;
276 chain_index += new_offset / cluster_size;
277 offset_in_cluster = new_offset % cluster_size;
278 }
279
280 self.chain_index = chain_index;
281 self.offset_in_cluster = offset_in_cluster;
282 if chain_index < chain.len() {
283 self.cluster.0 = chain[chain_index] as usize;
284 }
285 drop(data);
286 return Ok(total);
287 }
288
289 drop(data);
290 }
291
292 let buf_len = buf.len();
294 let mut total = 0usize;
295 while total < buf_len {
296 let n = self.read_one_chunk(&mut buf[total..]).await?;
297 if n == 0 {
298 break;
299 }
300 total += n;
301 }
302 Ok(total)
303 }
304
305 async fn read_one_chunk(&mut self, buf: &mut [u8]) -> Result<usize> {
309 if self.position >= self.size as u64 {
311 return Ok(0);
312 }
313
314 if self.cluster.0 < 2 {
318 return Ok(0);
319 }
320
321 let mut data = self.fs.data.lock();
322 let cluster_size = data.cluster_size;
323
324 if self.offset_in_cluster >= cluster_size {
326 #[cfg(feature = "alloc")]
327 {
328 if let Some(ref chain) = self.cached_chain {
329 self.chain_index += 1;
331 if self.chain_index >= chain.len() {
332 return Ok(0); }
334 self.cluster.0 = chain[self.chain_index] as usize;
335 self.offset_in_cluster = 0;
336 if let Some(ref mut buffer) = self.cluster_buffer {
338 buffer.clear();
339 }
340 } else {
341 self.cluster_steps = self.cluster_steps.saturating_add(1);
343 if self.cluster_steps > self.fs.fat.max_cluster() {
344 return Err(Error::ClusterLoop {
345 cluster: self.cluster.0 as u32,
346 });
347 }
348 drop(data);
351 let next = self.fs.next_cluster_routed(self.cluster.0).await?;
352 data = self.fs.data.lock();
353 match next {
354 Some(cluster) => {
355 self.cluster.0 = cluster as usize;
356 self.offset_in_cluster = 0;
357 if let Some(ref mut buffer) = self.cluster_buffer {
358 buffer.clear();
359 }
360 }
361 None => return Ok(0), }
363 }
364 }
365
366 #[cfg(not(feature = "alloc"))]
367 {
368 self.cluster_steps = self.cluster_steps.saturating_add(1);
369 if self.cluster_steps > self.fs.fat.max_cluster() {
370 return Err(Error::ClusterLoop {
371 cluster: self.cluster.0 as u32,
372 });
373 }
374 drop(data);
377 let next = self.fs.next_cluster_routed(self.cluster.0).await?;
378 data = self.fs.data.lock();
379 match next {
380 Some(cluster) => {
381 self.cluster.0 = cluster as usize;
382 self.offset_in_cluster = 0;
383 }
384 None => return Ok(0), }
386 }
387 }
388
389 let bytes_left_in_cluster = cluster_size - self.offset_in_cluster;
391 let bytes_left_in_file = (self.size as u64 - self.position) as usize;
392 let read_max = buf.len().min(bytes_left_in_cluster).min(bytes_left_in_file);
393
394 if read_max == 0 {
395 return Ok(0);
396 }
397
398 #[cfg(feature = "alloc")]
399 let bytes_read = if let Some(ref mut buffer) = self.cluster_buffer {
400 if buffer.is_empty() {
402 let cluster_start = self.cluster.to_bytes(self.fs.info.data_start, cluster_size);
403 data.seek(SeekFrom::Start(cluster_start as u64)).await?;
404
405 buffer.resize(cluster_size, 0);
406 data.read_exact(buffer).await?;
407 }
408
409 let src = &buffer[self.offset_in_cluster..self.offset_in_cluster + read_max];
410 buf[..read_max].copy_from_slice(src);
411 read_max
412 } else {
413 let seek_pos = self.cluster.to_bytes(self.fs.info.data_start, cluster_size)
415 + self.offset_in_cluster;
416 data.seek(SeekFrom::Start(seek_pos as u64)).await?;
417 data.read(&mut buf[..read_max]).await?
418 };
419
420 #[cfg(not(feature = "alloc"))]
421 let bytes_read = {
422 let seek_pos = self.cluster.to_bytes(self.fs.info.data_start, cluster_size)
423 + self.offset_in_cluster;
424 data.seek(SeekFrom::Start(seek_pos as u64)).await?;
425 data.read(&mut buf[..read_max]).await?
426 };
427
428 self.offset_in_cluster += bytes_read;
429 self.position += bytes_read as u64;
430
431 Ok(bytes_read)
432 }
433
434 pub async fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
441 fn invalid(message: &'static str) -> Error {
442 Error::Io(hadris_io::Error::new(ErrorKind::InvalidInput, message))
443 }
444
445 let target = match pos {
446 SeekFrom::Start(position) => Some(position),
447 SeekFrom::Current(offset) => self.position.checked_add_signed(offset),
448 SeekFrom::End(offset) => (self.size as u64).checked_add_signed(offset),
449 }
450 .ok_or_else(|| invalid("invalid seek position"))?;
451
452 if target >= self.size as u64 || self.first_cluster.0 < 2 {
453 self.position = target;
454 return Ok(target);
455 }
456
457 let target_usize = target as usize;
458 let cluster_size = self.fs.data.lock().cluster_size;
459 let target_cluster = target_usize / cluster_size;
460 let target_offset = target_usize % cluster_size;
461
462 #[cfg(feature = "alloc")]
463 if let Some(ref chain) = self.cached_chain {
464 let cluster = *chain
465 .get(target_cluster)
466 .ok_or(Error::UnexpectedEndOfChain {
467 cluster: chain.last().copied().unwrap_or(self.first_cluster.0 as u32),
468 })?;
469 if let Some(ref mut buffer) = self.cluster_buffer {
470 buffer.clear();
471 }
472 self.chain_index = target_cluster;
473 self.cluster.0 = cluster as usize;
474 self.offset_in_cluster = target_offset;
475 self.position = target;
476 return Ok(target);
477 }
478
479 let current_cluster = (self.position as usize).saturating_sub(self.offset_in_cluster)
480 / cluster_size;
481
482 let (mut cluster, mut hops, mut cluster_steps) = if self.position >= self.size as u64 {
483 (self.first_cluster.0, target_cluster, 0)
484 } else if target_cluster >= current_cluster {
485 (
486 self.cluster.0,
487 target_cluster - current_cluster,
488 self.cluster_steps,
489 )
490 } else {
491 (self.first_cluster.0, target_cluster, 0)
492 };
493
494 while hops > 0 {
495 cluster_steps = cluster_steps.saturating_add(1);
496 if cluster_steps > self.fs.fat.max_cluster() {
497 return Err(Error::ClusterLoop {
498 cluster: cluster as u32,
499 });
500 }
501 cluster = self
502 .fs
503 .next_cluster_routed(cluster)
504 .await?
505 .ok_or(Error::UnexpectedEndOfChain {
506 cluster: cluster as u32,
507 })? as usize;
508 hops -= 1;
509 }
510
511 #[cfg(feature = "alloc")]
512 if let Some(ref mut buffer) = self.cluster_buffer {
513 buffer.clear();
514 }
515 self.cluster_steps = cluster_steps;
516 self.cluster.0 = cluster;
517 self.offset_in_cluster = target_offset;
518 self.position = target;
519
520 Ok(target)
521 }
522
523 #[cfg(feature = "alloc")]
530 pub async fn read_to_vec(&mut self) -> Result<Vec<u8>> {
531 let remaining = self.remaining();
532 let volume_capacity = self.fs.info.max_cluster as u64 * self.fs.info.cluster_size as u64;
538 if remaining as u64 > volume_capacity {
539 return Err(Error::CorruptFilesystem {
540 context: "file size exceeds volume capacity",
541 });
542 }
543 const MAX_PREALLOC: usize = 16 * 1024 * 1024;
549 let mut buf = alloc::vec![0u8; remaining.min(MAX_PREALLOC)];
550 let mut filled = 0;
551 while filled < remaining {
552 if filled == buf.len() {
553 buf.resize((buf.len() * 2).min(remaining), 0);
554 }
555 let n = self.read_to_buf(&mut buf[filled..]).await?;
556 if n == 0 {
557 break;
558 }
559 filled += n;
560 }
561 buf.truncate(filled);
562 Ok(buf)
563 }
564}
565
566pub trait FatVolumeReadExt<DATA: Read + Seek> {
568 fn read_file<'a>(&'a self, entry: &FileEntry) -> Result<FileReader<'a, DATA>>;
570}
571
572impl<DATA: Read + Seek> FatVolumeReadExt<DATA> for FatVolume<DATA> {
573 fn read_file<'a>(&'a self, entry: &FileEntry) -> Result<FileReader<'a, DATA>> {
574 FileReader::new(self, entry)
575 }
576}
577
578}