Skip to content

Commit

Permalink
Implements ftruncate and truncate (#654)
Browse files Browse the repository at this point in the history
  • Loading branch information
SuchAFuriousDeath committed Feb 17, 2024
1 parent 7e2563a commit 0c02b15
Show file tree
Hide file tree
Showing 7 changed files with 224 additions and 17 deletions.
39 changes: 36 additions & 3 deletions src/kernel/src/fs/file.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::{IoCmd, Offset, Stat, Uio, UioMut, Vnode};
use super::{IoCmd, Offset, Stat, TruncateLength, Uio, UioMut, Vnode};
use crate::dmem::BlockPool;
use crate::errno::Errno;
use crate::errno::{ENOTTY, ENXIO, EOPNOTSUPP};
use crate::errno::{EINVAL, ENOTTY, ENXIO, EOPNOTSUPP};
use crate::kqueue::KernelQueue;
use crate::net::Socket;
use crate::process::VThread;
Expand Down Expand Up @@ -122,6 +122,20 @@ impl VFile {
}
}

pub fn truncate(
&self,
length: TruncateLength,
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
match &self.backend {
VFileType::Vnode(vn) => vn.truncate(self, length, td),
VFileType::Socket(so) | VFileType::IpcSocket(so) => so.truncate(self, length, td),
VFileType::KernelQueue(kq) => kq.truncate(self, length, td),
VFileType::SharedMemory(shm) => shm.truncate(self, length, td),
VFileType::Blockpool(bp) => bp.truncate(self, length, td),
}
}

pub fn is_seekable(&self) -> bool {
matches!(self.backend, VFileType::Vnode(_))
}
Expand Down Expand Up @@ -203,6 +217,16 @@ pub trait FileBackend: Debug + Send + Sync + 'static {

#[allow(unused_variables)]
fn stat(self: &Arc<Self>, file: &VFile, td: Option<&VThread>) -> Result<Stat, Box<dyn Errno>>;

#[allow(unused_variables)]
fn truncate(
self: &Arc<Self>,
file: &VFile,
length: TruncateLength,
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
Err(Box::new(DefaultError::TruncateNotSupported))
}
}

