From c4e6d5949284f644e0d6bea7081a85697491b2ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Harabie=C5=84?= Date: Wed, 8 Nov 2017 01:23:00 +0100 Subject: [PATCH] Add set_created and set_accessed public functions in File. Small code refactoring included. --- src/dir.rs | 163 ++++++++++++++++++++++++++++++++++++++++------------ src/file.rs | 79 +++++++++++++------------ 2 files changed, 166 insertions(+), 76 deletions(-) diff --git a/src/dir.rs b/src/dir.rs index 48c0dbf..3d442fc 100644 --- a/src/dir.rs +++ b/src/dir.rs @@ -107,13 +107,20 @@ pub(crate) struct DirFileEntryData { } impl DirFileEntryData { + fn new(name: [u8; 11], attrs: FileAttributes) -> Self { + DirFileEntryData { + name, attrs, + ..Default::default() + } + } + pub(crate) fn first_cluster(&self, fat_type: FatType) -> Option { let first_cluster_hi = if fat_type == FatType::Fat32 { self.first_cluster_hi } else { 0 }; let n = ((first_cluster_hi as u32) << 16) | self.first_cluster_lo as u32; if n == 0 { None } else { Some(n) } } - pub(crate) fn set_first_cluster(&mut self, cluster: Option, fat_type: FatType) { + fn set_first_cluster(&mut self, cluster: Option, fat_type: FatType) { let n = cluster.unwrap_or(0); if fat_type == FatType::Fat32 { self.first_cluster_hi = (n >> 16) as u16; @@ -129,7 +136,7 @@ impl DirFileEntryData { } } - pub(crate) fn set_size(&mut self, size: u32) { + fn set_size(&mut self, size: u32) { self.size = size; } @@ -162,19 +169,19 @@ impl DirFileEntryData { self.access_date = date.to_u16(); } - pub(crate) fn set_modified(&mut self, date_time: DateTime) { + fn set_modified(&mut self, date_time: DateTime) { self.modify_date = date_time.date.to_u16(); self.modify_time = date_time.time.to_u16(); } #[cfg(feature = "chrono")] - pub(crate) fn reset_created(&mut self) { + fn reset_created(&mut self) { let now = DateTime::from(chrono::Local::now()); self.set_created(now); } #[cfg(feature = "chrono")] - pub(crate) fn reset_accessed(&mut self) -> bool { + fn reset_accessed(&mut self) -> bool { let now = Date::from(chrono::Local::now().date()); if now == self.accessed() { false @@ -185,30 +192,30 @@ impl DirFileEntryData { } #[cfg(feature = "chrono")] - pub(crate) fn reset_modified(&mut self) { + fn reset_modified(&mut self) { let now = DateTime::from(chrono::Local::now()); self.set_modified(now); } #[cfg(not(feature = "chrono"))] - pub(crate) fn reset_created(&mut self) { + fn reset_created(&mut self) { // nop - user controls timestamps manually false } #[cfg(not(feature = "chrono"))] - pub(crate) fn reset_accessed(&mut self) -> bool { + fn reset_accessed(&mut self) -> bool { // nop - user controls timestamps manually false } #[cfg(not(feature = "chrono"))] - pub(crate) fn reset_modified(&mut self) { + fn reset_modified(&mut self) { // nop - user controls timestamps manually false } - pub(crate) fn serialize(&self, wrt: &mut Write) -> io::Result<()> { + fn serialize(&self, wrt: &mut Write) -> io::Result<()> { wrt.write_all(&self.name)?; wrt.write_u8(self.attrs.bits())?; wrt.write_u8(self.reserved_0)?; @@ -228,6 +235,10 @@ impl DirFileEntryData { self.name[0] == DIR_ENTRY_FREE_FLAG } + fn set_free(&mut self) { + self.name[0] = DIR_ENTRY_FREE_FLAG; + } + fn is_end(&self) -> bool { self.name[0] == 0 } @@ -247,6 +258,20 @@ struct DirLfnEntryData { } impl DirLfnEntryData { + fn new(order: u8, checksum: u8) -> Self { + DirLfnEntryData { + order, checksum, + attrs: FileAttributes::LFN, + ..Default::default() + } + } + + fn copy_name_from_slice(&mut self, lfn_part: &[u16; LFN_PART_LEN]) { + self.name_0.copy_from_slice(&lfn_part[0..5]); + self.name_1.copy_from_slice(&lfn_part[5..5+6]); + self.name_2.copy_from_slice(&lfn_part[11..11+2]); + } + fn serialize(&self, wrt: &mut Write) -> io::Result<()> { wrt.write_u8(self.order)?; for ch in self.name_0.iter() { @@ -269,6 +294,10 @@ impl DirLfnEntryData { self.order == DIR_ENTRY_FREE_FLAG } + fn set_free(&mut self) { + self.order = DIR_ENTRY_FREE_FLAG; + } + fn is_end(&self) -> bool { self.order == 0 } @@ -339,6 +368,13 @@ impl DirEntryData { } } + fn set_free(&mut self) { + match self { + &mut DirEntryData::File(ref mut file) => file.set_free(), + &mut DirEntryData::Lfn(ref mut lfn) => lfn.set_free(), + } + } + fn is_end(&self) -> bool { match self { &DirEntryData::File(ref file) => file.is_end(), @@ -443,13 +479,80 @@ impl From> for DateTime { } #[derive(Clone, Debug)] -pub(crate) struct FileEntryInfo { - pub(crate) data: DirFileEntryData, +pub(crate) struct DirEntryEditor { + data: DirFileEntryData, pos: u64, + dirty: bool, } -impl FileEntryInfo { - pub(crate) fn write(&self, fs: FileSystemRef) -> io::Result<()> { +impl DirEntryEditor { + fn new(data: DirFileEntryData, pos: u64) -> DirEntryEditor { + DirEntryEditor { + data, pos, + dirty: false, + } + } + + pub(crate) fn inner(&self) -> &DirFileEntryData { + &self.data + } + + pub(crate) fn set_first_cluster(&mut self, first_cluster: Option, fat_type: FatType) { + if first_cluster != self.data.first_cluster(fat_type) { + self.data.set_first_cluster(first_cluster, fat_type); + self.dirty = true; + } + } + + pub(crate) fn set_size(&mut self, size: u32) { + match self.data.size() { + Some(n) if size != n => { + self.data.set_size(size); + self.dirty = true; + }, + _ => {}, + } + } + + pub(crate) fn set_created(&mut self, date_time: DateTime) { + if date_time != self.data.created() { + self.data.set_created(date_time); + self.dirty = true; + } + } + + pub(crate) fn set_accessed(&mut self, date: Date) { + if date != self.data.accessed() { + self.data.set_accessed(date); + self.dirty = true; + } + } + + pub(crate) fn set_modified(&mut self, date_time: DateTime) { + if date_time != self.data.modified() { + self.data.set_modified(date_time); + self.dirty = true; + } + } + + pub(crate) fn reset_accessed(&mut self) { + self.dirty |= self.data.reset_accessed(); + } + + pub(crate) fn reset_modified(&mut self) { + self.data.reset_modified(); + self.dirty = true; + } + + pub(crate) fn flush(&mut self, fs: FileSystemRef) -> io::Result<()> { + if self.dirty { + self.write(fs)?; + self.dirty = false; + } + Ok(()) + } + + fn write(&self, fs: FileSystemRef) -> io::Result<()> { let mut disk = fs.disk.borrow_mut(); disk.seek(io::SeekFrom::Start(self.pos))?; self.data.serialize(&mut *disk) @@ -510,11 +613,8 @@ impl <'a, 'b> DirEntry<'a, 'b> { self.data.first_cluster(self.fs.fat_type) } - fn entry_info(&self) -> FileEntryInfo { - FileEntryInfo { - data: self.data.clone(), - pos: self.entry_pos, - } + fn entry_info(&self) -> DirEntryEditor { + DirEntryEditor::new(self.data.clone(), self.entry_pos) } /// Returns File struct for this entry. @@ -700,11 +800,7 @@ impl <'a, 'b> Dir<'a, 'b> { for _ in 0..num { let mut data = DirEntryData::deserialize(&mut stream)?; trace!("removing dir entry {:?}", data); - match data { - DirEntryData::File(ref mut data) => - data.name[0] = DIR_ENTRY_FREE_FLAG, - DirEntryData::Lfn(ref mut data) => data.order = DIR_ENTRY_FREE_FLAG, - }; + data.set_free(); stream.seek(SeekFrom::Current(-(DIR_ENTRY_SIZE as i64)))?; data.serialize(&mut stream)?; } @@ -821,24 +917,15 @@ impl <'a, 'b> Dir<'a, 'b> { if lfn_part_len < LFN_PART_LEN { lfn_part[lfn_part_len] = 0; } - let mut lfn_entry = DirLfnEntryData { - order, - attrs: FileAttributes::LFN, - checksum: lfn_chsum, - ..Default::default() - }; - lfn_entry.name_0.copy_from_slice(&lfn_part[0..5]); - lfn_entry.name_1.copy_from_slice(&lfn_part[5..5+6]); - lfn_entry.name_2.copy_from_slice(&lfn_part[11..11+2]); + let mut lfn_entry = DirLfnEntryData::new(order, lfn_chsum); + lfn_entry.copy_name_from_slice(&lfn_part); lfn_entry.serialize(&mut stream)?; } - let mut raw_entry = DirFileEntryData { - name: short_name, - attrs, - ..Default::default() - }; + let mut raw_entry = DirFileEntryData::new(short_name, attrs); raw_entry.set_first_cluster(first_cluster, self.fs.fat_type); raw_entry.reset_created(); + raw_entry.reset_accessed(); + raw_entry.reset_modified(); raw_entry.serialize(&mut stream)?; let end_pos = stream.seek(io::SeekFrom::Current(0))?; let abs_pos = stream.abs_pos().map(|p| p - DIR_ENTRY_SIZE); diff --git a/src/file.rs b/src/file.rs index e76df70..ffc689e 100644 --- a/src/file.rs +++ b/src/file.rs @@ -4,7 +4,7 @@ use std::io::{SeekFrom, ErrorKind}; use std::io; use fs::FileSystemRef; -use dir::{FileEntryInfo, DateTime}; +use dir::{DirEntryEditor, DateTime, Date}; /// FAT file used for reading and writing. #[derive(Clone)] @@ -16,19 +16,17 @@ pub struct File<'a, 'b: 'a> { // current position in this file offset: u32, // file dir entry - None for root dir - entry: Option, - // should file dir entry be flushed? - entry_dirty: bool, + entry: Option, + // file-system reference fs: FileSystemRef<'a, 'b>, } impl <'a, 'b> File<'a, 'b> { - pub(crate) fn new(first_cluster: Option, entry: Option, fs: FileSystemRef<'a, 'b>) -> Self { + pub(crate) fn new(first_cluster: Option, entry: Option, fs: FileSystemRef<'a, 'b>) -> Self { File { first_cluster, entry, fs, current_cluster: None, // cluster before first one offset: 0, - entry_dirty: false, } } @@ -36,11 +34,10 @@ impl <'a, 'b> File<'a, 'b> { let offset = self.offset; match self.entry { Some(ref mut e) => { - e.data.reset_modified(); - if e.data.size().map_or(false, |s| offset > s) { - e.data.set_size(offset); + e.reset_modified(); + if e.inner().size().map_or(false, |s| offset > s) { + e.set_size(offset); } - self.entry_dirty = true; }, _ => {}, } @@ -48,18 +45,12 @@ impl <'a, 'b> File<'a, 'b> { /// Truncate file to current position. pub fn truncate(&mut self) -> io::Result<()> { - let offset = self.offset; match self.entry { Some(ref mut e) => { - if e.data.size().map_or(false, |s| offset == s) { - return Ok(()); - } - - e.data.set_size(self.offset); + e.set_size(self.offset); if self.offset == 0 { - e.data.set_first_cluster(None, self.fs.fat_type); + e.set_first_cluster(None, self.fs.fat_type); } - self.entry_dirty = true; }, _ => {}, } @@ -91,32 +82,47 @@ impl <'a, 'b> File<'a, 'b> { } } - pub(crate) fn flush_dir_entry(&self) -> io::Result<()> { - if self.entry_dirty { - match self.entry { - Some(ref e) => e.write(self.fs)?, - _ => {}, - } + pub(crate) fn flush_dir_entry(&mut self) -> io::Result<()> { + match self.entry { + Some(ref mut e) => e.flush(self.fs)?, + _ => {}, } Ok(()) } + /// Set date and time of creation for this file. + /// + /// Note: if chrono feature is enabled (default) library automatically updates all timestamps + pub fn set_created(&mut self, date_time: DateTime) { + match self.entry { + Some(ref mut e) => e.set_created(date_time), + _ => {}, + } + } + + /// Set date of last access for this file. + /// + /// Note: if chrono feature is enabled (default) library automatically updates all timestamps + pub fn set_accessed(&mut self, date: Date) { + match self.entry { + Some(ref mut e) => e.set_accessed(date), + _ => {}, + } + } + /// Set date and time of last modification for this file. /// /// Note: if chrono feature is enabled (default) library automatically updates all timestamps pub fn set_modified(&mut self, date_time: DateTime) { match self.entry { - Some(ref mut e) => { - e.data.set_modified(date_time); - self.entry_dirty = true; - }, + Some(ref mut e) => e.set_modified(date_time), _ => {}, } } fn bytes_left_in_file(&self) -> Option { match self.entry { - Some(ref e) => e.data.size().map(|s| (s - self.offset) as usize), + Some(ref e) => e.inner().size().map(|s| (s - self.offset) as usize), None => None, } } @@ -124,12 +130,9 @@ impl <'a, 'b> File<'a, 'b> { fn set_first_cluster(&mut self, cluster: u32) { self.first_cluster = Some(cluster); match self.entry { - Some(ref mut e) => { - e.data.set_first_cluster(self.first_cluster, self.fs.fat_type); - }, + Some(ref mut e) => e.set_first_cluster(self.first_cluster, self.fs.fat_type), None => {}, } - self.entry_dirty = true; } pub(crate) fn first_cluster(&self) -> Option { @@ -190,7 +193,7 @@ impl<'a, 'b> Read for File<'a, 'b> { self.current_cluster = Some(current_cluster); match self.entry { - Some(ref mut e) if !self.fs.read_only => self.entry_dirty |= e.data.reset_accessed(), + Some(ref mut e) if !self.fs.read_only => e.reset_accessed(), _ => {}, } Ok(read_bytes) @@ -230,7 +233,7 @@ impl<'a, 'b> Write for File<'a, 'b> { if self.first_cluster.is_none() { self.set_first_cluster(new_cluster); } - if self.entry.clone().map_or(true, |e| e.data.size().is_none()) { + if self.entry.clone().map_or(true, |e| e.inner().size().is_none()) { // zero new directory cluster trace!("zeroing directory cluser {}", new_cluster); let abs_pos = self.fs.offset_from_cluster(new_cluster); @@ -279,16 +282,16 @@ impl<'a, 'b> Seek for File<'a, 'b> { let mut new_pos = match pos { SeekFrom::Current(x) => self.offset as i64 + x, SeekFrom::Start(x) => x as i64, - SeekFrom::End(x) => self.entry.iter().next().map_or(None, |e| e.data.size()).expect("cannot seek from end if size is unknown") as i64 + x, + SeekFrom::End(x) => self.entry.iter().next().map_or(None, |e| e.inner().size()).expect("cannot seek from end if size is unknown") as i64 + x, }; if new_pos < 0 { return Err(io::Error::new(ErrorKind::InvalidInput, "invalid seek")); } new_pos = match self.entry { Some(ref e) => { - if e.data.size().map_or(false, |s| new_pos > s as i64) { + if e.inner().size().map_or(false, |s| new_pos > s as i64) { info!("seek beyond end of file"); - e.data.size().unwrap() as i64 // safe + e.inner().size().unwrap() as i64 // safe } else { new_pos }