Skip to main content

hadris_fat/
fat_table.rs

1io_transform! {
2
3use core::mem::size_of;
4
5#[cfg(feature = "alloc")]
6use alloc::vec::Vec;
7
8use crate::error::{Error, Result};
9#[cfg(feature = "write")]
10use super::io::Write;
11use super::io::{Read, Seek, SeekFrom};
12
13/// Size of the sliding window used when reading FAT chains in bulk (bytes).
14/// Set at build time via `HADRIS_FAT_CACHE_SIZE` (e.g. 4MiB, 8M). Build script sets
15/// `FAT_CACHE_WINDOW_SIZE_BYTES` (rustc-env); we read it with `env!` and `.parse()`.
16#[cfg(feature = "alloc")]
17const FAT_CACHE_WINDOW_SIZE: &str = env!("FAT_CACHE_WINDOW_SIZE_BYTES");
18
19/// Decode a FAT12 entry from a byte slice (raw FAT window). Cluster N’s entry
20/// starts at byte offset (N * 3) / 2 and spans 2 bytes; even/odd determines layout.
21#[cfg(feature = "alloc")]
22fn fat12_entry_from_buf(buf: &[u8], window_start: usize, cluster: usize) -> u16 {
23    let offset_in_fat = (cluster * 3) / 2;
24    let buffer_offset = offset_in_fat - window_start;
25    let bytes = &buf[buffer_offset..][..2];
26    if cluster.is_multiple_of(2) {
27        u16::from(bytes[0]) | (u16::from(bytes[1] & 0x0F) << 8)
28    } else {
29        (u16::from(bytes[0]) >> 4) | (u16::from(bytes[1]) << 4)
30    }
31}
32
33/// Read a cluster chain in bulk using a 4 MiB sliding window (FAT12, FAT16, FAT32).
34///
35/// Used when `alloc` is enabled as the backend for [`with_cached_chain`](super::read::FileReader::with_cached_chain).
36/// `entry_size`: 0 = FAT12 (packed 12-bit), 2 = FAT16, 4 = FAT32. Panics if not 0, 2, or 4.
37#[cfg(feature = "alloc")]
38#[allow(clippy::too_many_arguments)]
39async fn read_chain_wide<R>(
40    reader: &mut R,
41    fat_start: usize,
42    fat_size: usize,
43    start_cluster: u32,
44    max_clusters: usize,
45    entry_size: usize,
46    entry_mask: u32,
47    is_end_of_chain: impl Fn(u32) -> bool,
48    is_bad_cluster: impl Fn(u32) -> bool,
49    validate_cluster: impl Fn(u32) -> Result<()>,
50) -> Result<Vec<u32>>
51where
52    R: Read + Seek,
53{
54    assert!(
55        entry_size == 0 || entry_size == 2 || entry_size == 4,
56        "FAT entry_size must be 0 (FAT12), 2 (FAT16), or 4 (FAT32), got {entry_size}"
57    );
58
59    let cache_size = FAT_CACHE_WINDOW_SIZE.parse::<usize>().unwrap();
60    let mut fat_buf = alloc::vec![0u8; FAT_CACHE_WINDOW_SIZE.parse::<usize>().unwrap()];
61    let mut window_start = usize::MAX;
62    let mut valid_len = 0usize;
63
64    let mut chain = Vec::new();
65    let mut current = start_cluster as usize;
66    let mut iterations = 0;
67
68    while current >= 2 && iterations <= max_clusters {
69        chain.push(current as u32);
70        iterations += 1;
71
72        let (offset_in_fat, span) = if entry_size == 0 {
73            ((current * 3) / 2, 2)
74        } else {
75            (current * entry_size, entry_size)
76        };
77
78        if offset_in_fat < window_start || offset_in_fat + span > window_start + valid_len {
79            window_start = offset_in_fat;
80            valid_len = cache_size.min(fat_size.saturating_sub(window_start));
81            reader
82                .seek(SeekFrom::Start((fat_start + window_start) as u64))
83                .await?;
84            reader.read_exact(&mut fat_buf[..valid_len]).await?;
85        }
86
87        let buffer_offset = offset_in_fat - window_start;
88        let cluster_u32 = if entry_size == 0 {
89            fat12_entry_from_buf(&fat_buf, window_start, current) as u32 & entry_mask
90        } else if entry_size == 2 {
91            let raw = u16::from_le_bytes(
92                fat_buf[buffer_offset..][..2].try_into().unwrap(),
93            );
94            (raw as u32) & entry_mask
95        } else {
96            let raw = u32::from_le_bytes(
97                fat_buf[buffer_offset..][..4].try_into().unwrap(),
98            );
99            raw & entry_mask
100        };
101
102        if is_end_of_chain(cluster_u32) {
103            break;
104        }
105        if is_bad_cluster(cluster_u32) {
106            return Err(Error::BadCluster {
107                cluster: current as u32,
108            });
109        }
110        validate_cluster(cluster_u32)?;
111        current = cluster_u32 as usize;
112    }
113    Ok(chain)
114}
115
116/// Allocation-table implementation selected for a mounted FAT volume.
117pub enum Fat {
118    /// FAT12 allocation table.
119    Fat12(Fat12),
120    /// FAT16 allocation table.
121    Fat16(Fat16),
122    /// FAT32 allocation table.
123    Fat32(Fat32),
124}
125
126impl Fat {
127    /// Returns the next cluster in a chain, or `None` at end-of-chain.
128    pub async fn next_cluster<T: Read + Seek>(
129        &self,
130        reader: &mut T,
131        cluster: usize,
132    ) -> Result<Option<u32>> {
133        match self {
134            Self::Fat12(fat12) => fat12.next_cluster(reader, cluster).await,
135            Self::Fat16(fat16) => fat16.next_cluster(reader, cluster).await,
136            Self::Fat32(fat32) => fat32.next_cluster(reader, cluster).await,
137        }
138    }
139
140    /// Read an entire cluster chain into a vector (alloc only).
141    ///
142    /// Uses a 4 MiB sliding window over the FAT for all types to reduce I/O.
143    #[cfg(feature = "alloc")]
144    pub(crate) async fn read_chain<T: Read + Seek>(
145        &self,
146        reader: &mut T,
147        start_cluster: u32,
148        max_clusters: usize,
149    ) -> Result<Vec<u32>> {
150        match self {
151            Self::Fat12(fat12) => {
152                read_chain_wide(
153                    reader,
154                    fat12.start,
155                    fat12.size,
156                    start_cluster,
157                    max_clusters,
158                    0, // FAT12: packed 12-bit
159                    0x0FFF,
160                    |v| Fat12::is_end_of_chain(v as u16),
161                    |v| Fat12::is_bad_cluster(v as u16),
162                    |v| fat12.validate_cluster(v as u16),
163                )
164                .await
165            }
166            Self::Fat16(fat16) => {
167                read_chain_wide(
168                    reader,
169                    fat16.start,
170                    fat16.size,
171                    start_cluster,
172                    max_clusters,
173                    2, // FAT16
174                    0xFFFF,
175                    |v| Fat16::is_end_of_chain(v as u16),
176                    |v| Fat16::is_bad_cluster(v as u16),
177                    |v| fat16.validate_cluster(v as u16),
178                )
179                .await
180            }
181            Self::Fat32(fat32) => {
182                read_chain_wide(
183                    reader,
184                    fat32.start,
185                    fat32.size,
186                    start_cluster,
187                    max_clusters,
188                    4, // FAT32
189                    Fat32::ENTRY_MASK,
190                    Fat32::is_end_of_chain,
191                    Fat32::is_bad_cluster,
192                    |v| fat32.validate_cluster(v),
193                )
194                .await
195            }
196        }
197    }
198
199    /// Get the FAT type for informational purposes
200    pub fn fat_type(&self) -> FatType {
201        match self {
202            Self::Fat12(_) => FatType::Fat12,
203            Self::Fat16(_) => FatType::Fat16,
204            Self::Fat32(_) => FatType::Fat32,
205        }
206    }
207
208    /// Highest valid cluster number on this volume (inclusive). Clusters 0 and 1
209    /// are reserved, so the chain-loop ceiling is `max_cluster - 1` distinct
210    /// clusters; one extra step lets the walker observe the end-of-chain marker
211    /// before declaring a loop.
212    pub fn max_cluster(&self) -> u32 {
213        match self {
214            Self::Fat12(f) => f.max_cluster as u32,
215            Self::Fat16(f) => f.max_cluster as u32,
216            Self::Fat32(f) => f.max_cluster,
217        }
218    }
219
220    /// Walk a cluster chain starting at `start`, calling `visit` for each
221    /// cluster (including `start`) until the chain ends. Returns the last
222    /// cluster visited.
223    ///
224    /// Aborts with [`Error::ClusterLoop`] if more than `max_steps`
225    /// clusters are walked. The natural upper bound is
226    /// [`Self::max_cluster`] — any chain longer than that must repeat a
227    /// cluster and is therefore corrupt.
228    pub async fn walk_chain<T, F>(
229        &self,
230        reader: &mut T,
231        start: u32,
232        max_steps: u32,
233        mut visit: F,
234    ) -> Result<u32>
235    where
236        T: Read + Seek,
237        F: FnMut(u32),
238    {
239        let mut current = start;
240        let mut steps: u32 = 0;
241        loop {
242            visit(current);
243            steps = steps.saturating_add(1);
244            if steps > max_steps {
245                return Err(Error::ClusterLoop { cluster: current });
246            }
247            match self.next_cluster(reader, current as usize).await? {
248                Some(next) => current = next,
249                None => return Ok(current),
250            }
251        }
252    }
253
254    /// Truncate a cluster chain after the specified cluster.
255    ///
256    /// The specified cluster becomes the end of chain (marked with end-of-chain marker).
257    /// All clusters following it are freed.
258    ///
259    /// Returns the number of clusters freed.
260    #[cfg(feature = "write")]
261    pub async fn truncate_chain<T: Read + Write + Seek>(
262        &self,
263        rw: &mut T,
264        cluster: usize,
265    ) -> Result<u32> {
266        match self {
267            Self::Fat12(fat12) => fat12.truncate_chain(rw, cluster as u16).await,
268            Self::Fat16(fat16) => fat16.truncate_chain(rw, cluster as u16).await,
269            Self::Fat32(fat32) => fat32.truncate_chain(rw, cluster as u32).await,
270        }
271    }
272
273    /// Free a cluster chain starting at `start`, returns count of freed clusters.
274    #[cfg(feature = "write")]
275    pub async fn free_chain<T: Read + Write + Seek>(&self, rw: &mut T, cluster: usize) -> Result<u32> {
276        match self {
277            Self::Fat12(fat12) => fat12.free_chain(rw, cluster as u16).await,
278            Self::Fat16(fat16) => fat16.free_chain(rw, cluster as u16).await,
279            Self::Fat32(fat32) => fat32.free_chain(rw, cluster as u32).await,
280        }
281    }
282
283    /// Mark a cluster as bad in the FAT.
284    ///
285    /// Writes the appropriate bad-cluster marker (0xFF7 / 0xFFF7 / 0x0FFFFFF7)
286    /// to the FAT entry for the given cluster. This prevents the cluster from
287    /// being allocated in the future.
288    #[cfg(feature = "write")]
289    pub async fn mark_bad<T: Read + Write + Seek>(&self, rw: &mut T, cluster: usize) -> Result<()> {
290        match self {
291            Self::Fat12(fat12) => fat12.mark_bad(rw, cluster as u16).await,
292            Self::Fat16(fat16) => fat16.mark_bad(rw, cluster as u16).await,
293            Self::Fat32(fat32) => fat32.mark_bad(rw, cluster as u32).await,
294        }
295    }
296
297    /// Read the FAT-resident status bits from `FAT[1]`.
298    ///
299    /// The FAT spec stores two volume-level status bits in the high bits of
300    /// the FAT entry for cluster 1:
301    ///   * "clean shutdown" (set = clean, cleared = dirty)
302    ///   * "no I/O errors" (set = ok, cleared = errors during last use)
303    /// FAT12 has no spare bits in its packed 12-bit entries, so it returns
304    /// `(false, false)` (treat as "clean, no errors") — matches the spec's
305    /// "FAT12 has no status word" reading.
306    ///
307    /// Returns `(dirty, io_errors)` — both `true` means trouble.
308    pub async fn read_status_flags<T: Read + Seek>(&self, reader: &mut T) -> Result<(bool, bool)> {
309        match self {
310            Self::Fat12(_) => Ok((false, false)),
311            Self::Fat16(f) => {
312                // FAT[1] sits at byte offset start + 2 (cluster 1, 16-bit entries).
313                let offset = f.start + 2;
314                reader.seek(SeekFrom::Start(offset as u64)).await?;
315                let mut bytes = [0u8; 2];
316                reader.read_exact(&mut bytes).await?;
317                let val = u16::from_le_bytes(bytes);
318                // Bit 15 cleared = dirty; bit 14 cleared = I/O errors.
319                Ok((val & 0x8000 == 0, val & 0x4000 == 0))
320            }
321            Self::Fat32(f) => {
322                // FAT[1] at byte offset start + 4 (cluster 1, 32-bit entries).
323                let offset = f.start + 4;
324                reader.seek(SeekFrom::Start(offset as u64)).await?;
325                let mut bytes = [0u8; 4];
326                reader.read_exact(&mut bytes).await?;
327                let val = u32::from_le_bytes(bytes);
328                // Bit 27 cleared = dirty; bit 26 cleared = I/O errors. Only
329                // these two bits are status; the rest of the high nibble is
330                // reserved and the low 28 bits are the cluster-1 entry value.
331                Ok((val & 0x0800_0000 == 0, val & 0x0400_0000 == 0))
332            }
333        }
334    }
335
336    /// Returns the number of FAT copies on disk (typically 1 or 2).
337    pub fn fat_copy_count(&self) -> usize {
338        match self {
339            Self::Fat12(f) => f.count,
340            Self::Fat16(f) => f.count,
341            Self::Fat32(f) => f.count,
342        }
343    }
344
345    /// Compare a FAT entry between the primary (index 0) and backup (index 1) copies.
346    ///
347    /// Returns `Ok(true)` if both copies match, `Ok(false)` if they differ.
348    /// Returns an error if there is only one FAT copy or on I/O failure.
349    pub async fn compare_entry<T: Read + Seek>(
350        &self,
351        reader: &mut T,
352        cluster: usize,
353    ) -> Result<bool> {
354        if self.fat_copy_count() < 2 {
355            return Err(Error::UnsupportedFatType("no backup FAT copy available"));
356        }
357        match self {
358            Self::Fat12(f) => {
359                let a = f.read_clus_at(reader, cluster, 0).await?;
360                let b = f.read_clus_at(reader, cluster, 1).await?;
361                Ok(a == b)
362            }
363            Self::Fat16(f) => {
364                let a = f.read_clus_at(reader, cluster, 0).await?;
365                let b = f.read_clus_at(reader, cluster, 1).await?;
366                Ok(a == b)
367            }
368            Self::Fat32(f) => {
369                let a = f.read_clus_at(reader, cluster, 0).await?;
370                let b = f.read_clus_at(reader, cluster, 1).await?;
371                Ok(a == b)
372            }
373        }
374    }
375
376    /// Read the next cluster, falling back to the backup FAT copy on error.
377    ///
378    /// Tries the primary FAT first. If reading fails and a backup FAT exists,
379    /// reads from the backup copy instead.
380    pub async fn next_cluster_with_fallback<T: Read + Seek>(
381        &self,
382        reader: &mut T,
383        cluster: usize,
384    ) -> Result<Option<u32>> {
385        match self.next_cluster(reader, cluster).await {
386            Ok(result) => Ok(result),
387            Err(_primary_err) if self.fat_copy_count() >= 2 => {
388                // Try reading from backup FAT (index 1)
389                match self {
390                    Self::Fat12(f) => {
391                        let entry = f.read_clus_at(reader, cluster, 1).await? & Fat12::ENTRY_MASK;
392                        if Fat12::is_end_of_chain(entry) { return Ok(None); }
393                        if Fat12::is_bad_cluster(entry) { return Err(Error::BadCluster { cluster: cluster as u32 }); }
394                        f.validate_cluster(entry)?;
395                        Ok(Some(entry as u32))
396                    }
397                    Self::Fat16(f) => {
398                        let entry = f.read_clus_at(reader, cluster, 1).await?;
399                        if Fat16::is_end_of_chain(entry) { return Ok(None); }
400                        if Fat16::is_bad_cluster(entry) { return Err(Error::BadCluster { cluster: cluster as u32 }); }
401                        f.validate_cluster(entry)?;
402                        Ok(Some(entry as u32))
403                    }
404                    Self::Fat32(f) => {
405                        let raw = f.read_clus_at(reader, cluster, 1).await?;
406                        let entry = raw & Fat32::ENTRY_MASK;
407                        if Fat32::is_end_of_chain(entry) { return Ok(None); }
408                        if Fat32::is_bad_cluster(entry) { return Err(Error::BadCluster { cluster: cluster as u32 }); }
409                        f.validate_cluster(entry)?;
410                        Ok(Some(entry))
411                    }
412                }
413            }
414            Err(e) => Err(e),
415        }
416    }
417}
418
419/// FAT filesystem type
420#[derive(Debug, Clone, Copy, PartialEq, Eq)]
421#[cfg_attr(feature = "defmt", derive(defmt::Format))]
422pub enum FatType {
423    /// 12-bit FAT entries.
424    Fat12,
425    /// 16-bit FAT entries.
426    Fat16,
427    /// 28-bit cluster values stored in 32-bit FAT entries.
428    Fat32,
429}
430
431impl core::fmt::Display for FatType {
432    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
433        match self {
434            Self::Fat12 => write!(f, "FAT12"),
435            Self::Fat16 => write!(f, "FAT16"),
436            Self::Fat32 => write!(f, "FAT32"),
437        }
438    }
439}
440
441/// FAT12 table implementation.
442///
443/// FAT12 uses 12-bit entries packed into 3 bytes for every 2 clusters.
444pub struct Fat12 {
445    start: usize,
446    size: usize,
447    count: usize,
448    max_cluster: u16,
449}
450
451impl Fat12 {
452    /// Mask for the 12-bit cluster number
453    const ENTRY_MASK: u16 = 0x0FFF;
454    /// End of chain markers: 0x0FF8 - 0x0FFF indicate end of cluster chain
455    const END_OF_CHAIN_MIN: u16 = 0x0FF8;
456    /// Bad cluster marker
457    const BAD_CLUSTER: u16 = 0x0FF7;
458    /// First valid data cluster (clusters 0 and 1 are reserved)
459    const FIRST_DATA_CLUSTER: u16 = 2;
460
461    /// Layout fields a [`crate::cache::FatSectorCache`] needs to mirror this
462    /// FAT: `(start_byte, size_per_copy, copy_count)`.
463    #[cfg(feature = "cache")]
464    pub(crate) fn cache_layout(&self) -> (usize, usize, usize) {
465        (self.start, self.size, self.count)
466    }
467
468    /// Creates a FAT12 table descriptor.
469    pub fn new(start: usize, size: usize, count: usize, max_cluster: u16) -> Self {
470        debug_assert!(count == 1 || count == 2);
471        Self {
472            start,
473            size,
474            count,
475            max_cluster,
476        }
477    }
478
479    /// Get the maximum cluster number.
480    pub fn max_cluster(&self) -> u16 {
481        self.max_cluster
482    }
483
484    sync_only! {
485        /// Calculates the byte offset used by synchronous analysis tooling.
486        #[cfg(feature = "tool")]
487        pub(crate) fn entry_byte_offset(&self, cluster: usize) -> usize {
488            self.start + (cluster * 3) / 2
489        }
490    }
491
492    async fn read_clus<T: Read + Seek>(&self, reader: &mut T, cluster: usize) -> Result<u16> {
493        self.read_clus_at(reader, cluster, 0).await
494    }
495
496    /// Read a FAT12 entry from a specific FAT copy (0 = primary, 1 = backup).
497    async fn read_clus_at<T: Read + Seek>(&self, reader: &mut T, cluster: usize, fat_index: usize) -> Result<u16> {
498        let byte_offset = self.start + fat_index * self.size + (cluster * 3) / 2;
499        reader.seek(SeekFrom::Start(byte_offset as u64)).await?;
500
501        let mut bytes = [0u8; 2];
502        reader.read_exact(&mut bytes).await?;
503
504        let value = if cluster.is_multiple_of(2) {
505            u16::from(bytes[0]) | (u16::from(bytes[1] & 0x0F) << 8)
506        } else {
507            (u16::from(bytes[0]) >> 4) | (u16::from(bytes[1]) << 4)
508        };
509
510        Ok(value)
511    }
512
513    /// Check if a cluster value represents end-of-chain
514    fn is_end_of_chain(value: u16) -> bool {
515        value >= Self::END_OF_CHAIN_MIN
516    }
517
518    /// Check if a cluster value represents a bad cluster
519    fn is_bad_cluster(value: u16) -> bool {
520        value == Self::BAD_CLUSTER
521    }
522
523    /// Validate that a cluster number is within bounds
524    fn validate_cluster(&self, cluster: u16) -> Result<()> {
525        if cluster < Self::FIRST_DATA_CLUSTER {
526            return Err(Error::ClusterOutOfBounds {
527                cluster: cluster as u32,
528                max: self.max_cluster as u32,
529            });
530        }
531        if cluster > self.max_cluster {
532            return Err(Error::ClusterOutOfBounds {
533                cluster: cluster as u32,
534                max: self.max_cluster as u32,
535            });
536        }
537        Ok(())
538    }
539
540    /// Returns the next cluster in a chain, or `None` at end-of-chain.
541    pub async fn next_cluster<T: Read + Seek>(
542        &self,
543        reader: &mut T,
544        cluster: usize,
545    ) -> Result<Option<u32>> {
546        let entry = self.read_clus(reader, cluster).await? & Self::ENTRY_MASK;
547
548        if Self::is_end_of_chain(entry) {
549            return Ok(None);
550        }
551
552        if Self::is_bad_cluster(entry) {
553            return Err(Error::BadCluster {
554                cluster: cluster as u32,
555            });
556        }
557
558        self.validate_cluster(entry)?;
559
560        Ok(Some(entry as u32))
561    }
562
563    /// Free cluster marker
564    #[cfg(feature = "write")]
565    const FREE_CLUSTER: u16 = 0x0000;
566    /// End of chain marker
567    #[cfg(feature = "write")]
568    const END_OF_CHAIN: u16 = 0x0FF8;
569
570    /// Write a FAT12 entry at the specified cluster index to a specific FAT copy.
571    #[cfg(feature = "write")]
572    async fn write_clus_at<T: Read + Write + Seek>(
573        &self,
574        rw: &mut T,
575        cluster: usize,
576        value: u16,
577        fat_index: usize,
578    ) -> Result<()> {
579        let byte_offset = self.start + fat_index * self.size + (cluster * 3) / 2;
580        rw.seek(SeekFrom::Start(byte_offset as u64)).await?;
581
582        // Read existing bytes (we need to preserve the other half)
583        let mut bytes = [0u8; 2];
584        rw.read_exact(&mut bytes).await?;
585
586        // Modify the appropriate bits
587        if cluster.is_multiple_of(2) {
588            // Even: modify lower 8 bits of bytes[0] and lower 4 bits of bytes[1]
589            bytes[0] = value as u8;
590            bytes[1] = (bytes[1] & 0xF0) | ((value >> 8) as u8 & 0x0F);
591        } else {
592            // Odd: modify upper 4 bits of bytes[0] and all of bytes[1]
593            bytes[0] = (bytes[0] & 0x0F) | ((value << 4) as u8);
594            bytes[1] = (value >> 4) as u8;
595        }
596
597        // Write back
598        rw.seek(SeekFrom::Start(byte_offset as u64)).await?;
599        rw.write_all(&bytes).await?;
600
601        Ok(())
602    }
603
604    /// Write a cluster entry to all FAT table copies
605    #[cfg(feature = "write")]
606    pub async fn write_clus<T: Read + Write + Seek>(
607        &self,
608        rw: &mut T,
609        cluster: usize,
610        value: u16,
611    ) -> Result<()> {
612        for i in 0..self.count {
613            self.write_clus_at(rw, cluster, value, i).await?;
614        }
615        Ok(())
616    }
617
618    /// Allocate a single cluster, returns the allocated cluster number.
619    #[cfg(feature = "write")]
620    pub async fn allocate_cluster<T: Read + Write + Seek>(&self, rw: &mut T, hint: u16) -> Result<u16> {
621        let start = if hint >= Self::FIRST_DATA_CLUSTER && hint <= self.max_cluster {
622            hint
623        } else {
624            Self::FIRST_DATA_CLUSTER
625        };
626
627        // Search from hint to max_cluster
628        for cluster in start..=self.max_cluster {
629            let entry = self.read_clus(rw, cluster as usize).await? & Self::ENTRY_MASK;
630            if entry == Self::FREE_CLUSTER {
631                self.write_clus(rw, cluster as usize, Self::END_OF_CHAIN).await?;
632                return Ok(cluster);
633            }
634        }
635
636        // Wrap around: search from first cluster to hint
637        for cluster in Self::FIRST_DATA_CLUSTER..start {
638            let entry = self.read_clus(rw, cluster as usize).await? & Self::ENTRY_MASK;
639            if entry == Self::FREE_CLUSTER {
640                self.write_clus(rw, cluster as usize, Self::END_OF_CHAIN).await?;
641                return Ok(cluster);
642            }
643        }
644
645        Err(Error::NoFreeSpace)
646    }
647
648    /// Allocate a linked chain of `count` clusters, returning the first cluster.
649    ///
650    /// Each cluster is allocated from a rolling hint (near the previous one) and
651    /// linked to its successor; the last is marked end-of-chain. Mirrors
652    /// [`Fat32::allocate_chain`]. On partial failure the already-allocated
653    /// clusters are not rolled back (matching the FAT32 behavior).
654    #[cfg(feature = "write")]
655    pub async fn allocate_chain<T: Read + Write + Seek>(
656        &self,
657        rw: &mut T,
658        count: usize,
659        hint: u16,
660    ) -> Result<u16> {
661        if count == 0 {
662            return Err(Error::NoFreeSpace);
663        }
664        let first = self.allocate_cluster(rw, hint).await?;
665        let mut prev = first;
666        for _ in 1..count {
667            let next = self.allocate_cluster(rw, prev + 1).await?;
668            self.write_clus(rw, prev as usize, next).await?;
669            prev = next;
670        }
671        Ok(first)
672    }
673
674    /// Extend the chain whose current last cluster is `last` by `count`
675    /// clusters, returning the first newly allocated cluster. If `count` is 0,
676    /// no clusters are allocated and `last` is returned unchanged. Mirrors
677    /// [`Fat32::extend_chain`].
678    #[cfg(feature = "write")]
679    pub async fn extend_chain<T: Read + Write + Seek>(
680        &self,
681        rw: &mut T,
682        last: u16,
683        count: usize,
684        hint: u16,
685    ) -> Result<u16> {
686        if count == 0 {
687            return Ok(last);
688        }
689        let first_new = self.allocate_chain(rw, count, hint).await?;
690        self.write_clus(rw, last as usize, first_new).await?;
691        Ok(first_new)
692    }
693
694    /// Free a cluster chain starting at `start`, returns count of freed clusters.
695    #[cfg(feature = "write")]
696    pub async fn free_chain<T: Read + Write + Seek>(&self, rw: &mut T, start: u16) -> Result<u32> {
697        let mut count = 0u32;
698        let mut current = start;
699
700        loop {
701            if current < Self::FIRST_DATA_CLUSTER || current > self.max_cluster {
702                break;
703            }
704
705            let next = self.read_clus(rw, current as usize).await? & Self::ENTRY_MASK;
706            self.write_clus(rw, current as usize, Self::FREE_CLUSTER).await?;
707            count += 1;
708
709            if Self::is_end_of_chain(next)
710                || Self::is_bad_cluster(next)
711                || next == Self::FREE_CLUSTER
712            {
713                break;
714            }
715
716            current = next;
717        }
718
719        Ok(count)
720    }
721
722    /// Truncate a cluster chain after the specified cluster.
723    ///
724    /// The specified cluster becomes the end of chain (marked with end-of-chain marker).
725    /// All clusters following it are freed.
726    ///
727    /// Returns the number of clusters freed.
728    #[cfg(feature = "write")]
729    pub async fn truncate_chain<T: Read + Write + Seek>(&self, rw: &mut T, cluster: u16) -> Result<u32> {
730        if cluster < Self::FIRST_DATA_CLUSTER || cluster > self.max_cluster {
731            return Ok(0);
732        }
733
734        // Read the next cluster in chain
735        let next = self.read_clus(rw, cluster as usize).await? & Self::ENTRY_MASK;
736
737        // Mark this cluster as end of chain
738        self.write_clus(rw, cluster as usize, Self::END_OF_CHAIN).await?;
739
740        // Free the rest of the chain if there is one
741        if !Self::is_end_of_chain(next)
742            && next >= Self::FIRST_DATA_CLUSTER
743            && next <= self.max_cluster
744        {
745            self.free_chain(rw, next).await
746        } else {
747            Ok(0)
748        }
749    }
750
751    /// Mark a cluster as bad (0x0FF7) in all FAT copies.
752    #[cfg(feature = "write")]
753    pub async fn mark_bad<T: Read + Write + Seek>(&self, rw: &mut T, cluster: u16) -> Result<()> {
754        self.write_clus(rw, cluster as usize, Self::BAD_CLUSTER).await
755    }
756}
757
758/// FAT16 table implementation.
759pub struct Fat16 {
760    start: usize,
761    size: usize,
762    count: usize,
763    max_cluster: u16,
764}
765
766impl Fat16 {
767    /// End of chain markers: 0xFFF8 - 0xFFFF indicate end of cluster chain
768    const END_OF_CHAIN_MIN: u16 = 0xFFF8;
769    /// Bad cluster marker
770    const BAD_CLUSTER: u16 = 0xFFF7;
771    /// First valid data cluster (clusters 0 and 1 are reserved)
772    const FIRST_DATA_CLUSTER: u16 = 2;
773
774    /// Layout fields a [`crate::cache::FatSectorCache`] needs to mirror this
775    /// FAT: `(start_byte, size_per_copy, copy_count)`.
776    #[cfg(feature = "cache")]
777    pub(crate) fn cache_layout(&self) -> (usize, usize, usize) {
778        (self.start, self.size, self.count)
779    }
780
781    /// Creates a FAT16 table descriptor.
782    pub fn new(start: usize, size: usize, count: usize, max_cluster: u16) -> Self {
783        debug_assert!(count == 1 || count == 2);
784        Self {
785            start,
786            size,
787            count,
788            max_cluster,
789        }
790    }
791
792    /// Get the maximum cluster number.
793    pub fn max_cluster(&self) -> u16 {
794        self.max_cluster
795    }
796
797    sync_only! {
798        #[cfg(feature = "tool")]
799        pub(crate) fn entry_offset(&self, cluster: usize) -> usize {
800            debug_assert!(cluster * size_of::<u16>() < self.size);
801            self.start + cluster * size_of::<u16>()
802        }
803    }
804
805    async fn read_clus<T: Read + Seek>(&self, reader: &mut T, cluster: usize) -> Result<u16> {
806        self.read_clus_at(reader, cluster, 0).await
807    }
808
809    /// Read a FAT16 entry from a specific FAT copy (0 = primary, 1 = backup).
810    async fn read_clus_at<T: Read + Seek>(&self, reader: &mut T, cluster: usize, fat_index: usize) -> Result<u16> {
811        let offset = self.start + fat_index * self.size + cluster * size_of::<u16>();
812        reader.seek(SeekFrom::Start(offset as u64)).await?;
813        let mut data = 0u16;
814        reader.read_exact(bytemuck::bytes_of_mut(&mut data)).await?;
815        Ok(u16::from_le(data))
816    }
817
818    /// Check if a cluster value represents end-of-chain
819    fn is_end_of_chain(value: u16) -> bool {
820        value >= Self::END_OF_CHAIN_MIN
821    }
822
823    /// Check if a cluster value represents a bad cluster
824    fn is_bad_cluster(value: u16) -> bool {
825        value == Self::BAD_CLUSTER
826    }
827
828    /// Validate that a cluster number is within bounds
829    fn validate_cluster(&self, cluster: u16) -> Result<()> {
830        if cluster < Self::FIRST_DATA_CLUSTER {
831            return Err(Error::ClusterOutOfBounds {
832                cluster: cluster as u32,
833                max: self.max_cluster as u32,
834            });
835        }
836        if cluster > self.max_cluster {
837            return Err(Error::ClusterOutOfBounds {
838                cluster: cluster as u32,
839                max: self.max_cluster as u32,
840            });
841        }
842        Ok(())
843    }
844
845    /// Returns the next cluster in a chain, or `None` at end-of-chain.
846    pub async fn next_cluster<T: Read + Seek>(
847        &self,
848        reader: &mut T,
849        cluster: usize,
850    ) -> Result<Option<u32>> {
851        let entry = self.read_clus(reader, cluster).await?;
852
853        if Self::is_end_of_chain(entry) {
854            return Ok(None);
855        }
856
857        if Self::is_bad_cluster(entry) {
858            return Err(Error::BadCluster {
859                cluster: cluster as u32,
860            });
861        }
862
863        self.validate_cluster(entry)?;
864
865        Ok(Some(entry as u32))
866    }
867
868    /// Free cluster marker
869    #[cfg(feature = "write")]
870    const FREE_CLUSTER: u16 = 0x0000;
871    /// End of chain marker
872    #[cfg(feature = "write")]
873    const END_OF_CHAIN: u16 = 0xFFF8;
874
875    /// Write a cluster entry to the FAT table at the specified FAT copy
876    #[cfg(feature = "write")]
877    async fn write_clus_at<T: Write + Seek>(
878        &self,
879        writer: &mut T,
880        cluster: usize,
881        value: u16,
882        fat_index: usize,
883    ) -> Result<()> {
884        let offset = self.start + fat_index * self.size + cluster * size_of::<u16>();
885        writer.seek(SeekFrom::Start(offset as u64)).await?;
886        writer.write_all(&value.to_le_bytes()).await?;
887        Ok(())
888    }
889
890    /// Write a cluster entry to all FAT table copies
891    #[cfg(feature = "write")]
892    pub async fn write_clus<T: Write + Seek>(
893        &self,
894        writer: &mut T,
895        cluster: usize,
896        value: u16,
897    ) -> Result<()> {
898        for i in 0..self.count {
899            self.write_clus_at(writer, cluster, value, i).await?;
900        }
901        Ok(())
902    }
903
904    /// Allocate a single cluster, returns the allocated cluster number.
905    #[cfg(feature = "write")]
906    pub async fn allocate_cluster<T: Read + Write + Seek>(&self, rw: &mut T, hint: u16) -> Result<u16> {
907        let start = if hint >= Self::FIRST_DATA_CLUSTER && hint <= self.max_cluster {
908            hint
909        } else {
910            Self::FIRST_DATA_CLUSTER
911        };
912
913        // Search from hint to max_cluster
914        for cluster in start..=self.max_cluster {
915            let entry = self.read_clus(rw, cluster as usize).await?;
916            if entry == Self::FREE_CLUSTER {
917                self.write_clus(rw, cluster as usize, Self::END_OF_CHAIN).await?;
918                return Ok(cluster);
919            }
920        }
921
922        // Wrap around: search from first cluster to hint
923        for cluster in Self::FIRST_DATA_CLUSTER..start {
924            let entry = self.read_clus(rw, cluster as usize).await?;
925            if entry == Self::FREE_CLUSTER {
926                self.write_clus(rw, cluster as usize, Self::END_OF_CHAIN).await?;
927                return Ok(cluster);
928            }
929        }
930
931        Err(Error::NoFreeSpace)
932    }
933
934    /// Allocate a linked chain of `count` clusters, returning the first cluster.
935    ///
936    /// Each cluster is allocated from a rolling hint (near the previous one) and
937    /// linked to its successor; the last is marked end-of-chain. Mirrors
938    /// [`Fat32::allocate_chain`]. On partial failure the already-allocated
939    /// clusters are not rolled back (matching the FAT32 behavior).
940    #[cfg(feature = "write")]
941    pub async fn allocate_chain<T: Read + Write + Seek>(
942        &self,
943        rw: &mut T,
944        count: usize,
945        hint: u16,
946    ) -> Result<u16> {
947        if count == 0 {
948            return Err(Error::NoFreeSpace);
949        }
950        let first = self.allocate_cluster(rw, hint).await?;
951        let mut prev = first;
952        for _ in 1..count {
953            let next = self.allocate_cluster(rw, prev + 1).await?;
954            self.write_clus(rw, prev as usize, next).await?;
955            prev = next;
956        }
957        Ok(first)
958    }
959
960    /// Extend the chain whose current last cluster is `last` by `count`
961    /// clusters, returning the first newly allocated cluster. If `count` is 0,
962    /// no clusters are allocated and `last` is returned unchanged. Mirrors
963    /// [`Fat32::extend_chain`].
964    #[cfg(feature = "write")]
965    pub async fn extend_chain<T: Read + Write + Seek>(
966        &self,
967        rw: &mut T,
968        last: u16,
969        count: usize,
970        hint: u16,
971    ) -> Result<u16> {
972        if count == 0 {
973            return Ok(last);
974        }
975        let first_new = self.allocate_chain(rw, count, hint).await?;
976        self.write_clus(rw, last as usize, first_new).await?;
977        Ok(first_new)
978    }
979
980    /// Free a cluster chain starting at `start`, returns count of freed clusters.
981    #[cfg(feature = "write")]
982    pub async fn free_chain<T: Read + Write + Seek>(&self, rw: &mut T, start: u16) -> Result<u32> {
983        let mut count = 0u32;
984        let mut current = start;
985
986        loop {
987            if current < Self::FIRST_DATA_CLUSTER || current > self.max_cluster {
988                break;
989            }
990
991            let next = self.read_clus(rw, current as usize).await?;
992            self.write_clus(rw, current as usize, Self::FREE_CLUSTER).await?;
993            count += 1;
994
995            if Self::is_end_of_chain(next)
996                || Self::is_bad_cluster(next)
997                || next == Self::FREE_CLUSTER
998            {
999                break;
1000            }
1001
1002            current = next;
1003        }
1004
1005        Ok(count)
1006    }
1007
1008    /// Truncate a cluster chain after the specified cluster.
1009    ///
1010    /// The specified cluster becomes the end of chain (marked with end-of-chain marker).
1011    /// All clusters following it are freed.
1012    ///
1013    /// Returns the number of clusters freed.
1014    #[cfg(feature = "write")]
1015    pub async fn truncate_chain<T: Read + Write + Seek>(&self, rw: &mut T, cluster: u16) -> Result<u32> {
1016        if cluster < Self::FIRST_DATA_CLUSTER || cluster > self.max_cluster {
1017            return Ok(0);
1018        }
1019
1020        // Read the next cluster in chain
1021        let next = self.read_clus(rw, cluster as usize).await?;
1022
1023        // Mark this cluster as end of chain
1024        self.write_clus(rw, cluster as usize, Self::END_OF_CHAIN).await?;
1025
1026        // Free the rest of the chain if there is one
1027        if !Self::is_end_of_chain(next)
1028            && next >= Self::FIRST_DATA_CLUSTER
1029            && next <= self.max_cluster
1030        {
1031            self.free_chain(rw, next).await
1032        } else {
1033            Ok(0)
1034        }
1035    }
1036
1037    /// Mark a cluster as bad (0xFFF7) in all FAT copies.
1038    #[cfg(feature = "write")]
1039    pub async fn mark_bad<T: Read + Write + Seek>(&self, rw: &mut T, cluster: u16) -> Result<()> {
1040        self.write_clus(rw, cluster as usize, Self::BAD_CLUSTER).await
1041    }
1042}
1043
1044/// FAT32 allocation-table descriptor.
1045pub struct Fat32 {
1046    start: usize,
1047    size: usize,
1048    count: usize,
1049    max_cluster: u32,
1050}
1051
1052impl Fat32 {
1053    /// Mask for the 28-bit cluster number (upper 4 bits are reserved)
1054    const ENTRY_MASK: u32 = 0x0FFF_FFFF;
1055    /// End of chain markers: 0x0FFFFFF8 - 0x0FFFFFFF indicate end of cluster chain
1056    const END_OF_CHAIN_MIN: u32 = 0x0FFF_FFF8;
1057    /// Bad cluster marker
1058    const BAD_CLUSTER: u32 = 0x0FFF_FFF7;
1059    /// First valid data cluster (clusters 0 and 1 are reserved)
1060    const FIRST_DATA_CLUSTER: u32 = 2;
1061
1062    /// Layout fields a [`crate::cache::FatSectorCache`] needs to mirror this
1063    /// FAT: `(start_byte, size_per_copy, copy_count)`.
1064    #[cfg(feature = "cache")]
1065    pub(crate) fn cache_layout(&self) -> (usize, usize, usize) {
1066        (self.start, self.size, self.count)
1067    }
1068
1069    /// Creates a FAT32 table descriptor.
1070    pub fn new(start: usize, size: usize, count: usize, max_cluster: u32) -> Self {
1071        debug_assert!(count == 1 || count == 2);
1072        Self {
1073            start,
1074            size,
1075            count,
1076            max_cluster,
1077        }
1078    }
1079
1080    /// Get the maximum cluster number.
1081    pub fn max_cluster(&self) -> u32 {
1082        self.max_cluster
1083    }
1084
1085    sync_only! {
1086        #[cfg(feature = "tool")]
1087        pub(crate) fn entry_offset(&self, cluster: usize) -> usize {
1088            debug_assert!(cluster * size_of::<u32>() < self.size);
1089            self.start + cluster * size_of::<u32>()
1090        }
1091    }
1092
1093    async fn read_clus<T: Read + Seek>(&self, reader: &mut T, cluster: usize) -> Result<u32> {
1094        self.read_clus_at(reader, cluster, 0).await
1095    }
1096
1097    /// Read a FAT32 entry from a specific FAT copy (0 = primary, 1 = backup).
1098    async fn read_clus_at<T: Read + Seek>(&self, reader: &mut T, cluster: usize, fat_index: usize) -> Result<u32> {
1099        let offset = self.start + fat_index * self.size + cluster * size_of::<u32>();
1100        reader.seek(SeekFrom::Start(offset as u64)).await?;
1101        let mut data = 0u32;
1102        reader.read_exact(bytemuck::bytes_of_mut(&mut data)).await?;
1103        Ok(u32::from_le(data))
1104    }
1105
1106    /// Check if a cluster value represents end-of-chain
1107    fn is_end_of_chain(value: u32) -> bool {
1108        value >= Self::END_OF_CHAIN_MIN
1109    }
1110
1111    /// Check if a cluster value represents a bad cluster
1112    fn is_bad_cluster(value: u32) -> bool {
1113        value == Self::BAD_CLUSTER
1114    }
1115
1116    /// Validate that a cluster number is within bounds
1117    fn validate_cluster(&self, cluster: u32) -> Result<()> {
1118        if cluster < Self::FIRST_DATA_CLUSTER {
1119            return Err(Error::ClusterOutOfBounds {
1120                cluster,
1121                max: self.max_cluster,
1122            });
1123        }
1124        if cluster > self.max_cluster {
1125            return Err(Error::ClusterOutOfBounds {
1126                cluster,
1127                max: self.max_cluster,
1128            });
1129        }
1130        Ok(())
1131    }
1132
1133    /// Returns the next cluster in a chain, or `None` at end-of-chain.
1134    pub async fn next_cluster<T: Read + Seek>(
1135        &self,
1136        reader: &mut T,
1137        cluster: usize,
1138    ) -> Result<Option<u32>> {
1139        // Read the FAT entry for this cluster
1140        let raw_entry = self.read_clus(reader, cluster).await?;
1141        let entry = raw_entry & Self::ENTRY_MASK;
1142
1143        // Check for end of chain
1144        if Self::is_end_of_chain(entry) {
1145            return Ok(None);
1146        }
1147
1148        // Check for bad cluster
1149        if Self::is_bad_cluster(entry) {
1150            return Err(Error::BadCluster {
1151                cluster: cluster as u32,
1152            });
1153        }
1154
1155        // Validate the next cluster is in bounds
1156        self.validate_cluster(entry)?;
1157
1158        Ok(Some(entry))
1159    }
1160
1161    /// Write a cluster entry to the FAT table at the specified FAT copy
1162    #[cfg(feature = "write")]
1163    async fn write_clus_at<T: Read + Write + Seek>(
1164        &self,
1165        io: &mut T,
1166        cluster: usize,
1167        value: u32,
1168        fat_index: usize,
1169    ) -> Result<()> {
1170        let offset = self.start + fat_index * self.size + cluster * size_of::<u32>();
1171        io.seek(SeekFrom::Start(offset as u64)).await?;
1172        let mut existing = [0_u8; size_of::<u32>()];
1173        io.read_exact(&mut existing).await?;
1174        let preserved = u32::from_le_bytes(existing) & !Self::ENTRY_MASK;
1175        let updated = preserved | (value & Self::ENTRY_MASK);
1176        io.seek(SeekFrom::Start(offset as u64)).await?;
1177        io.write_all(&updated.to_le_bytes()).await?;
1178        Ok(())
1179    }
1180
1181    /// Write a cluster entry to all FAT table copies
1182    #[cfg(feature = "write")]
1183    pub async fn write_clus<T: Read + Write + Seek>(
1184        &self,
1185        io: &mut T,
1186        cluster: usize,
1187        value: u32,
1188    ) -> Result<()> {
1189        for i in 0..self.count {
1190            self.write_clus_at(io, cluster, value, i).await?;
1191        }
1192        Ok(())
1193    }
1194
1195    /// Free cluster marker
1196    #[cfg(feature = "write")]
1197    const FREE_CLUSTER: u32 = 0x00000000;
1198    /// End of chain marker
1199    #[cfg(feature = "write")]
1200    const END_OF_CHAIN: u32 = 0x0FFFFFF8;
1201
1202    /// Allocate a single cluster, returns the allocated cluster number.
1203    /// Searches starting from `hint` for a free cluster.
1204    #[cfg(feature = "write")]
1205    pub async fn allocate_cluster<T: Read + Write + Seek>(&self, rw: &mut T, hint: u32) -> Result<u32> {
1206        // Start searching from hint, wrapping around if needed
1207        let start = if hint >= Self::FIRST_DATA_CLUSTER && hint <= self.max_cluster {
1208            hint
1209        } else {
1210            Self::FIRST_DATA_CLUSTER
1211        };
1212
1213        // Search from hint to max_cluster
1214        for cluster in start..=self.max_cluster {
1215            let entry = self.read_clus(rw, cluster as usize).await? & Self::ENTRY_MASK;
1216            if entry == Self::FREE_CLUSTER {
1217                // Mark as end of chain
1218                self.write_clus(rw, cluster as usize, Self::END_OF_CHAIN).await?;
1219                return Ok(cluster);
1220            }
1221        }
1222
1223        // Wrap around: search from first cluster to hint
1224        for cluster in Self::FIRST_DATA_CLUSTER..start {
1225            let entry = self.read_clus(rw, cluster as usize).await? & Self::ENTRY_MASK;
1226            if entry == Self::FREE_CLUSTER {
1227                // Mark as end of chain
1228                self.write_clus(rw, cluster as usize, Self::END_OF_CHAIN).await?;
1229                return Ok(cluster);
1230            }
1231        }
1232
1233        Err(Error::NoFreeSpace)
1234    }
1235
1236    /// Allocate a chain of clusters, linking them together.
1237    /// Returns the first cluster of the allocated chain.
1238    #[cfg(feature = "write")]
1239    pub async fn allocate_chain<T: Read + Write + Seek>(
1240        &self,
1241        rw: &mut T,
1242        count: usize,
1243        hint: u32,
1244    ) -> Result<u32> {
1245        if count == 0 {
1246            return Err(Error::NoFreeSpace);
1247        }
1248
1249        let first = self.allocate_cluster(rw, hint).await?;
1250        let mut prev = first;
1251
1252        for _ in 1..count {
1253            let next = self.allocate_cluster(rw, prev + 1).await?;
1254            // Link previous cluster to this one
1255            self.write_clus(rw, prev as usize, next).await?;
1256            prev = next;
1257        }
1258
1259        Ok(first)
1260    }
1261
1262    /// Free a cluster chain starting at `start`, returns count of freed clusters.
1263    #[cfg(feature = "write")]
1264    pub async fn free_chain<T: Read + Write + Seek>(&self, rw: &mut T, start: u32) -> Result<u32> {
1265        let mut count = 0;
1266        let mut current = start;
1267
1268        loop {
1269            // Validate cluster
1270            if current < Self::FIRST_DATA_CLUSTER || current > self.max_cluster {
1271                break;
1272            }
1273
1274            // Read the next cluster before freeing
1275            let raw_entry = self.read_clus(rw, current as usize).await?;
1276            let next = raw_entry & Self::ENTRY_MASK;
1277
1278            // Free this cluster
1279            self.write_clus(rw, current as usize, Self::FREE_CLUSTER).await?;
1280            count += 1;
1281
1282            // Check if this was the end of chain
1283            if Self::is_end_of_chain(next)
1284                || Self::is_bad_cluster(next)
1285                || next == Self::FREE_CLUSTER
1286            {
1287                break;
1288            }
1289
1290            current = next;
1291        }
1292
1293        Ok(count)
1294    }
1295
1296    /// Truncate a cluster chain after the specified cluster.
1297    ///
1298    /// The specified cluster becomes the end of chain (marked with end-of-chain marker).
1299    /// All clusters following it are freed.
1300    ///
1301    /// Returns the number of clusters freed.
1302    #[cfg(feature = "write")]
1303    pub async fn truncate_chain<T: Read + Write + Seek>(&self, rw: &mut T, cluster: u32) -> Result<u32> {
1304        if cluster < Self::FIRST_DATA_CLUSTER || cluster > self.max_cluster {
1305            return Ok(0);
1306        }
1307
1308        // Read the next cluster in chain
1309        let raw_entry = self.read_clus(rw, cluster as usize).await?;
1310        let next = raw_entry & Self::ENTRY_MASK;
1311
1312        // Mark this cluster as end of chain
1313        self.write_clus(rw, cluster as usize, Self::END_OF_CHAIN).await?;
1314
1315        // Free the rest of the chain if there is one
1316        if !Self::is_end_of_chain(next)
1317            && next >= Self::FIRST_DATA_CLUSTER
1318            && next <= self.max_cluster
1319        {
1320            self.free_chain(rw, next).await
1321        } else {
1322            Ok(0)
1323        }
1324    }
1325
1326    /// Mark a cluster as bad (0x0FFFFFF7) in all FAT copies.
1327    #[cfg(feature = "write")]
1328    pub async fn mark_bad<T: Read + Write + Seek>(&self, rw: &mut T, cluster: u32) -> Result<()> {
1329        self.write_clus(rw, cluster as usize, Self::BAD_CLUSTER).await
1330    }
1331
1332    /// Extend a cluster chain by appending new clusters.
1333    /// Returns the first cluster of the newly allocated portion.
1334    #[cfg(feature = "write")]
1335    pub async fn extend_chain<T: Read + Write + Seek>(
1336        &self,
1337        rw: &mut T,
1338        last: u32,
1339        count: usize,
1340        hint: u32,
1341    ) -> Result<u32> {
1342        if count == 0 {
1343            return Ok(last);
1344        }
1345
1346        let first_new = self.allocate_chain(rw, count, hint).await?;
1347        // Link the last cluster of existing chain to the new chain
1348        self.write_clus(rw, last as usize, first_new).await?;
1349        Ok(first_new)
1350    }
1351}
1352
1353} // end io_transform!