1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
/* filesystem.rs
*
* Developed by Tim Walls <tim.walls@snowgoons.com>
* Copyright (c) All Rights Reserved, Tim Walls
*/
//! Doc comment for this file
//!
// Imports ===================================================================
use core::ops::{AddAssign, SubAssign};
use avr_oxide::io::IoError;
use avr_oxide::OxideResult;
use avrox_storage::fs::{File, OpenOptions};
use avrox_storage::{FileAddr, SAddr};
// Declarations ==============================================================
#[derive(Copy,Clone,PartialEq,Eq)]
#[cfg_attr(not(target_arch="avr"), derive(Debug))]
#[cfg_attr(target_arch="avr", derive(ufmt::derive::uDebug))]
pub struct BlockNumber(u16);
pub const BLOCKSIZE : usize = 256;
pub type FileSystemResult<T> = OxideResult<T,IoError>;
pub trait FileSystemRead {
type FID : Copy;
const BLOCK_DATA_SIZE: usize;
/// Read from the given file location into the buffer. The number of
/// bytes read, and the new location at the end of the read, are returned.
///
/// This method does not guarantee to read all the bytes requested,
/// you must pay attention to the number of bytes read returned.
fn read_from_location(&self, file: Self::FID, block: BlockNumber, offset: usize, buf: &mut [u8]) -> FileSystemResult<(usize,(BlockNumber,usize))>;
/// Check if the given file exists
fn check_exists(&self, file: Self::FID) -> bool;
/// Return the size of the given file
fn get_file_size(&self, file: Self::FID) -> FileSystemResult<FileAddr>;
/// Return the approximate amount of free space, in bytes
fn get_free_space(&self) -> FileSystemResult<u64>;
/// Return the (block,offset) address for the given absolute file location
/// (bytes since start of file).
fn block_and_offset_for_file_location(&self, file: Self::FID, addr: FileAddr) -> FileSystemResult<(BlockNumber,usize)>;
/// Return the filesystem entry following the given filesystem entry in
/// the directory listing
fn get_next_file_in_directory(&self, parent: Option<Self::FID>, previous: Option<Self::FID>) -> Option<Self::FID>;
}
pub trait FileSystemWrite : FileSystemRead {
/// Open or create the identified file with the options given.
/// See the [`OpenOptions`] documentation for further details.
///
/// [`OpenOptions`]: avrox_storage::fs::OpenOptions
fn open<P: Into<Self::FID>>(&self, path: P, options: &OpenOptions) -> OxideResult<File<Self>,IoError> where Self: Sized;
/// Create the given file, with zero length
fn create_file(&self, file: Self::FID) -> OxideResult<(),IoError>;
/// Write from the given buffer to the given file location. The number
/// of bytes written, and the new location at the end of the last write,
/// are returned.
///
/// This method does not guarantee to write all the bytes requested,
/// you must pay attention to the number of bytes written returned.
fn write_at_location(&self, file: Self::FID, block: BlockNumber, offset: usize, buf: &[u8])
-> FileSystemResult<(usize,(BlockNumber,usize))>;
/// Truncate the given file so the location given points to the end of
/// the file. All remaining space is freed for re-allocation.
fn truncate_at(&self, file: Self::FID, block: BlockNumber, offset: usize) -> FileSystemResult<()>;
/// Delete the given file. The directory entry and all space associated
/// with the file is freed for reallocation.
fn remove_file(&self, file: Self::FID) -> FileSystemResult<()>;
/// Sync all data to the underlying storage
fn sync(&self) -> FileSystemResult<()>;
}
// Code ======================================================================
impl BlockNumber {
pub const INVALID : BlockNumber = BlockNumber(0);
pub const ZERO : BlockNumber = BlockNumber(0);
pub(crate) fn as_bytes(&self) -> [u8; 2] {
[
(self.0 >> 8) as u8,
self.0 as u8
]
}
pub(crate) fn from_bytes(buf: &[u8]) -> BlockNumber {
BlockNumber(((buf[0] as u16) << 8) | buf[1] as u16)
}
pub(crate) fn offset_addr(&self) -> SAddr {
BLOCKSIZE as SAddr * self.0 as SAddr
}
pub fn value(&self) -> u16 {
self.0
}
pub fn is_invalid(&self) -> bool {
self.0 == 0
}
pub fn is_valid(&self) -> bool {
!self.is_invalid()
}
}
impl AddAssign<u16> for BlockNumber {
fn add_assign(&mut self, rhs: u16) {
self.0 += rhs
}
}
impl SubAssign<u16> for BlockNumber {
fn sub_assign(&mut self, rhs: u16) {
self.0 -= rhs
}
}
impl From<u32> for BlockNumber {
fn from(val: u32) -> Self {
Self(val as u16)
}
}
// Tests =====================================================================