diff --git a/Cargo.lock b/Cargo.lock index 821c112..741476f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,6 +3,7 @@ name = "rust-fat" version = "0.1.0" dependencies = [ "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -10,5 +11,97 @@ name = "byteorder" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "chrono" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.31" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "num" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-integer" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-iter" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "redox_syscall" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "time" +version = "0.1.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [metadata] "checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d" +"checksum chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c20ebe0b2b08b0aeddba49c609fe7957ba2e33449882cb186a180bc60682fa9" +"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "d1419b2939a0bc44b77feb34661583c7546b532b192feab36249ab584b86856c" +"checksum num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "a311b77ebdc5dd4cf6449d81e4135d9f0e3b153839ac90e648a8ef538f923525" +"checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba" +"checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01" +"checksum num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "99843c856d68d8b4313b03a17e33c4bb42ae8f6610ea81b28abe076ac721b9b0" +"checksum redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "8dde11f18c108289bef24469638a04dce49da56084f2d50618b226e47eb04509" +"checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520" +"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" +"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/Cargo.toml b/Cargo.toml index 5ec99d0..7fe934f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,3 +5,4 @@ authors = ["Rafał Harabień "] [dependencies] byteorder = "1" +chrono = "0.4" diff --git a/src/dir.rs b/src/dir.rs index d6c33f6..b987e77 100644 --- a/src/dir.rs +++ b/src/dir.rs @@ -1,11 +1,11 @@ -use std::fs::File; use std::io::prelude::*; -use std::io::BufReader; use std::io; use std::str; -use std::io::{Error, ErrorKind, SeekFrom}; use byteorder::{LittleEndian, ReadBytesExt}; -use fs::{FatFileSystem, FatType}; +use fs::FatFileSystem; +use file::FatFile; +use std::io::Cursor; +use chrono::{DateTime, Date, TimeZone, Local}; #[derive(Debug, PartialEq)] #[allow(dead_code)] @@ -24,50 +24,74 @@ pub struct FatDirEntry { name: [u8; 11], attrs: u8, reserved_0: u8, - creation_time_0: u8, - creation_time_1: u16, - creation_date: u16, + create_time_0: u8, + create_time_1: u16, + create_date: u16, access_date: u16, first_cluster_hi: u16, - mod_time: u16, - mod_date: u16, + modify_time: u16, + modify_date: u16, first_cluster_lo: u16, size: u32, } -pub struct FatDir { - cluster: u32, +fn convert_date(dos_date: u16) -> Date { + let (year, month, day) = ((dos_date >> 9) + 1980, (dos_date >> 5) & 0xF, dos_date & 0x1F); + Local.ymd(year as i32, month as u32, day as u32) } -impl FatDir { - pub fn new(cluster: u32) -> FatDir { - FatDir { - cluster: cluster, - } +fn convert_date_time(dos_date: u16, dos_time: u16) -> DateTime { + let (hour, min, sec) = (dos_time >> 11, (dos_time >> 5) & 0x3F, (dos_time & 0x1F) * 2); + convert_date(dos_date).and_hms(hour as u32, min as u32, sec as u32) +} + +impl FatDirEntry { + + pub fn get_name(&self) -> String { + return str::from_utf8(&self.name).unwrap().trim_right().to_string(); + } + + pub fn get_cluster(&self) -> u32 { + ((self.first_cluster_hi as u32) << 16) | self.first_cluster_lo as u32 + } + + pub fn get_file(&self, fs: &FatFileSystem) -> FatFile { + FatFile::new(fs.sector_from_cluster(self.get_cluster()), self.size) + } + + pub fn get_size(&self) -> u32 { + self.size + } + + pub fn get_create_time(&self) -> DateTime { + convert_date_time(self.create_date, self.create_time_1) + } + + pub fn get_access_date(&self) -> Date { + convert_date(self.access_date) + } + + pub fn get_modify_time(&self) -> DateTime { + convert_date_time(self.modify_date, self.modify_time) } } -trait DirEntry { - fn get_name(&self) -> str; -} - -trait ReadDir { - fn read_dir(&mut self, dir: &FatDir) -> io::Result>; -} - impl FatFileSystem { - pub fn read_dir(&mut self, dir: FatDir) -> io::Result> { + pub fn read_dir(&mut self, dir: &mut FatFile) -> io::Result> { + + let mut cur = Cursor::new(vec![0; 512]); + self.read(dir, cur.get_mut())?; + let mut entries = Vec::new(); loop { - let entry = read_dir_entry(&mut self.rdr)?; + let entry = read_dir_entry(&mut cur)?; if entry.name[0] == 0 { break; // end of dir } if entry.name[0] == 0xE5 { continue; // deleted } - let name_str = str::from_utf8(&entry.name).unwrap().trim_right(); - println!("name {} size {} cluster {}", name_str, entry.size, entry.first_cluster_lo); + entries.push(entry); } Ok(entries) } @@ -80,41 +104,14 @@ fn read_dir_entry(rdr: &mut Read) -> io::Result { name: name, attrs: rdr.read_u8()?, reserved_0: rdr.read_u8()?, - creation_time_0: rdr.read_u8()?, - creation_time_1: rdr.read_u16::()?, - creation_date: rdr.read_u16::()?, + create_time_0: rdr.read_u8()?, + create_time_1: rdr.read_u16::()?, + create_date: rdr.read_u16::()?, access_date: rdr.read_u16::()?, first_cluster_hi: rdr.read_u16::()?, - mod_time: rdr.read_u16::()?, - mod_date: rdr.read_u16::()?, + modify_time: rdr.read_u16::()?, + modify_date: rdr.read_u16::()?, first_cluster_lo: rdr.read_u16::()?, size: rdr.read_u32::()?, }) } - -// impl FatDir { -// pub fn new(rdr: &mut Read) -> io::Result { -// let dir = FatDir { -// entries: Vec::new(), -// }; -// read_dir_entry(rdr)?; -// Ok(dir) -// } -// -// pub fn print(&mut self) -> io::Result<()> { -// //let pos = self.rdr.seek(SeekFrom::Current(0))?; -// //println!("Reading dir at {}", pos); -// loop { -// let entry = self.read_dir_entry()?; -// if entry.name[0] == 0 { -// break; // end of dir -// } -// if entry.name[0] == 0xE5 { -// continue; // deleted -// } -// let name_str = str::from_utf8(&entry.name).unwrap().trim_right(); -// println!("name {} size {} cluster {}", name_str, entry.size, entry.first_cluster_lo); -// } -// Ok(()) -// } -// } diff --git a/src/file.rs b/src/file.rs new file mode 100644 index 0000000..6d5b1d1 --- /dev/null +++ b/src/file.rs @@ -0,0 +1,34 @@ +use std::io::prelude::*; +use std::io; +use fs::FatFileSystem; + +#[allow(dead_code)] +pub struct FatFile { + first_sector: u32, + size: u32, + offset: u32, +} + +impl FatFile { + pub fn new(first_sector: u32, size: u32) -> FatFile { + FatFile { first_sector, size, offset: 0 } + } +} + +impl FatFileSystem { + + pub fn file_from_cluster(&mut self, cluster: u32, size: u32) -> FatFile { + FatFile { + first_sector: self.sector_from_cluster(cluster), + size: size, + offset: 0, + } + } + + pub fn read(&mut self, file: &mut FatFile, buf: &mut [u8]) -> io::Result { + self.seek_to_sector(file.first_sector as u64)?; + let size = self.rdr.read(buf)?; + file.offset += size as u32; + Ok(size) + } +} diff --git a/src/fs.rs b/src/fs.rs index cf0c402..a4cc73c 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -1,11 +1,9 @@ -use std::fs::File; use std::io::prelude::*; -use std::io::BufReader; use std::io; use std::str; use std::io::{Error, ErrorKind, SeekFrom}; use byteorder::{LittleEndian, ReadBytesExt}; -use dir::FatDir; +use file::FatFile; // FAT implementation based on: // http://wiki.osdev.org/FAT @@ -16,11 +14,12 @@ pub enum FatType { Fat12, Fat16, Fat32, ExFat } +#[allow(dead_code)] pub struct FatFileSystem { pub(crate) rdr: T, pub(crate) fat_type: FatType, pub(crate) boot: FatBootRecord, - pub(crate) first_fat_sector: u32, + first_fat_sector: u32, pub(crate) first_data_sector: u32, pub(crate) root_dir_sectors: u32, } @@ -197,13 +196,17 @@ impl FatFileSystem { pub fn sector_from_cluster(&self, cluster: u32) -> u32 { ((cluster - 2) * self.boot.bpb.sectors_per_cluster as u32) + self.first_data_sector } - - pub fn open_root_dir(&mut self) -> io::Result { - let first_root_dir_sector = match self.fat_type { + + pub(crate) fn get_root_dir_sector(&self) -> u32 { + match self.fat_type { FatType::Fat12 | FatType::Fat16 => self.first_data_sector - self.root_dir_sectors, _ => self.sector_from_cluster(self.boot.bpb.root_cluster) - }; - self.seek_to_sector(first_root_dir_sector as u64)?; - Ok(FatDir::new(0)) + } + } + + pub fn root_dir(&mut self) -> FatFile { + let first_root_dir_sector = self.get_root_dir_sector(); + let root_dir_size = self.root_dir_sectors * self.boot.bpb.bytes_per_sector as u32; + FatFile::new(first_root_dir_sector, root_dir_size) } } diff --git a/src/main.rs b/src/main.rs index 1222c10..f86ee53 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,23 +1,26 @@ extern crate byteorder; +extern crate chrono; use std::fs::File; -use std::io::prelude::*; use std::io::BufReader; use std::io; use std::str; -use std::io::{Error, ErrorKind, SeekFrom}; -use byteorder::{LittleEndian, ReadBytesExt}; use fs::FatFileSystem; -mod fs; -mod dir; +pub mod fs; +pub mod dir; +pub mod file; fn fat_test() -> io::Result<()> { let file = File::open("resources/floppy.img")?; let mut buf_rdr = BufReader::new(file); let mut fs = FatFileSystem::new(&mut buf_rdr)?; - let root_dir = fs.open_root_dir()?; - fs.read_dir(root_dir)?; + let mut root_dir = fs.root_dir(); + let entries = fs.read_dir(&mut root_dir)?; + for e in entries { + println!("{} - size {} - modified {}", e.get_name(), e.get_size(), e.get_modify_time()); + //println!("name {} size {} cluster {}", name_str, entry.size, entry.first_cluster_lo); + } Ok(()) }