Adding openat syscall

This commit is contained in:
Darley Barreto
2025-07-13 12:43:20 +00:00
committed by Jeremy Soller
parent caf5fa955b
commit 66ea2b46ee
5 changed files with 176 additions and 13 deletions
+42
View File
@@ -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
View File
@@ -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,
+33
View File
@@ -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
View File
@@ -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() {
+1
View File
@@ -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),