Skip to content

Commit

Permalink
v0.6.3: support ls, cd and cat
Browse files Browse the repository at this point in the history
  • Loading branch information
GZTimeWalker committed May 6, 2022
1 parent aa0d6ba commit 2308965
Show file tree
Hide file tree
Showing 12 changed files with 327 additions and 97 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 37 additions & 8 deletions pkg/fs/src/device/disk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//!
//! reference: https://github.com/rust-embedded-community/embedded-sdmmc-rs/blob/develop/src/fat.rs#L1350

use crate::Block;
use super::*;
use crate::{dir_entry::*, partition::PartitionMetaData, structs::*};

Expand Down Expand Up @@ -118,6 +119,10 @@ pub enum VolumeError {
InvalidOperation,
BadCluster,
EndOfFile,
NotADirectory,
NotAFile,
ReadOnly,
Unsupported,
DeviceError(DeviceError),
FileNameError(FilenameError),
}
Expand All @@ -134,6 +139,28 @@ where
pub first_root_dir_sector: usize,
}

impl<'a, T> Device<Block> for FAT16Volume<'a, T>
where
T: BlockDevice,
{
fn read(&self, buf: &mut [Block], offset: usize, size: usize) -> Result<usize, DeviceError> {
self.volume.read(buf, offset, size)
}
}

impl<'a, T> BlockDevice for FAT16Volume<'a, T>
where
T: BlockDevice,
{
fn block_count(&self) -> Result<usize, DeviceError> {
self.volume.block_count()
}

fn read_block(&self, offset: usize) -> Result<Block, DeviceError> {
self.volume.read_block(offset)
}
}

