use super::*;
#[cfg(not(feature = "std"))]
use alloc::{boxed::Box, string::String};
use crate::*;
use ::time;
use bincode::{impl_borrow_decode, Decode, Encode};
use bitflags::bitflags;
use embedded_io::*;
use time::{Date, PrimitiveDateTime};
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq)]
pub(crate) struct RawAttributes: u8 {
const READ_ONLY = 0x01;
const HIDDEN = 0x02;
const SYSTEM = 0x04;
const VOLUME_ID = 0x08;
const DIRECTORY = 0x10;
const ARCHIVE = 0x20;
const LFN = Self::READ_ONLY.bits() |
Self::HIDDEN.bits() |
Self::SYSTEM.bits() |
Self::VOLUME_ID.bits();
}
}
impl<Context> bincode::Decode<Context> for RawAttributes {
fn decode<D: bincode::de::Decoder<Context = Context>>(
decoder: &mut D,
) -> Result<Self, bincode::error::DecodeError> {
Ok(RawAttributes::from_bits_truncate(
<u8 as bincode::Decode<Context>>::decode(decoder)?,
))
}
}
impl_borrow_decode!(RawAttributes);
impl bincode::Encode for RawAttributes {
fn encode<E: bincode::enc::Encoder>(
&self,
encoder: &mut E,
) -> Result<(), bincode::error::EncodeError> {
bincode::Encode::encode(&self.bits(), encoder)?;
Ok(())
}
}
impl RawAttributes {
pub(crate) fn from_attributes(attributes: Attributes, is_dir: bool) -> Self {
let mut raw_attributes = RawAttributes::empty();
raw_attributes.set(RawAttributes::READ_ONLY, attributes.read_only);
raw_attributes.set(RawAttributes::HIDDEN, attributes.hidden);
raw_attributes.set(RawAttributes::SYSTEM, attributes.system);
raw_attributes.set(RawAttributes::ARCHIVE, attributes.archive);
raw_attributes.set(RawAttributes::DIRECTORY, is_dir);
raw_attributes
}
}
pub(crate) const NONROOT_MIN_DIRENTRIES: usize = 2;
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub(crate) struct FATDirEntry {
pub(crate) sfn: Sfn,
pub(crate) attributes: RawAttributes,
pub(crate) _reserved: [u8; 1],
pub(crate) created: EntryCreationTime,
pub(crate) accessed: EntryLastAccessedTime,
pub(crate) cluster_high: u16,
pub(crate) modified: EntryModificationTime,
pub(crate) cluster_low: u16,
pub(crate) file_size: FileSize,
}
#[derive(Debug, Clone)]
pub(crate) struct MinProperties {
pub(crate) name: Box<str>,
pub(crate) sfn: Sfn,
pub(crate) attributes: RawAttributes,
pub(crate) created: Option<PrimitiveDateTime>,
pub(crate) modified: PrimitiveDateTime,
pub(crate) accessed: Option<Date>,
pub(crate) file_size: FileSize,
pub(crate) data_cluster: ClusterIndex,
}
impl From<RawProperties> for MinProperties {
fn from(value: RawProperties) -> Self {
Self {
name: Box::from(value.name),
sfn: value.sfn,
attributes: value.attributes,
created: value.created,
modified: value.modified,
accessed: value.accessed,
file_size: value.file_size,
data_cluster: value.data_cluster,
}
}
}
impl From<Properties> for MinProperties {
fn from(value: Properties) -> Self {
Self::from(RawProperties::from(value))
}
}
impl<S> From<DirEntry<'_, S>> for MinProperties
where
S: Read + Seek,
{
fn from(value: DirEntry<'_, S>) -> Self {
Self::from(value.entry)
}
}
#[derive(Debug, Clone)]
pub(crate) struct RawProperties {
pub(crate) name: String,
pub(crate) sfn: Sfn,
pub(crate) is_dir: bool,
pub(crate) attributes: RawAttributes,
pub(crate) created: Option<PrimitiveDateTime>,
pub(crate) modified: PrimitiveDateTime,
pub(crate) accessed: Option<Date>,
pub(crate) file_size: FileSize,
pub(crate) data_cluster: ClusterIndex,
pub(crate) chain: DirEntryChain,
}
impl RawProperties {
pub(crate) fn into_dir_entry<'a, P, S>(self, path: P, fs: &'a FileSystem<S>) -> DirEntry<'a, S>
where
P: AsRef<Path>,
S: Read + Seek,
{
let entry_path = path.as_ref().join(&self.name);
DirEntry {
entry: Properties::from_raw(self, entry_path.into(), fs.options.codepage),
fs,
}
}
pub(crate) fn from_chain(props: MinProperties, chain: DirEntryChain) -> Self {
Self {
name: String::from(props.name),
sfn: props.sfn,
is_dir: props.attributes.contains(RawAttributes::DIRECTORY),
attributes: props.attributes,
created: props.created,
modified: props.modified,
accessed: props.accessed,
file_size: props.file_size,
data_cluster: props.data_cluster,
chain,
}
}
}
impl From<Properties> for RawProperties {
fn from(value: Properties) -> Self {
Self {
name: String::from(value.path.file_name().expect("the path is normalized")),
sfn: value.sfn.0,
is_dir: value.is_dir,
attributes: RawAttributes::from_attributes(value.attributes, value.is_dir),
created: value.created,
modified: value.modified,
accessed: value.accessed,
file_size: value.file_size,
data_cluster: value.data_cluster,
chain: value.chain,
}
}
}
impl From<MinProperties> for FATDirEntry {
fn from(value: MinProperties) -> Self {
Self {
sfn: value.sfn,
attributes: value.attributes,
_reserved: [0x00],
created: value.created.into(),
accessed: value.accessed.into(),
cluster_high: (value.data_cluster >> (u32::BITS / 2)) as u16,
modified: value.modified.into(),
#[allow(clippy::cast_possible_truncation)] cluster_low: value.data_cluster as u16,
file_size: value.file_size,
}
}
}