Add read_status_flags API for getting dirty and IO error volume flags.

This commit is contained in:
Rafał Harabień 2017-12-01 17:24:02 +01:00
parent 2318bd0c5c
commit 8bb24994e0
3 changed files with 89 additions and 9 deletions

View File

@ -8,7 +8,7 @@ use byteorder::{LittleEndian, ReadBytesExt};
use file::File; use file::File;
use dir::{DirRawStream, Dir}; use dir::{DirRawStream, Dir};
use dir_entry::DIR_ENTRY_SIZE; use dir_entry::DIR_ENTRY_SIZE;
use table::{ClusterIterator, alloc_cluster}; use table::{ClusterIterator, alloc_cluster, read_fat_flags};
// FAT implementation based on: // FAT implementation based on:
// http://wiki.osdev.org/FAT // 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 {} pub trait ReadSeek: Read + Seek {}
impl<T> ReadSeek for T where T: Read + Seek {} impl<T> ReadSeek for T where T: Read + Seek {}
@ -137,6 +142,13 @@ impl BiosParameterBlock {
fn active_fat(&self) -> u16 { fn active_fat(&self) -> u16 {
self.extended_flags & 0x0F 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)] #[allow(dead_code)]
@ -317,6 +329,15 @@ impl <'a> FileSystem<'a> {
let mut disk_slice = self.fat_slice(); let mut disk_slice = self.fat_slice();
alloc_cluster(&mut disk_slice, self.fat_type, prev_cluster) alloc_cluster(&mut disk_slice, self.fat_type, prev_cluster)
} }
pub fn read_status_flags(&self) -> io::Result<FsStatusFlags> {
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)] #[derive(Clone)]

View File

@ -1,7 +1,7 @@
use std::io; use std::io;
use std::io::prelude::*; use std::io::prelude::*;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use fs::{FatType, DiskSlice, ReadSeek}; use fs::{FatType, FsStatusFlags, DiskSlice, ReadSeek};
struct Fat<T> { struct Fat<T> {
#[allow(dead_code)] #[allow(dead_code)]
@ -24,6 +24,7 @@ trait FatTrait {
fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result<FatValue>; fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result<FatValue>;
fn set(fat: &mut DiskSlice, cluster: u32, value: FatValue) -> io::Result<()>; fn set(fat: &mut DiskSlice, cluster: u32, value: FatValue) -> io::Result<()>;
fn find_free(fat: &mut ReadSeek, hint_cluster: u32) -> io::Result<u32>; fn find_free(fat: &mut ReadSeek, hint_cluster: u32) -> io::Result<u32>;
fn get_raw(fat: &mut ReadSeek, cluster: u32) -> io::Result<u32>;
} }
fn read_fat(fat: &mut ReadSeek, fat_type: FatType, cluster: u32) -> io::Result<FatValue> { fn read_fat(fat: &mut ReadSeek, fat_type: FatType, cluster: u32) -> io::Result<FatValue> {
@ -70,15 +71,43 @@ pub(crate) fn alloc_cluster(fat: &mut DiskSlice, fat_type: FatType, prev_cluster
Ok(new_cluster) Ok(new_cluster)
} }
pub(crate) fn read_fat_flags(fat: &mut DiskSlice, fat_type: FatType) -> io::Result<FsStatusFlags> {
// 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 { impl FatTrait for Fat12 {
fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result<FatValue> { fn get_raw(fat: &mut ReadSeek, cluster: u32) -> io::Result<u32> {
let fat_offset = cluster + (cluster / 2); let fat_offset = cluster + (cluster / 2);
fat.seek(io::SeekFrom::Start(fat_offset as u64))?; fat.seek(io::SeekFrom::Start(fat_offset as u64))?;
let packed_val = fat.read_u16::<LittleEndian>()?; let packed_val = fat.read_u16::<LittleEndian>()?;
let val = match cluster & 1 { Ok(match cluster & 1 {
0 => packed_val & 0x0FFF, 0 => packed_val & 0x0FFF,
_ => packed_val >> 4, _ => packed_val >> 4,
}; } as u32)
}
fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result<FatValue> {
let val = Self::get_raw(fat, cluster)?;
Ok(match val { Ok(match val {
0 => FatValue::Free, 0 => FatValue::Free,
0xFF7 => FatValue::Bad, 0xFF7 => FatValue::Bad,
@ -132,9 +161,13 @@ impl FatTrait for Fat12 {
} }
impl FatTrait for Fat16 { impl FatTrait for Fat16 {
fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result<FatValue> { fn get_raw(fat: &mut ReadSeek, cluster: u32) -> io::Result<u32> {
fat.seek(io::SeekFrom::Start((cluster*2) as u64))?; fat.seek(io::SeekFrom::Start((cluster*2) as u64))?;
let val = fat.read_u16::<LittleEndian>()?; Ok(fat.read_u16::<LittleEndian>()? as u32)
}
fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result<FatValue> {
let val = Self::get_raw(fat, cluster)?;
Ok(match val { Ok(match val {
0 => FatValue::Free, 0 => FatValue::Free,
0xFFF7 => FatValue::Bad, 0xFFF7 => FatValue::Bad,
@ -169,9 +202,13 @@ impl FatTrait for Fat16 {
} }
impl FatTrait for Fat32 { impl FatTrait for Fat32 {
fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result<FatValue> { fn get_raw(fat: &mut ReadSeek, cluster: u32) -> io::Result<u32> {
fat.seek(io::SeekFrom::Start((cluster*4) as u64))?; fat.seek(io::SeekFrom::Start((cluster*4) as u64))?;
let val = fat.read_u32::<LittleEndian>()? & 0x0FFFFFFF; Ok(fat.read_u32::<LittleEndian>()? & 0x0FFFFFFF)
}
fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result<FatValue> {
let val = Self::get_raw(fat, cluster)?;
Ok(match val { Ok(match val {
0 => FatValue::Free, 0 => FatValue::Free,
0x0FFFFFF7 => FatValue::Bad, 0x0FFFFFF7 => FatValue::Bad,

View File

@ -188,3 +188,25 @@ fn test_volume_metadata_fat16() {
fn test_volume_metadata_fat32() { fn test_volume_metadata_fat32() {
call_with_fs(&|fs| test_volume_metadata(fs, FatType::Fat32), FAT32_IMG) 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)
}