Add set_created and set_accessed public functions in File.
Small code refactoring included.
This commit is contained in:
parent
b38ea78f3e
commit
c4e6d59492
163
src/dir.rs
163
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<u32> {
|
||||
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<u32>, fat_type: FatType) {
|
||||
fn set_first_cluster(&mut self, cluster: Option<u32>, 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<chrono::DateTime<Local>> 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<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();
|
||||
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);
|
||||
|
75
src/file.rs
75
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<FileEntryInfo>,
|
||||
// should file dir entry be flushed?
|
||||
entry_dirty: bool,
|
||||
entry: Option<DirEntryEditor>,
|
||||
// file-system reference
|
||||
fs: FileSystemRef<'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 {
|
||||
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,14 +82,32 @@ impl <'a, 'b> File<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn flush_dir_entry(&self) -> io::Result<()> {
|
||||
if self.entry_dirty {
|
||||
pub(crate) fn flush_dir_entry(&mut self) -> io::Result<()> {
|
||||
match self.entry {
|
||||
Some(ref e) => e.write(self.fs)?,
|
||||
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),
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
||||
/// 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.
|
||||
@ -106,17 +115,14 @@ impl <'a, 'b> File<'a, 'b> {
|
||||
/// 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<usize> {
|
||||
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<u32> {
|
||||
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user