Adding openat syscall
This commit is contained in:
committed by
Jeremy Soller
parent
caf5fa955b
commit
66ea2b46ee
@@ -88,6 +88,37 @@ int_like!(SchemeId, usize);
|
||||
// Unique identifier for a file descriptor.
|
||||
int_like!(FileHandle, AtomicFileHandle, usize, AtomicUsize);
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub enum StrOrBytes<'a> {
|
||||
Str(&'a str),
|
||||
Bytes(&'a [u8]),
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl<'a> StrOrBytes<'a> {
|
||||
pub fn as_str(&self) -> Result<&str, core::str::Utf8Error> {
|
||||
match self {
|
||||
StrOrBytes::Str(path) => Ok(path),
|
||||
StrOrBytes::Bytes(slice) => core::str::from_utf8(slice),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
match self {
|
||||
StrOrBytes::Str(path) => path.as_bytes(),
|
||||
StrOrBytes::Bytes(slice) => slice,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(path: &'a str) -> Self {
|
||||
StrOrBytes::Str(path)
|
||||
}
|
||||
|
||||
pub fn from_bytes(slice: &'a [u8]) -> Self {
|
||||
StrOrBytes::Bytes(slice)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SchemeIter<'a> {
|
||||
inner: Option<indexmap::map::Iter<'a, Box<str>, SchemeId>>,
|
||||
}
|
||||
@@ -365,6 +396,17 @@ pub trait KernelScheme: Send + Sync + 'static {
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
|
||||
fn kopenat(
|
||||
&self,
|
||||
file: usize,
|
||||
path: StrOrBytes,
|
||||
flags: usize,
|
||||
fcntl_flags: u32,
|
||||
_ctx: CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
Err(Error::new(EOPNOTSUPP))
|
||||
}
|
||||
|
||||
fn kfmap(
|
||||
&self,
|
||||
number: usize,
|
||||
|
||||
+28
-1
@@ -19,7 +19,7 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
use super::{CallerCtx, GlobalSchemes, KernelScheme, OpenResult};
|
||||
use super::{CallerCtx, GlobalSchemes, KernelScheme, OpenResult, StrOrBytes};
|
||||
|
||||
// TODO: Preallocate a number of scheme IDs, since there can only be *one* root namespace, and
|
||||
// therefore only *one* pipe scheme.
|
||||
@@ -146,6 +146,33 @@ impl KernelScheme for PipeScheme {
|
||||
Ok(OpenResult::SchemeLocal(read_id, InternalFlags::empty()))
|
||||
}
|
||||
|
||||
fn kopenat(
|
||||
&self,
|
||||
id: usize,
|
||||
user_buf: StrOrBytes,
|
||||
_flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
_ctx: CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
let (_, key) = from_raw_id(id);
|
||||
|
||||
let buf = user_buf.as_str().or(Err(Error::new(EINVAL)))?;
|
||||
if buf == "write" {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
|
||||
let pipe = Arc::clone(PIPES.read().get(&key).ok_or(Error::new(EBADF))?);
|
||||
|
||||
if pipe.has_run_dup.swap(true, Ordering::SeqCst) {
|
||||
return Err(Error::new(EBADF));
|
||||
}
|
||||
|
||||
Ok(OpenResult::SchemeLocal(
|
||||
key | WRITE_NOT_READ_BIT,
|
||||
InternalFlags::empty(),
|
||||
))
|
||||
}
|
||||
|
||||
fn kread(
|
||||
&self,
|
||||
id: usize,
|
||||
|
||||
@@ -1388,6 +1388,39 @@ impl KernelScheme for UserScheme {
|
||||
Response::Fd(desc) => Ok(OpenResult::External(desc)),
|
||||
}
|
||||
}
|
||||
|
||||
fn kopenat(
|
||||
&self,
|
||||
file: usize,
|
||||
path: super::StrOrBytes,
|
||||
flags: usize,
|
||||
fcntl_flags: u32,
|
||||
ctx: CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
|
||||
let mut address = inner.copy_and_capture_tail(path.as_bytes())?;
|
||||
let result = inner.call_extended(
|
||||
ctx,
|
||||
None,
|
||||
Opcode::OpenAt,
|
||||
[file, address.base(), address.len(), flags, fcntl_flags as _],
|
||||
address.span(),
|
||||
);
|
||||
|
||||
address.release()?;
|
||||
|
||||
match result? {
|
||||
Response::Regular(code, fl) => Ok({
|
||||
let fd = Error::demux(code)?;
|
||||
OpenResult::SchemeLocal(
|
||||
fd,
|
||||
InternalFlags::from_extra0(fl).ok_or(Error::new(EINVAL))?,
|
||||
)
|
||||
}),
|
||||
Response::Fd(desc) => Ok(OpenResult::External(desc)),
|
||||
}
|
||||
}
|
||||
|
||||
fn rmdir(&self, path: &str, _ctx: CallerCtx) -> Result<()> {
|
||||
let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
|
||||
let mut address = inner.copy_and_capture_tail(path.as_bytes())?;
|
||||
|
||||
+72
-12
@@ -1,7 +1,7 @@
|
||||
//! Filesystem syscalls
|
||||
use core::num::NonZeroUsize;
|
||||
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use alloc::{string::String, sync::Arc, vec::Vec};
|
||||
use redox_path::RedoxPath;
|
||||
use spin::RwLock;
|
||||
|
||||
@@ -12,7 +12,7 @@ use crate::{
|
||||
memory::{AddrSpace, GenericFlusher, Grant, PageSpan, TlbShootdownActions},
|
||||
},
|
||||
paging::{Page, VirtualAddress, PAGE_SIZE},
|
||||
scheme::{self, CallerCtx, FileHandle, KernelScheme, OpenResult},
|
||||
scheme::{self, CallerCtx, FileHandle, KernelScheme, OpenResult, StrOrBytes},
|
||||
syscall::{data::Stat, error::*, flag::*},
|
||||
};
|
||||
|
||||
@@ -41,19 +41,28 @@ pub fn file_op_generic_ext<T>(
|
||||
|
||||
op(&*scheme, file.description, desc)
|
||||
}
|
||||
pub fn copy_path_to_buf(raw_path: UserSliceRo, max_len: usize) -> Result<alloc::string::String> {
|
||||
pub fn copy_path_to_buf(raw_path: UserSliceRo, max_len: usize) -> Result<String> {
|
||||
let mut path_buf = vec![0_u8; max_len];
|
||||
if raw_path.len() > path_buf.len() {
|
||||
return Err(Error::new(ENAMETOOLONG));
|
||||
}
|
||||
let path_len = raw_path.copy_common_bytes_to_slice(&mut path_buf)?;
|
||||
path_buf.truncate(path_len);
|
||||
alloc::string::String::from_utf8(path_buf).map_err(|_| Error::new(EINVAL))
|
||||
String::from_utf8(path_buf).map_err(|_| Error::new(EINVAL))
|
||||
//core::str::from_utf8(&path_buf[..path_len]).map_err(|_| Error::new(EINVAL))
|
||||
}
|
||||
// TODO: Define elsewhere
|
||||
const PATH_MAX: usize = PAGE_SIZE;
|
||||
|
||||
#[inline]
|
||||
fn is_legacy(path_buf: &String) -> bool {
|
||||
// FIXME remove entries from this list as the respective programs get updated
|
||||
path_buf.starts_with(':')
|
||||
|| path_buf == "null:" // FIXME Remove exception at next rustc update (rust#138457)
|
||||
|| path_buf == "sys:exe" // FIXME Remove exception at next rustc update (rust#138457)
|
||||
|| path_buf.starts_with("orbital:")
|
||||
}
|
||||
|
||||
/// Open syscall
|
||||
pub fn open(raw_path: UserSliceRo, flags: usize) -> Result<FileHandle> {
|
||||
let (pid, uid, gid, scheme_ns) = match context::current().read() {
|
||||
@@ -70,12 +79,7 @@ pub fn open(raw_path: UserSliceRo, flags: usize) -> Result<FileHandle> {
|
||||
|
||||
// Display a deprecation warning for any usage of the legacy scheme syntax (scheme:/path)
|
||||
// FIXME remove entries from this list as the respective programs get updated
|
||||
if path_buf.contains(':')
|
||||
&& !path_buf.starts_with(':')
|
||||
&& path_buf != "null:" // FIXME Remove exception at next rustc update (rust#138457)
|
||||
&& path_buf != "sys:exe" // FIXME Remove exception at next rustc update (rust#138457)
|
||||
&& !path_buf.starts_with("orbital:")
|
||||
{
|
||||
if path_buf.contains(':') && !is_legacy(&path_buf) {
|
||||
let name = context::current().read().name.clone();
|
||||
if name.contains("cosmic") && (path_buf == "event:" || path_buf.starts_with("time:")) {
|
||||
// FIXME cosmic apps likely need crate updates
|
||||
@@ -83,7 +87,6 @@ pub fn open(raw_path: UserSliceRo, flags: usize) -> Result<FileHandle> {
|
||||
println!("deprecated: legacy path {:?} used by {}", path_buf, name);
|
||||
}
|
||||
}
|
||||
|
||||
let path = RedoxPath::from_absolute(&path_buf).ok_or(Error::new(EINVAL))?;
|
||||
let (scheme_name, reference) = path.as_parts().ok_or(Error::new(EINVAL))?;
|
||||
|
||||
@@ -110,7 +113,6 @@ pub fn open(raw_path: UserSliceRo, flags: usize) -> Result<FileHandle> {
|
||||
}
|
||||
};
|
||||
//drop(path_buf);
|
||||
|
||||
context::current()
|
||||
.read()
|
||||
.add_file(FileDescriptor {
|
||||
@@ -120,6 +122,64 @@ pub fn open(raw_path: UserSliceRo, flags: usize) -> Result<FileHandle> {
|
||||
.ok_or(Error::new(EMFILE))
|
||||
}
|
||||
|
||||
pub fn openat(
|
||||
fh: FileHandle,
|
||||
raw_path: UserSliceRo,
|
||||
flags: usize,
|
||||
fcntl_flags: u32,
|
||||
) -> Result<FileHandle> {
|
||||
let path_buf = copy_path_to_buf(raw_path, PATH_MAX)?;
|
||||
|
||||
if is_legacy(&path_buf) {
|
||||
// TODO: implement
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
|
||||
let pipe = context::current()
|
||||
.read()
|
||||
.get_file(fh)
|
||||
.ok_or(Error::new(EBADF))?;
|
||||
|
||||
let description = pipe.description.read();
|
||||
|
||||
let caller_ctx = context::current().read().caller_ctx();
|
||||
|
||||
let new_description = {
|
||||
let scheme = scheme::schemes()
|
||||
.get(description.scheme)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
.clone();
|
||||
|
||||
let res = scheme.kopenat(
|
||||
description.number,
|
||||
StrOrBytes::from_str(&path_buf),
|
||||
flags,
|
||||
fcntl_flags,
|
||||
caller_ctx,
|
||||
);
|
||||
|
||||
match res? {
|
||||
OpenResult::SchemeLocal(number, internal_flags) => {
|
||||
Arc::new(RwLock::new(FileDescription {
|
||||
offset: 0,
|
||||
internal_flags,
|
||||
scheme: description.scheme,
|
||||
number,
|
||||
flags: description.flags,
|
||||
}))
|
||||
}
|
||||
OpenResult::External(desc) => desc,
|
||||
}
|
||||
};
|
||||
|
||||
context::current()
|
||||
.read()
|
||||
.add_file(FileDescriptor {
|
||||
description: new_description,
|
||||
cloexec: false,
|
||||
})
|
||||
.ok_or(Error::new(EMFILE))
|
||||
}
|
||||
/// rmdir syscall
|
||||
pub fn rmdir(raw_path: UserSliceRo) -> Result<()> {
|
||||
let (scheme_ns, caller_ctx) = match context::current().read() {
|
||||
|
||||
@@ -178,6 +178,7 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> us
|
||||
),
|
||||
|
||||
SYS_OPEN => open(UserSlice::ro(b, c)?, d).map(FileHandle::into),
|
||||
SYS_OPENAT => openat(fd, UserSlice::ro(c, d)?, e, f as _).map(FileHandle::into),
|
||||
SYS_RMDIR => rmdir(UserSlice::ro(b, c)?).map(|()| 0),
|
||||
SYS_UNLINK => unlink(UserSlice::ro(b, c)?).map(|()| 0),
|
||||
SYS_YIELD => sched_yield().map(|()| 0),
|
||||
|
||||
Reference in New Issue
Block a user