#[derive(Debug, Error, Errno)]
Expand All @@ -215,10 +239,19 @@ pub enum DefaultError {
#[errno(ENXIO)]
WriteNotSupported,

#[error("iocll is not supported")]
#[error("ioctl is not supported")]
#[errno(ENOTTY)]
IoctlNotSupported,

#[error("truncating is not supported")]
#[errno(ENXIO)]
TruncateNotSupported,

/// This is used by some file backends to indicate that the operation is not supported.
#[error("invalid value provided")]
#[errno(EINVAL)]
InvalidValue,

#[error("operation is not supported")]
#[errno(EOPNOTSUPP)]
OperationNotSupported,
Expand Down
116 changes: 116 additions & 0 deletions src/kernel/src/fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ impl Fs {
sys.register(290, &fs, Self::sys_pwritev);
sys.register(476, &fs, Self::sys_pwrite);
sys.register(478, &fs, Self::sys_lseek);
sys.register(479, &fs, Self::sys_truncate);
sys.register(480, &fs, Self::sys_ftruncate);
sys.register(493, &fs, Self::sys_fstatat);
sys.register(496, &fs, Self::sys_mkdirat);

Expand Down Expand Up @@ -797,6 +799,50 @@ impl Fs {
todo!()
}

fn sys_truncate(self: &Arc<Self>, i: &SysIn) -> Result<SysOut, SysErr> {
let path = unsafe { i.args[0].to_path() }?.unwrap();
let length = i.args[1].into();

let td = VThread::current().unwrap();

self.truncate(path, length, &td)?;

Ok(SysOut::ZERO)
}

fn truncate(&self, path: &VPath, length: i64, td: &VThread) -> Result<(), TruncateError> {
let _length: TruncateLength = length.try_into()?;

let _vn = self.lookup(path, Some(&td))?;

todo!()
}

fn sys_ftruncate(self: &Arc<Self>, i: &SysIn) -> Result<SysOut, SysErr> {
let fd = i.args[0].try_into().unwrap();
let length = i.args[1].into();

let td = VThread::current().unwrap();

self.ftruncate(fd, length, &td)?;

Ok(SysOut::ZERO)
}

fn ftruncate(&self, fd: i32, length: i64, td: &VThread) -> Result<(), FileTruncateError> {
let length = length.try_into()?;

let file = td.proc().files().get(fd)?;

if !file.flags().contains(VFileFlags::WRITE) {
return Err(FileTruncateError::FileNotWritable);
}

file.truncate(length, Some(&td))?;

Ok(())
}

fn sys_mkdirat(self: &Arc<Self>, i: &SysIn) -> Result<SysOut, SysErr> {
let td = VThread::current().unwrap();

Expand Down Expand Up @@ -1048,6 +1094,20 @@ struct PollFd {
revents: i16, // likewise
}

pub struct TruncateLength(i64);

impl TryFrom<i64> for TruncateLength {
type Error = TruncateLengthError;
fn try_from(value: i64) -> Result<Self, Self::Error> {
if value < 0 {
Err(TruncateLengthError(()))
} else {
Ok(Self(value))
}
}
}
pub struct TruncateLengthError(());

/// Represents an error when FS was failed to initialized.
#[derive(Debug, Error)]
pub enum FsError {
Expand Down Expand Up @@ -1200,6 +1260,62 @@ impl Errno for StatError {
}
}

#[derive(Debug, Error)]
pub enum TruncateError {
#[error("the provided length is invalid")]
InvalidLength,

#[error("failed to get file")]
FailedToLookupFile(#[from] LookupError),
}

impl Errno for TruncateError {
fn errno(&self) -> NonZeroI32 {
match self {
Self::InvalidLength => EINVAL,
Self::FailedToLookupFile(e) => e.errno(),
}
}
}

impl From<TruncateLengthError> for TruncateError {
fn from(_: TruncateLengthError) -> Self {
Self::InvalidLength
}
}

#[derive(Debug, Error)]
pub enum FileTruncateError {
#[error("the provided length is invalid")]
InvalidLength,

#[error("failed to get file")]
FailedToGetFile(#[from] GetFileError),

#[error("file is not writable")]
FileNotWritable,

#[error(transparent)]
TruncateError(#[from] Box<dyn Errno>),
}

impl Errno for FileTruncateError {
fn errno(&self) -> NonZeroI32 {
match self {
Self::InvalidLength => EINVAL,
Self::FailedToGetFile(e) => e.errno(),
Self::FileNotWritable => EINVAL,
Self::TruncateError(e) => e.errno(),
}
}
}

impl From<TruncateLengthError> for FileTruncateError {
fn from(_: TruncateLengthError) -> Self {
Self::InvalidLength
}
}

static HOST: FsConfig = FsConfig {
name: "exfatfs",
ty: 0x2C,
Expand Down
15 changes: 13 additions & 2 deletions src/kernel/src/fs/vnode.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::{
unixify_access, Access, FileBackend, IoCmd, Mode, Mount, OpenFlags, RevokeFlags, Stat, Uio,
UioMut, VFile,
unixify_access, Access, FileBackend, IoCmd, Mode, Mount, OpenFlags, RevokeFlags, Stat,
TruncateLength, Uio, UioMut, VFile,
};
use crate::errno::{Errno, ENOTDIR, ENOTTY, EOPNOTSUPP, EPERM};
use crate::process::VThread;
Expand Down Expand Up @@ -154,9 +154,20 @@ impl FileBackend for Vnode {
todo!()
}

#[allow(unused_variables)] // TODO: remove when implementing
fn stat(self: &Arc<Self>, file: &VFile, td: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
todo!()
}

#[allow(unused_variables)] // TODO: remove when implementing
fn truncate(
self: &Arc<Self>,
file: &VFile,
length: TruncateLength,
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
todo!()
}
}

impl Drop for Vnode {
Expand Down
18 changes: 12 additions & 6 deletions src/kernel/src/kqueue/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::{
budget::BudgetType,
fs::{FileBackend, Stat, VFile, VFileFlags, VFileType},
errno::Errno,
fs::{DefaultError, FileBackend, Stat, TruncateLength, VFile, VFileFlags, VFileType},
process::{FileDesc, VThread},
syscalls::{SysErr, SysIn, SysOut, Syscalls},
};
Expand Down Expand Up @@ -57,15 +58,20 @@ impl KernelQueue {
}

impl FileBackend for KernelQueue {
fn stat(
self: &Arc<Self>,
_: &VFile,
_: Option<&VThread>,
) -> Result<Stat, Box<dyn crate::errno::Errno>> {
fn stat(self: &Arc<Self>, _: &VFile, _: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
let mut stat = Stat::zeroed();

stat.mode = 0o10000;

Ok(stat)
}

fn truncate(
self: &Arc<Self>,
_: &VFile,
_: TruncateLength,
_: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
Err(DefaultError::InvalidValue.into())
}
}
12 changes: 11 additions & 1 deletion src/kernel/src/net/socket.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::fs::{FileBackend, IoCmd, Stat, Uio, UioMut, VFile};
use crate::fs::{DefaultError, FileBackend, IoCmd, Stat, TruncateLength, Uio, UioMut, VFile};
use crate::ucred::Ucred;
use crate::{
errno::{Errno, EPIPE},
Expand Down Expand Up @@ -101,9 +101,19 @@ impl FileBackend for Socket {
todo!()
}

#[allow(unused_variables)] // TODO: remove when implementing
fn stat(self: &Arc<Self>, file: &VFile, td: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
todo!()
}

fn truncate(
self: &Arc<Self>,
_: &VFile,
_: TruncateLength,
_: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
Err(DefaultError::InvalidValue.into())
}
}

#[derive(Debug, Error)]
Expand Down
30 changes: 26 additions & 4 deletions src/kernel/src/shm/mod.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
use thiserror::Error;

use crate::{
errno::{Errno, EINVAL},
fs::{
check_access, Access, DefaultError, FileBackend, IoCmd, Mode, OpenFlags, Stat, Uio, UioMut,
VFile, VFileFlags, VPathBuf,
check_access, Access, DefaultError, FileBackend, IoCmd, Mode, OpenFlags, Stat,
TruncateLength, Uio, UioMut, VFile, VFileFlags, VPathBuf,
},
memory::MemoryManager,
process::VThread,
syscalls::{SysErr, SysIn, SysOut, Syscalls},
ucred::{Gid, Ucred, Uid},
};
use std::{convert::Infallible, sync::Arc};
use std::{convert::Infallible, num::NonZeroI32, sync::Arc};

pub struct SharedMemoryManager {
mm: Arc<MemoryManager>,
Expand Down Expand Up @@ -85,7 +87,7 @@ pub struct Shm {

impl Shm {
/// See `shm_do_truncate` on the PS4 for a reference.
fn truncate(&self, size: usize) {
fn do_truncate(&self, length: TruncateLength) -> Result<(), TruncateError> {
todo!()
}

Expand Down Expand Up @@ -146,4 +148,24 @@ impl FileBackend for Shm {

todo!()
}

fn truncate(
self: &Arc<Self>,
_: &VFile,
length: TruncateLength,
_: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
self.do_truncate(length)?;

Ok(())
}
}

#[derive(Debug, Error)]
pub enum TruncateError {}

impl Errno for TruncateError {
fn errno(&self) -> NonZeroI32 {
match *self {}
}
}
11 changes: 10 additions & 1 deletion src/kernel/src/time/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,16 @@ pub struct TimeSpec {

impl TimeSpec {
pub fn now() -> Self {
todo!()
TimeVal::microtime().expect("Couldn't get time").into()
}
}

impl From<TimeVal> for TimeSpec {
fn from(tv: TimeVal) -> Self {
Self {
sec: tv.sec,
nsec: tv.usec * 1000,
}
}
}

Expand Down

0 comments on commit 0c02b15

Please sign in to comment.