Add set_created and set_accessed public functions in File.

Small code refactoring included.
This commit is contained in:
Rafał Harabień 2017-11-08 01:23:00 +01:00
parent b38ea78f3e
commit c4e6d59492
2 changed files with 166 additions and 76 deletions

View File

@ -107,13 +107,20 @@ pub(crate) struct DirFileEntryData {
} }
impl 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<u32> { pub(crate) fn first_cluster(&self, fat_type: FatType) -> Option<u32> {
let first_cluster_hi = if fat_type == FatType::Fat32 { self.first_cluster_hi } else { 0 }; 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; let n = ((first_cluster_hi as u32) << 16) | self.first_cluster_lo as u32;
if n == 0 { None } else { Some(n) } if n == 0 { None } else { Some(n) }
} }
pub(crate) fn set_first_cluster(&mut self, cluster: Option<u32>, fat_type: FatType) { fn set_first_cluster(&mut self, cluster: Option<u32>, fat_type: FatType) {
let n = cluster.unwrap_or(0); let n = cluster.unwrap_or(0);
if fat_type == FatType::Fat32 { if fat_type == FatType::Fat32 {
self.first_cluster_hi = (n >> 16) as u16; 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; self.size = size;
} }
@ -162,19 +169,19 @@ impl DirFileEntryData {
self.access_date = date.to_u16(); 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_date = date_time.date.to_u16();
self.modify_time = date_time.time.to_u16(); self.modify_time = date_time.time.to_u16();
} }
#[cfg(feature = "chrono")] #[cfg(feature = "chrono")]
pub(crate) fn reset_created(&mut self) { fn reset_created(&mut self) {
let now = DateTime::from(chrono::Local::now()); let now = DateTime::from(chrono::Local::now());
self.set_created(now); self.set_created(now);
} }
#[cfg(feature = "chrono")] #[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()); let now = Date::from(chrono::Local::now().date());
if now == self.accessed() { if now == self.accessed() {
false false
@ -185,30 +192,30 @@ impl DirFileEntryData {
} }
#[cfg(feature = "chrono")] #[cfg(feature = "chrono")]
pub(crate) fn reset_modified(&mut self) { fn reset_modified(&mut self) {
let now = DateTime::from(chrono::Local::now()); let now = DateTime::from(chrono::Local::now());
self.set_modified(now); self.set_modified(now);
} }
#[cfg(not(feature = "chrono"))] #[cfg(not(feature = "chrono"))]
pub(crate) fn reset_created(&mut self) { fn reset_created(&mut self) {
// nop - user controls timestamps manually // nop - user controls timestamps manually
false false
} }
#[cfg(not(feature = "chrono"))] #[cfg(not(feature = "chrono"))]
pub(crate) fn reset_accessed(&mut self) -> bool { fn reset_accessed(&mut self) -> bool {
// nop - user controls timestamps manually // nop - user controls timestamps manually
false false
} }
#[cfg(not(feature = "chrono"))] #[cfg(not(feature = "chrono"))]
pub(crate) fn reset_modified(&mut self) { fn reset_modified(&mut self) {
// nop - user controls timestamps manually // nop - user controls timestamps manually
false 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_all(&self.name)?;
wrt.write_u8(self.attrs.bits())?; wrt.write_u8(self.attrs.bits())?;
wrt.write_u8(self.reserved_0)?; wrt.write_u8(self.reserved_0)?;
@ -228,6 +235,10 @@ impl DirFileEntryData {
self.name[0] == DIR_ENTRY_FREE_FLAG self.name[0] == DIR_ENTRY_FREE_FLAG
} }
fn set_free(&mut self) {
self.name[0] = DIR_ENTRY_FREE_FLAG;
}
fn is_end(&self) -> bool { fn is_end(&self) -> bool {
self.name[0] == 0 self.name[0] == 0
} }
@ -247,6 +258,20 @@ struct DirLfnEntryData {
} }
impl 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<()> { fn serialize(&self, wrt: &mut Write) -> io::Result<()> {
wrt.write_u8(self.order)?; wrt.write_u8(self.order)?;
for ch in self.name_0.iter() { for ch in self.name_0.iter() {
@ -269,6 +294,10 @@ impl DirLfnEntryData {
self.order == DIR_ENTRY_FREE_FLAG self.order == DIR_ENTRY_FREE_FLAG
} }
fn set_free(&mut self) {
self.order = DIR_ENTRY_FREE_FLAG;
}
fn is_end(&self) -> bool { fn is_end(&self) -> bool {
self.order == 0 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 { fn is_end(&self) -> bool {
match self { match self {
&DirEntryData::File(ref file) => file.is_end(), &DirEntryData::File(ref file) => file.is_end(),
@ -443,13 +479,80 @@ impl From<chrono::DateTime<Local>> for DateTime {
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(crate) struct FileEntryInfo { pub(crate) struct DirEntryEditor {
pub(crate) data: DirFileEntryData, data: DirFileEntryData,
pos: u64, pos: u64,
dirty: bool,
} }
impl FileEntryInfo { impl DirEntryEditor {
pub(crate) fn write(&self, fs: FileSystemRef) -> io::Result<()> { 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<u32>, 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(); let mut disk = fs.disk.borrow_mut();
disk.seek(io::SeekFrom::Start(self.pos))?; disk.seek(io::SeekFrom::Start(self.pos))?;
self.data.serialize(&mut *disk) self.data.serialize(&mut *disk)
@ -510,11 +613,8 @@ impl <'a, 'b> DirEntry<'a, 'b> {
self.data.first_cluster(self.fs.fat_type) self.data.first_cluster(self.fs.fat_type)
} }
fn entry_info(&self) -> FileEntryInfo { fn entry_info(&self) -> DirEntryEditor {
FileEntryInfo { DirEntryEditor::new(self.data.clone(), self.entry_pos)
data: self.data.clone(),
pos: self.entry_pos,
}
} }
/// Returns File struct for this entry. /// Returns File struct for this entry.
@ -700,11 +800,7 @@ impl <'a, 'b> Dir<'a, 'b> {
for _ in 0..num { for _ in 0..num {
let mut data = DirEntryData::deserialize(&mut stream)?; let mut data = DirEntryData::deserialize(&mut stream)?;
trace!("removing dir entry {:?}", data); trace!("removing dir entry {:?}", data);
match data { data.set_free();
DirEntryData::File(ref mut data) =>
data.name[0] = DIR_ENTRY_FREE_FLAG,
DirEntryData::Lfn(ref mut data) => data.order = DIR_ENTRY_FREE_FLAG,
};
stream.seek(SeekFrom::Current(-(DIR_ENTRY_SIZE as i64)))?; stream.seek(SeekFrom::Current(-(DIR_ENTRY_SIZE as i64)))?;
data.serialize(&mut stream)?; data.serialize(&mut stream)?;
} }
@ -821,24 +917,15 @@ impl <'a, 'b> Dir<'a, 'b> {
if lfn_part_len < LFN_PART_LEN { if lfn_part_len < LFN_PART_LEN {
lfn_part[lfn_part_len] = 0; lfn_part[lfn_part_len] = 0;
} }
let mut lfn_entry = DirLfnEntryData { let mut lfn_entry = DirLfnEntryData::new(order, lfn_chsum);
order, lfn_entry.copy_name_from_slice(&lfn_part);
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]);
lfn_entry.serialize(&mut stream)?; lfn_entry.serialize(&mut stream)?;
} }
let mut raw_entry = DirFileEntryData { let mut raw_entry = DirFileEntryData::new(short_name, attrs);
name: short_name,
attrs,
..Default::default()
};
raw_entry.set_first_cluster(first_cluster, self.fs.fat_type); raw_entry.set_first_cluster(first_cluster, self.fs.fat_type);
raw_entry.reset_created(); raw_entry.reset_created();
raw_entry.reset_accessed();
raw_entry.reset_modified();
raw_entry.serialize(&mut stream)?; raw_entry.serialize(&mut stream)?;
let end_pos = stream.seek(io::SeekFrom::Current(0))?; let end_pos = stream.seek(io::SeekFrom::Current(0))?;
let abs_pos = stream.abs_pos().map(|p| p - DIR_ENTRY_SIZE); let abs_pos = stream.abs_pos().map(|p| p - DIR_ENTRY_SIZE);

View File

@ -4,7 +4,7 @@ use std::io::{SeekFrom, ErrorKind};
use std::io; use std::io;
use fs::FileSystemRef; use fs::FileSystemRef;
use dir::{FileEntryInfo, DateTime}; use dir::{DirEntryEditor, DateTime, Date};
/// FAT file used for reading and writing. /// FAT file used for reading and writing.
#[derive(Clone)] #[derive(Clone)]
@ -16,19 +16,17 @@ pub struct File<'a, 'b: 'a> {
// current position in this file // current position in this file
offset: u32, offset: u32,
// file dir entry - None for root dir // file dir entry - None for root dir
entry: Option<FileEntryInfo>, entry: Option<DirEntryEditor>,
// should file dir entry be flushed? // file-system reference
entry_dirty: bool,
fs: FileSystemRef<'a, 'b>, fs: FileSystemRef<'a, 'b>,
} }
impl <'a, 'b> File<'a, 'b> { impl <'a, 'b> File<'a, 'b> {
pub(crate) fn new(first_cluster: Option<u32>, entry: Option<FileEntryInfo>, fs: FileSystemRef<'a, 'b>) -> Self { pub(crate) fn new(first_cluster: Option<u32>, entry: Option<DirEntryEditor>, fs: FileSystemRef<'a, 'b>) -> Self {
File { File {
first_cluster, entry, fs, first_cluster, entry, fs,
current_cluster: None, // cluster before first one current_cluster: None, // cluster before first one
offset: 0, offset: 0,
entry_dirty: false,
} }
} }
@ -36,11 +34,10 @@ impl <'a, 'b> File<'a, 'b> {
let offset = self.offset; let offset = self.offset;
match self.entry { match self.entry {
Some(ref mut e) => { Some(ref mut e) => {
e.data.reset_modified(); e.reset_modified();
if e.data.size().map_or(false, |s| offset > s) { if e.inner().size().map_or(false, |s| offset > s) {
e.data.set_size(offset); e.set_size(offset);
} }
self.entry_dirty = true;
}, },
_ => {}, _ => {},
} }
@ -48,18 +45,12 @@ impl <'a, 'b> File<'a, 'b> {
/// Truncate file to current position. /// Truncate file to current position.
pub fn truncate(&mut self) -> io::Result<()> { pub fn truncate(&mut self) -> io::Result<()> {
let offset = self.offset;
match self.entry { match self.entry {
Some(ref mut e) => { Some(ref mut e) => {
if e.data.size().map_or(false, |s| offset == s) { e.set_size(self.offset);
return Ok(());
}
e.data.set_size(self.offset);
if self.offset == 0 { 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<()> { pub(crate) fn flush_dir_entry(&mut self) -> io::Result<()> {
if self.entry_dirty { match self.entry {
match self.entry { Some(ref mut e) => e.flush(self.fs)?,
Some(ref e) => e.write(self.fs)?, _ => {},
_ => {},
}
} }
Ok(()) 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. /// Set date and time of last modification for this file.
/// ///
/// Note: if chrono feature is enabled (default) library automatically updates all timestamps /// Note: if chrono feature is enabled (default) library automatically updates all timestamps
pub fn set_modified(&mut self, date_time: DateTime) { pub fn set_modified(&mut self, date_time: DateTime) {
match self.entry { match self.entry {
Some(ref mut e) => { Some(ref mut e) => e.set_modified(date_time),
e.data.set_modified(date_time);
self.entry_dirty = true;
},
_ => {}, _ => {},
} }
} }
fn bytes_left_in_file(&self) -> Option<usize> { fn bytes_left_in_file(&self) -> Option<usize> {
match self.entry { 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, None => None,
} }
} }
@ -124,12 +130,9 @@ impl <'a, 'b> File<'a, 'b> {
fn set_first_cluster(&mut self, cluster: u32) { fn set_first_cluster(&mut self, cluster: u32) {
self.first_cluster = Some(cluster); self.first_cluster = Some(cluster);
match self.entry { match self.entry {
Some(ref mut e) => { Some(ref mut e) => e.set_first_cluster(self.first_cluster, self.fs.fat_type),
e.data.set_first_cluster(self.first_cluster, self.fs.fat_type);
},
None => {}, None => {},
} }
self.entry_dirty = true;
} }
pub(crate) fn first_cluster(&self) -> Option<u32> { pub(crate) fn first_cluster(&self) -> Option<u32> {
@ -190,7 +193,7 @@ impl<'a, 'b> Read for File<'a, 'b> {
self.current_cluster = Some(current_cluster); self.current_cluster = Some(current_cluster);
match self.entry { 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) Ok(read_bytes)
@ -230,7 +233,7 @@ impl<'a, 'b> Write for File<'a, 'b> {
if self.first_cluster.is_none() { if self.first_cluster.is_none() {
self.set_first_cluster(new_cluster); 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 // zero new directory cluster
trace!("zeroing directory cluser {}", new_cluster); trace!("zeroing directory cluser {}", new_cluster);
let abs_pos = self.fs.offset_from_cluster(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 { let mut new_pos = match pos {
SeekFrom::Current(x) => self.offset as i64 + x, SeekFrom::Current(x) => self.offset as i64 + x,
SeekFrom::Start(x) => x as i64, 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 { if new_pos < 0 {
return Err(io::Error::new(ErrorKind::InvalidInput, "invalid seek")); return Err(io::Error::new(ErrorKind::InvalidInput, "invalid seek"));
} }
new_pos = match self.entry { new_pos = match self.entry {
Some(ref e) => { 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"); info!("seek beyond end of file");
e.data.size().unwrap() as i64 // safe e.inner().size().unwrap() as i64 // safe
} else { } else {
new_pos new_pos
} }