forked from M-Labs/rust-fatfs
Add TimeProvider trait and time_provider option
This functionality is very useful for embedded usage where chrono feature cannot be enabled.
This commit is contained in:
parent
30f3f96537
commit
1f8f8365d6
1
TODO.md
1
TODO.md
@ -4,5 +4,4 @@ TODO
|
||||
* support for a volume label file in the root directory
|
||||
* format volume API
|
||||
* add method for getting `DirEntry` from a path (possible names: metadata, lookup)
|
||||
* add time provier so the crate writes a proper timestamps when `chrono` is unavailable
|
||||
* do not create LFN entries if the name fits in a SFN entry
|
||||
|
@ -406,9 +406,10 @@ impl<'a, T: ReadWriteSeek + 'a> Dir<'a, T> {
|
||||
fn create_sfn_entry(&self, short_name: [u8; 11], attrs: FileAttributes, first_cluster: Option<u32>) -> DirFileEntryData {
|
||||
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();
|
||||
let now = self.fs.options.time_provider.get_current_date_time();
|
||||
raw_entry.set_created(now);
|
||||
raw_entry.set_accessed(now.date);
|
||||
raw_entry.set_modified(now);
|
||||
raw_entry
|
||||
}
|
||||
|
||||
|
@ -219,61 +219,22 @@ impl DirFileEntryData {
|
||||
DateTime::decode(self.modify_date, self.modify_time, 0)
|
||||
}
|
||||
|
||||
fn set_created(&mut self, date_time: DateTime) {
|
||||
pub(crate) fn set_created(&mut self, date_time: DateTime) {
|
||||
self.create_date = date_time.date.encode();
|
||||
let encoded_time = date_time.time.encode();
|
||||
self.create_time_1 = encoded_time.0;
|
||||
self.create_time_0 = encoded_time.1;
|
||||
}
|
||||
|
||||
fn set_accessed(&mut self, date: Date) {
|
||||
pub(crate) fn set_accessed(&mut self, date: Date) {
|
||||
self.access_date = date.encode();
|
||||
}
|
||||
|
||||
fn set_modified(&mut self, date_time: DateTime) {
|
||||
pub(crate) fn set_modified(&mut self, date_time: DateTime) {
|
||||
self.modify_date = date_time.date.encode();
|
||||
self.modify_time = date_time.time.encode().0;
|
||||
}
|
||||
|
||||
#[cfg(feature = "chrono")]
|
||||
pub(crate) 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 {
|
||||
let now = Date::from(chrono::Local::now().date());
|
||||
if now == self.accessed() {
|
||||
false
|
||||
} else {
|
||||
self.set_accessed(now);
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "chrono")]
|
||||
pub(crate) 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) {
|
||||
// nop - user controls timestamps manually
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "chrono"))]
|
||||
pub(crate) fn reset_accessed(&mut self) -> bool {
|
||||
// nop - user controls timestamps manually
|
||||
false
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "chrono"))]
|
||||
pub(crate) fn reset_modified(&mut self) {
|
||||
// nop - user controls timestamps manually
|
||||
}
|
||||
|
||||
pub(crate) fn serialize(&self, wrt: &mut Write) -> io::Result<()> {
|
||||
wrt.write_all(&self.name)?;
|
||||
wrt.write_u8(self.attrs.bits())?;
|
||||
@ -642,15 +603,6 @@ impl DirEntryEditor {
|
||||
}
|
||||
}
|
||||
|
||||
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<T: ReadWriteSeek>(&mut self, fs: &FileSystem<T>) -> io::Result<()> {
|
||||
if self.dirty {
|
||||
self.write(fs)?;
|
||||
|
15
src/file.rs
15
src/file.rs
@ -36,10 +36,11 @@ impl<'a, T: ReadWriteSeek> File<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn update_size(&mut self) {
|
||||
fn update_dir_entry_after_write(&mut self) {
|
||||
let offset = self.offset;
|
||||
if let Some(ref mut e) = self.entry {
|
||||
e.reset_modified();
|
||||
let now = self.fs.options.time_provider.get_current_date_time();
|
||||
e.set_modified(now);
|
||||
if e.inner().size().map_or(false, |s| offset > s) {
|
||||
e.set_size(offset);
|
||||
}
|
||||
@ -199,9 +200,11 @@ impl<'a, T: ReadWriteSeek> Read for File<'a, T> {
|
||||
self.offset += read_bytes as u32;
|
||||
self.current_cluster = Some(current_cluster);
|
||||
|
||||
match self.entry {
|
||||
Some(ref mut e) if self.fs.options.update_accessed_date => e.reset_accessed(),
|
||||
_ => {},
|
||||
if let Some(ref mut e) = self.entry {
|
||||
if self.fs.options.update_accessed_date {
|
||||
let now = self.fs.options.time_provider.get_current_date();
|
||||
e.set_accessed(now);
|
||||
}
|
||||
}
|
||||
Ok(read_bytes)
|
||||
}
|
||||
@ -276,7 +279,7 @@ impl<'a, T: ReadWriteSeek> Write for File<'a, T> {
|
||||
// some bytes were writter - update position and optionally size
|
||||
self.offset += written_bytes as u32;
|
||||
self.current_cluster = Some(current_cluster);
|
||||
self.update_size();
|
||||
self.update_dir_entry_after_write();
|
||||
Ok(written_bytes)
|
||||
}
|
||||
|
||||
|
44
src/fs.rs
44
src/fs.rs
@ -12,7 +12,7 @@ use byteorder::LittleEndian;
|
||||
use byteorder_ext::{ReadBytesExt, WriteBytesExt};
|
||||
|
||||
use dir::{Dir, DirRawStream};
|
||||
use dir_entry::DIR_ENTRY_SIZE;
|
||||
use dir_entry::{self, DIR_ENTRY_SIZE};
|
||||
use file::File;
|
||||
use table::{alloc_cluster, count_free_clusters, read_fat_flags, ClusterIterator};
|
||||
|
||||
@ -303,6 +303,7 @@ impl FsInfoSector {
|
||||
pub struct FsOptions {
|
||||
pub(crate) update_accessed_date: bool,
|
||||
pub(crate) oem_cp_converter: &'static OemCpConverter,
|
||||
pub(crate) time_provider: &'static TimeProvider,
|
||||
}
|
||||
|
||||
impl FsOptions {
|
||||
@ -311,6 +312,7 @@ impl FsOptions {
|
||||
FsOptions {
|
||||
update_accessed_date: false,
|
||||
oem_cp_converter: &LOSSY_OEM_CP_CONVERTER,
|
||||
time_provider: &DEFAULT_TIME_PROVIDER,
|
||||
}
|
||||
}
|
||||
|
||||
@ -325,6 +327,12 @@ impl FsOptions {
|
||||
self.oem_cp_converter = oem_cp_converter;
|
||||
self
|
||||
}
|
||||
|
||||
/// Changes default time provider.
|
||||
pub fn time_provider(mut self, time_provider: &'static TimeProvider) -> Self {
|
||||
self.time_provider = time_provider;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// A FAT volume statistics.
|
||||
@ -745,3 +753,37 @@ impl OemCpConverter for LossyOemCpConverter {
|
||||
}
|
||||
|
||||
pub(crate) static LOSSY_OEM_CP_CONVERTER: LossyOemCpConverter = LossyOemCpConverter { _dummy: () };
|
||||
|
||||
pub trait TimeProvider {
|
||||
fn get_current_date(&self) -> dir_entry::Date;
|
||||
fn get_current_date_time(&self) -> dir_entry::DateTime;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct DefaultTimeProvider {
|
||||
_dummy: (),
|
||||
}
|
||||
|
||||
impl TimeProvider for DefaultTimeProvider {
|
||||
#[cfg(feature = "chrono")]
|
||||
fn get_current_date(&self) -> dir_entry::Date {
|
||||
use chrono;
|
||||
dir_entry::Date::from(chrono::Local::now().date())
|
||||
}
|
||||
#[cfg(not(feature = "chrono"))]
|
||||
fn get_current_date(&self) -> dir_entry::Date {
|
||||
dir_entry::Date::decode(0)
|
||||
}
|
||||
|
||||
#[cfg(feature = "chrono")]
|
||||
fn get_current_date_time(&self) -> dir_entry::DateTime {
|
||||
use chrono;
|
||||
dir_entry::DateTime::from(chrono::Local::now())
|
||||
}
|
||||
#[cfg(not(feature = "chrono"))]
|
||||
fn get_current_date_time(&self) -> dir_entry::DateTime {
|
||||
dir_entry::DateTime::decode(0, 0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) static DEFAULT_TIME_PROVIDER: DefaultTimeProvider = DefaultTimeProvider { _dummy: () };
|
||||
|
Loading…
Reference in New Issue
Block a user