Update README and add more doc comments.

This commit is contained in:
Rafał Harabień 2017-10-21 16:25:04 +02:00
parent 2a61b0d175
commit 9d3780f859
5 changed files with 58 additions and 11 deletions

View File

@ -12,17 +12,12 @@ Introduction
FAT filesystem library implemented in Rust. FAT filesystem library implemented in Rust.
Features: Features:
* FAT12, FAT16, FAT32 supported, * read file and directory,
* read directory entries, * write file and directory,
* read file contents, * FAT12, FAT16, FAT32 compatibility,
* LFN (Long File Names), * LFN (Long File Names) extension supported.
* basic write support (write and truncate existing file).
Missing features (yet): Planned features (Nice to Have):
* create new file/directory,
* remove file/directory,
Other planned features (Nice to Have):
* no_std environment support. * no_std environment support.
License License

View File

@ -63,6 +63,7 @@ impl <'a, 'b> Seek for DirRawStream<'a, 'b> {
} }
bitflags! { bitflags! {
/// FAT file attributes
#[derive(Default)] #[derive(Default)]
pub struct FileAttributes: u8 { pub struct FileAttributes: u8 {
const READ_ONLY = 0x01; const READ_ONLY = 0x01;
@ -266,6 +267,7 @@ impl DirEntryData {
} }
} }
/// DOS compatible date
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct Date { pub struct Date {
pub year: u16, pub year: u16,
@ -284,6 +286,7 @@ impl Date {
} }
} }
/// DOS compatible time
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct Time { pub struct Time {
pub hour: u16, pub hour: u16,
@ -302,6 +305,7 @@ impl Time {
} }
} }
/// DOS compatible date and time
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct DateTime { pub struct DateTime {
pub date: Date, pub date: Date,
@ -346,6 +350,9 @@ impl FileEntryInfo {
} }
} }
/// FAT directory entry.
///
/// Returned by DirIter.
#[derive(Clone)] #[derive(Clone)]
pub struct DirEntry<'a, 'b: 'a> { pub struct DirEntry<'a, 'b: 'a> {
data: DirFileEntryData, data: DirFileEntryData,
@ -356,6 +363,7 @@ pub struct DirEntry<'a, 'b: 'a> {
} }
impl <'a, 'b> DirEntry<'a, 'b> { impl <'a, 'b> DirEntry<'a, 'b> {
/// Returns short file name
pub fn short_file_name(&self) -> String { pub fn short_file_name(&self) -> String {
let name_str = String::from_utf8_lossy(&self.data.name[0..8]); let name_str = String::from_utf8_lossy(&self.data.name[0..8]);
let ext_str = String::from_utf8_lossy(&self.data.name[8..11]); let ext_str = String::from_utf8_lossy(&self.data.name[8..11]);
@ -368,6 +376,7 @@ impl <'a, 'b> DirEntry<'a, 'b> {
} }
} }
/// Returns long file name or if it doesn't exist fallbacks to short file name.
pub fn file_name(&self) -> String { pub fn file_name(&self) -> String {
if self.lfn.len() > 0 { if self.lfn.len() > 0 {
String::from_utf16_lossy(&self.lfn) String::from_utf16_lossy(&self.lfn)
@ -376,14 +385,17 @@ impl <'a, 'b> DirEntry<'a, 'b> {
} }
} }
/// Returns file attributes
pub fn attributes(&self) -> FileAttributes { pub fn attributes(&self) -> FileAttributes {
self.data.attrs self.data.attrs
} }
/// Checks if entry belongs to directory.
pub fn is_dir(&self) -> bool { pub fn is_dir(&self) -> bool {
self.data.is_dir() self.data.is_dir()
} }
/// Checks if entry belongs to regular file.
pub fn is_file(&self) -> bool { pub fn is_file(&self) -> bool {
self.data.is_file() self.data.is_file()
} }
@ -399,11 +411,17 @@ impl <'a, 'b> DirEntry<'a, 'b> {
} }
} }
/// Returns File struct for this entry.
///
/// Panics if this is not a file.
pub fn to_file(&self) -> File<'a, 'b> { pub fn to_file(&self) -> File<'a, 'b> {
assert!(!self.is_dir(), "Not a file entry"); assert!(!self.is_dir(), "Not a file entry");
File::new(self.first_cluster(), Some(self.entry_info()), self.fs) File::new(self.first_cluster(), Some(self.entry_info()), self.fs)
} }
/// Returns Dir struct for this entry.
///
/// Panics if this is not a directory.
pub fn to_dir(&self) -> Dir<'a, 'b> { pub fn to_dir(&self) -> Dir<'a, 'b> {
assert!(self.is_dir(), "Not a directory entry"); assert!(self.is_dir(), "Not a directory entry");
match self.first_cluster() { match self.first_cluster() {
@ -415,18 +433,22 @@ impl <'a, 'b> DirEntry<'a, 'b> {
} }
} }
/// Returns file size or 0 for directory.
pub fn len(&self) -> u64 { pub fn len(&self) -> u64 {
self.data.size as u64 self.data.size as u64
} }
/// Returns file creation date and time.
pub fn created(&self) -> DateTime { pub fn created(&self) -> DateTime {
DateTime::from_u16(self.data.create_date, self.data.create_time_1) DateTime::from_u16(self.data.create_date, self.data.create_time_1)
} }
/// Returns file last access date.
pub fn accessed(&self) -> Date { pub fn accessed(&self) -> Date {
Date::from_u16(self.data.access_date) Date::from_u16(self.data.access_date)
} }
/// Returns file last modification date and time.
pub fn modified(&self) -> DateTime { pub fn modified(&self) -> DateTime {
DateTime::from_u16(self.data.modify_date, self.data.modify_time) DateTime::from_u16(self.data.modify_date, self.data.modify_time)
} }
@ -438,6 +460,7 @@ impl <'a, 'b> fmt::Debug for DirEntry<'a, 'b> {
} }
} }
/// FAT directory
#[derive(Clone)] #[derive(Clone)]
pub struct Dir<'a, 'b: 'a> { pub struct Dir<'a, 'b: 'a> {
stream: DirRawStream<'a, 'b>, stream: DirRawStream<'a, 'b>,
@ -450,6 +473,7 @@ impl <'a, 'b> Dir<'a, 'b> {
Dir { stream, fs } Dir { stream, fs }
} }
/// Creates directory entries iterator
pub fn iter(&self) -> DirIter<'a, 'b> { pub fn iter(&self) -> DirIter<'a, 'b> {
DirIter { DirIter {
stream: self.stream.clone(), stream: self.stream.clone(),
@ -475,6 +499,7 @@ impl <'a, 'b> Dir<'a, 'b> {
Err(io::Error::new(ErrorKind::NotFound, "file not found")) Err(io::Error::new(ErrorKind::NotFound, "file not found"))
} }
/// Opens existing directory
pub fn open_dir(&mut self, path: &str) -> io::Result<Dir<'a, 'b>> { pub fn open_dir(&mut self, path: &str) -> io::Result<Dir<'a, 'b>> {
let (name, rest_opt) = Self::split_path(path); let (name, rest_opt) = Self::split_path(path);
let e = self.find_entry(name)?; let e = self.find_entry(name)?;
@ -484,6 +509,7 @@ impl <'a, 'b> Dir<'a, 'b> {
} }
} }
/// Opens existing file.
pub fn open_file(&mut self, path: &str) -> io::Result<File<'a, 'b>> { pub fn open_file(&mut self, path: &str) -> io::Result<File<'a, 'b>> {
let (name, rest_opt) = Self::split_path(path); let (name, rest_opt) = Self::split_path(path);
let e = self.find_entry(name)?; let e = self.find_entry(name)?;
@ -493,6 +519,7 @@ impl <'a, 'b> Dir<'a, 'b> {
} }
} }
/// Creates new file or opens existing.
pub fn create_file(&mut self, path: &str) -> io::Result<File<'a, 'b>> { pub fn create_file(&mut self, path: &str) -> io::Result<File<'a, 'b>> {
let (name, rest_opt) = Self::split_path(path); let (name, rest_opt) = Self::split_path(path);
let r = self.find_entry(name); let r = self.find_entry(name);
@ -518,6 +545,10 @@ impl <'a, 'b> Dir<'a, 'b> {
Ok(true) Ok(true)
} }
/// Removes existing file or directory.
///
/// Make sure there is no reference to this file (no File instance) or filesystem corruption
/// can happen.
pub fn remove(&mut self, path: &str) -> io::Result<()> { pub fn remove(&mut self, path: &str) -> io::Result<()> {
let (name, rest_opt) = Self::split_path(path); let (name, rest_opt) = Self::split_path(path);
let e = self.find_entry(name)?; let e = self.find_entry(name)?;
@ -657,6 +688,7 @@ impl <'a, 'b> Dir<'a, 'b> {
} }
} }
/// Directory entries iterator.
#[derive(Clone)] #[derive(Clone)]
pub struct DirIter<'a, 'b: 'a> { pub struct DirIter<'a, 'b: 'a> {
stream: DirRawStream<'a, 'b>, stream: DirRawStream<'a, 'b>,

View File

@ -6,6 +6,7 @@ use std::io;
use fs::FileSystemRef; use fs::FileSystemRef;
use dir::{FileEntryInfo, DateTime}; use dir::{FileEntryInfo, DateTime};
/// FAT file used for reading and writing.
#[derive(Clone)] #[derive(Clone)]
pub struct File<'a, 'b: 'a> { pub struct File<'a, 'b: 'a> {
// Note first_cluster is None if file is empty // Note first_cluster is None if file is empty
@ -44,6 +45,7 @@ impl <'a, 'b> File<'a, 'b> {
} }
} }
/// Truncate file to current position.
pub fn truncate(&mut self) -> io::Result<()> { pub fn truncate(&mut self) -> io::Result<()> {
let offset = self.offset; let offset = self.offset;
match self.entry { match self.entry {
@ -98,6 +100,9 @@ impl <'a, 'b> File<'a, 'b> {
Ok(()) Ok(())
} }
/// Set date and time of last modification for this file.
///
/// Note: this library doesn't know current time so changing timestamp must be done manually.
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) => {

View File

@ -79,6 +79,7 @@ impl Default for BootRecord {
pub(crate) type FileSystemRef<'a, 'b: 'a> = &'a FileSystem<'b>; pub(crate) type FileSystemRef<'a, 'b: 'a> = &'a FileSystem<'b>;
/// FAT filesystem main struct.
pub struct FileSystem<'a> { pub struct FileSystem<'a> {
pub(crate) disk: RefCell<&'a mut ReadWriteSeek>, pub(crate) disk: RefCell<&'a mut ReadWriteSeek>,
pub(crate) fat_type: FatType, pub(crate) fat_type: FatType,
@ -88,7 +89,10 @@ pub struct FileSystem<'a> {
} }
impl <'a> FileSystem<'a> { impl <'a> FileSystem<'a> {
/// Creates new filesystem object instance.
///
/// Note: creating multiple filesystem objects with one underlying device/disk image can
/// cause filesystem corruption.
pub fn new<T: ReadWriteSeek>(disk: &'a mut T) -> io::Result<FileSystem<'a>> { pub fn new<T: ReadWriteSeek>(disk: &'a mut T) -> io::Result<FileSystem<'a>> {
let boot = Self::read_boot_record(disk)?; let boot = Self::read_boot_record(disk)?;
if boot.boot_sig != [0x55, 0xAA] { if boot.boot_sig != [0x55, 0xAA] {
@ -112,18 +116,25 @@ impl <'a> FileSystem<'a> {
}) })
} }
/// Returns type of used File Allocation Table (FAT).
pub fn fat_type(&self) -> FatType { pub fn fat_type(&self) -> FatType {
self.fat_type self.fat_type
} }
/// Returns volume identifier read from BPB in Boot Sector.
pub fn volume_id(&self) -> u32 { pub fn volume_id(&self) -> u32 {
self.boot.bpb.volume_id self.boot.bpb.volume_id
} }
/// Returns volume label from BPB in Boot Sector.
///
/// Note: File with VOLUME_ID attribute in root directory is ignored by this library.
/// Only label from BPB is used.
pub fn volume_label(&self) -> String { pub fn volume_label(&self) -> String {
String::from_utf8_lossy(&self.boot.bpb.volume_label).trim_right().to_string() String::from_utf8_lossy(&self.boot.bpb.volume_label).trim_right().to_string()
} }
/// Returns root directory object allowing futher penetration of filesystem structure.
pub fn root_dir<'b>(&'b self) -> Dir<'b, 'a> { pub fn root_dir<'b>(&'b self) -> Dir<'b, 'a> {
let root_rdr = { let root_rdr = {
match self.fat_type { match self.fat_type {

View File

@ -18,7 +18,11 @@ pub struct BufStream<T: Read+Write+Seek> {
write: bool, write: bool,
} }
/// The BufStream struct adds buffering to underlying file or device.
///
/// It's basically composition of BufReader and BufWritter.
impl<T: Read+Write+Seek> BufStream<T> { impl<T: Read+Write+Seek> BufStream<T> {
/// Creates new BufStream object for given stream.
pub fn new(inner: T) -> Self { pub fn new(inner: T) -> Self {
BufStream::<T> { BufStream::<T> {
inner, inner,