mirror of
https://github.com/obhq/obliteration.git
synced 2024-06-12 09:37:15 -04:00
Revises vectored I/O system (#837)
This commit is contained in:
parent
88659fc8f2
commit
44ee7747f6
|
@ -1,12 +1,10 @@
|
|||
use crate::{
|
||||
errno::Errno,
|
||||
fs::{
|
||||
make_dev, CharacterDevice, DeviceDriver, DriverFlags, IoCmd, MakeDevError, MakeDevFlags,
|
||||
Mode, OpenFlags, Uio, UioMut,
|
||||
},
|
||||
process::VThread,
|
||||
ucred::{Gid, Uid},
|
||||
use crate::errno::Errno;
|
||||
use crate::fs::{
|
||||
make_dev, CharacterDevice, DeviceDriver, DriverFlags, IoCmd, IoLen, IoVec, IoVecMut,
|
||||
MakeDevError, MakeDevFlags, Mode, OpenFlags,
|
||||
};
|
||||
use crate::process::VThread;
|
||||
use crate::ucred::{Gid, Uid};
|
||||
use std::sync::Arc;
|
||||
use thiserror::Error;
|
||||
|
||||
|
@ -35,9 +33,10 @@ impl DeviceDriver for Camera {
|
|||
fn read(
|
||||
&self,
|
||||
dev: &Arc<CharacterDevice>,
|
||||
data: &mut UioMut,
|
||||
off: Option<u64>,
|
||||
buf: &mut [IoVecMut],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
@ -45,9 +44,10 @@ impl DeviceDriver for Camera {
|
|||
fn write(
|
||||
&self,
|
||||
dev: &Arc<CharacterDevice>,
|
||||
data: &mut Uio,
|
||||
off: Option<u64>,
|
||||
buf: &[IoVec],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use crate::errno::Errno;
|
||||
use crate::fs::{
|
||||
make_dev, CharacterDevice, DeviceDriver, DriverFlags, MakeDevError, MakeDevFlags, Mode,
|
||||
OpenFlags, Uio, UioMut,
|
||||
make_dev, CharacterDevice, DeviceDriver, DriverFlags, IoLen, IoVec, IoVecMut, MakeDevError,
|
||||
MakeDevFlags, Mode, OpenFlags,
|
||||
};
|
||||
use crate::process::VThread;
|
||||
use crate::ucred::{Gid, Uid};
|
||||
use crate::{errno::Errno, process::VThread};
|
||||
use std::sync::Arc;
|
||||
use thiserror::Error;
|
||||
|
||||
|
@ -32,9 +33,10 @@ impl DeviceDriver for Driver {
|
|||
fn read(
|
||||
&self,
|
||||
dev: &Arc<CharacterDevice>,
|
||||
data: &mut UioMut,
|
||||
off: Option<u64>,
|
||||
buf: &mut [IoVecMut],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
@ -42,9 +44,10 @@ impl DeviceDriver for Driver {
|
|||
fn write(
|
||||
&self,
|
||||
dev: &Arc<CharacterDevice>,
|
||||
data: &mut Uio,
|
||||
off: Option<u64>,
|
||||
buf: &[IoVec],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
use crate::{
|
||||
errno::Errno,
|
||||
fs::{CharacterDevice, DeviceDriver, IoCmd, UioMut},
|
||||
process::VThread,
|
||||
};
|
||||
use crate::errno::Errno;
|
||||
use crate::fs::{CharacterDevice, DeviceDriver, IoCmd, IoLen, IoVecMut};
|
||||
use crate::process::VThread;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -13,9 +11,10 @@ impl DeviceDriver for Hid {
|
|||
fn read(
|
||||
&self,
|
||||
dev: &Arc<CharacterDevice>,
|
||||
data: &mut UioMut,
|
||||
off: Option<u64>,
|
||||
buf: &mut [IoVecMut],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
use crate::{
|
||||
errno::Errno,
|
||||
fs::{CharacterDevice, DefaultDeviceError, DeviceDriver, IoCmd, Uio, UioMut},
|
||||
process::VThread,
|
||||
};
|
||||
use crate::errno::Errno;
|
||||
use crate::fs::{CharacterDevice, DefaultDeviceError, DeviceDriver, IoCmd, IoLen, IoVec, IoVecMut};
|
||||
use crate::process::VThread;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -13,9 +11,10 @@ impl DeviceDriver for Random {
|
|||
fn read(
|
||||
&self,
|
||||
dev: &Arc<CharacterDevice>,
|
||||
data: &mut UioMut,
|
||||
off: Option<u64>,
|
||||
buf: &mut [IoVecMut],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
@ -23,9 +22,10 @@ impl DeviceDriver for Random {
|
|||
fn write(
|
||||
&self,
|
||||
dev: &Arc<CharacterDevice>,
|
||||
data: &mut Uio,
|
||||
off: Option<u64>,
|
||||
buf: &[IoVec],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use crate::errno::{Errno, EPERM};
|
||||
use crate::fs::{
|
||||
make_dev, CharacterDevice, DeviceDriver, DriverFlags, IoCmd, MakeDevError, MakeDevFlags, Mode,
|
||||
OpenFlags, Uio, UioMut,
|
||||
make_dev, CharacterDevice, DeviceDriver, DriverFlags, IoCmd, IoLen, IoVec, IoVecMut,
|
||||
MakeDevError, MakeDevFlags, Mode, OpenFlags,
|
||||
};
|
||||
use crate::process::VThread;
|
||||
use crate::ucred::{Gid, Uid};
|
||||
use crate::{errno::Errno, process::VThread};
|
||||
use macros::Errno;
|
||||
use std::sync::Arc;
|
||||
use thiserror::Error;
|
||||
|
@ -35,9 +36,10 @@ impl DeviceDriver for TtyConsole {
|
|||
fn read(
|
||||
&self,
|
||||
dev: &Arc<CharacterDevice>,
|
||||
data: &mut UioMut,
|
||||
off: Option<u64>,
|
||||
buf: &mut [IoVecMut],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
@ -45,9 +47,10 @@ impl DeviceDriver for TtyConsole {
|
|||
fn write(
|
||||
&self,
|
||||
dev: &Arc<CharacterDevice>,
|
||||
data: &mut Uio,
|
||||
off: Option<u64>,
|
||||
buf: &[IoVec],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
|
|
@ -1,25 +1,23 @@
|
|||
use crate::errno::Errno;
|
||||
use crate::fs::{DefaultFileBackendError, FileBackend, IoCmd, PollEvents, Stat, VFile};
|
||||
use crate::process::VThread;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BlockPool {}
|
||||
|
||||
impl BlockPool {
|
||||
pub fn new() -> Arc<Self> {
|
||||
Arc::new(Self {})
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl FileBackend for BlockPool {
|
||||
fn is_seekable(&self) -> bool {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[allow(unused_variables)] // TODO: remove when implementing
|
||||
fn ioctl(
|
||||
self: &Arc<Self>,
|
||||
file: &VFile,
|
||||
cmd: IoCmd,
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
fn ioctl(&self, file: &VFile, cmd: IoCmd, td: Option<&VThread>) -> Result<(), Box<dyn Errno>> {
|
||||
match cmd {
|
||||
IoCmd::BPOOLEXPAND(args) => todo!(),
|
||||
IoCmd::BPOOLSTATS(out) => todo!(),
|
||||
|
@ -28,11 +26,11 @@ impl FileBackend for BlockPool {
|
|||
}
|
||||
|
||||
#[allow(unused_variables)] // TODO: remove when implementing
|
||||
fn poll(self: &Arc<Self>, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents {
|
||||
fn poll(&self, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn stat(self: &Arc<Self>, _: &VFile, _: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
|
||||
fn stat(&self, _: &VFile, _: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
|
||||
let mut stat = Stat::zeroed();
|
||||
|
||||
stat.block_size = 0x10000;
|
||||
|
|
|
@ -137,10 +137,12 @@ impl DmemManager {
|
|||
|
||||
let flags = VFileFlags::from_bits_retain(flags) | VFileFlags::WRITE;
|
||||
|
||||
let fd = td
|
||||
.proc()
|
||||
.files()
|
||||
.alloc(Arc::new(VFile::new(VFileType::Blockpool(bp), flags)));
|
||||
let fd = td.proc().files().alloc(Arc::new(VFile::new(
|
||||
VFileType::Blockpool,
|
||||
flags,
|
||||
None,
|
||||
Box::new(bp),
|
||||
)));
|
||||
|
||||
info!("Opened a blockpool at fd = {fd}");
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
//! This module contains errno used in a PS4 system. The value of each errno must be the same as the
|
||||
//! PS4.
|
||||
use std::convert::Infallible;
|
||||
use std::error::Error;
|
||||
use std::hint::unreachable_unchecked;
|
||||
use std::num::NonZeroI32;
|
||||
|
||||
// This file contains errno used in a PS4 system. The value of each errno must be the same as the
|
||||
// PS4.
|
||||
|
||||
macro_rules! error_numbers {
|
||||
($($name:ident($num:expr) => $desc:literal,)*) => {
|
||||
$(
|
||||
|
@ -127,7 +127,7 @@ error_numbers! {
|
|||
}
|
||||
|
||||
/// An object that is mappable to PS4 errno.
|
||||
pub trait Errno: Error {
|
||||
pub trait Errno: Error + Send + Sync {
|
||||
fn errno(&self) -> NonZeroI32;
|
||||
}
|
||||
|
||||
|
@ -143,14 +143,16 @@ impl<T: Errno + 'static> From<T> for Box<dyn Errno> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Errno for Infallible {
|
||||
fn errno(&self) -> NonZeroI32 {
|
||||
// SAFETY: This is safe because Infallible type guarantee its value cannot be constructed,
|
||||
// which imply this method cannot be called because it required a value of Infallible type.
|
||||
unsafe { unreachable_unchecked() };
|
||||
}
|
||||
}
|
||||
|
||||
/// Get human readable text.
|
||||
pub fn strerror(num: NonZeroI32) -> &'static str {
|
||||
// This function is generated inside the macro `error_numbers!`.
|
||||
strerror_impl(num)
|
||||
}
|
||||
|
||||
impl Errno for Infallible {
|
||||
fn errno(&self) -> NonZeroI32 {
|
||||
match *self {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use super::dirent::Dirent;
|
||||
use crate::errno::{Errno, ENODEV, ENOTTY};
|
||||
use crate::fs::Uio;
|
||||
use crate::fs::{
|
||||
FileBackend, IoCmd, Mode, OpenFlags, PollEvents, Stat, TruncateLength, UioMut, VFile,
|
||||
FileBackend, IoCmd, IoLen, IoVec, IoVecMut, Mode, OpenFlags, PollEvents, Stat, TruncateLength,
|
||||
VFile,
|
||||
};
|
||||
use crate::process::VThread;
|
||||
use crate::time::TimeSpec;
|
||||
|
@ -109,56 +109,61 @@ impl CharacterDevice {
|
|||
}
|
||||
}
|
||||
|
||||
impl FileBackend for CharacterDevice {
|
||||
#[allow(unused_variables)] // TODO: remove when implementing
|
||||
/// Implementation of `devfs_ops_f`.
|
||||
#[derive(Debug)]
|
||||
pub(super) struct CdevFileBackend(Arc<CharacterDevice>);
|
||||
|
||||
impl CdevFileBackend {
|
||||
pub fn new(dev: Arc<CharacterDevice>) -> Self {
|
||||
Self(dev)
|
||||
}
|
||||
}
|
||||
|
||||
impl FileBackend for CdevFileBackend {
|
||||
fn is_seekable(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn read(
|
||||
self: &Arc<Self>,
|
||||
&self,
|
||||
file: &VFile,
|
||||
buf: &mut UioMut,
|
||||
off: u64,
|
||||
buf: &mut [IoVecMut],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[allow(unused_variables)] // TODO: remove when implementing
|
||||
fn write(
|
||||
self: &Arc<Self>,
|
||||
&self,
|
||||
file: &VFile,
|
||||
buf: &mut Uio,
|
||||
off: u64,
|
||||
buf: &[IoVec],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[allow(unused_variables)] // TODO: remove when implementing
|
||||
fn ioctl(
|
||||
self: &Arc<Self>,
|
||||
file: &VFile,
|
||||
cmd: IoCmd,
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
fn ioctl(&self, file: &VFile, cmd: IoCmd, td: Option<&VThread>) -> Result<(), Box<dyn Errno>> {
|
||||
match cmd {
|
||||
IoCmd::FIODTYPE(_) => todo!(),
|
||||
IoCmd::FIODGNAME(_) => todo!(),
|
||||
_ => self.driver.ioctl(self, cmd, td)?,
|
||||
_ => self.0.driver.ioctl(&self.0, cmd, td)?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(unused_variables)] // TODO: remove when implementing
|
||||
fn poll(self: &Arc<Self>, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents {
|
||||
fn poll(&self, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[allow(unused_variables)] // TODO: remove when implementing
|
||||
fn stat(self: &Arc<Self>, file: &VFile, td: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
|
||||
fn stat(&self, file: &VFile, td: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[allow(unused_variables)] // TODO: remove when implementing
|
||||
fn truncate(
|
||||
self: &Arc<Self>,
|
||||
&self,
|
||||
file: &VFile,
|
||||
length: TruncateLength,
|
||||
td: Option<&VThread>,
|
||||
|
@ -209,9 +214,10 @@ pub trait DeviceDriver: Debug + Sync + Send + 'static {
|
|||
fn read(
|
||||
&self,
|
||||
dev: &Arc<CharacterDevice>,
|
||||
data: &mut UioMut,
|
||||
off: Option<u64>, // TODO: Check if we actually need this for a character device.
|
||||
buf: &mut [IoVecMut],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
Err(Box::new(DefaultDeviceError::ReadNotSupported))
|
||||
}
|
||||
|
||||
|
@ -219,9 +225,10 @@ pub trait DeviceDriver: Debug + Sync + Send + 'static {
|
|||
fn write(
|
||||
&self,
|
||||
dev: &Arc<CharacterDevice>,
|
||||
data: &mut Uio,
|
||||
off: Option<u64>, // TODO: Check if we actually need this for a character device.
|
||||
buf: &[IoVec],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
Err(Box::new(DefaultDeviceError::WriteNotSupported))
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
use super::dirent::Dirent;
|
||||
use super::{AllocVnodeError, DevFs};
|
||||
use super::{AllocVnodeError, CdevFileBackend, DevFs};
|
||||
use crate::errno::{Errno, EIO, ENOENT, ENOTDIR, ENXIO};
|
||||
use crate::fs::{
|
||||
check_access, Access, IoCmd, RevokeFlags, Uio, UioMut, Vnode, VnodeAttrs, VnodeType,
|
||||
check_access, Access, FileBackend, IoCmd, IoLen, IoVec, IoVecMut, RevokeFlags, Vnode,
|
||||
VnodeAttrs, VnodeFileBackend, VnodeItem, VnodeType,
|
||||
};
|
||||
use crate::process::VThread;
|
||||
use macros::Errno;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
use thiserror::Error;
|
||||
|
||||
|
@ -174,21 +176,30 @@ impl crate::fs::VnodeBackend for VnodeBackend {
|
|||
|
||||
fn read(
|
||||
&self,
|
||||
#[allow(unused_variables)] vn: &Arc<Vnode>,
|
||||
#[allow(unused_variables)] buf: &mut UioMut,
|
||||
#[allow(unused_variables)] td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
vn: &Arc<Vnode>,
|
||||
off: u64,
|
||||
buf: &mut [IoVecMut],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn write(
|
||||
&self,
|
||||
#[allow(unused_variables)] vn: &Arc<Vnode>,
|
||||
#[allow(unused_variables)] buf: &mut Uio,
|
||||
#[allow(unused_variables)] td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
vn: &Arc<Vnode>,
|
||||
off: u64,
|
||||
buf: &[IoVec],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn to_file_backend(&self, vn: &Arc<Vnode>) -> Box<dyn FileBackend> {
|
||||
match vn.item().deref() {
|
||||
Some(VnodeItem::Device(d)) => Box::new(CdevFileBackend::new(d.clone())),
|
||||
_ => Box::new(VnodeFileBackend::new(vn.clone())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents an error when [`lookup()`] is failed.
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
use super::{CharacterDevice, IoCmd, Stat, TruncateLength, Uio, UioMut, Vnode};
|
||||
use crate::dmem::BlockPool;
|
||||
use crate::errno::Errno;
|
||||
use crate::errno::{EINVAL, ENOTTY, ENXIO, EOPNOTSUPP};
|
||||
use super::{IoCmd, IoLen, IoVecMut, Stat, TruncateLength, Vnode};
|
||||
use crate::errno::{Errno, EINVAL, ENOTTY, ENXIO, EOPNOTSUPP};
|
||||
use crate::fs::{IoVec, PollEvents};
|
||||
use crate::kqueue::KernelQueue;
|
||||
use crate::net::Socket;
|
||||
use crate::process::VThread;
|
||||
use crate::shm::SharedMemory;
|
||||
use bitflags::bitflags;
|
||||
use gmtx::{Gutex, GutexGroup};
|
||||
use macros::Errno;
|
||||
|
@ -18,19 +13,28 @@ use thiserror::Error;
|
|||
/// An implementation of `file` structure.
|
||||
#[derive(Debug)]
|
||||
pub struct VFile {
|
||||
ty: VFileType, // f_type
|
||||
flags: VFileFlags, // f_flag
|
||||
offset: Gutex<i64>, // f_offset
|
||||
ty: VFileType, // f_type
|
||||
flags: VFileFlags, // f_flag
|
||||
vnode: Option<Arc<Vnode>>, // f_vnode
|
||||
offset: Gutex<u64>, // f_offset
|
||||
backend: Box<dyn FileBackend>,
|
||||
}
|
||||
|
||||
impl VFile {
|
||||
pub fn new(ty: VFileType, flags: VFileFlags) -> Self {
|
||||
pub fn new(
|
||||
ty: VFileType,
|
||||
flags: VFileFlags,
|
||||
vnode: Option<Arc<Vnode>>,
|
||||
backend: Box<dyn FileBackend>,
|
||||
) -> Self {
|
||||
let gg = GutexGroup::new();
|
||||
|
||||
Self {
|
||||
ty,
|
||||
flags,
|
||||
vnode,
|
||||
offset: gg.spawn(0),
|
||||
backend,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,78 +46,20 @@ impl VFile {
|
|||
self.flags
|
||||
}
|
||||
|
||||
/// Checking if this returns `Some` is equivalent to when FreeBSD and the PS4 check
|
||||
/// fp->f_ops->fo_flags & DFLAG_SEEKABLE != 0, therefore we use this instead.
|
||||
pub fn seekable_vnode(&self) -> Option<&Arc<Vnode>> {
|
||||
match &self.ty {
|
||||
VFileType::Vnode(vn) => Some(vn),
|
||||
VFileType::Device(_) => todo!(),
|
||||
_ => None,
|
||||
}
|
||||
pub fn is_seekable(&self) -> bool {
|
||||
self.backend.is_seekable()
|
||||
}
|
||||
|
||||
/// See `dofileread` on the PS4 for a reference.
|
||||
pub fn do_read(&self, mut uio: UioMut, td: Option<&VThread>) -> Result<usize, Box<dyn Errno>> {
|
||||
if uio.bytes_left == 0 {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
// TODO: consider implementing ktrace.
|
||||
|
||||
todo!()
|
||||
pub fn vnode(&self) -> Option<&Arc<Vnode>> {
|
||||
self.vnode.as_ref()
|
||||
}
|
||||
|
||||
/// See `dofilewrite` on the PS4 for a reference.
|
||||
pub fn do_write(&self, mut uio: Uio, td: Option<&VThread>) -> Result<usize, Box<dyn Errno>> {
|
||||
// TODO: consider implementing ktrace.
|
||||
// TODO: implement bwillwrite.
|
||||
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn read(&self, buf: &mut UioMut, td: Option<&VThread>) -> Result<(), Box<dyn Errno>> {
|
||||
match &self.ty {
|
||||
VFileType::Vnode(vn) => FileBackend::read(vn, self, buf, td),
|
||||
VFileType::Socket(so) | VFileType::IpcSocket(so) => so.read(self, buf, td),
|
||||
VFileType::KernelQueue(kq) => kq.read(self, buf, td),
|
||||
VFileType::SharedMemory(shm) => shm.read(self, buf, td),
|
||||
VFileType::Device(dev) => dev.read(self, buf, td),
|
||||
VFileType::Blockpool(bp) => bp.read(self, buf, td),
|
||||
}
|
||||
}
|
||||
|
||||
fn write(&self, buf: &mut Uio, td: Option<&VThread>) -> Result<(), Box<dyn Errno>> {
|
||||
match &self.ty {
|
||||
VFileType::Vnode(vn) => FileBackend::write(vn, self, buf, td),
|
||||
VFileType::Socket(so) | VFileType::IpcSocket(so) => so.write(self, buf, td),
|
||||
VFileType::KernelQueue(kq) => kq.write(self, buf, td),
|
||||
VFileType::SharedMemory(shm) => shm.write(self, buf, td),
|
||||
VFileType::Device(dev) => dev.write(self, buf, td),
|
||||
VFileType::Blockpool(bp) => bp.write(self, buf, td),
|
||||
}
|
||||
}
|
||||
|
||||
/// See `fo_ioctl` on the PS4 for a reference.
|
||||
pub fn ioctl(&self, cmd: IoCmd, td: Option<&VThread>) -> Result<(), Box<dyn Errno>> {
|
||||
match &self.ty {
|
||||
VFileType::Vnode(vn) => vn.ioctl(self, cmd, td),
|
||||
VFileType::Socket(so) | VFileType::IpcSocket(so) => so.ioctl(self, cmd, td),
|
||||
VFileType::KernelQueue(kq) => kq.ioctl(self, cmd, td),
|
||||
VFileType::SharedMemory(shm) => shm.ioctl(self, cmd, td),
|
||||
VFileType::Device(dev) => dev.ioctl(self, cmd, td),
|
||||
VFileType::Blockpool(bp) => bp.ioctl(self, cmd, td),
|
||||
}
|
||||
self.backend.ioctl(self, cmd, td)
|
||||
}
|
||||
|
||||
pub fn stat(&self, td: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
|
||||
match &self.ty {
|
||||
VFileType::Vnode(vn) => vn.stat(self, td),
|
||||
VFileType::Socket(so) | VFileType::IpcSocket(so) => so.stat(self, td),
|
||||
VFileType::KernelQueue(kq) => kq.stat(self, td),
|
||||
VFileType::SharedMemory(shm) => shm.stat(self, td),
|
||||
VFileType::Device(dev) => dev.stat(self, td),
|
||||
VFileType::Blockpool(bp) => bp.stat(self, td),
|
||||
}
|
||||
self.backend.stat(self, td)
|
||||
}
|
||||
|
||||
pub fn truncate(
|
||||
|
@ -121,20 +67,18 @@ impl VFile {
|
|||
length: TruncateLength,
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
match &self.ty {
|
||||
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::Device(dev) => dev.truncate(self, length, td),
|
||||
VFileType::Blockpool(bp) => bp.truncate(self, length, td),
|
||||
}
|
||||
self.backend.truncate(self, length, td)
|
||||
}
|
||||
}
|
||||
|
||||
impl Seek for VFile {
|
||||
fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
|
||||
self.seekable_vnode().ok_or(ErrorKind::Other)?;
|
||||
use std::io::Error;
|
||||
|
||||
// Check if seekable.
|
||||
if !self.backend.is_seekable() {
|
||||
return Err(Error::from(ErrorKind::Unsupported));
|
||||
}
|
||||
|
||||
// Negative seeks should not be allowed here
|
||||
let offset: u64 = match pos {
|
||||
|
@ -147,68 +91,48 @@ impl Seek for VFile {
|
|||
}
|
||||
};
|
||||
|
||||
*self.offset.write() = if let Ok(offset) = offset.try_into() {
|
||||
offset
|
||||
} else {
|
||||
todo!()
|
||||
};
|
||||
*self.offset.get_mut() = offset;
|
||||
|
||||
Ok(offset as u64)
|
||||
Ok(offset)
|
||||
}
|
||||
|
||||
fn rewind(&mut self) -> std::io::Result<()> {
|
||||
*self.offset.write() = 0;
|
||||
|
||||
*self.offset.get_mut() = 0;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn stream_position(&mut self) -> std::io::Result<u64> {
|
||||
if let Ok(offset) = (*self.offset.read()).try_into() {
|
||||
Ok(offset)
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
Ok(*self.offset.get_mut())
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for VFile {
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
let total = buf.len();
|
||||
let len = IoLen::from_usize(buf.len()).unwrap_or(IoLen::MAX);
|
||||
let mut buf = unsafe { IoVecMut::new(buf.as_mut_ptr(), len) };
|
||||
let off = *self.offset.get_mut();
|
||||
let read = self
|
||||
.backend
|
||||
.read(self, off, std::slice::from_mut(&mut buf), None)
|
||||
.map_err(|e| std::io::Error::new(ErrorKind::Other, e))?;
|
||||
|
||||
let ref mut iovec = IoVec::from_slice(buf);
|
||||
*self.offset.get_mut() += read.get() as u64;
|
||||
|
||||
let mut offset = self.offset.write();
|
||||
|
||||
let mut uio = UioMut::from_single_vec(iovec, *offset);
|
||||
|
||||
if let Err(e) = VFile::read(self, &mut uio, None) {
|
||||
println!("Error: {:?}", e);
|
||||
|
||||
todo!()
|
||||
};
|
||||
|
||||
let read = total - uio.bytes_left;
|
||||
|
||||
if let Ok(read) = TryInto::<i64>::try_into(read) {
|
||||
*offset += read;
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
|
||||
Ok(read)
|
||||
Ok(read.get())
|
||||
}
|
||||
}
|
||||
|
||||
/// Type of [`VFile`].
|
||||
#[derive(Debug)]
|
||||
#[repr(i16)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum VFileType {
|
||||
Vnode(Arc<Vnode>), // DTYPE_VNODE = 1
|
||||
Socket(Arc<Socket>), // DTYPE_SOCKET = 2,
|
||||
KernelQueue(Arc<KernelQueue>), // DTYPE_KQUEUE = 5,
|
||||
SharedMemory(Arc<SharedMemory>), // DTYPE_SHM = 8,
|
||||
Device(Arc<CharacterDevice>), // DTYPE_DEV = 11,
|
||||
IpcSocket(Arc<Socket>), // DTYPE_IPCSOCKET = 15,
|
||||
Blockpool(Arc<BlockPool>), // DTYPE_BLOCKPOOL = 17,
|
||||
Vnode = 1, // DTYPE_VNODE
|
||||
Socket = 2, // DTYPE_SOCKET
|
||||
KernelQueue = 5, // DTYPE_KQUEUE
|
||||
SharedMemory = 8, // DTYPE_SHM
|
||||
Device = 11, // DTYPE_DEV
|
||||
IpcSocket = 15, // DTYPE_IPCSOCKET
|
||||
Blockpool = 17, // DTYPE_BLOCKPOOL
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
|
@ -222,51 +146,45 @@ bitflags! {
|
|||
|
||||
/// An implementation of `fileops` structure.
|
||||
pub trait FileBackend: Debug + Send + Sync + 'static {
|
||||
#[allow(unused_variables)]
|
||||
/// Implementation of `fo_flags` with `DFLAG_SEEKABLE`.
|
||||
fn is_seekable(&self) -> bool;
|
||||
|
||||
/// An implementation of `fo_read`.
|
||||
fn read(
|
||||
self: &Arc<Self>,
|
||||
&self,
|
||||
file: &VFile,
|
||||
buf: &mut UioMut,
|
||||
off: u64,
|
||||
buf: &mut [IoVecMut],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
Err(Box::new(DefaultFileBackendError::ReadNotSupported))
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
/// An implementation of `fo_write`.
|
||||
fn write(
|
||||
self: &Arc<Self>,
|
||||
&self,
|
||||
file: &VFile,
|
||||
buf: &mut Uio,
|
||||
off: u64,
|
||||
buf: &[IoVec],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
Err(Box::new(DefaultFileBackendError::WriteNotSupported))
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
/// An implementation of `fo_ioctl`.
|
||||
fn ioctl(
|
||||
self: &Arc<Self>,
|
||||
file: &VFile,
|
||||
cmd: IoCmd,
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
fn ioctl(&self, file: &VFile, cmd: IoCmd, td: Option<&VThread>) -> Result<(), Box<dyn Errno>> {
|
||||
Err(Box::new(DefaultFileBackendError::IoctlNotSupported))
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
/// An implementation of `fo_poll`.
|
||||
fn poll(self: &Arc<Self>, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents;
|
||||
fn poll(&self, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents;
|
||||
|
||||
#[allow(unused_variables)]
|
||||
/// An implementation of `fo_stat`.
|
||||
fn stat(self: &Arc<Self>, file: &VFile, td: Option<&VThread>) -> Result<Stat, Box<dyn Errno>>;
|
||||
fn stat(&self, file: &VFile, td: Option<&VThread>) -> Result<Stat, Box<dyn Errno>>;
|
||||
|
||||
#[allow(unused_variables)]
|
||||
/// An implementation of `fo_truncate`.
|
||||
fn truncate(
|
||||
self: &Arc<Self>,
|
||||
&self,
|
||||
file: &VFile,
|
||||
length: TruncateLength,
|
||||
td: Option<&VThread>,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::fs::UioMut;
|
||||
use crate::fs::{IoLen, IoVecMut};
|
||||
use std::collections::HashMap;
|
||||
use std::io::Error;
|
||||
use std::mem::zeroed;
|
||||
|
@ -46,6 +46,7 @@ impl HostFile {
|
|||
};
|
||||
use windows_sys::Win32::Storage::FileSystem::{
|
||||
FILE_READ_ATTRIBUTES, FILE_READ_EA, FILE_SHARE_READ, FILE_SHARE_WRITE,
|
||||
FILE_WRITE_ATTRIBUTES, FILE_WRITE_EA,
|
||||
};
|
||||
use windows_sys::Win32::System::Kernel::OBJ_CASE_INSENSITIVE;
|
||||
|
||||
|
@ -78,14 +79,14 @@ impl HostFile {
|
|||
let err = unsafe {
|
||||
NtCreateFile(
|
||||
&mut handle,
|
||||
FILE_READ_ATTRIBUTES | FILE_READ_EA,
|
||||
Self::directory_access_flags(),
|
||||
&mut attr,
|
||||
&mut status,
|
||||
null_mut(),
|
||||
0,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
0,
|
||||
FILE_OPEN,
|
||||
FILE_DIRECTORY_FILE,
|
||||
Self::directory_options(),
|
||||
null_mut(),
|
||||
0,
|
||||
)
|
||||
|
@ -207,10 +208,12 @@ impl HostFile {
|
|||
fn raw_mkdir(parent: RawFile, name: &str, _mode: u32) -> Result<RawFile, Error> {
|
||||
use std::mem::size_of;
|
||||
use std::ptr::null_mut;
|
||||
use windows_sys::Wdk::Storage::FileSystem::FILE_CREATE;
|
||||
use windows_sys::Wdk::{
|
||||
Foundation::OBJECT_ATTRIBUTES,
|
||||
Storage::FileSystem::{NtCreateFile, FILE_DIRECTORY_FILE, FILE_OPEN},
|
||||
Storage::FileSystem::{NtCreateFile, FILE_DIRECTORY_FILE},
|
||||
};
|
||||
use windows_sys::Win32::Storage::FileSystem::{DELETE, SYNCHRONIZE};
|
||||
use windows_sys::Win32::{
|
||||
Foundation::{RtlNtStatusToDosError, STATUS_SUCCESS, UNICODE_STRING},
|
||||
Storage::FileSystem::{
|
||||
|
@ -245,19 +248,14 @@ impl HostFile {
|
|||
let error = unsafe {
|
||||
NtCreateFile(
|
||||
&mut handle,
|
||||
FILE_READ_ATTRIBUTES
|
||||
| FILE_READ_EA
|
||||
| FILE_WRITE_ATTRIBUTES
|
||||
| FILE_WRITE_EA
|
||||
| FILE_LIST_DIRECTORY
|
||||
| FILE_TRAVERSE,
|
||||
DELETE | Self::directory_access_flags(),
|
||||
&mut attr,
|
||||
&mut status,
|
||||
null_mut(),
|
||||
FILE_ATTRIBUTE_DIRECTORY,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
FILE_OPEN,
|
||||
FILE_DIRECTORY_FILE,
|
||||
0,
|
||||
FILE_CREATE,
|
||||
Self::directory_options(),
|
||||
null_mut(),
|
||||
0,
|
||||
)
|
||||
|
@ -273,90 +271,59 @@ impl HostFile {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub(super) fn read(&self, buf: &mut UioMut) -> Result<(), Error> {
|
||||
use libc::pread;
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
pub fn read(&self, off: u64, buf: &mut [IoVecMut]) -> Result<IoLen, Error> {
|
||||
use libc::preadv;
|
||||
|
||||
buf.write_with::<Error>(|iov, mut offset| {
|
||||
let nbytes = if let Ok(nbytes) = iov.len().try_into() {
|
||||
nbytes
|
||||
} else {
|
||||
todo!()
|
||||
};
|
||||
// Our iovec implementation has the same layout as iovec on Linux and macOS so we can pass
|
||||
// it directly to preadv.
|
||||
let vecs = buf.as_ptr().cast();
|
||||
let off = off.try_into().unwrap();
|
||||
let read = unsafe { preadv(self.raw, vecs, buf.len().try_into().unwrap(), off) };
|
||||
|
||||
let nread = unsafe { pread(self.raw, iov.ptr().cast(), nbytes, offset) };
|
||||
|
||||
match nread {
|
||||
0.. if nread == nbytes as isize => Ok(nread as u64),
|
||||
0.. => todo!(),
|
||||
_ => todo!(),
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
if read < 0 {
|
||||
Err(Error::last_os_error())
|
||||
} else {
|
||||
Ok(IoLen::from_usize(read as _).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub(super) fn read(&self, buf: &mut UioMut) -> Result<(), Error> {
|
||||
use std::ptr::null_mut;
|
||||
use windows_sys::{
|
||||
Wdk::Storage::FileSystem::NtReadFile,
|
||||
Win32::{
|
||||
Foundation::{STATUS_END_OF_FILE, STATUS_PENDING},
|
||||
System::{
|
||||
Threading::{WaitForSingleObject, INFINITE},
|
||||
IO::{IO_STATUS_BLOCK, IO_STATUS_BLOCK_0},
|
||||
},
|
||||
},
|
||||
pub fn read(&self, off: u64, buf: &mut [IoVecMut]) -> Result<IoLen, Error> {
|
||||
use std::ptr::null;
|
||||
use windows_sys::Wdk::Storage::FileSystem::NtReadFile;
|
||||
use windows_sys::Win32::Foundation::{
|
||||
RtlNtStatusToDosError, STATUS_END_OF_FILE, STATUS_SUCCESS,
|
||||
};
|
||||
|
||||
buf.write_with::<Error>(|iov, mut offset| {
|
||||
let nbytes = if let Ok(nbytes) = iov.len().try_into() {
|
||||
nbytes
|
||||
} else {
|
||||
todo!()
|
||||
};
|
||||
|
||||
let mut io_status = IO_STATUS_BLOCK {
|
||||
Anonymous: IO_STATUS_BLOCK_0 {
|
||||
Status: STATUS_PENDING,
|
||||
},
|
||||
Information: 0,
|
||||
};
|
||||
|
||||
let status = unsafe {
|
||||
NtReadFile(
|
||||
self.raw,
|
||||
0,
|
||||
None,
|
||||
null_mut(),
|
||||
&mut io_status,
|
||||
iov.ptr().cast(),
|
||||
nbytes,
|
||||
&mut offset,
|
||||
null_mut(),
|
||||
)
|
||||
};
|
||||
|
||||
let status = if status == STATUS_PENDING {
|
||||
unsafe {
|
||||
WaitForSingleObject(self.raw, INFINITE);
|
||||
io_status.Anonymous.Status
|
||||
}
|
||||
} else {
|
||||
status
|
||||
};
|
||||
|
||||
match status {
|
||||
STATUS_PENDING => todo!(),
|
||||
STATUS_END_OF_FILE => todo!(),
|
||||
0.. if io_status.Information == nbytes as usize => Ok(io_status.Information as u64),
|
||||
0.. => todo!(),
|
||||
_ => todo!(),
|
||||
// Windows does not provide preadv equivalent so we can fill only the first IoVecMut to
|
||||
// achieve atomic read.
|
||||
let off = off.try_into().unwrap();
|
||||
let buf = &mut buf[0];
|
||||
let mut status = unsafe { zeroed() };
|
||||
let read = match unsafe {
|
||||
NtReadFile(
|
||||
self.raw,
|
||||
0,
|
||||
None,
|
||||
null(),
|
||||
&mut status,
|
||||
buf.as_mut_ptr().cast(),
|
||||
buf.len().get().try_into().unwrap(),
|
||||
&off,
|
||||
null(),
|
||||
)
|
||||
} {
|
||||
STATUS_SUCCESS => status.Information,
|
||||
STATUS_END_OF_FILE => 0,
|
||||
v => {
|
||||
return Err(Error::from_raw_os_error(unsafe {
|
||||
RtlNtStatusToDosError(v).try_into().unwrap()
|
||||
}));
|
||||
}
|
||||
})?;
|
||||
};
|
||||
|
||||
Ok(())
|
||||
Ok(IoLen::from_usize(read).unwrap())
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
|
@ -432,13 +399,16 @@ impl HostFile {
|
|||
use windows_sys::Wdk::Foundation::OBJECT_ATTRIBUTES;
|
||||
use windows_sys::Wdk::Storage::FileSystem::{
|
||||
NtCreateFile, FILE_DIRECTORY_FILE, FILE_NON_DIRECTORY_FILE, FILE_OPEN,
|
||||
FILE_RANDOM_ACCESS,
|
||||
FILE_RANDOM_ACCESS, FILE_SYNCHRONOUS_IO_NONALERT,
|
||||
};
|
||||
use windows_sys::Win32::Foundation::{
|
||||
RtlNtStatusToDosError, STATUS_SUCCESS, UNICODE_STRING,
|
||||
RtlNtStatusToDosError, STATUS_FILE_IS_A_DIRECTORY, STATUS_NOT_A_DIRECTORY,
|
||||
STATUS_SUCCESS, UNICODE_STRING,
|
||||
};
|
||||
use windows_sys::Win32::Storage::FileSystem::{
|
||||
DELETE, FILE_GENERIC_READ, FILE_GENERIC_WRITE,
|
||||
DELETE, FILE_APPEND_DATA, FILE_LIST_DIRECTORY, FILE_READ_ATTRIBUTES, FILE_READ_DATA,
|
||||
FILE_READ_EA, FILE_TRAVERSE, FILE_WRITE_ATTRIBUTES, FILE_WRITE_DATA, FILE_WRITE_EA,
|
||||
SYNCHRONIZE,
|
||||
};
|
||||
|
||||
// Encode name.
|
||||
|
@ -463,51 +433,91 @@ impl HostFile {
|
|||
// Try open as a file first.
|
||||
let mut handle = 0;
|
||||
let mut status = unsafe { zeroed() };
|
||||
let err = unsafe {
|
||||
NtCreateFile(
|
||||
&mut handle,
|
||||
DELETE | FILE_GENERIC_READ | FILE_GENERIC_WRITE,
|
||||
&mut attr,
|
||||
&mut status,
|
||||
null_mut(),
|
||||
0,
|
||||
0,
|
||||
FILE_OPEN,
|
||||
FILE_NON_DIRECTORY_FILE | FILE_RANDOM_ACCESS,
|
||||
null_mut(),
|
||||
0,
|
||||
)
|
||||
};
|
||||
|
||||
if err == STATUS_SUCCESS {
|
||||
Ok(handle)
|
||||
} else {
|
||||
// Try open as a directory.
|
||||
loop {
|
||||
let err = unsafe {
|
||||
NtCreateFile(
|
||||
&mut handle,
|
||||
DELETE | FILE_GENERIC_READ | FILE_GENERIC_WRITE,
|
||||
DELETE
|
||||
| FILE_READ_DATA
|
||||
| FILE_READ_ATTRIBUTES
|
||||
| FILE_READ_EA
|
||||
| FILE_WRITE_DATA
|
||||
| FILE_WRITE_ATTRIBUTES
|
||||
| FILE_WRITE_EA
|
||||
| FILE_APPEND_DATA
|
||||
| SYNCHRONIZE,
|
||||
&mut attr,
|
||||
&mut status,
|
||||
null_mut(),
|
||||
0,
|
||||
0,
|
||||
FILE_OPEN,
|
||||
FILE_DIRECTORY_FILE,
|
||||
FILE_NON_DIRECTORY_FILE | FILE_RANDOM_ACCESS | FILE_SYNCHRONOUS_IO_NONALERT,
|
||||
null_mut(),
|
||||
0,
|
||||
)
|
||||
};
|
||||
|
||||
if err == STATUS_SUCCESS {
|
||||
Ok(handle)
|
||||
} else {
|
||||
Err(Error::from_raw_os_error(unsafe {
|
||||
break Ok(handle);
|
||||
} else if err != STATUS_FILE_IS_A_DIRECTORY {
|
||||
break Err(Error::from_raw_os_error(unsafe {
|
||||
RtlNtStatusToDosError(err).try_into().unwrap()
|
||||
}))
|
||||
}));
|
||||
}
|
||||
|
||||
// Try open as a directory.
|
||||
let err = unsafe {
|
||||
NtCreateFile(
|
||||
&mut handle,
|
||||
DELETE | Self::directory_access_flags(),
|
||||
&mut attr,
|
||||
&mut status,
|
||||
null_mut(),
|
||||
0,
|
||||
0,
|
||||
FILE_OPEN,
|
||||
Self::directory_options(),
|
||||
null_mut(),
|
||||
0,
|
||||
)
|
||||
};
|
||||
|
||||
if err == STATUS_SUCCESS {
|
||||
break Ok(handle);
|
||||
} else if err != STATUS_NOT_A_DIRECTORY {
|
||||
break Err(Error::from_raw_os_error(unsafe {
|
||||
RtlNtStatusToDosError(err).try_into().unwrap()
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
const fn directory_access_flags() -> u32 {
|
||||
use windows_sys::Win32::Storage::FileSystem::{
|
||||
FILE_LIST_DIRECTORY, FILE_READ_ATTRIBUTES, FILE_READ_EA, FILE_TRAVERSE,
|
||||
FILE_WRITE_ATTRIBUTES, FILE_WRITE_EA, SYNCHRONIZE,
|
||||
};
|
||||
|
||||
FILE_READ_ATTRIBUTES
|
||||
| FILE_READ_EA
|
||||
| FILE_WRITE_ATTRIBUTES
|
||||
| FILE_WRITE_EA
|
||||
| SYNCHRONIZE
|
||||
| FILE_LIST_DIRECTORY
|
||||
| FILE_TRAVERSE
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
const fn directory_options() -> u32 {
|
||||
use windows_sys::Wdk::Storage::FileSystem::{
|
||||
FILE_DIRECTORY_FILE, FILE_SYNCHRONOUS_IO_NONALERT,
|
||||
};
|
||||
|
||||
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for HostFile {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::file::HostFile;
|
||||
use super::{GetVnodeError, HostFs};
|
||||
use crate::errno::{Errno, EEXIST, EIO, ENOENT, ENOTDIR};
|
||||
use crate::fs::{Access, IoCmd, Mode, Uio, UioMut, Vnode, VnodeAttrs, VnodeType};
|
||||
use crate::fs::{Access, IoCmd, IoLen, IoVec, IoVecMut, Mode, Vnode, VnodeAttrs, VnodeType};
|
||||
use crate::process::VThread;
|
||||
use crate::ucred::{Gid, Uid};
|
||||
use macros::Errno;
|
||||
|
@ -127,20 +127,23 @@ impl crate::fs::VnodeBackend for VnodeBackend {
|
|||
fn read(
|
||||
&self,
|
||||
_: &Arc<Vnode>,
|
||||
buf: &mut UioMut,
|
||||
off: u64,
|
||||
buf: &mut [IoVecMut],
|
||||
_: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
let read = self.file.read(buf).map_err(ReadError::ReadFailed)?;
|
||||
|
||||
Ok(read)
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
match self.file.read(off, buf) {
|
||||
Ok(v) => Ok(v),
|
||||
Err(e) => Err(Box::new(ReadError::ReadFailed(e))),
|
||||
}
|
||||
}
|
||||
|
||||
fn write(
|
||||
&self,
|
||||
#[allow(unused_variables)] vn: &Arc<Vnode>,
|
||||
#[allow(unused_variables)] buf: &mut Uio,
|
||||
#[allow(unused_variables)] td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
vn: &Arc<Vnode>,
|
||||
off: u64,
|
||||
buf: &[IoVec],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -152,10 +152,10 @@ impl Fs {
|
|||
sys.register(188, &fs, Self::sys_stat);
|
||||
sys.register(189, &fs, Self::sys_fstat);
|
||||
sys.register(190, &fs, Self::sys_lstat);
|
||||
sys.register(191, &fs, Self::sys_pread);
|
||||
sys.register(209, &fs, Self::sys_poll);
|
||||
sys.register(289, &fs, Self::sys_preadv);
|
||||
sys.register(290, &fs, Self::sys_pwritev);
|
||||
sys.register(475, &fs, Self::sys_pread);
|
||||
sys.register(476, &fs, Self::sys_pwrite);
|
||||
sys.register(478, &fs, Self::sys_lseek);
|
||||
sys.register(479, &fs, Self::sys_truncate);
|
||||
|
@ -179,14 +179,9 @@ impl Fs {
|
|||
let vnode = self
|
||||
.lookup(path, true, td)
|
||||
.map_err(OpenError::LookupFailed)?;
|
||||
let backend = vnode.to_file_backend();
|
||||
|
||||
let ty = if let Some(VnodeItem::Device(dev)) = vnode.item().as_ref() {
|
||||
VFileType::Device(dev.clone())
|
||||
} else {
|
||||
VFileType::Vnode(vnode.clone())
|
||||
};
|
||||
|
||||
Ok(VFile::new(ty, flags))
|
||||
Ok(VFile::new(VFileType::Vnode, flags, Some(vnode), backend))
|
||||
}
|
||||
|
||||
pub fn lookup(
|
||||
|
@ -377,8 +372,6 @@ impl Fs {
|
|||
|
||||
info!("Reading {len} bytes from fd {fd}.");
|
||||
|
||||
let iovec = unsafe { IoVec::try_from_raw_parts(ptr, len) }?;
|
||||
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
@ -389,8 +382,6 @@ impl Fs {
|
|||
|
||||
info!("Writing {len} bytes to fd {fd}.");
|
||||
|
||||
let iovec = unsafe { IoVec::try_from_raw_parts(ptr, len) }?;
|
||||
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
@ -528,12 +519,10 @@ impl Fs {
|
|||
todo!()
|
||||
}
|
||||
|
||||
fn readv(&self, fd: i32, uio: UioMut, td: &VThread) -> Result<usize, SysErr> {
|
||||
fn readv(&self, fd: i32, td: &VThread) -> Result<usize, SysErr> {
|
||||
let file = td.proc().files().get_for_read(fd)?;
|
||||
|
||||
let read = file.do_read(uio, Some(td))?;
|
||||
|
||||
Ok(read)
|
||||
todo!();
|
||||
}
|
||||
|
||||
fn sys_writev(self: &Arc<Self>, td: &VThread, i: &SysIn) -> Result<SysOut, SysErr> {
|
||||
|
@ -544,12 +533,10 @@ impl Fs {
|
|||
todo!()
|
||||
}
|
||||
|
||||
fn writev(&self, fd: i32, uio: Uio, td: &VThread) -> Result<usize, SysErr> {
|
||||
fn writev(&self, fd: i32, td: &VThread) -> Result<usize, SysErr> {
|
||||
let file = td.proc().files().get_for_write(fd)?;
|
||||
|
||||
let written = file.do_write(uio, Some(td))?;
|
||||
|
||||
Ok(written)
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn sys_stat(self: &Arc<Self>, td: &VThread, i: &SysIn) -> Result<SysOut, SysErr> {
|
||||
|
@ -615,97 +602,133 @@ impl Fs {
|
|||
fn sys_pread(self: &Arc<Self>, td: &VThread, i: &SysIn) -> Result<SysOut, SysErr> {
|
||||
let fd: i32 = i.args[0].try_into().unwrap();
|
||||
let ptr: *mut u8 = i.args[1].into();
|
||||
let len: usize = i.args[2].try_into().unwrap();
|
||||
let len: IoLen = i.args[2].try_into()?;
|
||||
let offset: i64 = i.args[3].into();
|
||||
let mut buf = unsafe { IoVecMut::new(ptr, len) };
|
||||
|
||||
info!("Reading {len} bytes from fd {fd} at offset {offset}.");
|
||||
|
||||
let iovec = unsafe { IoVec::try_from_raw_parts(ptr, len) }?;
|
||||
|
||||
let uio = UioMut {
|
||||
vecs: &mut [iovec],
|
||||
bytes_left: len,
|
||||
offset,
|
||||
};
|
||||
|
||||
let read = self.preadv(fd, uio, td)?;
|
||||
let read = self.preadv(fd, offset, std::slice::from_mut(&mut buf), td)?;
|
||||
|
||||
Ok(read.into())
|
||||
}
|
||||
|
||||
fn sys_pwrite(self: &Arc<Self>, td: &VThread, i: &SysIn) -> Result<SysOut, SysErr> {
|
||||
let fd: i32 = i.args[0].try_into().unwrap();
|
||||
let ptr: *mut u8 = i.args[1].into();
|
||||
let len: usize = i.args[2].try_into().unwrap();
|
||||
let ptr: *const u8 = i.args[1].into();
|
||||
let len: IoLen = i.args[2].try_into()?;
|
||||
let offset: i64 = i.args[3].into();
|
||||
let buf = unsafe { IoVec::new(ptr, len) };
|
||||
|
||||
info!("Writing {len} bytes to fd {fd} at offset {offset}.");
|
||||
|
||||
let iovec = unsafe { IoVec::try_from_raw_parts(ptr, len) }?;
|
||||
|
||||
let uio = Uio {
|
||||
vecs: &[iovec],
|
||||
bytes_left: len,
|
||||
offset,
|
||||
};
|
||||
|
||||
let written = self.pwritev(fd, uio, td)?;
|
||||
let written = self.pwritev(fd, offset, std::slice::from_ref(&buf), td)?;
|
||||
|
||||
Ok(written.into())
|
||||
}
|
||||
|
||||
fn sys_preadv(self: &Arc<Self>, td: &VThread, i: &SysIn) -> Result<SysOut, SysErr> {
|
||||
// Get arguments.
|
||||
let fd: i32 = i.args[0].try_into().unwrap();
|
||||
let iovec: *mut IoVec = i.args[1].into();
|
||||
let iovec: *mut IoVecMut = i.args[1].into();
|
||||
let count: u32 = i.args[2].try_into().unwrap();
|
||||
let offset: i64 = i.args[3].into();
|
||||
let buf = if count >= 1025 {
|
||||
return Err(SysErr::Raw(EINVAL));
|
||||
} else {
|
||||
unsafe { std::slice::from_raw_parts_mut(iovec, count.try_into().unwrap()) }
|
||||
};
|
||||
|
||||
let uio = unsafe { UioMut::copyin(iovec, count, offset) }?;
|
||||
// Check if total length exceed the limit.
|
||||
let mut total = IoLen::ZERO;
|
||||
|
||||
let read = self.preadv(fd, uio, td)?;
|
||||
for v in buf.iter() {
|
||||
match total.checked_add(v.len()) {
|
||||
Some(v) => total = v,
|
||||
None => return Err(SysErr::Raw(EINVAL)),
|
||||
}
|
||||
}
|
||||
|
||||
// Read the file.
|
||||
let read = self.preadv(fd, offset, buf, td)?;
|
||||
|
||||
Ok(read.into())
|
||||
}
|
||||
|
||||
fn preadv(&self, fd: i32, uio: UioMut, td: &VThread) -> Result<usize, SysErr> {
|
||||
/// See `kern_preadv` on the PS4 for a reference.
|
||||
fn preadv(
|
||||
&self,
|
||||
fd: i32,
|
||||
off: i64,
|
||||
buf: &mut [IoVecMut],
|
||||
td: &VThread,
|
||||
) -> Result<IoLen, SysErr> {
|
||||
// Check if file seekable.
|
||||
let file = td.proc().files().get_for_read(fd)?;
|
||||
|
||||
let vnode = file.seekable_vnode().ok_or(SysErr::Raw(ESPIPE))?;
|
||||
|
||||
if uio.offset < 0 && !vnode.is_character() {
|
||||
return Err(SysErr::Raw(EINVAL));
|
||||
if !file.is_seekable() {
|
||||
return Err(SysErr::Raw(ESPIPE));
|
||||
}
|
||||
|
||||
let read = file.do_read(uio, Some(td))?;
|
||||
// Check offset.
|
||||
let off = if off > -1 {
|
||||
Some(TryInto::<u64>::try_into(off).unwrap())
|
||||
} else if !file.vnode().unwrap().is_character() {
|
||||
return Err(SysErr::Raw(EINVAL));
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(read)
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn sys_pwritev(self: &Arc<Self>, td: &VThread, i: &SysIn) -> Result<SysOut, SysErr> {
|
||||
// Get arguments.
|
||||
let fd: i32 = i.args[0].try_into().unwrap();
|
||||
let iovec: *const IoVec = i.args[1].into();
|
||||
let count: u32 = i.args[2].try_into().unwrap();
|
||||
let offset: i64 = i.args[3].into();
|
||||
let buf = if count >= 1025 {
|
||||
return Err(SysErr::Raw(EINVAL));
|
||||
} else {
|
||||
unsafe { std::slice::from_raw_parts(iovec, count.try_into().unwrap()) }
|
||||
};
|
||||
|
||||
let uio = unsafe { Uio::copyin(iovec, count, offset) }?;
|
||||
// Check if total length exceed the limit.
|
||||
let mut total = IoLen::ZERO;
|
||||
|
||||
let written = self.pwritev(fd, uio, td)?;
|
||||
for v in buf {
|
||||
match total.checked_add(v.len()) {
|
||||
Some(v) => total = v,
|
||||
None => return Err(SysErr::Raw(EINVAL)),
|
||||
}
|
||||
}
|
||||
|
||||
// Write the file.
|
||||
let written = self.pwritev(fd, offset, buf, td)?;
|
||||
|
||||
Ok(written.into())
|
||||
}
|
||||
|
||||
fn pwritev(&self, fd: i32, uio: Uio, td: &VThread) -> Result<usize, SysErr> {
|
||||
/// See `kern_pwritev` on the PS4 for a reference.
|
||||
fn pwritev(&self, fd: i32, off: i64, buf: &[IoVec], td: &VThread) -> Result<IoLen, SysErr> {
|
||||
// Check if file seekable.
|
||||
let file = td.proc().files().get_for_write(fd)?;
|
||||
|
||||
let vnode = file.seekable_vnode().ok_or(SysErr::Raw(ESPIPE))?;
|
||||
|
||||
if uio.offset < 0 && !vnode.is_character() {
|
||||
return Err(SysErr::Raw(EINVAL));
|
||||
if !file.is_seekable() {
|
||||
return Err(SysErr::Raw(ESPIPE));
|
||||
}
|
||||
|
||||
let written = file.do_write(uio, Some(td))?;
|
||||
// Check offset.
|
||||
let off = if off > -1 {
|
||||
Some(TryInto::<u64>::try_into(off).unwrap())
|
||||
} else if !file.vnode().unwrap().is_character() {
|
||||
return Err(SysErr::Raw(EINVAL));
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(written)
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn sys_fstatat(self: &Arc<Self>, td: &VThread, i: &SysIn) -> Result<SysOut, SysErr> {
|
||||
|
@ -767,8 +790,9 @@ impl Fs {
|
|||
|
||||
let file = td.proc().files().get(fd)?;
|
||||
|
||||
#[allow(unused_variables)] // Remove this when is implementing.
|
||||
let vnode = file.seekable_vnode().ok_or(SysErr::Raw(ESPIPE))?;
|
||||
if !file.is_seekable() {
|
||||
return Err(SysErr::Raw(ESPIPE));
|
||||
}
|
||||
|
||||
// check vnode type
|
||||
|
||||
|
@ -1028,7 +1052,6 @@ bitflags! {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub struct TruncateLength(i64);
|
||||
|
||||
impl TryFrom<i64> for TruncateLength {
|
||||
|
|
|
@ -1,36 +1,26 @@
|
|||
use crate::{
|
||||
errno::{Errno, EISDIR, EROFS},
|
||||
fs::{
|
||||
null::hash::NULL_HASHTABLE, perm::Access, Mount, MountFlags, Uio, UioMut, Vnode,
|
||||
VnodeAttrs, VnodeType,
|
||||
},
|
||||
process::VThread,
|
||||
};
|
||||
use super::hash::NULL_HASHTABLE;
|
||||
use crate::errno::{Errno, EISDIR, EROFS};
|
||||
use crate::fs::{Access, IoLen, IoVec, IoVecMut, Mount, MountFlags, Vnode, VnodeAttrs, VnodeType};
|
||||
use crate::process::VThread;
|
||||
use macros::Errno;
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::sync::Arc;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct VnodeBackend {
|
||||
lower: Arc<Vnode>,
|
||||
null_node: Weak<Vnode>,
|
||||
}
|
||||
|
||||
impl VnodeBackend {
|
||||
pub(super) fn new(lower: &Arc<Vnode>, null_node: &Weak<Vnode>) -> Self {
|
||||
pub(super) fn new(lower: &Arc<Vnode>) -> Self {
|
||||
Self {
|
||||
lower: lower.clone(),
|
||||
null_node: null_node.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn lower(&self) -> &Arc<Vnode> {
|
||||
&self.lower
|
||||
}
|
||||
|
||||
pub(super) fn null_node(&self) -> &Weak<Vnode> {
|
||||
&self.null_node
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::fs::VnodeBackend for VnodeBackend {
|
||||
|
@ -94,27 +84,27 @@ impl crate::fs::VnodeBackend for VnodeBackend {
|
|||
fn read(
|
||||
&self,
|
||||
_: &Arc<Vnode>,
|
||||
buf: &mut UioMut,
|
||||
off: u64,
|
||||
buf: &mut [IoVecMut],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
self.lower
|
||||
.read(buf, td)
|
||||
.map_err(ReadError::ReadFromLowerFailed)?;
|
||||
|
||||
Ok(())
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
match self.lower.read(off, buf, td) {
|
||||
Ok(v) => Ok(v),
|
||||
Err(e) => Err(Box::new(ReadError::ReadFromLowerFailed(e))),
|
||||
}
|
||||
}
|
||||
|
||||
fn write(
|
||||
&self,
|
||||
_: &Arc<Vnode>,
|
||||
buf: &mut Uio,
|
||||
vn: &Arc<Vnode>,
|
||||
off: u64,
|
||||
buf: &[IoVec],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
self.lower
|
||||
.write(buf, td)
|
||||
.map_err(WriteError::WriteFromLowerFailed)?;
|
||||
|
||||
Ok(())
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
match self.lower.write(off, buf, td) {
|
||||
Ok(v) => Ok(v),
|
||||
Err(e) => Err(Box::new(WriteError::WriteFromLowerFailed(e))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,11 +119,7 @@ pub(super) fn null_nodeget(
|
|||
return Ok(nullnode);
|
||||
}
|
||||
|
||||
let nullnode = Vnode::new_cyclic(|null_node| {
|
||||
let backend = Arc::new(VnodeBackend::new(lower, null_node));
|
||||
|
||||
Vnode::new_plain(mnt, lower.ty().clone(), "nullfs", backend)
|
||||
});
|
||||
let nullnode = Vnode::new(mnt, lower.ty().clone(), "nullfs", VnodeBackend::new(lower));
|
||||
|
||||
table.insert(mnt, lower, &nullnode);
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use super::{AllocVnodeError, TempFs};
|
||||
use crate::errno::{Errno, ENOENT, ENOSPC};
|
||||
use crate::fs::{Access, Uio, UioMut, Vnode, VnodeAttrs, VnodeType};
|
||||
use crate::fs::{Access, Vnode, VnodeAttrs, VnodeType};
|
||||
use crate::process::VThread;
|
||||
use gmtx::{Gutex, GutexGroup, GutexWriteGuard};
|
||||
use macros::Errno;
|
||||
|
@ -204,19 +204,21 @@ impl crate::fs::VnodeBackend for VnodeBackend {
|
|||
|
||||
fn read(
|
||||
&self,
|
||||
#[allow(unused_variables)] vn: &Arc<Vnode>,
|
||||
#[allow(unused_variables)] buf: &mut UioMut,
|
||||
#[allow(unused_variables)] td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
vn: &Arc<Vnode>,
|
||||
off: u64,
|
||||
buf: &mut [crate::fs::IoVecMut],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<crate::fs::IoLen, Box<dyn Errno>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn write(
|
||||
&self,
|
||||
#[allow(unused_variables)] vn: &Arc<Vnode>,
|
||||
#[allow(unused_variables)] buf: &mut Uio,
|
||||
#[allow(unused_variables)] td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
vn: &Arc<Vnode>,
|
||||
off: u64,
|
||||
buf: &[crate::fs::IoVec],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<crate::fs::IoLen, Box<dyn Errno>> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,163 +1,162 @@
|
|||
use crate::errno::{Errno, EINVAL};
|
||||
use macros::Errno;
|
||||
use crate::syscalls::{SysArg, SysOut};
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::marker::PhantomData;
|
||||
use std::num::NonZeroI32;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use thiserror::Error;
|
||||
|
||||
const UIO_MAXIOV: u32 = 1024;
|
||||
const IOSIZE_MAX: usize = 0x7fffffff;
|
||||
|
||||
/// Implementation of `iovec` structure for writing.
|
||||
#[repr(C)]
|
||||
pub struct IoVec<'a> {
|
||||
ptr: *const u8,
|
||||
len: usize,
|
||||
_phantom: std::marker::PhantomData<&'a [u8]>,
|
||||
len: IoLen,
|
||||
phantom: PhantomData<&'a [u8]>,
|
||||
}
|
||||
|
||||
impl<'a> IoVec<'a> {
|
||||
/// This is for when the PS4 DOES check the length (such as in read, write, pread and pwrite)
|
||||
pub unsafe fn try_from_raw_parts(base: *const u8, len: usize) -> Result<Self, IoVecError> {
|
||||
if len > IOSIZE_MAX {
|
||||
return Err(IoVecError::MaxLenExceeded);
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
ptr: base,
|
||||
len,
|
||||
_phantom: std::marker::PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
/// This is for when the PS4 DOES NOT check the length (such as in recvmsg, recvfrom, sendmsg and sendto)
|
||||
pub unsafe fn from_raw_parts(base: *const u8, len: usize) -> Self {
|
||||
/// # Safety
|
||||
/// `ptr` must outlive `'a`.
|
||||
pub unsafe fn new(ptr: *const u8, len: IoLen) -> Self {
|
||||
Self {
|
||||
ptr: base,
|
||||
ptr,
|
||||
len,
|
||||
_phantom: std::marker::PhantomData,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_slice(slice: &'a mut [u8]) -> Self {
|
||||
Self {
|
||||
ptr: slice.as_ptr(),
|
||||
len: slice.len(),
|
||||
_phantom: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ptr(&self) -> *mut u8 {
|
||||
self.ptr as _
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
pub fn len(&self) -> IoLen {
|
||||
self.len
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Uio<'a> {
|
||||
pub(super) vecs: &'a [IoVec<'a>], // uio_iov + uio_iovcnt
|
||||
pub(super) bytes_left: usize, // uio_resid
|
||||
pub(super) offset: i64, // uio_offset
|
||||
}
|
||||
impl<'a> Deref for IoVec<'a> {
|
||||
type Target = [u8];
|
||||
|
||||
impl<'a> Uio<'a> {
|
||||
/// See `copyinuio` on the PS4 for a reference.
|
||||
pub unsafe fn copyin(
|
||||
first: *const IoVec<'a>,
|
||||
count: u32,
|
||||
offset: i64,
|
||||
) -> Result<Self, CopyInUioError> {
|
||||
if count > UIO_MAXIOV {
|
||||
return Err(CopyInUioError::TooManyVecs);
|
||||
}
|
||||
|
||||
let vecs = std::slice::from_raw_parts(first, count as usize);
|
||||
let bytes_left = vecs.iter().map(|v| v.len).try_fold(0, |acc, len| {
|
||||
if acc > IOSIZE_MAX - len {
|
||||
Err(CopyInUioError::MaxLenExceeded)
|
||||
} else {
|
||||
Ok(acc + len)
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(Self {
|
||||
vecs,
|
||||
bytes_left,
|
||||
offset,
|
||||
})
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { std::slice::from_raw_parts(self.ptr, self.len.get()) }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UioMut<'a> {
|
||||
pub(super) vecs: &'a mut [IoVec<'a>], // uio_iov + uio_iovcnt
|
||||
pub(super) bytes_left: usize, // uio_resid
|
||||
pub(super) offset: i64, // uio_offset
|
||||
/// Implementation of `iovec` structure for reading.
|
||||
#[repr(C)]
|
||||
pub struct IoVecMut<'a> {
|
||||
ptr: *mut u8,
|
||||
len: IoLen,
|
||||
phantom: PhantomData<&'a mut [u8]>,
|
||||
}
|
||||
|
||||
impl<'a> UioMut<'a> {
|
||||
/// See `copyinuio` on the PS4 for a reference.
|
||||
pub unsafe fn copyin(
|
||||
first: *mut IoVec<'a>,
|
||||
count: u32,
|
||||
offset: i64,
|
||||
) -> Result<Self, CopyInUioError> {
|
||||
if count > UIO_MAXIOV {
|
||||
return Err(CopyInUioError::TooManyVecs);
|
||||
}
|
||||
|
||||
let vecs = std::slice::from_raw_parts_mut(first, count as usize);
|
||||
let bytes_left = vecs.iter().map(|v| v.len).try_fold(0, |acc, len| {
|
||||
if acc > IOSIZE_MAX - len {
|
||||
Err(CopyInUioError::MaxLenExceeded)
|
||||
} else {
|
||||
Ok(acc + len)
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(Self {
|
||||
vecs,
|
||||
bytes_left,
|
||||
offset,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_single_vec(vec: &'a mut IoVec<'a>, offset: i64) -> Self {
|
||||
let bytes_left = vec.len;
|
||||
|
||||
impl<'a> IoVecMut<'a> {
|
||||
/// # Safety
|
||||
/// `ptr` must outlive `'a`.
|
||||
pub unsafe fn new(ptr: *mut u8, len: IoLen) -> Self {
|
||||
Self {
|
||||
vecs: std::slice::from_mut(vec),
|
||||
bytes_left,
|
||||
offset,
|
||||
ptr,
|
||||
len,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_with<E>(
|
||||
&mut self,
|
||||
func: impl Fn(&mut IoVec, i64) -> Result<u64, E>,
|
||||
) -> Result<(), E> {
|
||||
for vec in self.vecs.iter_mut() {
|
||||
let written = func(vec, self.offset)?;
|
||||
|
||||
self.offset = self.offset.checked_add_unsigned(written).unwrap();
|
||||
self.bytes_left -= written as usize;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
pub fn len(&self) -> IoLen {
|
||||
self.len
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error, Errno)]
|
||||
pub enum IoVecError {
|
||||
#[error("len exceed the maximum value")]
|
||||
#[errno(EINVAL)]
|
||||
MaxLenExceeded,
|
||||
impl<'a> Deref for IoVecMut<'a> {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { std::slice::from_raw_parts(self.ptr, self.len.get()) }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error, Errno)]
|
||||
pub enum CopyInUioError {
|
||||
#[error("too many iovecs")]
|
||||
#[errno(EINVAL)]
|
||||
TooManyVecs,
|
||||
|
||||
#[error("the sum of iovec lengths is too large")]
|
||||
#[errno(EINVAL)]
|
||||
MaxLenExceeded,
|
||||
impl<'a> DerefMut for IoVecMut<'a> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
unsafe { std::slice::from_raw_parts_mut(self.ptr, self.len.get()) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a length of [`IoVec`] and [`IoVecMut`].
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct IoLen(usize);
|
||||
|
||||
impl IoLen {
|
||||
pub const ZERO: Self = Self(0);
|
||||
pub const MAX: Self = Self(0x7fffffff);
|
||||
|
||||
pub fn from_usize(v: usize) -> Result<Self, IoLenError> {
|
||||
let v = Self(v);
|
||||
|
||||
if v > Self::MAX {
|
||||
Err(IoLenError(()))
|
||||
} else {
|
||||
Ok(v)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(self) -> usize {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn checked_add(self, rhs: Self) -> Option<Self> {
|
||||
let r = self.0.checked_add(rhs.0).map(IoLen)?;
|
||||
|
||||
if r > Self::MAX {
|
||||
None
|
||||
} else {
|
||||
Some(r)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn saturating_add(self, rhs: Self) -> Self {
|
||||
let r = Self(self.0.saturating_add(rhs.0));
|
||||
|
||||
if r > Self::MAX {
|
||||
Self::MAX
|
||||
} else {
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
pub fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(IoLen)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<SysArg> for IoLen {
|
||||
type Error = IoLenError;
|
||||
|
||||
fn try_from(value: SysArg) -> Result<Self, Self::Error> {
|
||||
Self::from_usize(value.get())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<usize> for IoLen {
|
||||
fn eq(&self, other: &usize) -> bool {
|
||||
self.0 == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for IoLen {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IoLen> for SysOut {
|
||||
fn from(value: IoLen) -> Self {
|
||||
value.0.into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents an error when [`IoLen`] fails to construct.
|
||||
#[derive(Debug, Error)]
|
||||
#[error("invalid value")]
|
||||
pub struct IoLenError(());
|
||||
|
||||
impl Errno for IoLenError {
|
||||
fn errno(&self) -> NonZeroI32 {
|
||||
EINVAL
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
use super::{
|
||||
unixify_access, Access, CharacterDevice, FileBackend, IoCmd, Mode, Mount, RevokeFlags, Stat,
|
||||
TruncateLength, Uio, UioMut, VFile,
|
||||
unixify_access, Access, CharacterDevice, FileBackend, IoCmd, IoLen, IoVec, IoVecMut, Mode,
|
||||
Mount, PollEvents, RevokeFlags, Stat, TruncateLength, VFile,
|
||||
};
|
||||
use crate::arnd;
|
||||
use crate::errno::{Errno, ENOTDIR, ENOTTY, EOPNOTSUPP, EPERM};
|
||||
use crate::fs::PollEvents;
|
||||
use crate::process::VThread;
|
||||
use crate::ucred::{Gid, Uid};
|
||||
use gmtx::{Gutex, GutexGroup, GutexReadGuard, GutexWriteGuard};
|
||||
|
@ -24,7 +23,7 @@ pub struct Vnode {
|
|||
mount: Arc<Mount>, // v_mount
|
||||
ty: VnodeType, // v_type
|
||||
tag: &'static str, // v_tag
|
||||
backend: Arc<dyn VnodeBackend>, // v_op + v_data
|
||||
backend: Box<dyn VnodeBackend>, // v_op + v_data
|
||||
hash: u32, // v_hash
|
||||
item: Gutex<Option<VnodeItem>>, // v_un
|
||||
}
|
||||
|
@ -37,24 +36,15 @@ impl Vnode {
|
|||
tag: &'static str,
|
||||
backend: impl VnodeBackend,
|
||||
) -> Arc<Self> {
|
||||
Arc::new(Self::new_plain(mount, ty, tag, Arc::new(backend)))
|
||||
}
|
||||
|
||||
pub(super) fn new_plain(
|
||||
mount: &Arc<Mount>,
|
||||
ty: VnodeType,
|
||||
tag: &'static str,
|
||||
backend: Arc<impl VnodeBackend>,
|
||||
) -> Self {
|
||||
let gg = GutexGroup::new();
|
||||
|
||||
ACTIVE.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
Self {
|
||||
Arc::new(Self {
|
||||
mount: mount.clone(),
|
||||
ty,
|
||||
tag,
|
||||
backend,
|
||||
backend: Box::new(backend),
|
||||
hash: {
|
||||
let mut buf = [0u8; 4];
|
||||
arnd::rand_bytes(&mut buf);
|
||||
|
@ -62,11 +52,7 @@ impl Vnode {
|
|||
u32::from_ne_bytes(buf)
|
||||
},
|
||||
item: gg.spawn(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_cyclic(f: impl FnOnce(&Weak<Vnode>) -> Vnode) -> Arc<Self> {
|
||||
Arc::new_cyclic(f)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn mount(&self) -> &Arc<Mount> {
|
||||
|
@ -141,68 +127,24 @@ impl Vnode {
|
|||
|
||||
pub fn read(
|
||||
self: &Arc<Self>,
|
||||
buf: &mut UioMut,
|
||||
off: u64,
|
||||
buf: &mut [IoVecMut],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
self.backend.read(self, buf, td)
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
self.backend.read(self, off, buf, td)
|
||||
}
|
||||
|
||||
pub fn write(
|
||||
self: &Arc<Self>,
|
||||
buf: &mut Uio,
|
||||
off: u64,
|
||||
buf: &[IoVec],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
self.backend.write(self, buf, td)
|
||||
}
|
||||
}
|
||||
|
||||
impl FileBackend for Vnode {
|
||||
fn read(
|
||||
self: &Arc<Self>,
|
||||
_: &VFile,
|
||||
buf: &mut UioMut,
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
self.backend.read(self, buf, td)
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
self.backend.write(self, off, buf, td)
|
||||
}
|
||||
|
||||
fn write(
|
||||
self: &Arc<Self>,
|
||||
_: &VFile,
|
||||
buf: &mut Uio,
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
self.backend.write(self, buf, td)
|
||||
}
|
||||
|
||||
#[allow(unused_variables)] // TODO: remove when implementing
|
||||
fn ioctl(
|
||||
self: &Arc<Self>,
|
||||
file: &VFile,
|
||||
cmd: IoCmd,
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[allow(unused_variables)] // TODO: remove when implementing
|
||||
fn poll(self: &Arc<Self>, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents {
|
||||
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!()
|
||||
pub fn to_file_backend(self: &Arc<Self>) -> Box<dyn FileBackend> {
|
||||
self.backend.to_file_backend(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -318,17 +260,23 @@ pub(super) trait VnodeBackend: Debug + Send + Sync + 'static {
|
|||
fn read(
|
||||
&self,
|
||||
#[allow(unused_variables)] vn: &Arc<Vnode>,
|
||||
#[allow(unused_variables)] buf: &mut UioMut,
|
||||
#[allow(unused_variables)] off: u64,
|
||||
#[allow(unused_variables)] buf: &mut [IoVecMut],
|
||||
#[allow(unused_variables)] td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>>;
|
||||
) -> Result<IoLen, Box<dyn Errno>>;
|
||||
|
||||
/// An implementation of `vop_write`.
|
||||
fn write(
|
||||
&self,
|
||||
#[allow(unused_variables)] vn: &Arc<Vnode>,
|
||||
#[allow(unused_variables)] buf: &mut Uio,
|
||||
#[allow(unused_variables)] off: u64,
|
||||
#[allow(unused_variables)] buf: &[IoVec],
|
||||
#[allow(unused_variables)] td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>>;
|
||||
) -> Result<IoLen, Box<dyn Errno>>;
|
||||
|
||||
fn to_file_backend(&self, vn: &Arc<Vnode>) -> Box<dyn FileBackend> {
|
||||
Box::new(VnodeFileBackend(vn.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
/// An implementation of `vattr` struct.
|
||||
|
@ -341,7 +289,64 @@ pub struct VnodeAttrs {
|
|||
pub fsid: u32, // va_fsid
|
||||
}
|
||||
|
||||
/// Represents an error when [`DEFAULT_VNODEOPS`] fails.
|
||||
/// Implementation of `vnops`.
|
||||
#[derive(Debug)]
|
||||
pub(super) struct VnodeFileBackend(Arc<Vnode>);
|
||||
|
||||
impl VnodeFileBackend {
|
||||
pub fn new(vn: Arc<Vnode>) -> Self {
|
||||
Self(vn)
|
||||
}
|
||||
}
|
||||
|
||||
impl FileBackend for VnodeFileBackend {
|
||||
fn is_seekable(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn read(
|
||||
&self,
|
||||
_: &VFile,
|
||||
off: u64,
|
||||
buf: &mut [IoVecMut],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
self.0.read(off, buf, td)
|
||||
}
|
||||
|
||||
fn write(
|
||||
&self,
|
||||
_: &VFile,
|
||||
off: u64,
|
||||
buf: &[IoVec],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
self.0.write(off, buf, td)
|
||||
}
|
||||
|
||||
fn ioctl(&self, file: &VFile, cmd: IoCmd, td: Option<&VThread>) -> Result<(), Box<dyn Errno>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn poll(&self, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn stat(&self, file: &VFile, td: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn truncate(
|
||||
&self,
|
||||
file: &VFile,
|
||||
length: TruncateLength,
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents an error when default implementation of [`VnodeBackend`] fails.
|
||||
#[derive(Debug, Error, Errno)]
|
||||
enum DefaultError {
|
||||
#[error("operation not supported")]
|
||||
|
|
|
@ -1,17 +1,12 @@
|
|||
use crate::{
|
||||
budget::BudgetType,
|
||||
errno::Errno,
|
||||
fs::{
|
||||
DefaultFileBackendError, FileBackend, PollEvents, Stat, TruncateLength, VFile, VFileFlags,
|
||||
VFileType,
|
||||
},
|
||||
process::{FileDesc, VThread},
|
||||
syscalls::{SysErr, SysIn, SysOut, Syscalls},
|
||||
};
|
||||
use std::{
|
||||
convert::Infallible,
|
||||
sync::{Arc, Weak},
|
||||
use crate::budget::BudgetType;
|
||||
use crate::errno::Errno;
|
||||
use crate::fs::{
|
||||
DefaultFileBackendError, PollEvents, Stat, TruncateLength, VFile, VFileFlags, VFileType,
|
||||
};
|
||||
use crate::process::{FileDesc, VThread};
|
||||
use crate::syscalls::{SysErr, SysIn, SysOut, Syscalls};
|
||||
use std::convert::Infallible;
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
pub struct KernelQueueManager {}
|
||||
|
||||
|
@ -39,8 +34,10 @@ impl KernelQueueManager {
|
|||
filedesc.insert_kqueue(kq.clone());
|
||||
|
||||
Ok(VFile::new(
|
||||
VFileType::KernelQueue(kq),
|
||||
VFileType::KernelQueue,
|
||||
VFileFlags::READ | VFileFlags::WRITE,
|
||||
None,
|
||||
Box::new(FileBackend(kq)),
|
||||
))
|
||||
},
|
||||
BudgetType::FdEqueue,
|
||||
|
@ -63,13 +60,21 @@ impl KernelQueue {
|
|||
}
|
||||
}
|
||||
|
||||
impl FileBackend for KernelQueue {
|
||||
#[allow(unused_variables)] // TODO: remove when implementing
|
||||
fn poll(self: &Arc<Self>, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents {
|
||||
/// Implementation of [`crate::fs::FileBackend`] for kqueue.
|
||||
#[derive(Debug)]
|
||||
struct FileBackend(Arc<KernelQueue>);
|
||||
|
||||
impl crate::fs::FileBackend for FileBackend {
|
||||
fn is_seekable(&self) -> bool {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn stat(self: &Arc<Self>, _: &VFile, _: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
|
||||
#[allow(unused_variables)] // TODO: remove when implementing
|
||||
fn poll(&self, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn stat(&self, _: &VFile, _: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
|
||||
let mut stat = Stat::zeroed();
|
||||
|
||||
stat.mode = 0o10000;
|
||||
|
@ -78,7 +83,7 @@ impl FileBackend for KernelQueue {
|
|||
}
|
||||
|
||||
fn truncate(
|
||||
self: &Arc<Self>,
|
||||
&self,
|
||||
_: &VFile,
|
||||
_: TruncateLength,
|
||||
_: Option<&VThread>,
|
||||
|
|
|
@ -199,12 +199,17 @@ impl NetManager {
|
|||
let so = Socket::new(domain, ty, proto, td.cred(), td, None)?;
|
||||
|
||||
let ty = if domain == 1 {
|
||||
VFileType::IpcSocket(so)
|
||||
VFileType::IpcSocket
|
||||
} else {
|
||||
VFileType::Socket(so)
|
||||
VFileType::Socket
|
||||
};
|
||||
|
||||
Ok(VFile::new(ty, VFileFlags::READ | VFileFlags::WRITE))
|
||||
Ok(VFile::new(
|
||||
ty,
|
||||
VFileFlags::READ | VFileFlags::WRITE,
|
||||
None,
|
||||
todo!(),
|
||||
))
|
||||
},
|
||||
budget,
|
||||
)?;
|
||||
|
@ -261,12 +266,17 @@ impl NetManager {
|
|||
let so = Socket::new(domain, ty, proto, td.cred(), td, name)?;
|
||||
|
||||
let ty = if domain == 1 {
|
||||
VFileType::IpcSocket(so)
|
||||
VFileType::IpcSocket
|
||||
} else {
|
||||
VFileType::Socket(so)
|
||||
VFileType::Socket
|
||||
};
|
||||
|
||||
Ok(VFile::new(ty, VFileFlags::READ | VFileFlags::WRITE))
|
||||
Ok(VFile::new(
|
||||
ty,
|
||||
VFileFlags::READ | VFileFlags::WRITE,
|
||||
None,
|
||||
todo!(),
|
||||
))
|
||||
},
|
||||
budget,
|
||||
)?;
|
||||
|
@ -301,12 +311,10 @@ impl NetManager {
|
|||
let to: *const u8 = i.args[4].into();
|
||||
let tolen: u32 = i.args[5].try_into().unwrap();
|
||||
|
||||
let ref iovec = unsafe { IoVec::from_raw_parts(buf, buflen) };
|
||||
|
||||
let msg = MsgHdr {
|
||||
name: to,
|
||||
len: tolen,
|
||||
iovec: iovec as *const IoVec,
|
||||
iovec: todo!(),
|
||||
iovec_len: 1,
|
||||
control: core::ptr::null(),
|
||||
control_len: 0,
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
use super::proto::{Protocol, SocketBackend};
|
||||
use super::{GetOptError, SetOptError, SockAddr, SockOpt};
|
||||
use crate::errno::{Errno, EPROTONOSUPPORT};
|
||||
use crate::fs::{
|
||||
DefaultFileBackendError, FileBackend, IoCmd, PollEvents, Stat, TruncateLength, Uio, UioMut,
|
||||
VFile,
|
||||
DefaultFileBackendError, FileBackend, IoCmd, IoLen, IoVec, IoVecMut, PollEvents, Stat,
|
||||
TruncateLength, VFile,
|
||||
};
|
||||
use crate::process::VThread;
|
||||
use crate::ucred::Ucred;
|
||||
use crate::{
|
||||
errno::{Errno, EPROTONOSUPPORT},
|
||||
process::VThread,
|
||||
};
|
||||
use macros::Errno;
|
||||
use std::num::NonZeroI32;
|
||||
use std::sync::Arc;
|
||||
|
@ -63,13 +61,13 @@ impl Socket {
|
|||
|
||||
/// See `sosend` on the PS4 for a reference.
|
||||
#[allow(unused)] // TODO: remove when used
|
||||
fn send(&self, buf: &mut Uio, td: Option<&VThread>) -> Result<usize, SendError> {
|
||||
fn send(&self, buf: &[IoVec], td: Option<&VThread>) -> Result<usize, SendError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// See `soreceive` on the PS4 for a reference.
|
||||
#[allow(unused)] // TODO: remove when used
|
||||
fn receive(&self, buf: &mut UioMut, td: Option<&VThread>) -> Result<usize, ReceiveError> {
|
||||
fn receive(&self, buf: &mut [IoVecMut], td: Option<&VThread>) -> Result<usize, ReceiveError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
@ -97,35 +95,36 @@ impl Socket {
|
|||
}
|
||||
|
||||
impl FileBackend for Socket {
|
||||
fn is_seekable(&self) -> bool {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[allow(unused_variables)] // TODO: remove when implementing
|
||||
/// See soo_read on the PS4 for a reference.
|
||||
fn read(
|
||||
self: &Arc<Self>,
|
||||
&self,
|
||||
_: &VFile,
|
||||
buf: &mut UioMut,
|
||||
off: u64,
|
||||
buf: &mut [IoVecMut],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[allow(unused_variables)] // TODO: remove when implementing
|
||||
/// See soo_write on the PS4 for a reference.
|
||||
fn write(
|
||||
self: &Arc<Self>,
|
||||
&self,
|
||||
_: &VFile,
|
||||
buf: &mut Uio,
|
||||
off: u64,
|
||||
buf: &[IoVec],
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[allow(unused_variables)] // TODO: remove when implementing
|
||||
fn ioctl(
|
||||
self: &Arc<Self>,
|
||||
file: &VFile,
|
||||
cmd: IoCmd,
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
fn ioctl(&self, file: &VFile, cmd: IoCmd, td: Option<&VThread>) -> Result<(), Box<dyn Errno>> {
|
||||
match cmd {
|
||||
IoCmd::FIONBIO(_) => todo!("socket ioctl with FIONBIO"),
|
||||
IoCmd::FIOASYNC(_) => todo!("socket ioctl with FIOASYNC"),
|
||||
|
@ -137,22 +136,22 @@ impl FileBackend for Socket {
|
|||
IoCmd::SIOCSPGRP(_) => todo!("socket ioctl with SIOCSPGRP"),
|
||||
IoCmd::SIOCGPGRP(_) => todo!("socket ioctl with SIOCGPGRP"),
|
||||
IoCmd::SIOCATMARK(_) => todo!("socket ioctl with SIOCATMARK"),
|
||||
_ => self.backend.control(self, cmd, td),
|
||||
_ => self.backend.control(todo!(), cmd, td),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables)] // TODO: remove when implementing
|
||||
fn poll(self: &Arc<Self>, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents {
|
||||
fn poll(&self, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[allow(unused_variables)] // TODO: remove when implementing
|
||||
fn stat(self: &Arc<Self>, file: &VFile, td: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
|
||||
fn stat(&self, file: &VFile, td: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn truncate(
|
||||
self: &Arc<Self>,
|
||||
&self,
|
||||
_: &VFile,
|
||||
_: TruncateLength,
|
||||
_: Option<&VThread>,
|
||||
|
|
|
@ -119,11 +119,11 @@ impl FileDesc {
|
|||
pub fn get_socket(&self, fd: i32) -> Result<Arc<Socket>, GetSocketError> {
|
||||
let file = self.get(fd)?;
|
||||
|
||||
let (VFileType::Socket(so) | VFileType::IpcSocket(so)) = file.ty() else {
|
||||
let (VFileType::Socket | VFileType::IpcSocket) = file.ty() else {
|
||||
return Err(GetSocketError::NotSocket);
|
||||
};
|
||||
|
||||
Ok(so.clone())
|
||||
Ok(todo!())
|
||||
}
|
||||
|
||||
/// See `fget` on the PS4 for a reference.
|
||||
|
|
|
@ -165,7 +165,7 @@ impl Memory {
|
|||
let prot = seg.prot;
|
||||
|
||||
if let Err(e) = proc.vm().mprotect(addr, len, prot) {
|
||||
return Err(MapError::ProtectMemoryFailed(addr, len, prot, e));
|
||||
return Err(MapError::ProtectMemoryFailed(addr as _, len, prot, e));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -293,7 +293,9 @@ impl Memory {
|
|||
let prot = Protections::CPU_READ | Protections::CPU_WRITE;
|
||||
|
||||
if let Err(e) = self.proc.vm().mprotect(ptr, len, prot) {
|
||||
return Err(UnprotectSegmentError::MprotectFailed(ptr, len, prot, e));
|
||||
return Err(UnprotectSegmentError::MprotectFailed(
|
||||
ptr as _, len, prot, e,
|
||||
));
|
||||
}
|
||||
|
||||
Ok(UnprotectedSegment {
|
||||
|
@ -326,7 +328,7 @@ impl Memory {
|
|||
let prot = Protections::CPU_READ | Protections::CPU_WRITE;
|
||||
|
||||
if let Err(e) = self.proc.vm().mprotect(self.ptr, end, prot) {
|
||||
return Err(UnprotectError::MprotectFailed(self.ptr, end, prot, e));
|
||||
return Err(UnprotectError::MprotectFailed(self.ptr as _, end, prot, e));
|
||||
}
|
||||
|
||||
Ok(UnprotectedMemory {
|
||||
|
@ -506,13 +508,13 @@ pub enum CodeWorkspaceError {
|
|||
/// Represents an error when [`Memory::unprotect_segment()`] is failed.
|
||||
#[derive(Debug, Error)]
|
||||
pub enum UnprotectSegmentError {
|
||||
#[error("cannot protect {1:#018x} bytes starting at {0:p} with {2}")]
|
||||
MprotectFailed(*const u8, usize, Protections, #[source] MemoryUpdateError),
|
||||
#[error("cannot protect {1:#018x} bytes starting at {0:#x} with {2}")]
|
||||
MprotectFailed(usize, usize, Protections, #[source] MemoryUpdateError),
|
||||
}
|
||||
|
||||
/// Represents an error when [`Memory::unprotect()`] is failed.
|
||||
#[derive(Debug, Error)]
|
||||
pub enum UnprotectError {
|
||||
#[error("cannot protect {1:#018x} bytes starting at {0:p} with {2}")]
|
||||
MprotectFailed(*const u8, usize, Protections, #[source] MemoryUpdateError),
|
||||
#[error("cannot protect {1:#018x} bytes starting at {0:#x} with {2}")]
|
||||
MprotectFailed(usize, usize, Protections, #[source] MemoryUpdateError),
|
||||
}
|
||||
|
|
|
@ -1254,8 +1254,8 @@ pub enum MapError {
|
|||
#[error("cannot allocate {0} bytes")]
|
||||
MemoryAllocationFailed(usize, #[source] MmapError),
|
||||
|
||||
#[error("cannot protect {1:#018x} bytes starting at {0:p} with {2}")]
|
||||
ProtectMemoryFailed(*const u8, usize, Protections, #[source] MemoryUpdateError),
|
||||
#[error("cannot protect {1:#018x} bytes starting at {0:#x} with {2}")]
|
||||
ProtectMemoryFailed(usize, usize, Protections, #[source] MemoryUpdateError),
|
||||
|
||||
#[error("cannot unprotect segment {0}")]
|
||||
UnprotectSegmentFailed(usize, #[source] UnprotectSegmentError),
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
use crate::{
|
||||
errno::{Errno, EINVAL},
|
||||
fs::{
|
||||
check_access, Access, AccessError, DefaultFileBackendError, FileBackend, IoCmd, Mode,
|
||||
OpenFlags, PollEvents, Stat, TruncateLength, Uio, UioMut, VFile, VFileFlags, VPathBuf,
|
||||
},
|
||||
process::VThread,
|
||||
syscalls::{SysErr, SysIn, SysOut, Syscalls},
|
||||
ucred::{Gid, Ucred, Uid},
|
||||
use crate::errno::{Errno, EINVAL};
|
||||
use crate::fs::{
|
||||
check_access, Access, AccessError, DefaultFileBackendError, FileBackend, IoCmd, IoLen, IoVec,
|
||||
IoVecMut, Mode, OpenFlags, PollEvents, Stat, TruncateLength, VFile, VFileFlags, VPathBuf,
|
||||
};
|
||||
use crate::process::VThread;
|
||||
use crate::syscalls::{SysErr, SysIn, SysOut, Syscalls};
|
||||
use crate::ucred::{Gid, Ucred, Uid};
|
||||
use macros::Errno;
|
||||
use std::{convert::Infallible, sync::Arc};
|
||||
use std::convert::Infallible;
|
||||
use std::sync::Arc;
|
||||
use thiserror::Error;
|
||||
|
||||
pub struct SharedMemoryManager {}
|
||||
|
@ -108,41 +107,42 @@ impl SharedMemory {
|
|||
}
|
||||
|
||||
impl FileBackend for SharedMemory {
|
||||
fn is_seekable(&self) -> bool {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn read(
|
||||
self: &Arc<Self>,
|
||||
&self,
|
||||
_: &VFile,
|
||||
_: &mut UioMut,
|
||||
_: u64,
|
||||
_: &mut [IoVecMut],
|
||||
_: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
Err(Box::new(DefaultFileBackendError::OperationNotSupported))
|
||||
}
|
||||
|
||||
fn write(
|
||||
self: &Arc<Self>,
|
||||
&self,
|
||||
_: &VFile,
|
||||
_: &mut Uio,
|
||||
_: u64,
|
||||
_: &[IoVec],
|
||||
_: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
) -> Result<IoLen, Box<dyn Errno>> {
|
||||
Err(Box::new(DefaultFileBackendError::OperationNotSupported))
|
||||
}
|
||||
|
||||
#[allow(unused_variables)] // remove when implementing
|
||||
fn ioctl(
|
||||
self: &Arc<Self>,
|
||||
file: &VFile,
|
||||
cmd: IoCmd,
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
fn ioctl(&self, file: &VFile, cmd: IoCmd, td: Option<&VThread>) -> Result<(), Box<dyn Errno>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[allow(unused_variables)] // TODO: remove when implementing
|
||||
fn poll(self: &Arc<Self>, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents {
|
||||
fn poll(&self, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[allow(unused_variables)] // remove when implementing
|
||||
fn stat(self: &Arc<Self>, file: &VFile, td: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
|
||||
fn stat(&self, file: &VFile, td: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
|
||||
let mut stat = Stat::zeroed();
|
||||
|
||||
stat.block_size = 0x4000;
|
||||
|
@ -151,7 +151,7 @@ impl FileBackend for SharedMemory {
|
|||
}
|
||||
|
||||
fn truncate(
|
||||
self: &Arc<Self>,
|
||||
&self,
|
||||
_: &VFile,
|
||||
length: TruncateLength,
|
||||
_: Option<&VThread>,
|
||||
|
|
|
@ -394,7 +394,7 @@ impl Vm {
|
|||
|
||||
// TODO: Check if PS4 requires contiguous allocations.
|
||||
if !prev.is_null() && info.addr != prev {
|
||||
return Err(MemoryUpdateError::UnmappedAddr(prev));
|
||||
return Err(MemoryUpdateError::UnmappedAddr(prev as _));
|
||||
}
|
||||
|
||||
prev = info.end();
|
||||
|
@ -963,8 +963,8 @@ pub enum MemoryUpdateError {
|
|||
#[error("invalid addr")]
|
||||
InvalidAddr,
|
||||
|
||||
#[error("address {0:p} is not mapped")]
|
||||
UnmappedAddr(*const u8),
|
||||
#[error("address {0:#x} is not mapped")]
|
||||
UnmappedAddr(usize),
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
|
Loading…
Reference in a new issue