Skip to content
This repository has been archived by the owner on Mar 15, 2024. It is now read-only.

Commit

Permalink
test(ext2): add basic file write tests
Browse files Browse the repository at this point in the history
  • Loading branch information
RatCornu committed Jan 7, 2024
1 parent aadfe4d commit b25cf03
Show file tree
Hide file tree
Showing 10 changed files with 190 additions and 134 deletions.
9 changes: 6 additions & 3 deletions src/dev/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,14 +195,14 @@ pub trait Device<T: Copy, E: core::error::Error> {
///
/// # Errors
///
/// Returns an [`Error`](Device::Error) if the read could not be completed.
/// Returns an [`Error`] if the read could not be completed.
fn slice(&self, addr_range: Range<Address>) -> Result<Slice<'_, T>, Error<E>>;

/// Writes the [`Commit`] onto the device.
///
/// # Errors
///
/// Returns an [`Error`](Device::Error) if the write could not be completed.
/// Returns an [`Error`] if the write could not be completed.
fn commit(&mut self, commit: Commit<T>) -> Result<(), Error<E>>;

/// Read an element of type `O` on the device starting at the address `starting_addr`.
Expand Down Expand Up @@ -230,6 +230,9 @@ pub trait Device<T: Copy, E: core::error::Error> {

/// Writes an element of type `O` on the device starting at the address `starting_addr`.
///
/// Beware, the `object` **must be the owned `O` object and not a borrow**, otherwise the pointer to the object will be copied,
/// and not the object itself.
///
/// # Errors
///
/// Returns an [`Error`] if the read tries to go out of the device's bounds or if [`Device::slice`] or [`Device::commit`]
Expand Down Expand Up @@ -325,7 +328,7 @@ impl_device!(&mut [T]);
impl_device!(Vec<T>);
impl_device!(Box<[T]>);

#[cfg(feature = "std")]
#[cfg(not(no_std))]
impl<E: core::error::Error> Device<u8, E> for RefCell<File> {
#[inline]
fn size(&self) -> Size {
Expand Down
4 changes: 2 additions & 2 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub enum Error<E: core::error::Error> {
Path(PathError),

/// Standard I/O error
#[cfg(feature = "std")]
#[cfg(not(no_std))]
IO(std::io::Error),
}

Expand All @@ -32,7 +32,7 @@ impl<E: core::error::Error> Display for Error<E> {
Self::Device(device_error) => write!(formatter, "Device Error: {device_error}"),
Self::Fs(fs_error) => write!(formatter, "Filesystem Error: {fs_error}"),
Self::Path(path_error) => write!(formatter, "Path Error: {path_error}"),
#[cfg(feature = "std")]
#[cfg(not(no_std))]
Self::IO(io_error) => write!(formatter, "I/O Error: {io_error}"),
}
}
Expand Down
102 changes: 83 additions & 19 deletions src/fs/ext2/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,27 @@ impl<Dev: Device<u8, Ext2Error>> Block<Dev> {
let block_group_descriptor = BlockGroupDescriptor::parse(&fs.device, fs.superblock(), block_group)?;
let mut block_group_descriptor_bitmap_block = Self::new(self.filesystem.clone(), block_group_descriptor.block_bitmap);

let bitmap = block_group_descriptor_bitmap_block.read_all()?;
let bitmap_index = self.group_index();

let bitmap_index = u64::from(self.group_index());
let byte_index = bitmap_index / 8;
let byte_offset = bitmap_index % 8;

// SAFETY: `bitmap_index < block_size`
Ok(unsafe { (bitmap.get_unchecked(byte_index as usize) >> byte_offset) & 1 } == 0)
let mut buffer = [0_u8];
block_group_descriptor_bitmap_block.seek(SeekFrom::Start(byte_index))?;
block_group_descriptor_bitmap_block.read(&mut buffer)?;

Ok((buffer[0] >> byte_offset) & 1 == 0)
}

/// Returns whether this block is currently used or not.
///
/// As this operation needs to read directly from the given device, it is quite costly in computational time.
///
/// # Errors
///
/// Returns a [`Error`] if the device cannot be read.
#[inline]
pub fn is_used(&self) -> Result<bool, Error<Ext2Error>> {
self.is_free().map(|is_free| !is_free)
}

/// Sets the current block usage in the block bitmap, and updates the superblock accordingly.
Expand All @@ -105,6 +118,8 @@ impl<Dev: Device<u8, Ext2Error>> Block<Dev> {
///
/// Returns an [`BlockAlreadyInUse`](Ext2Error::BlockAlreadyInUse) error if the given block was already in use.
///
/// Returns an [`BlockAlreadyFree`](Ext2Error::BlockAlreadyFree) error if the given block was already free.
///
/// Otherwise, returns an [`Error`] if the device cannot be written.
fn set_usage(&mut self, used: bool) -> Result<(), Error<Ext2Error>> {
let fs = self.filesystem.borrow();
Expand All @@ -122,18 +137,13 @@ impl<Dev: Device<u8, Ext2Error>> Block<Dev> {
block_group_descriptor_bitmap_block.seek(SeekFrom::Start(u64::from(byte_index)))?;
block_group_descriptor_bitmap_block.read(&mut buffer)?;

if (buffer[0] >> byte_offset) & 1 == used.into() {
if used {
Err(Ext2Error::BlockAlreadyInUse(self.number).into())
} else {
Err(Ext2Error::BlockAlreadyFree(self.number).into())
}
} else if used {
buffer[0] |= 1 << byte_offset;
block_group_descriptor_bitmap_block.write(&buffer)?;
Ok(())
if (buffer[0] >> byte_offset) & 1 == 1 && used {
Err(Ext2Error::BlockAlreadyInUse(self.number).into())
} else if (buffer[0] >> byte_offset) & 1 == 0 && !used {
Err(Ext2Error::BlockAlreadyFree(self.number).into())
} else {
buffer[0] &= 0 << byte_offset;
buffer[0] ^= 1 << byte_offset;
block_group_descriptor_bitmap_block.seek(SeekFrom::Current(-1_i64))?;
block_group_descriptor_bitmap_block.write(&buffer)?;
Ok(())
}
Expand All @@ -143,7 +153,7 @@ impl<Dev: Device<u8, Ext2Error>> Block<Dev> {
///
/// # Errors
///
/// Returns an [`BlockAlreadyInUse`](Ext2Error::BlockAlreadyInUse) error if the given block was already in use.
/// Returns an [`BlockAlreadyFree`](Ext2Error::BlockAlreadyFree) error if the given block was already free.
///
/// Otherwise, returns an [`Error`] if the device cannot be written.
#[inline]
Expand Down Expand Up @@ -193,7 +203,7 @@ impl<Dev: Device<u8, Ext2Error>> Read<Ext2Error> for Block<Dev> {
let device = fs.device.borrow();

let length = ((fs.superblock().block_size() - self.io_offset) as usize).min(buf.len());
let starting_addr = Address::new((self.number * fs.superblock().block_size()) as usize);
let starting_addr = Address::new((self.number * fs.superblock().block_size() + self.io_offset) as usize);
let slice = device.slice(starting_addr..starting_addr + length)?;
buf.clone_from_slice(slice.as_ref());

Expand Down Expand Up @@ -276,7 +286,7 @@ mod test {

#[test]
fn block_read() {
const BLOCK_NUMBER: u32 = 9;
const BLOCK_NUMBER: u32 = 2;

let file = RefCell::new(File::options().read(true).write(true).open("./tests/fs/ext2/io_operations.ext2").unwrap());
let celled_file = Celled::new(file);
Expand Down Expand Up @@ -327,4 +337,58 @@ mod test {

fs::remove_file("./tests/fs/ext2/io_operations_copy_block_write.ext2").unwrap();
}

#[test]
fn block_set_free() {
// This block should not be free
const BLOCK_NUMBER: u32 = 9;

fs::copy("./tests/fs/ext2/io_operations.ext2", "./tests/fs/ext2/io_operations_copy_block_set_free.ext2").unwrap();

let file = RefCell::new(
File::options()
.read(true)
.write(true)
.open("./tests/fs/ext2/io_operations_copy_block_set_free.ext2")
.unwrap(),
);
let ext2 = Celled::new(Ext2::new(file, 0).unwrap());

let mut block = Block::new(ext2, BLOCK_NUMBER);

assert!(block.is_used().unwrap());

block.set_free().unwrap();

assert!(block.is_free().unwrap());

fs::remove_file("./tests/fs/ext2/io_operations_copy_block_set_free.ext2").unwrap();
}

#[test]
fn block_set_used() {
// This block should not be used
const BLOCK_NUMBER: u32 = 1234;

fs::copy("./tests/fs/ext2/io_operations.ext2", "./tests/fs/ext2/io_operations_copy_block_set_used.ext2").unwrap();

let file = RefCell::new(
File::options()
.read(true)
.write(true)
.open("./tests/fs/ext2/io_operations_copy_block_set_used.ext2")
.unwrap(),
);
let ext2 = Celled::new(Ext2::new(file, 0).unwrap());

let mut block = Block::new(ext2, BLOCK_NUMBER);

assert!(block.is_free().unwrap());

block.set_used().unwrap();

assert!(block.is_used().unwrap());

fs::remove_file("./tests/fs/ext2/io_operations_copy_block_set_used.ext2").unwrap();
}
}
Loading

0 comments on commit b25cf03

Please sign in to comment.