impl<'a, T> FAT16Volume<'a, T>
where
T: BlockDevice,
Expand Down Expand Up @@ -168,7 +195,7 @@ where
{
debug!("Iterating directory: {:?}", dir);
let mut current_cluster = Some(dir.cluster);
let mut dir_sector_num = self.cluster_to_sector(dir.cluster);
let mut dir_sector_num = self.cluster_to_sector(&dir.cluster);
let dir_size = match dir.cluster {
Cluster::ROOT_DIR => self.first_data_sector - self.first_root_dir_sector,
_ => self.bpb.sectors_per_cluster() as usize,
Expand All @@ -194,7 +221,7 @@ where
current_cluster = if cluster != Cluster::ROOT_DIR {
match self.next_cluster(cluster) {
Ok(n) => {
dir_sector_num = self.cluster_to_sector(n);
dir_sector_num = self.cluster_to_sector(&n);
Some(n)
}
_ => None,
Expand All @@ -212,10 +239,11 @@ where
dir: &Directory,
name: &str,
) -> Result<DirEntry, VolumeError> {
let match_name = ShortFileName::parse(name).map_err(|_| VolumeError::InvalidOperation)?;
let match_name = ShortFileName::parse(name)
.map_err(|x| VolumeError::FileNameError(x))?;

let mut current_cluster = Some(dir.cluster);
let mut dir_sector_num = self.cluster_to_sector(dir.cluster);
let mut dir_sector_num = self.cluster_to_sector(&dir.cluster);
let dir_size = match dir.cluster {
Cluster::ROOT_DIR => self.first_data_sector - self.first_root_dir_sector,
_ => self.bpb.sectors_per_cluster() as usize,
Expand All @@ -230,7 +258,7 @@ where
current_cluster = if cluster != Cluster::ROOT_DIR {
match self.next_cluster(cluster) {
Ok(n) => {
dir_sector_num = self.cluster_to_sector(n);
dir_sector_num = self.cluster_to_sector(&n);
Some(n)
}
_ => None,
Expand All @@ -242,8 +270,8 @@ where
Err(VolumeError::FileNotFound)
}

pub fn cluster_to_sector(&self, cluster: Cluster) -> usize {
match cluster {
pub fn cluster_to_sector(&self, cluster: &Cluster) -> usize {
match *cluster {
Cluster::ROOT_DIR => self.first_root_dir_sector,
Cluster(c) => {
// FirstSectorofCluster = ((N – 2) * BPB_SecPerClus) + FirstDataSector;
Expand All @@ -254,7 +282,7 @@ where
}

/// look for next cluster in FAT
fn next_cluster(&self, cluster: Cluster) -> Result<Cluster, VolumeError> {
pub fn next_cluster(&self, cluster: Cluster) -> Result<Cluster, VolumeError> {
let fat_offset = (cluster.0 * 2) as usize;
let cur_fat_sector = self.fat_start + fat_offset / Block::SIZE;
let offset = (fat_offset % Block::SIZE) as usize;
Expand Down Expand Up @@ -283,6 +311,7 @@ where
let end = (entry + 1) * DirEntry::LEN;
let dir_entry = DirEntry::parse(&block.inner()[start..end])
.map_err(|_| VolumeError::InvalidOperation)?;
trace!("matching {} to {}...", dir_entry.filename(), match_name);
if dir_entry.is_eod() {
// Can quit early
return Err(VolumeError::FileNotFound);
Expand Down
134 changes: 128 additions & 6 deletions pkg/fs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,11 @@ extern crate log;
pub mod device;
pub mod structs;

pub use structs::*;
use alloc::vec::Vec;
use device::BlockDevice;
pub use device::*;
use structs::dir_entry::Cluster;

pub fn root_dir() -> Directory {
Directory::new( Cluster::ROOT_DIR)
}
pub use structs::*;
use structs::{dir_entry::Cluster, file::Mode};

// 1. The disk structure
// How to read a file from disk
Expand All @@ -34,3 +32,127 @@ pub fn root_dir() -> Directory {
// The BPB contains information about the filesystem.
//
// [ FAT16 BPB ] [ Data ]


pub fn root_dir() -> Directory {
Directory::new(Cluster::ROOT_DIR)
}

/// Call a callback function for each directory entry in a directory.
pub fn iterate_dir<'a, T, F>(
volume: &FAT16Volume<'a, T>,
dir: &Directory,
func: F,
) -> Result<(), VolumeError>
where
T: BlockDevice,
F: FnMut(&DirEntry),
{
volume.iterate_dir(dir, func)
}

/// Look in a directory for a named file.
pub fn find_directory_entry<'a, T>(
volume: &FAT16Volume<'a, T>,
dir: &Directory,
name: &str,
) -> Result<Directory, VolumeError>
where
T: BlockDevice,
{
if name.len() < 2 {
return Ok(root_dir());
}

let res = volume.find_directory_entry(dir, name)?;

if res.is_directory() {
Ok(Directory::from_entry(res))
} else {
Err(VolumeError::NotADirectory)
}
}

/// Open a dir in a dir
pub fn open_dir<'a, T>(
volume: &FAT16Volume<'a, T>,
parent: &Directory,
name: &str,
) -> Result<Directory, VolumeError>
where
T: BlockDevice,
{
let dir_entry = volume.find_directory_entry(parent, name)?;

if !dir_entry.is_directory() {
return Err(VolumeError::NotADirectory);
}

let dir = Directory::from_entry(dir_entry);

trace!("opened dir: \n{:#?}", &dir);

Ok(dir)
}

/// Open a file in a dir
pub fn open_file<'a, T>(
volume: &FAT16Volume<'a, T>,
parent: &Directory,
name: &str,
mode: Mode,
) -> Result<File, VolumeError>
where
T: BlockDevice,
{
trace!("try open file: {}", name);
let dir_entry = volume.find_directory_entry(parent, name)?;

if dir_entry.is_directory() {
return Err(VolumeError::NotAFile);
}

if dir_entry.is_readonly() && mode != Mode::ReadOnly {
return Err(VolumeError::ReadOnly);
}

let file = match mode {
Mode::ReadOnly => File {
start_cluster: dir_entry.cluster,
length: dir_entry.size,
mode,
entry: dir_entry,
},
_ => return Err(VolumeError::Unsupported),
};

trace!("opened file: \n{:#?}", &file);

Ok(file)
}

/// read a file
pub fn read<'a, T>(
volume: &FAT16Volume<'a, T>,
file: &File
) -> Result<Vec<u8>, VolumeError>
where
T: BlockDevice,
{
let mut data = vec![0u8; file.length() as usize];
let mut length = file.length() as usize;
for i in 0..file.length() as usize / Block::SIZE + 1 {
let sector = volume.cluster_to_sector(&file.start_cluster());
let block = volume.read_block(sector as usize + i).unwrap();
if length > Block::SIZE {
data[i * Block::SIZE..(i + 1) * Block::SIZE]
.copy_from_slice(&block.inner()[..]);
length -= Block::SIZE;
} else {
data[i * Block::SIZE..i * Block::SIZE + length as usize]
.copy_from_slice(&block.inner()[..length as usize]);
break;
}
}
Ok(data)
}
13 changes: 8 additions & 5 deletions pkg/fs/src/structs/dir_entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,9 @@ impl DirEntry {
let accessed_time = prase_datetime(time);

let cluster = (data[27] as u32) << 8
| (data[26] as u32)
| (data[20] as u32) << 16
| (data[21] as u32) << 24;
| (data[26] as u32) << 0
| (data[21] as u32) << 24
| (data[20] as u32) << 16;

time = u32::from_le_bytes([data[22], data[23], data[24], data[25]]);
let moditified_time = prase_datetime(time);
Expand Down Expand Up @@ -204,8 +204,8 @@ impl ShortFileName {

pub fn parse(name: &str) -> Result<ShortFileName, FilenameError> {
let mut sfn = ShortFileName {
name: [0; 8],
ext: [0; 3],
name: [0x20; 8],
ext: [0x20; 3],
};
let mut idx = 0;
let mut seen_dot = false;
Expand Down Expand Up @@ -235,12 +235,14 @@ impl ShortFileName {
b'.' => {
if idx >= 1 && idx <= 8 {
seen_dot = true;
idx = 8;
} else {
return Err(FilenameError::MisplacedPeriod);
}
}
_ => {
let ch = ch.to_ascii_uppercase();
trace!("char: '{}', at: {}", ch as char, idx);
if seen_dot {
if idx >= 8 && idx < 11 {
sfn.ext[idx - 8] = ch;
Expand All @@ -250,6 +252,7 @@ impl ShortFileName {
} else if idx < 8 {
sfn.name[idx] = ch;
} else {
trace!("1");
return Err(FilenameError::NameTooLong);
}
idx += 1;
Expand Down
7 changes: 7 additions & 0 deletions pkg/fs/src/structs/directory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ impl Directory {
entry: None,
}
}

pub fn from_entry(entry: DirEntry) -> Self {
Directory {
cluster: entry.cluster,
entry: Some(entry),
}
}
}

impl core::fmt::Display for Directory {
Expand Down
Loading

0 comments on commit 2308965

Please sign in to comment.