diff --git a/src/fs.rs b/src/fs.rs index 57a4b6e..6e63294 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -8,7 +8,7 @@ use byteorder::{LittleEndian, ReadBytesExt}; use file::File; use dir::{DirRawStream, Dir}; use dir_entry::DIR_ENTRY_SIZE; -use table::{ClusterIterator, alloc_cluster}; +use table::{ClusterIterator, alloc_cluster, read_fat_flags}; // FAT implementation based on: // http://wiki.osdev.org/FAT @@ -31,6 +31,11 @@ impl FatType { } } +pub struct FsStatusFlags { + pub dirty: bool, + pub io_error: bool, +} + pub trait ReadSeek: Read + Seek {} impl ReadSeek for T where T: Read + Seek {} @@ -137,6 +142,13 @@ impl BiosParameterBlock { fn active_fat(&self) -> u16 { self.extended_flags & 0x0F } + + fn status_flags(&self) -> FsStatusFlags { + FsStatusFlags { + dirty: self.reserved_1 & 1 != 0, + io_error: self.reserved_1 & 2 != 0, + } + } } #[allow(dead_code)] @@ -317,6 +329,15 @@ impl <'a> FileSystem<'a> { let mut disk_slice = self.fat_slice(); alloc_cluster(&mut disk_slice, self.fat_type, prev_cluster) } + + pub fn read_status_flags(&self) -> io::Result { + let bpb_status = self.bpb.status_flags(); + let fat_status = read_fat_flags(&mut self.fat_slice(), self.fat_type)?; + Ok(FsStatusFlags { + dirty: bpb_status.dirty || fat_status.dirty, + io_error: bpb_status.io_error || fat_status.io_error, + }) + } } #[derive(Clone)] diff --git a/src/table.rs b/src/table.rs index 0851335..f955709 100644 --- a/src/table.rs +++ b/src/table.rs @@ -1,7 +1,7 @@ use std::io; use std::io::prelude::*; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use fs::{FatType, DiskSlice, ReadSeek}; +use fs::{FatType, FsStatusFlags, DiskSlice, ReadSeek}; struct Fat { #[allow(dead_code)] @@ -24,6 +24,7 @@ trait FatTrait { fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result; fn set(fat: &mut DiskSlice, cluster: u32, value: FatValue) -> io::Result<()>; fn find_free(fat: &mut ReadSeek, hint_cluster: u32) -> io::Result; + fn get_raw(fat: &mut ReadSeek, cluster: u32) -> io::Result; } fn read_fat(fat: &mut ReadSeek, fat_type: FatType, cluster: u32) -> io::Result { @@ -70,15 +71,43 @@ pub(crate) fn alloc_cluster(fat: &mut DiskSlice, fat_type: FatType, prev_cluster Ok(new_cluster) } + + +pub(crate) fn read_fat_flags(fat: &mut DiskSlice, fat_type: FatType) -> io::Result { + // check MSB (except in FAT12) + let val = match fat_type { + FatType::Fat12 => 0xFFF, + FatType::Fat16 => Fat16::get_raw(fat, 1)?, + FatType::Fat32 => Fat32::get_raw(fat, 1)?, + }; + let dirty = match fat_type { + FatType::Fat12 => false, + FatType::Fat16 => val & (1 << 15) == 0, + FatType::Fat32 => val & (1 << 27) == 0, + }; + let io_error = match fat_type { + FatType::Fat12 => false, + FatType::Fat16 => val & (1 << 14) == 0, + FatType::Fat32 => val & (1 << 26) == 0, + }; + Ok(FsStatusFlags { + dirty, io_error, + }) +} + impl FatTrait for Fat12 { - fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result { + fn get_raw(fat: &mut ReadSeek, cluster: u32) -> io::Result { let fat_offset = cluster + (cluster / 2); fat.seek(io::SeekFrom::Start(fat_offset as u64))?; let packed_val = fat.read_u16::()?; - let val = match cluster & 1 { + Ok(match cluster & 1 { 0 => packed_val & 0x0FFF, _ => packed_val >> 4, - }; + } as u32) + } + + fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result { + let val = Self::get_raw(fat, cluster)?; Ok(match val { 0 => FatValue::Free, 0xFF7 => FatValue::Bad, @@ -132,9 +161,13 @@ impl FatTrait for Fat12 { } impl FatTrait for Fat16 { - fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result { + fn get_raw(fat: &mut ReadSeek, cluster: u32) -> io::Result { fat.seek(io::SeekFrom::Start((cluster*2) as u64))?; - let val = fat.read_u16::()?; + Ok(fat.read_u16::()? as u32) + } + + fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result { + let val = Self::get_raw(fat, cluster)?; Ok(match val { 0 => FatValue::Free, 0xFFF7 => FatValue::Bad, @@ -169,9 +202,13 @@ impl FatTrait for Fat16 { } impl FatTrait for Fat32 { - fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result { + fn get_raw(fat: &mut ReadSeek, cluster: u32) -> io::Result { fat.seek(io::SeekFrom::Start((cluster*4) as u64))?; - let val = fat.read_u32::()? & 0x0FFFFFFF; + Ok(fat.read_u32::()? & 0x0FFFFFFF) + } + + fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result { + let val = Self::get_raw(fat, cluster)?; Ok(match val { 0 => FatValue::Free, 0x0FFFFFF7 => FatValue::Bad, diff --git a/tests/read.rs b/tests/read.rs index bad06e2..bf00d1d 100644 --- a/tests/read.rs +++ b/tests/read.rs @@ -188,3 +188,25 @@ fn test_volume_metadata_fat16() { fn test_volume_metadata_fat32() { call_with_fs(&|fs| test_volume_metadata(fs, FatType::Fat32), FAT32_IMG) } + +fn test_status_flags(fs: FileSystem) { + let status_flags = fs.read_status_flags().unwrap(); + assert_eq!(status_flags.dirty, false); + assert_eq!(status_flags.io_error, false); +} + +#[test] +fn test_status_flags_fat12() { + call_with_fs(&|fs| test_status_flags(fs), FAT12_IMG) +} + +#[test] +fn test_status_flags_fat16() { + call_with_fs(&|fs| test_status_flags(fs), FAT16_IMG) +} + +#[test] +fn test_status_flags_fat32() { + call_with_fs(&|fs| test_status_flags(fs), FAT32_IMG) +} +