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

Commit

Permalink
feat(fs): add file truncate
Browse files Browse the repository at this point in the history
  • Loading branch information
RatCornu committed Jan 25, 2024
1 parent f497a62 commit dba6601
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 18 deletions.
20 changes: 16 additions & 4 deletions src/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,29 @@ pub struct Stat {
///
/// Defined in [this POSIX definition](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_164).
pub trait File {
/// Error type associated with the directories of the [`FileSystem`](crate::fs::FileSystem) they belong to.
type Error: core::error::Error;

/// Retrieves information about this file.
fn stat(&self) -> Stat;

/// Retrieves the [`Type`] of this file.
fn get_type(&self) -> Type;
}

/// A file that is a randomly accessible sequence of bytes, with no further structure imposed by the system.
///
/// Defined in [this POSIX definition](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_323).
pub trait Regular: File + Read + Write + Seek {}
pub trait Regular: File + Read + Write + Seek {
/// Trunctates the file size to the given `size` (in bytes).
///
/// If the given `size` is greater than the previous file size, this function does nothing.
///
/// # Errors
///
/// Returns an [`DevError`](crate::dev::error::DevError) if the device on which the directory is located could not be read.
fn truncate(&mut self, size: u64) -> Result<(), Error<<Self as File>::Error>>;
}

/// An object that associates a filename with a file. Several directory entries can associate names with the same file.
///
Expand All @@ -87,9 +102,6 @@ pub struct DirectoryEntry<'path, Dir: Directory> {
///
/// Defined in [this POSIX definition](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_129).
pub trait Directory: Sized + File {
/// Error type associated with the directories of the [`FileSystem`](crate::fs::FileSystem) they belong to.
type Error: core::error::Error;

/// Type of the regular files in the [`FileSystem`](crate::fs::FileSystem) this directory belongs to.
type Regular: Regular;

Expand Down
56 changes: 54 additions & 2 deletions src/fs/ext2/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ impl<D: Device<u8, Ext2Error>> File<D> {
}

impl<D: Device<u8, Ext2Error>> file::File for File<D> {
type Error = Ext2Error;

#[inline]
fn stat(&self) -> file::Stat {
let filesystem = self.filesystem.borrow();
Expand Down Expand Up @@ -142,6 +144,12 @@ impl<D: Device<u8, Ext2Error>> file::File for File<D> {
blkcnt: Blkcnt(self.inode.blocks.try_into().unwrap_or_default()),
}
}

#[inline]
fn get_type(&self) -> file::Type {
// SAFETY: the file type as been checked during the inode's parse
unsafe { self.inode.file_type().unwrap_unchecked() }
}
}

/// Implementation of a regular file.
Expand Down Expand Up @@ -761,10 +769,17 @@ impl<D: Device<u8, Ext2Error>> Regular<D> {
}

impl<D: Device<u8, Ext2Error>> file::File for Regular<D> {
type Error = Ext2Error;

#[inline]
fn stat(&self) -> Stat {
self.file.stat()
}

#[inline]
fn get_type(&self) -> file::Type {
self.file.get_type()
}
}

impl<D: Device<u8, Ext2Error>> Base for Regular<D> {
Expand Down Expand Up @@ -797,7 +812,31 @@ impl<D: Device<u8, Ext2Error>> Seek for Regular<D> {
}
}

impl<D: Device<u8, Ext2Error>> file::Regular for Regular<D> {}
impl<D: Device<u8, Ext2Error>> file::Regular for Regular<D> {
#[inline]
fn truncate(&mut self, size: u64) -> Result<(), Error<<Self as file::File>::Error>> {
if u64::from(self.file.inode.size) <= size {
return Ok(());
}

let fs = self.file.filesystem.borrow();

let mut new_inode = self.file.inode;
// SAFETY: the result is smaller than `u32::MAX`
new_inode.size = unsafe { u32::try_from(u64::from(u32::MAX) & size).unwrap_unchecked() };

let starting_addr = Inode::starting_addr(&fs.device, fs.superblock(), self.file.inode_number)?;

// SAFETY: this writes an inode at the starting address of the inode
unsafe {
fs.device.borrow_mut().write_at(starting_addr, new_inode)?;
};

drop(fs);

self.file.update_inner_inode()
}
}

/// Interface for ext2's directories.
#[derive(Debug)]
Expand Down Expand Up @@ -837,14 +876,20 @@ impl<D: Device<u8, Ext2Error>> Directory<D> {
}

impl<D: Device<u8, Ext2Error>> file::File for Directory<D> {
type Error = Ext2Error;

#[inline]
fn stat(&self) -> Stat {
self.file.stat()
}

#[inline]
fn get_type(&self) -> file::Type {
self.file.get_type()
}
}

impl<Dev: Device<u8, Ext2Error>> file::Directory for Directory<Dev> {
type Error = Ext2Error;
type File = File<Dev>;
type Regular = Regular<Dev>;
type SymbolicLink = SymbolicLink<Dev>;
Expand Down Expand Up @@ -912,10 +957,17 @@ impl<D: Device<u8, Ext2Error>> SymbolicLink<D> {
}

impl<D: Device<u8, Ext2Error>> file::File for SymbolicLink<D> {
type Error = Ext2Error;

#[inline]
fn stat(&self) -> Stat {
self.file.stat()
}

#[inline]
fn get_type(&self) -> file::Type {
self.file.get_type()
}
}

impl<D: Device<u8, Ext2Error>> file::SymbolicLink for SymbolicLink<D> {
Expand Down
4 changes: 2 additions & 2 deletions src/fs/ext2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ impl<Dev: Device<u8, Ext2Error>> Celled<Ext2<Dev>> {

impl<Dev: Device<u8, Ext2Error>> FileSystem<Directory<Dev>> for Celled<Ext2<Dev>> {
#[inline]
fn root(&self) -> Result<Directory<Dev>, Error<<Directory<Dev> as crate::file::Directory>::Error>> {
fn root(&self) -> Result<Directory<Dev>, Error<<Directory<Dev> as crate::file::File>::Error>> {
self.file(ROOT_DIRECTORY_INODE).and_then(|root| match root {
TypeWithFile::Directory(root_dir) => Ok(root_dir),
TypeWithFile::Regular(_) | TypeWithFile::SymbolicLink(_) | TypeWithFile::Other(_) => {
Expand All @@ -429,7 +429,7 @@ impl<Dev: Device<u8, Ext2Error>> FileSystem<Directory<Dev>> for Celled<Ext2<Dev>
}

#[inline]
fn double_slash_root(&self) -> Result<Directory<Dev>, Error<<Directory<Dev> as crate::file::Directory>::Error>> {
fn double_slash_root(&self) -> Result<Directory<Dev>, Error<<Directory<Dev> as crate::file::File>::Error>> {
self.root()
}
}
Expand Down
16 changes: 6 additions & 10 deletions src/fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub trait FileSystem<Dir: Directory> {
///
/// If you do not have any idea of what this is, you are probably looking for [`root`](trait.FileSystem.html#tymethod.root).
///
/// See [`Component::DoubleSlashRootDir`] and [`Path`] for more information.
/// See [`DoubleSlashRootDir`](Component::DoubleSlashRootDir) and [`Path`] for more information.
///
/// # Errors
///
Expand All @@ -64,19 +64,14 @@ pub trait FileSystem<Dir: Directory> {
///
/// Returns an [`NoEnt`](FsError::NoEnt) error if an encountered symlink points to a non-existing file.
#[inline]
fn pathname_resolution(
&self,
path: &Path,
current_dir: Dir,
symlink_resolution: bool,
) -> Result<TypeWithFile<Dir>, Error<Dir::Error>>
fn get_file(&self, path: &Path, current_dir: Dir, symlink_resolution: bool) -> Result<TypeWithFile<Dir>, Error<Dir::Error>>
where
Self: Sized,
{
/// Auxiliary function used to store the visited symlinks during the pathname resolution to detect loops caused bt symbolic
/// links.
#[inline]
fn inner_resolution<
fn path_resolution<
E: core::error::Error,
R: Regular,
SL: SymbolicLink,
Expand Down Expand Up @@ -132,6 +127,7 @@ pub trait FileSystem<Dir: Directory> {
TypeWithFile::Directory(dir) => {
current_dir = dir;
},

// This case is the symbolic link resolution, which is the one described as **not** being the one
// explained in the following paragraph from the POSIX definition of the
// pathname resolution:
Expand Down Expand Up @@ -187,12 +183,12 @@ pub trait FileSystem<Dir: Directory> {
if complete_path.len() >= PATH_MAX {
Err(Error::Fs(FsError::NameTooLong(complete_path.to_string())))
} else {
inner_resolution(fs, &complete_path, current_dir, symlink_resolution, visited_symlinks)
path_resolution(fs, &complete_path, current_dir, symlink_resolution, visited_symlinks)
}
},
}
}

inner_resolution(self, path, current_dir, symlink_resolution, vec![])
path_resolution(self, path, current_dir, symlink_resolution, vec![])
}
}

0 comments on commit dba6601

Please sign in to comment.