use anyhow::anyhow;
use bitvec::{order::Lsb0, vec::BitVec};
use serde::{Deserialize, Serialize};
use std::fs::{File, OpenOptions};
use std::io::{BufRead, BufReader, BufWriter, Cursor, Seek, SeekFrom};
use std::{
collections::BTreeMap,
ffi::OsString,
io::{Read, Write},
path::Path,
};
use util::*;
const MAGIC: [u8; 7] = *b"*bitfs*";
const FS_VERSION: u32 = 1;
const ROOT_INODE_INDEX: u32 = 2;
const BLOCK_SIZE: u32 = 4096;
const BLOCKS_PER_GROUP: u32 = BLOCK_SIZE * 8;
const INODE_CAPACITY: usize = 4047;
const INODE_MAX_REGION: usize = 500;
pub mod util;
#[derive(Debug)]
pub struct FS {
pub superblock: Superblock,
pub file: File,
pub groups: Vec<Group>,
pub lookup_table: Vec<u8>,
}
impl FS {
pub fn init<P>(path: P, secret: &str) -> anyhow::Result<Self>
where
P: AsRef<Path>,
{
let file = OpenOptions::new()
.read(true)
.write(true)
.create_new(true)
.open(path.as_ref())?;
let superblock = Superblock::new();
let mut fs = Self {
superblock,
file,
groups: vec![],
lookup_table: create_lookup_table(secret.as_bytes(), BLOCK_SIZE),
};
let mut group = Group::init();
group.force_allocate_at(0);
fs.add_group(group)?;
fs.init_directory_index()?;
Ok(fs)
}
pub fn new<P>(path: P, secret: &str) -> anyhow::Result<Self>
where
P: AsRef<Path>,
{
let mut file = OpenOptions::new()
.read(true)
.write(true)
.open(path.as_ref())?;
let mut r = BufReader::new(&mut file);
r.seek(SeekFrom::Start(0))?;
let superblock: Superblock = Superblock::deserialize_from(&mut r)?;
let mut groups = vec![];
for group_index in 0..superblock.group_count {
let group = Group::deserialize_from(&mut r, group_index)?;
groups.push(group);
}
let fs = Self {
superblock,
groups,
file,
lookup_table: create_lookup_table(secret.as_bytes(), BLOCK_SIZE),
};
Ok(fs)
}
#[inline]
pub fn get_directory_index(&self) -> anyhow::Result<DirectoryIndex> {
let mut inode = self.get_inode(ROOT_INODE_INDEX)?;
let mut data = vec![];
{
let mut w = BufWriter::new(&mut data);
self.read_inode_data(&mut inode, &mut w)?;
}
let mut directory_index: DirectoryIndex = bincode::deserialize(&data)?;
if !directory_index.verify_checksum() {
return Err(anyhow!("Directory index checksum error"));
}
Ok(directory_index)
}
fn save_directory_index(&mut self, mut directory_index: DirectoryIndex) -> anyhow::Result<()> {
let mut inode = self.get_inode(ROOT_INODE_INDEX)?;
directory_index.checksum();
let data = bincode::serialize(&directory_index)?;
let mut w = Cursor::new(&data);
self.write_inode_data(&mut inode, &mut w, data.len() as u64)?;
Ok(())
}
fn init_directory_index(&mut self) -> anyhow::Result<()> {
let di = DirectoryIndex::init();
let di_data = bincode::serialize(&di)?;
let mut r = Cursor::new(&di_data);
let mut directory_index_inode = Inode::new(ROOT_INODE_INDEX);
self.save_inode(&mut directory_index_inode)?;
self.write_inode_data(&mut directory_index_inode, &mut r, di_data.len() as u64)?;
Ok(())
}
#[inline]
pub fn find_directory<P>(&self, dir: P) -> anyhow::Result<(Directory, u32)>
where
P: AsRef<Path>,
{
let directory_index = self.get_directory_index()?;
if let Some(directory_inode_index) = directory_index.find_dir(dir) {
let mut directory_inode = self.get_inode(*directory_inode_index)?;
let mut data = Vec::new();
{
let mut w = BufWriter::new(&mut data);
self.read_inode_data(&mut directory_inode, &mut w)?;
}
let directory: Directory = bincode::deserialize(&data)?;
return Ok((directory, *directory_inode_index));
} else {
return Err(anyhow!("Directory not found"));
}
}
#[inline]
fn save_directory(
&mut self,
directory: Directory,
directory_inode_index: u32,
) -> anyhow::Result<Directory> {
let mut directory_inode = self.get_inode(directory_inode_index)?;
let data = bincode::serialize(&directory)?;
let mut reader = Cursor::new(&data);
self.write_inode_data(&mut directory_inode, &mut reader, data.len() as u64)?;
Ok(directory)
}
#[inline]
pub fn create_directory<P>(&mut self, dir: P) -> anyhow::Result<Directory>
where
P: AsRef<Path>,
{
let mut directory_index = self.get_directory_index()?;
let directory_inode = if let Some(i) = self.allocate_inode() {
i
} else {
return Err(anyhow!("Could not allocate inode block"));
};
if let None = directory_index.create_dir(dir, directory_inode.block_index) {
self.release_inode(directory_inode.block_index)?;
}
self.save_directory_index(directory_index)?;
let directory = Directory::init();
self.save_directory(directory, directory_inode.block_index)
}
#[inline]
pub fn get_file_info<P>(&mut self, dir: P, file_name: &str) -> anyhow::Result<Inode>
where
P: AsRef<Path>,
{
let (dir, _dir_inode_index) = self.find_directory(dir)?;
if let Some(inode_block_index) = dir.get_file(file_name) {
return self.get_inode(inode_block_index);
} else {
return Err(anyhow!("File not found"));
}
}
#[inline]
pub fn add_file<P, R>(
&mut self,
dir: P,
file_name: &str,
data: &mut R,
data_len: u64,
) -> anyhow::Result<()>
where
P: AsRef<Path>,
R: BufRead,
{
let (mut dir, dir_inode_index) = self.find_directory(dir)?;
let mut file_inode = if let Some(inode_block_index) = dir.get_file(file_name) {
self.get_inode(inode_block_index)?
} else {
let file_inode = self.allocate_inode().unwrap();
dir.add_file(file_name, file_inode.block_index)?;
self.save_directory(dir, dir_inode_index)?;
self.superblock_mut().file_count += 1;
file_inode
};
self.write_inode_data(&mut file_inode, data, data_len)?;
self.save_superblock()?;
Ok(())
}
#[inline]
pub fn remove_file(&mut self, dir: &str, file_name: &str) -> anyhow::Result<()> {
let (mut dir, dir_inode_index) = self.find_directory(dir)?;
let file_inode = if let Some(inode_block_index) = dir.get_file(file_name) {
if let Ok(inode) = self.get_inode(inode_block_index) {
inode
} else {
return Err(anyhow!("No file found in dir!"));
}
} else {
return Err(anyhow!("Unknown directory!"));
};
self.release_inode(file_inode.block_index)?;
dir.remove_file(file_name)?;
self.save_directory(dir, dir_inode_index)?;
self.save_superblock()?;
Ok(())
}
#[inline]
pub fn get_file_data<P, W>(&mut self, dir: P, file_name: &str, w: &mut W) -> anyhow::Result<u32>
where
P: AsRef<Path>,
W: Write,
{
let (directory, _) = self.find_directory(dir)?;
let mut file_inode = if let Some(file_inode_index) = directory.get_file(file_name) {
self.get_inode(file_inode_index)?
} else {
return Err(anyhow!("File not found"));
};
self.read_inode_data(&mut file_inode, w)
}
#[inline]
fn superblock_check(&mut self) {
self.superblock.group_count = self.groups.len() as u32;
self.superblock.free_blocks = self
.groups
.iter()
.map(|g| g.block_bitmap.count_zeros() as u32)
.sum();
self.superblock.block_count = self
.groups
.iter()
.map(|g| g.total_data_blocks() as u32)
.sum();
self.superblock.modified = now();
self.superblock.checksum();
}
#[inline]
fn save_superblock(&mut self) -> anyhow::Result<()> {
self.superblock_check();
let mut w = BufWriter::new(&self.file);
let mut data = bincode::serialize(&self.superblock)?;
w.seek(SeekFrom::Start(0))?;
w.write_all(&mut data)?;
Ok(())
}
#[inline]
fn get_inode(&self, inode_block_index: u32) -> anyhow::Result<Inode> {
let mut r = BufReader::new(&self.file);
r.seek(SeekFrom::Start(
block_seek_position(inode_block_index) as u64
))?;
let inode: Inode = Inode::deserialize_from(r)?;
Ok(inode)
}
#[inline]
fn save_inode(&mut self, inode: &mut Inode) -> anyhow::Result<()> {
let mut w = BufWriter::new(&self.file);
w.seek(SeekFrom::Start(
block_seek_position(inode.block_index) as u64
))?;
inode.set_last_modified();
inode.serialize_into(w)?;
Ok(())
}
#[inline]
fn save_group(&mut self, group: Group, group_index: u32) -> anyhow::Result<()> {
self.groups[group_index as usize] = group.clone();
let mut w = BufWriter::new(&self.file);
w.seek(SeekFrom::Start(Group::seek_position(group_index) as u64))?;
group.serialize_into(w)?;
Ok(())
}
#[inline]
fn read_inode_data<W>(&self, inode: &mut Inode, w: &mut W) -> anyhow::Result<u32>
where
W: Write,
{
let mut checksum = Checksum::new();
let mut r = BufReader::new(&self.file);
match &mut inode.data {
Data::Raw(data) => {
encrypt(data, &self.lookup_table);
checksum.update(&data);
w.write_all(&data)?;
}
Data::DirectPointers(pointers) => {
let mut data_left = inode.size;
let mut block_buffer: Vec<u8> = Vec::with_capacity(BLOCK_SIZE as usize);
unsafe { block_buffer.set_len(BLOCK_SIZE as usize) };
for (block_index, range) in pointers {
r.seek(SeekFrom::Start(block_seek_position(*block_index) as u64))?;
for _ in *block_index..(*block_index + *range) {
if data_left < BLOCK_SIZE as u64 {
block_buffer = Vec::with_capacity(data_left as usize);
unsafe { block_buffer.set_len(data_left as usize) };
};
r.read_exact(&mut block_buffer)?;
encrypt(&mut block_buffer, &self.lookup_table);
checksum.update(&block_buffer);
w.write_all(&mut block_buffer)?;
data_left -= block_buffer.capacity() as u64;
}
}
}
}
Ok(checksum.finalize())
}
#[inline]
fn write_inode_data<R>(
&mut self,
inode: &mut Inode,
data: &mut R,
data_len: u64,
) -> anyhow::Result<()>
where
R: BufRead,
{
match &inode.data {
Data::Raw(_) => (),
Data::DirectPointers(pointers) => self.release_inode_data(pointers.clone())?,
}
if data_len as usize <= INODE_CAPACITY {
let mut buffer = vec![];
data.read_to_end(&mut buffer)?;
encrypt(&mut buffer, &self.lookup_table);
let mut data = Cursor::new(&buffer);
inode.set_raw_data(&mut data, data_len)?;
self.save_inode(inode)?;
return Ok(());
}
inode.size = data_len;
self.save_inode(inode)?;
let mut ranges: Vec<(u32, u32)> = vec![];
let blocks_to_allocate = |data_size| {
data_size / BLOCK_SIZE as u64 + u64::from(data_size % BLOCK_SIZE as u64 != 0)
};
let mut block_to_allocate = blocks_to_allocate(data_len);
while self.superblock().free_blocks < block_to_allocate as u32 {
self.add_group(Group::init())?;
}
let groups = self.groups.clone();
for (group_index, mut group) in groups.into_iter().enumerate() {
if block_to_allocate > 0 {
let (mut range, left) = group.allocate_region(
group_index as u32,
block_to_allocate as usize,
INODE_MAX_REGION,
);
self.save_group(group, group_index as u32)?;
ranges.append(&mut range);
block_to_allocate = left as u64;
}
}
inode.set_direct_pointers(ranges.clone(), data_len);
self.save_inode(inode)?;
let mut data_left = data_len;
let mut w = BufWriter::new(&self.file);
let mut block_buffer: Vec<u8> = Vec::with_capacity(BLOCK_SIZE as usize);
unsafe { block_buffer.set_len(BLOCK_SIZE as usize) };
for (block_index, range) in ranges {
w.seek(SeekFrom::Start(block_seek_position(block_index) as u64))?;
for _ in block_index..(block_index + range) {
if data_left < BLOCK_SIZE as u64 {
block_buffer = Vec::with_capacity(data_left as usize);
unsafe { block_buffer.set_len(data_left as usize) };
};
data.read_exact(&mut block_buffer)?;
encrypt(&mut block_buffer, &self.lookup_table);
w.write_all(&mut block_buffer)?;
data_left -= block_buffer.capacity() as u64;
}
}
assert!(data_left == 0);
w.flush()?;
Ok(())
}
#[inline]
fn truncate(&mut self) -> anyhow::Result<()> {
let size =
BLOCK_SIZE + (self.groups.len() as u32) * (BLOCK_SIZE + BLOCKS_PER_GROUP * BLOCK_SIZE);
self.file.set_len(size as u64)?;
Ok(())
}
#[inline]
fn allocate_inode(&mut self) -> Option<Inode> {
let mut res = None;
for (group_index, group) in self.groups_mut().iter_mut().enumerate() {
if let Some(inode_block_index) = group.allocate_one(group_index as u32) {
let inode = Inode::new(inode_block_index);
res = Some(inode);
break;
}
}
if let Some(inode) = &mut res {
self.save_inode(inode).unwrap();
}
res
}
#[inline]
fn add_group(&mut self, group: Group) -> anyhow::Result<()> {
self.groups.push(group.clone());
self.save_group(group, self.groups.len() as u32 - 1)?;
self.superblock.group_count += 1;
self.truncate()?;
self.save_superblock()?;
Ok(())
}
#[inline]
fn groups_mut(&mut self) -> &mut [Group] {
&mut self.groups
}
#[inline]
fn superblock(&self) -> &Superblock {
&self.superblock
}
#[inline]
fn superblock_mut(&mut self) -> &mut Superblock {
&mut self.superblock
}
#[inline]
fn release_inode_data(&mut self, data_pointers: Vec<(u32, u32)>) -> anyhow::Result<()> {
let mut groups = self.groups_mut().as_mut().to_owned();
for (block_index, range) in data_pointers {
let (group_index, bitmap_index) = Group::translate_public_address(block_index);
groups[group_index as usize].release_data_region(bitmap_index, range);
}
for (group_index, group) in groups.into_iter().enumerate() {
{
self.save_group(group, group_index as u32)?;
}
}
Ok(())
}
#[inline]
fn release_inode(&mut self, inode_block_index: u32) -> anyhow::Result<()> {
let inode = self.get_inode(inode_block_index)?;
let (group_index, bitmap_index) = Group::translate_public_address(inode_block_index);
match inode.data {
Data::Raw(_) => (),
Data::DirectPointers(direct_pointers) => self.release_inode_data(direct_pointers)?,
}
let mut group = self.groups[group_index as usize].to_owned();
{
group.release_one(bitmap_index);
}
self.save_group(group, group_index)?;
Ok(())
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Superblock {
magic: [u8; 7], fs_version: u32, block_size: u32, group_count: u32, block_count: u32, free_blocks: u32, file_count: u32, created: u64, modified: u64, checksum: u32, }
impl Superblock {
fn new() -> Self {
Self {
magic: MAGIC,
fs_version: FS_VERSION,
block_size: BLOCK_SIZE,
group_count: 0,
block_count: 1,
free_blocks: 0,
file_count: 0,
created: now(),
modified: now(),
checksum: 0,
}
}
pub fn update_modified(&mut self) {
self.modified = now();
}
#[allow(dead_code)]
pub fn serialize(&mut self) -> anyhow::Result<Vec<u8>> {
self.checksum();
bincode::serialize(self).map_err(|e| e.into())
}
#[inline]
pub fn serialize_into<W>(&mut self, w: W) -> anyhow::Result<()>
where
W: Write,
{
self.checksum();
bincode::serialize_into(w, self).map_err(|e| e.into())
}
#[inline]
pub fn deserialize_from<R>(r: R) -> anyhow::Result<Self>
where
R: Read,
{
let mut sb: Self = bincode::deserialize_from(r)?;
if !sb.verify_checksum() {
return Err(anyhow!("Superblock checksum verification failed"));
}
Ok(sb)
}
#[inline]
fn checksum(&mut self) {
self.checksum = 0;
self.checksum = calculate_checksum(&self);
}
#[inline]
fn verify_checksum(&mut self) -> bool {
let checksum = self.checksum;
self.checksum = 0;
let ok = checksum == calculate_checksum(&self);
self.checksum = checksum;
ok
}
}
#[derive(Debug, Default, Clone)]
pub struct Group {
pub block_bitmap: BitVec<u8, Lsb0>,
}
impl Group {
fn new(block_bitmap: BitVec<u8, Lsb0>) -> Self {
Self { block_bitmap }
}
pub fn init() -> Self {
let mut block_bitmap = BitVec::<u8, Lsb0>::with_capacity(BLOCK_SIZE as usize * 8);
block_bitmap.resize(BLOCK_SIZE as usize * 8, false);
Self { block_bitmap }
}
#[inline]
fn seek_position(group_index: u32) -> u32 {
BLOCK_SIZE + (group_index * (BLOCK_SIZE + BLOCKS_PER_GROUP * BLOCK_SIZE))
}
#[inline]
pub fn create_public_address(group_index: u32, bitmap_index: u32) -> u32 {
Self::seek_position(group_index) / BLOCK_SIZE + bitmap_index + 1
}
#[inline]
pub fn translate_public_address(mut block_index: u32) -> (u32, u32) {
block_index -= 1;
let n = BLOCKS_PER_GROUP + 1;
let group_index = (block_index as u32) / n;
let bitmap_index = if group_index == 0 {
block_index - 1
} else {
block_index % (group_index * n) - 1
};
(group_index, bitmap_index)
}
#[inline]
pub fn serialize_into<W>(&self, mut w: W) -> anyhow::Result<()>
where
W: Write + Seek,
{
w.write_all(self.block_bitmap.as_raw_slice())?;
Ok(())
}
#[inline]
pub fn deserialize_from<R>(mut r: R, group_index: u32) -> anyhow::Result<Group>
where
R: Read + Seek,
{
let mut buf = Vec::with_capacity(BLOCK_SIZE as usize);
unsafe {
buf.set_len(BLOCK_SIZE as usize);
}
let offset = Self::seek_position(group_index);
r.seek(SeekFrom::Start(offset as u64))?;
r.read_exact(&mut buf)?;
let data_bitmap = BitVec::<u8, Lsb0>::from_slice(&buf);
Ok(Group::new(data_bitmap))
}
#[inline]
pub fn free_data_blocks(&self) -> usize {
self.block_bitmap.count_zeros()
}
#[inline]
pub fn total_data_blocks(&self) -> usize {
self.block_bitmap.len()
}
#[inline]
fn release_one(&mut self, bitmap_index: u32) {
self.block_bitmap.set(bitmap_index as usize, false);
}
#[inline]
pub fn release_data_region(&mut self, bitmap_index: u32, length: u32) {
for i in bitmap_index..(bitmap_index + length) {
self.block_bitmap.set(i as usize, false);
}
}
#[inline]
fn force_allocate_at(&mut self, bitmap_index: u32) {
self.block_bitmap.set(bitmap_index as usize, true);
}
#[inline]
fn allocate_one(&mut self, group_index: u32) -> Option<u32> {
if let Some(bitmap_index) = self.block_bitmap.iter_zeros().next() {
self.block_bitmap.set(bitmap_index, true);
return Some(Self::create_public_address(
group_index,
bitmap_index as u32,
));
}
None
}
#[inline]
fn allocate_region(
&mut self,
group_index: u32,
mut blocks_to_allocate: usize,
max_regions: usize,
) -> (Vec<(u32, u32)>, usize) {
let mut regions = Vec::new();
let mut region: Option<(u32, u32)> = None;
let mut iter = self.block_bitmap.iter_mut().enumerate().peekable();
while let Some((bitmap_index, mut i)) = iter.next() {
if blocks_to_allocate == 0 {
if let Some(r) = region.take() {
regions.push(r);
}
break;
}
if !*i {
if let Some((_block_index, region_length)) = region.as_mut() {
*region_length += 1;
} else {
region = Some((
Self::create_public_address(group_index, bitmap_index as u32),
1,
));
}
blocks_to_allocate -= 1;
i.set(true);
} else {
if let Some(r) = region.take() {
regions.push(r);
if regions.len() == max_regions {
break;
}
}
}
if let None = iter.peek() {
if let Some(r) = region.take() {
regions.push(r);
}
}
}
(regions, blocks_to_allocate)
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Inode {
pub block_index: u32,
pub created: u64,
pub last_modified: u64,
pub size: u64,
pub data_checksum: u32,
pub data: Data,
}
#[derive(Serialize, Deserialize, Debug)]
pub enum Data {
Raw(Vec<u8>),
DirectPointers(Vec<(u32, u32)>),
}
impl Default for Data {
fn default() -> Self {
Self::Raw(vec![])
}
}
impl Inode {
pub fn new(block_index: u32) -> Self {
Self {
block_index,
created: now(),
last_modified: now(),
size: 0,
data_checksum: calculate_checksum(&()),
data: Data::Raw(vec![]),
}
}
#[inline]
pub fn serialize_into<W>(&self, mut w: W) -> anyhow::Result<()>
where
W: Write + Seek,
{
let serialized = bincode::serialize(&self)?;
assert!(serialized.len() as u32 <= BLOCK_SIZE);
w.write_all(&serialized)?;
w.flush()?;
Ok(())
}
#[inline]
pub fn deserialize_from<R>(mut r: R) -> anyhow::Result<Self>
where
R: Read + Seek,
{
let inode: Inode = bincode::deserialize_from(&mut r)?;
Ok(inode)
}
#[inline]
fn set_last_modified(&mut self) {
self.last_modified = now();
}
#[inline]
fn set_raw_data<R>(&mut self, data: &mut R, data_size: u64) -> anyhow::Result<()>
where
R: Read,
{
let mut buffer = vec![];
let data_len = data.read_to_end(&mut buffer)?;
if data_len != data_size as usize {
return Err(anyhow!("Data read and given data size are not the same"));
}
if data_len > INODE_CAPACITY as usize {
return Err(anyhow!(
"Data is too big to be raw data. Does not fit inside inode"
));
}
self.size = data_size;
self.data = Data::Raw(buffer);
Ok(())
}
#[inline]
fn set_direct_pointers(&mut self, pointers: Vec<(u32, u32)>, data_size: u64) {
self.data = Data::DirectPointers(pointers);
self.size = data_size;
}
}
#[derive(Serialize, Deserialize, Default, Debug)]
pub struct DirectoryIndex {
directories: BTreeMap<OsString, u32>,
checksum: u32,
}
impl DirectoryIndex {
pub fn init() -> Self {
let mut r = Self {
directories: BTreeMap::new(),
checksum: 0,
};
r.checksum();
r
}
pub fn find_dir<P>(&self, dir: P) -> Option<&u32>
where
P: AsRef<Path>,
{
self.directories.get(dir.as_ref().as_os_str())
}
pub fn create_dir<P>(&mut self, dir: P, inode_index: u32) -> Option<&u32>
where
P: AsRef<Path>,
{
if self.find_dir(&dir).is_some() {
return None;
}
self.directories
.insert(dir.as_ref().as_os_str().to_os_string(), inode_index);
self.find_dir(dir)
}
pub fn move_dir<P>(&mut self, from: P, to: P) -> anyhow::Result<()>
where
P: AsRef<Path>,
{
if self.find_dir(&from).is_none() {
return Err(anyhow!("From directory not found"));
}
if self.find_dir(&to).is_some() {
return Err(anyhow!("Target directory has already exist"));
}
let dir_inode = self.directories.remove(from.as_ref().as_os_str()).unwrap();
let _ = self
.directories
.insert(to.as_ref().as_os_str().to_os_string(), dir_inode);
Ok(())
}
pub fn directories(&self) -> &BTreeMap<OsString, u32> {
&self.directories
}
fn checksum(&mut self) {
self.checksum = 0;
self.checksum = calculate_checksum(&self);
}
fn verify_checksum(&mut self) -> bool {
let checksum = self.checksum;
self.checksum = 0;
let ok = checksum == calculate_checksum(&self);
self.checksum = checksum;
ok
}
}
#[derive(Serialize, Deserialize, Debug, Default)]
pub struct Directory {
pub files: BTreeMap<String, u32>,
checksum: u32,
}
impl Directory {
fn init() -> Self {
let mut dir = Directory {
files: BTreeMap::new(),
checksum: 0,
};
dir.checksum();
dir
}
pub fn get_file(&self, file_name: &str) -> Option<u32> {
self.files.get(file_name).map(|x| *x)
}
pub fn add_file(&mut self, file_name: &str, inode_block_index: u32) -> anyhow::Result<()> {
match self.get_file(file_name) {
Some(_) => Err(anyhow!("File already exist")),
None => {
self.files.insert(file_name.into(), inode_block_index);
Ok(())
}
}
}
fn remove_file(&mut self, file_name: &str) -> anyhow::Result<()> {
match self.files.remove(file_name) {
Some(_) => Ok(()),
None => Err(anyhow!("File not found!")),
}
}
fn checksum(&mut self) {
self.checksum = 0;
self.checksum = calculate_checksum(&self);
}
fn verify_checksum(&mut self) -> bool {
let checksum = self.checksum;
self.checksum = 0;
let ok = checksum == calculate_checksum(&self);
self.checksum = checksum;
ok
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_block_bitmap_seek_position() {
}
}