Adapt with new redox-path
This commit is contained in:
Generated
+2
-2
@@ -447,9 +447,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "redox-path"
|
||||
version = "0.3.1"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "436d45c2b6a5b159d43da708e62b25be3a4a3d5550d654b72216ade4c4bfd717"
|
||||
checksum = "54ec1b67c01c63545205ea6d218b336751399f0d8974c1a635c28604bedb81bc"
|
||||
|
||||
[[package]]
|
||||
name = "redox-rt"
|
||||
|
||||
+1
-1
@@ -68,7 +68,7 @@ workspace = true
|
||||
bitflags = "2"
|
||||
ioslice = { version = "0.6", default-features = false }
|
||||
plain = "0.2"
|
||||
redox-path = "0.3"
|
||||
redox-path = "0.4.0"
|
||||
redox_protocols = { package = "libredox", version = "0.1.18", default-features = false, features = ["protocol"] }
|
||||
redox_syscall = "0.9.0"
|
||||
|
||||
|
||||
+4
-1
@@ -268,7 +268,7 @@ impl<'a, T: Kind> NulStr<'a, T> {
|
||||
}
|
||||
impl<'a> CStr<'a> {
|
||||
pub fn to_owned_cstring(self) -> CString {
|
||||
CString::from(unsafe { core::ffi::CStr::from_ptr(self.ptr.as_ptr()) })
|
||||
CString::from(self.to_cstr())
|
||||
}
|
||||
pub fn borrow(string: &'a CString) -> Self {
|
||||
unsafe { Self::from_ptr(string.as_ptr()) }
|
||||
@@ -284,6 +284,9 @@ impl<'a> CStr<'a> {
|
||||
pub fn to_str(self) -> Result<&'a str, Utf8Error> {
|
||||
core::str::from_utf8(self.to_bytes())
|
||||
}
|
||||
pub fn to_cstr(self) -> &'a core::ffi::CStr {
|
||||
unsafe { core::ffi::CStr::from_ptr(self.ptr.as_ptr()) }
|
||||
}
|
||||
pub fn to_string_lossy(self) -> Cow<'a, str> {
|
||||
String::from_utf8_lossy(self.to_bytes())
|
||||
}
|
||||
|
||||
+2
-1
@@ -386,7 +386,8 @@ pub unsafe fn init_inner(auxvs: Box<[[usize; 2]]>) {
|
||||
.expect("failed to move cwd fd to upper table")
|
||||
}),
|
||||
) {
|
||||
self::sys::path::set_cwd_manual(cwd_path, cwd_fd);
|
||||
self::sys::path::set_cwd_manual(cwd_path, cwd_fd)
|
||||
.expect("cwd_path is not valid redox path")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::header::{
|
||||
|
||||
use super::libredox::RawResult;
|
||||
|
||||
use redox_path::RedoxStr;
|
||||
use syscall::{EINVAL, Error, Result};
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
@@ -18,7 +19,7 @@ pub unsafe extern "C" fn redox_event_queue_create_v1(flags: u32) -> RawResult {
|
||||
}
|
||||
Ok(super::libredox::openat(
|
||||
AT_FDCWD,
|
||||
"/scheme/event",
|
||||
RedoxStr::new("/scheme/event").unwrap(),
|
||||
O_CLOEXEC | O_CREAT | O_RDWR,
|
||||
0o700,
|
||||
)? as usize)
|
||||
|
||||
@@ -2,6 +2,7 @@ use core::{mem, slice, str};
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use ioslice::IoSlice;
|
||||
use redox_path::RedoxStr;
|
||||
use redox_protocols::protocol::{ProcKillTarget, SocketCall, WaitFlags};
|
||||
use redox_rt::sys::{WaitpidTarget, posix_read, posix_write, std_fs_call_ro, std_fs_call_wo};
|
||||
use syscall::{
|
||||
@@ -23,20 +24,20 @@ use super::Sys;
|
||||
|
||||
pub type RawResult = usize;
|
||||
|
||||
pub fn openat(dirfd: c_int, path: &str, oflag: c_int, mode: mode_t) -> Result<usize> {
|
||||
pub fn openat(dirfd: c_int, path: RedoxStr<'_>, oflag: c_int, mode: mode_t) -> Result<usize> {
|
||||
let usize_fd = super::path::openat(
|
||||
dirfd,
|
||||
path,
|
||||
((oflag as usize) & 0xFFFF_0000) | ((mode as usize) & 0xFFFF),
|
||||
)?;
|
||||
|
||||
c_int::try_from(usize_fd)
|
||||
.map_err(|_| {
|
||||
let _ = redox_rt::sys::close(usize_fd);
|
||||
Error::new(EMFILE)
|
||||
})
|
||||
.map(|f| f as usize)
|
||||
if let Err(_) = c_int::try_from(usize_fd) {
|
||||
let _ = redox_rt::sys::close(usize_fd);
|
||||
return Err(Error::new(EMFILE));
|
||||
}
|
||||
Ok(usize_fd)
|
||||
}
|
||||
|
||||
pub fn fchmod(fd: usize, new_mode: u16) -> Result<()> {
|
||||
std_fs_call_wo(
|
||||
fd,
|
||||
@@ -226,12 +227,12 @@ pub unsafe extern "C" fn redox_open_v1(
|
||||
flags: u32,
|
||||
mode: u16,
|
||||
) -> RawResult {
|
||||
Error::mux(openat(
|
||||
AT_FDCWD,
|
||||
unsafe { str::from_utf8_unchecked(slice::from_raw_parts(path_base, path_len)) },
|
||||
flags as c_int,
|
||||
mode as mode_t,
|
||||
))
|
||||
let path = unsafe { str::from_utf8_unchecked(slice::from_raw_parts(path_base, path_len)) };
|
||||
let path = match RedoxStr::new(path) {
|
||||
Some(path) => path,
|
||||
None => return Error::mux(Err(Error::new(EINVAL))),
|
||||
};
|
||||
Error::mux(openat(AT_FDCWD, path, flags as c_int, mode as mode_t))
|
||||
}
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn redox_openat_v1(
|
||||
@@ -241,9 +242,11 @@ pub unsafe extern "C" fn redox_openat_v1(
|
||||
flags: u32,
|
||||
fcntl_flags: u32,
|
||||
) -> RawResult {
|
||||
// Goes straight to redox_rt, no need parsing RedoxStr
|
||||
let path = unsafe { str::from_utf8_unchecked(slice::from_raw_parts(path_base, path_len)) };
|
||||
Error::mux(redox_rt::sys::openat(
|
||||
fd,
|
||||
unsafe { str::from_utf8_unchecked(slice::from_raw_parts(path_base, path_len)) },
|
||||
path,
|
||||
flags as usize,
|
||||
fcntl_flags as usize,
|
||||
))
|
||||
|
||||
+28
-27
@@ -1,3 +1,4 @@
|
||||
use alloc::borrow::Cow;
|
||||
use core::{
|
||||
convert::TryFrom,
|
||||
mem::{self, size_of},
|
||||
@@ -5,20 +6,21 @@ use core::{
|
||||
ptr, slice, str,
|
||||
};
|
||||
use object::bytes_of_slice_mut;
|
||||
use redox_path::RedoxStr;
|
||||
use redox_protocols::protocol::{WaitFlags, wifstopped};
|
||||
use redox_rt::{
|
||||
RtTcb,
|
||||
sys::{Resugid, WaitpidTarget},
|
||||
};
|
||||
use syscall::{
|
||||
self, EILSEQ, ESRCH, Error, MODE_PERM, StdFsCallKind, StdFsCallMeta,
|
||||
self, ESRCH, Error, MODE_PERM, StdFsCallKind, StdFsCallMeta,
|
||||
data::{Map, TimeSpec as redox_timespec},
|
||||
dirent::DirentHeader,
|
||||
};
|
||||
|
||||
use self::{
|
||||
exec::Executable,
|
||||
path::{FileLock, canonicalize, openat2, openat2_path},
|
||||
path::{FileLock, openat2, openat2_path},
|
||||
};
|
||||
use super::{Pal, Read, types::*};
|
||||
use crate::{
|
||||
@@ -185,7 +187,7 @@ impl Pal for Sys {
|
||||
}
|
||||
|
||||
fn chdir(path: CStr) -> Result<()> {
|
||||
let path = path.to_str().map_err(|_| Errno(EINVAL))?;
|
||||
let path = RedoxStr::new_c(path.to_cstr()).ok_or_else(|| Errno(EINVAL))?;
|
||||
path::chdir(path)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -286,14 +288,12 @@ impl Pal for Sys {
|
||||
if MASK & flags != 0 {
|
||||
return Err(Errno(EINVAL));
|
||||
}
|
||||
let mut path = path
|
||||
.and_then(|cs| str::from_utf8(cs.to_bytes()).ok())
|
||||
.ok_or(Errno(ENOENT))?;
|
||||
let mut path = path.ok_or(Errno(ENOENT))?;
|
||||
|
||||
if path.is_empty() {
|
||||
if flags & AT_EMPTY_PATH == AT_EMPTY_PATH {
|
||||
if dirfd == AT_FDCWD {
|
||||
path = ".";
|
||||
path = c".".into();
|
||||
} else {
|
||||
return Ok(libredox::fchmod(dirfd as usize, mode as u16)?);
|
||||
}
|
||||
@@ -313,11 +313,11 @@ impl Pal for Sys {
|
||||
if MASK & flags != 0 {
|
||||
return Err(Errno(EINVAL));
|
||||
}
|
||||
let mut path = path.to_str().map_err(|_| Errno(ENOENT))?;
|
||||
let mut path = path;
|
||||
if path.is_empty() {
|
||||
if flags & AT_EMPTY_PATH == AT_EMPTY_PATH {
|
||||
if fildes == AT_FDCWD {
|
||||
path = ".";
|
||||
path = c".".into();
|
||||
} else {
|
||||
return Ok(libredox::fchown(fildes as usize, owner as _, group as _)?);
|
||||
}
|
||||
@@ -465,13 +465,12 @@ impl Pal for Sys {
|
||||
|
||||
fn fstatat(dirfd: c_int, path: Option<CStr>, mut buf: Out<stat>, flags: c_int) -> Result<()> {
|
||||
// `path` should be non-null.
|
||||
let path = path.ok_or(Errno(EFAULT))?;
|
||||
let mut path = str::from_utf8(path.to_bytes()).ok().ok_or(Errno(EILSEQ))?;
|
||||
let mut path = path.ok_or(Errno(EFAULT))?;
|
||||
|
||||
if path.is_empty() {
|
||||
if flags & AT_EMPTY_PATH == AT_EMPTY_PATH {
|
||||
if dirfd == AT_FDCWD {
|
||||
path = ".";
|
||||
path = c".".into();
|
||||
} else {
|
||||
return Ok(unsafe { libredox::fstat(dirfd as usize, buf.as_mut_ptr()) }?);
|
||||
}
|
||||
@@ -526,11 +525,11 @@ impl Pal for Sys {
|
||||
times: *const timespec,
|
||||
flag: c_int,
|
||||
) -> Result<()> {
|
||||
let mut path = path.to_str().map_err(|_| Errno(ENOENT))?;
|
||||
let mut path = path;
|
||||
if path.is_empty() {
|
||||
if flag & AT_EMPTY_PATH == AT_EMPTY_PATH {
|
||||
if dirfd == AT_FDCWD {
|
||||
path = ".";
|
||||
path = c".".into();
|
||||
} else {
|
||||
return Ok(unsafe { libredox::futimens(dirfd as usize, times) }?);
|
||||
}
|
||||
@@ -774,7 +773,7 @@ impl Pal for Sys {
|
||||
if (flags & !(AT_SYMLINK_FOLLOW)) != 0 {
|
||||
return Err(Errno(EINVAL));
|
||||
}
|
||||
let newpath = newpath.to_str().map_err(|_| Errno(EINVAL))?;
|
||||
let newpath = RedoxStr::new_c(newpath.to_cstr()).ok_or_else(|| Errno(EINVAL))?;
|
||||
|
||||
// By default, we don't follow the symlink if there is one.
|
||||
// We only follow it if AT_SYMLINK_FOLLOW is passed in flags.
|
||||
@@ -786,7 +785,7 @@ impl Pal for Sys {
|
||||
}
|
||||
|
||||
let file = File::openat(fd1, oldpath, oflags)?;
|
||||
let newpath = openat2_path(fd2, newpath, 0)?;
|
||||
let newpath: Cow<'_, str> = openat2_path(fd2, newpath, 0)?.into();
|
||||
syscall::flink(*file as usize, newpath)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -954,7 +953,7 @@ impl Pal for Sys {
|
||||
}
|
||||
|
||||
fn openat(dirfd: c_int, path: CStr, oflag: c_int, mode: mode_t) -> Result<c_int> {
|
||||
let path = path.to_str().map_err(|_| Errno(EINVAL))?;
|
||||
let path = RedoxStr::new_c(path.to_cstr()).ok_or(Errno(EINVAL))?;
|
||||
|
||||
// POSIX states that umask should affect the following:
|
||||
//
|
||||
@@ -1099,7 +1098,6 @@ impl Pal for Sys {
|
||||
}
|
||||
|
||||
fn readlinkat(dirfd: c_int, path: CStr, out: &mut [u8]) -> Result<usize> {
|
||||
let path = str::from_utf8(path.to_bytes()).map_err(|_| Errno(ENOENT))?;
|
||||
let file = openat2(
|
||||
dirfd,
|
||||
path,
|
||||
@@ -1121,21 +1119,24 @@ impl Pal for Sys {
|
||||
return Err(Errno(EOPNOTSUPP));
|
||||
}
|
||||
|
||||
let new_path = new_path.to_str().map_err(|_| Errno(EINVAL))?;
|
||||
let new_path = RedoxStr::new_c(new_path.to_cstr()).ok_or(Errno(EINVAL))?;
|
||||
// Fail if the target exists with RENAME_NOREPLACE.
|
||||
if flags & RENAME_NOREPLACE != 0
|
||||
&& let Ok(fd) =
|
||||
libredox::openat(new_dir, &new_path, fcntl::O_PATH | fcntl::O_CLOEXEC, 0)
|
||||
.map(FdGuard::new)
|
||||
&& let Ok(fd) = libredox::openat(
|
||||
new_dir,
|
||||
new_path.clone(),
|
||||
fcntl::O_PATH | fcntl::O_CLOEXEC,
|
||||
0,
|
||||
)
|
||||
.map(FdGuard::new)
|
||||
{
|
||||
return Err(Errno(EEXIST));
|
||||
}
|
||||
|
||||
let old_path = old_path.to_str().map_err(|_| Errno(EINVAL))?;
|
||||
// oflags are the same as Sys::rename above.
|
||||
let source = openat2(old_dir, old_path, 0, fcntl::O_NOFOLLOW | fcntl::O_PATH)?;
|
||||
|
||||
let target = openat2_path(new_dir, new_path, 0)?;
|
||||
let target: Cow<'_, str> = openat2_path(new_dir, new_path, 0)?.into();
|
||||
// I'm avoiding Sys::rename to avoid reallocating a CString from a String.
|
||||
syscall::frename(*source as usize, target)
|
||||
.map(|_| ())
|
||||
@@ -1795,10 +1796,10 @@ impl Pal for Sys {
|
||||
if (flags & !AT_REMOVEDIR) != 0 {
|
||||
return Err(Errno(EINVAL));
|
||||
}
|
||||
let path = path.to_str().map_err(|_| Errno(EINVAL))?;
|
||||
let path = RedoxStr::new_c(path.to_cstr()).ok_or(Errno(EINVAL))?;
|
||||
let path = openat2_path(fd, path, 0)?;
|
||||
let canon = canonicalize(&path)?;
|
||||
redox_rt::sys::unlink(&canon, flags.try_into().map_err(|_| Errno(EINVAL))?)?;
|
||||
let path: Cow<'_, str> = path.into();
|
||||
redox_rt::sys::unlink(path, flags.try_into().map_err(|_| Errno(EINVAL))?)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
+126
-274
@@ -1,20 +1,17 @@
|
||||
use alloc::{
|
||||
collections::btree_set::BTreeSet,
|
||||
ffi::CString,
|
||||
string::{String, ToString},
|
||||
vec::Vec,
|
||||
};
|
||||
use alloc::{borrow::Cow, string::ToString};
|
||||
use arrayvec::ArrayString;
|
||||
use core::{
|
||||
ffi::c_int,
|
||||
str::{self, FromStr},
|
||||
};
|
||||
use redox_path::{RedoxReference, RedoxStr};
|
||||
use redox_protocols::protocol::O_CLOEXEC;
|
||||
use redox_rt::{proc::FdGuardUpper, signal::tmp_disable_signals};
|
||||
use syscall::{data::Stat, error::*, flag::*};
|
||||
|
||||
use super::{FdGuard, Pal, Sys, libcscheme};
|
||||
use crate::{
|
||||
c_str::CStr,
|
||||
error::Errno,
|
||||
fs::File,
|
||||
header::{fcntl, limits, sys_file},
|
||||
@@ -22,111 +19,36 @@ use crate::{
|
||||
sync::rwlock::{ReadGuard, RwLock},
|
||||
};
|
||||
|
||||
pub use redox_path::{RedoxPath, canonicalize_using_cwd};
|
||||
|
||||
pub fn normalize_path<'a>(path: &'a str) -> Option<(bool, String)> {
|
||||
let absolute = match RedoxPath::from_absolute(path) {
|
||||
Some(absolute) => absolute,
|
||||
None => return Some((true, partially_canonical(path)?)),
|
||||
};
|
||||
let canonical = absolute.canonical()?;
|
||||
Some((false, canonical.to_string()))
|
||||
}
|
||||
|
||||
pub fn normalize_scheme_rooted_path<'a>(path: &'a str) -> Option<(bool, String)> {
|
||||
let absolute = match RedoxPath::from_absolute(path) {
|
||||
Some(absolute) => absolute,
|
||||
None => return Some((true, partially_canonical(path)?)),
|
||||
};
|
||||
let canonical = absolute.canonical()?;
|
||||
Some((false, scheme_rooted_path(&canonical.to_string()).ok()?))
|
||||
}
|
||||
|
||||
fn partially_canonical(path: &str) -> Option<String> {
|
||||
let mut stack = Vec::new();
|
||||
let mut paths_to_check = BTreeSet::new();
|
||||
let mut up_counts = 0;
|
||||
|
||||
for part in path.split('/') {
|
||||
if part.is_empty() || part == "." {
|
||||
continue;
|
||||
} else if part == ".." {
|
||||
if let Some(part) = stack.pop() {
|
||||
paths_to_check.insert(
|
||||
core::iter::repeat("..")
|
||||
.take(up_counts)
|
||||
.chain(stack.clone())
|
||||
.chain(core::iter::once(part))
|
||||
.collect::<Vec<_>>()
|
||||
.join("/"),
|
||||
);
|
||||
} else {
|
||||
up_counts += 1;
|
||||
}
|
||||
} else {
|
||||
stack.push(part);
|
||||
}
|
||||
}
|
||||
|
||||
for path in paths_to_check {
|
||||
let _ = current_dir()
|
||||
.ok()?
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.fd
|
||||
.openat(&path, O_STAT, 0)
|
||||
.ok()?;
|
||||
}
|
||||
|
||||
Some(
|
||||
core::iter::repeat("..")
|
||||
.take(up_counts)
|
||||
.chain(stack)
|
||||
.collect::<Vec<_>>()
|
||||
.join("/"),
|
||||
)
|
||||
}
|
||||
pub use redox_path::RedoxPath;
|
||||
|
||||
// POSIX states chdir is both thread-safe and signal-safe. Thus we need to synchronize access to CWD, but at the
|
||||
// same time forbid signal handlers from running in the meantime, to avoid reentrant deadlock.
|
||||
pub fn chdir(path: &str) -> Result<()> {
|
||||
pub fn chdir(path: RedoxStr<'_>) -> Result<()> {
|
||||
let _siglock = tmp_disable_signals();
|
||||
let mut cwd_guard = CWD.write();
|
||||
let (is_relative, path) = normalize_path(path).ok_or(Error::new(ENOENT))?;
|
||||
if is_relative {
|
||||
let fd = cwd_guard
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.fd
|
||||
.openat_into_upper(&path, O_STAT, 0)?;
|
||||
let mut stat = Stat::default();
|
||||
if fd.fstat(&mut stat).is_err() || (stat.st_mode & MODE_TYPE) != MODE_DIR {
|
||||
return Err(Error::new(ENOTDIR));
|
||||
let (redox, fd) = match path {
|
||||
RedoxStr::Absolute(path) => {
|
||||
let path = path.to_standard_canon();
|
||||
let fd = FdGuard::open_into_upper(&path.as_reference(), O_STAT);
|
||||
(path.into_owned(), fd?)
|
||||
}
|
||||
|
||||
let canon = canonicalize_using_cwd(cwd_guard.as_ref().map(|c| c.path.as_ref()), &path)
|
||||
.ok_or(Error::new(ENOENT))?;
|
||||
*cwd_guard = Some(Cwd {
|
||||
path: to_cwd_path(&canon)?,
|
||||
fd,
|
||||
});
|
||||
} else {
|
||||
let canon_with_scheme = scheme_rooted_path(&path)?;
|
||||
|
||||
let fd = FdGuard::open(&canon_with_scheme, O_STAT)?
|
||||
.to_upper()
|
||||
.unwrap();
|
||||
let mut stat = Stat::default();
|
||||
if fd.fstat(&mut stat).is_err() || (stat.st_mode & MODE_TYPE) != MODE_DIR {
|
||||
return Err(Error::new(ENOTDIR));
|
||||
RedoxStr::Relative(redox_reference) => {
|
||||
let Some(cwd) = cwd_guard.as_ref() else {
|
||||
return Err(Error::new(ENOENT));
|
||||
};
|
||||
let fd = cwd
|
||||
.fd
|
||||
.openat_into_upper(redox_reference.as_ref(), O_STAT, 0);
|
||||
let path = cwd.redox.canonicalize_as_cwd(redox_reference.into());
|
||||
(path.into_owned(), fd?)
|
||||
}
|
||||
|
||||
*cwd_guard = Some(Cwd {
|
||||
path: to_cwd_path(&path)?,
|
||||
fd,
|
||||
});
|
||||
};
|
||||
let mut stat = Stat::default();
|
||||
if fd.fstat(&mut stat).is_err() || (stat.st_mode & MODE_TYPE) != MODE_DIR {
|
||||
return Err(Error::new(ENOTDIR));
|
||||
}
|
||||
|
||||
let path = to_cwd_path(redox.as_reference().as_ref())?;
|
||||
*cwd_guard = Some(Cwd { path, redox, fd });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -144,7 +66,7 @@ pub fn fchdir(fd: c_int) -> Result<()> {
|
||||
)?)
|
||||
.to_upper()
|
||||
.unwrap();
|
||||
set_cwd_manual(buf, fd);
|
||||
set_cwd_manual(buf, fd)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -166,7 +88,7 @@ pub fn getcwd(mut buf: Out<[u8]>) -> Result<usize> {
|
||||
}
|
||||
|
||||
// Get Cwd object
|
||||
pub fn current_dir() -> Result<ReadGuard<'static, Option<Cwd>>> {
|
||||
pub fn current_dir() -> Result<ReadGuard<'static, Option<Cwd<'static>>>> {
|
||||
let _siglock = tmp_disable_signals();
|
||||
let guard = CWD.read();
|
||||
|
||||
@@ -177,56 +99,27 @@ pub fn current_dir() -> Result<ReadGuard<'static, Option<Cwd>>> {
|
||||
Ok(guard)
|
||||
}
|
||||
|
||||
fn scheme_rooted_path(path: &str) -> Result<String> {
|
||||
let standard_scheme = path == "/scheme" || path.starts_with("/scheme/");
|
||||
let legacy_scheme = path
|
||||
.split("/")
|
||||
.next()
|
||||
.map(|c| c.contains(":"))
|
||||
.unwrap_or(false);
|
||||
|
||||
Ok(if standard_scheme || legacy_scheme {
|
||||
path.to_string()
|
||||
} else {
|
||||
let mut result = format!("/scheme/file{}", path);
|
||||
|
||||
// Trim trailing / to keep path canonical.
|
||||
if result.as_bytes().last() == Some(&b'/') {
|
||||
result.pop();
|
||||
}
|
||||
|
||||
result
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: How much of this logic should be in redox-path?
|
||||
fn canonicalize_with_cwd_internal(cwd: Option<&str>, path: &str) -> Result<String> {
|
||||
let path = canonicalize_using_cwd(cwd, path).ok_or(Error::new(ENOENT))?;
|
||||
scheme_rooted_path(&path)
|
||||
}
|
||||
|
||||
pub fn canonicalize(path: &str) -> Result<String> {
|
||||
let _siglock = tmp_disable_signals();
|
||||
let cwd_guard = CWD.read();
|
||||
canonicalize_with_cwd_internal(cwd_guard.as_ref().map(|c| c.path.as_ref()), path)
|
||||
}
|
||||
|
||||
pub type CwdPath = ArrayString<{ limits::PATH_MAX }>;
|
||||
|
||||
pub struct Cwd {
|
||||
pub struct Cwd<'a> {
|
||||
pub path: CwdPath,
|
||||
pub redox: RedoxPath<'a>,
|
||||
pub fd: FdGuardUpper,
|
||||
}
|
||||
|
||||
static CWD: RwLock<Option<Cwd>> = RwLock::new(None);
|
||||
static CWD: RwLock<Option<Cwd<'_>>> = RwLock::new(None);
|
||||
|
||||
pub fn to_cwd_path(path: &str) -> Result<CwdPath> {
|
||||
ArrayString::from_str(&path).or(Err(Error::new(ENAMETOOLONG)))
|
||||
}
|
||||
|
||||
pub fn set_cwd_manual(path: CwdPath, fd: FdGuardUpper) {
|
||||
pub fn set_cwd_manual(path: CwdPath, fd: FdGuardUpper) -> Result<()> {
|
||||
let Some(redox) = RedoxPath::from_absolute(path.to_string()) else {
|
||||
return Err(Error::new(EBADF));
|
||||
};
|
||||
let _siglock = tmp_disable_signals();
|
||||
*CWD.write() = Some(Cwd { path, fd });
|
||||
*CWD.write() = Some(Cwd { path, redox, fd });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn clone_cwd() -> Option<CwdPath> {
|
||||
@@ -242,51 +135,47 @@ fn open_absolute(path: &str, flags: usize) -> Result<usize> {
|
||||
}
|
||||
}
|
||||
|
||||
fn link_target(fd: FdGuard) -> Result<String> {
|
||||
let mut resolve_buf = [0_u8; limits::PATH_MAX];
|
||||
let count = fd.read(&mut resolve_buf)?;
|
||||
if count == resolve_buf.len() {
|
||||
// TODO: make resolve_buf PATH_MAX + 1 bytes?
|
||||
return Err(Error::new(ENAMETOOLONG));
|
||||
}
|
||||
// If the symbolic link path is non-UTF8, it cannot be opened, and is thus
|
||||
// considered a "dangling symbolic link".
|
||||
core::str::from_utf8(&resolve_buf[..count])
|
||||
.map_err(|_| Error::new(ENOENT))
|
||||
.map(|s| s.to_string())
|
||||
}
|
||||
|
||||
fn read_link_content(path: &str, is_relative: bool) -> Result<String> {
|
||||
// Read symlink content
|
||||
fn read_link_content<'a, 'b>(
|
||||
dirfd: Option<&FdGuard>,
|
||||
path: &'a str,
|
||||
is_relative: bool,
|
||||
) -> Result<RedoxStr<'b>> {
|
||||
let resolve_flags = O_CLOEXEC | O_SYMLINK | O_RDONLY;
|
||||
|
||||
let fd = if is_relative {
|
||||
current_dir()?
|
||||
let fd = match (is_relative, dirfd) {
|
||||
(false, _) => FdGuard::open(path, resolve_flags)?,
|
||||
(true, None) => current_dir()?
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.fd
|
||||
.openat(path, resolve_flags, 0)?
|
||||
} else {
|
||||
FdGuard::open(path, resolve_flags)?
|
||||
.openat(path, resolve_flags, 0)?,
|
||||
(true, Some(dirfd)) => dirfd.openat(path, resolve_flags, 0)?,
|
||||
};
|
||||
|
||||
link_target(fd)
|
||||
let mut resolve_buf = [0_u8; limits::PATH_MAX + 1];
|
||||
let count = fd.read(&mut resolve_buf)?;
|
||||
if count == resolve_buf.len() {
|
||||
return Err(Error::new(ENAMETOOLONG));
|
||||
}
|
||||
|
||||
// If the symbolic link path is non-UTF8, it cannot be opened, and is thus
|
||||
// considered a "dangling symbolic link".
|
||||
let path = core::str::from_utf8(&resolve_buf[..count]).map_err(|_| Error::new(ENOENT))?;
|
||||
RedoxStr::new(path.to_string()).ok_or(Error::new(EBADF))
|
||||
}
|
||||
|
||||
fn calc_next_abs_path(current_abs: &str, link_target: &str) -> Result<String> {
|
||||
let parent = get_parent_path(current_abs).ok_or(Error::new(ENOENT))?;
|
||||
|
||||
canonicalize_using_cwd(Some(&parent), link_target).ok_or(Error::new(ENOENT))
|
||||
}
|
||||
|
||||
fn resolve_sym_links(mut current_path_string: String, flags: usize) -> Result<usize> {
|
||||
// Sym reolve loop
|
||||
/// Resolve symlink and open as a fd. Requires `current_path_string` as canonicalized.
|
||||
fn resolve_sym_links<'a>(mut current_path_string: RedoxPath<'a>, flags: usize) -> Result<usize> {
|
||||
// Sym resolve loop
|
||||
for _ in 0..limits::SYMLOOP_MAX {
|
||||
match open_absolute(¤t_path_string, flags) {
|
||||
let dirname = current_path_string.dirname();
|
||||
let cow: Cow<'_, str> = current_path_string.into();
|
||||
match open_absolute(&cow, flags) {
|
||||
Ok(fd) => return Ok(fd),
|
||||
Err(e) if e == Error::new(EXDEV) => {
|
||||
let link_target = read_link_content(¤t_path_string, false)?;
|
||||
|
||||
current_path_string = calc_next_abs_path(¤t_path_string, &link_target)?;
|
||||
// dirfd is None because it's canonicalized
|
||||
let link_target = read_link_content(None, &cow, false)?;
|
||||
current_path_string = dirname.canonicalize_as_cwd(link_target);
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
@@ -296,66 +185,58 @@ fn resolve_sym_links(mut current_path_string: String, flags: usize) -> Result<us
|
||||
}
|
||||
|
||||
// TODO: Move to redox-rt, or maybe part of it?
|
||||
pub fn openat(dirfd: c_int, path: &str, flags: usize) -> Result<usize> {
|
||||
pub fn openat(dirfd: c_int, path: RedoxStr<'_>, flags: usize) -> Result<usize> {
|
||||
if path.is_empty() && flags as i32 & fcntl::AT_EMPTY_PATH != fcntl::AT_EMPTY_PATH {
|
||||
return Err(Error::new(ENOENT));
|
||||
}
|
||||
|
||||
let (is_relative, path_to_open) = normalize_path(path).ok_or(Error::new(ENOENT))?;
|
||||
|
||||
if !is_relative {
|
||||
if !path.is_relative() {
|
||||
return open(path, flags);
|
||||
}
|
||||
|
||||
let _siglock = tmp_disable_signals();
|
||||
let fcntl_flags = flags & syscall::O_FCNTL_MASK;
|
||||
let path: Cow<'_, str> = path.into();
|
||||
|
||||
// First try
|
||||
let initial_res = if dirfd == fcntl::AT_FDCWD {
|
||||
current_dir()?
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.fd
|
||||
.openat(&path_to_open, flags, fcntl_flags)
|
||||
.openat(&path, flags, fcntl_flags)
|
||||
.map(|fd: FdGuard| fd.take())
|
||||
} else {
|
||||
redox_rt::sys::openat(dirfd as usize, &path_to_open, flags, fcntl_flags)
|
||||
redox_rt::sys::openat(dirfd as usize, &path, flags, fcntl_flags)
|
||||
};
|
||||
|
||||
let current_path_string = match initial_res {
|
||||
Ok(fd) => return Ok(fd),
|
||||
match initial_res {
|
||||
Ok(fd) => Ok(fd),
|
||||
Err(e) if e == Error::new(EXDEV) => {
|
||||
let resolve_flags = O_CLOEXEC | O_SYMLINK | O_RDONLY;
|
||||
|
||||
let fd = if dirfd == fcntl::AT_FDCWD {
|
||||
current_dir()?
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.fd
|
||||
.openat(path, resolve_flags, 0)?
|
||||
let (link_path, dirfd) = if dirfd == fcntl::AT_FDCWD {
|
||||
let link_path = read_link_content(None, &path, true);
|
||||
(link_path, dirfd)
|
||||
} else {
|
||||
redox_rt::sys::openat(dirfd as usize, &path_to_open, flags, fcntl_flags)
|
||||
.map(FdGuard::new)?
|
||||
let fd = FdGuard::new(dirfd as usize);
|
||||
let link_path = read_link_content(Some(&fd), &path, true);
|
||||
(link_path, fd.take() as i32)
|
||||
};
|
||||
|
||||
let link_target = link_target(fd)?;
|
||||
|
||||
let current_abs = openat2_path(dirfd, path, 0)?;
|
||||
calc_next_abs_path(¤t_abs, &link_target)?
|
||||
let link_path = openat2_path(dirfd, link_path?, 0)?;
|
||||
resolve_sym_links(link_path, flags)
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
|
||||
resolve_sym_links(current_path_string, flags)
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Move to redox-rt, or maybe part of it?
|
||||
pub fn open(path: &str, flags: usize) -> Result<usize> {
|
||||
let _siglock = tmp_disable_signals();
|
||||
if path == "" {
|
||||
pub fn open(path: RedoxStr<'_>, flags: usize) -> Result<usize> {
|
||||
if path.is_empty() {
|
||||
return Err(Error::new(ENOENT));
|
||||
}
|
||||
|
||||
let (is_relative, canon) = normalize_scheme_rooted_path(path).ok_or(Error::new(ENOENT))?;
|
||||
let is_relative = path.is_relative();
|
||||
let _siglock = tmp_disable_signals();
|
||||
let path: Cow<'_, str> = path.into();
|
||||
|
||||
// First try
|
||||
let initial_res = if is_relative {
|
||||
@@ -364,78 +245,39 @@ pub fn open(path: &str, flags: usize) -> Result<usize> {
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.fd
|
||||
.openat(&canon, flags, fcntl_flags)
|
||||
.openat(&path, flags, fcntl_flags)
|
||||
.map(|fd: FdGuard| fd.take())
|
||||
} else {
|
||||
open_absolute(&canon, flags)
|
||||
open_absolute(&path, flags)
|
||||
};
|
||||
|
||||
let current_path_string = match initial_res {
|
||||
Ok(fd) => return Ok(fd),
|
||||
match initial_res {
|
||||
Ok(fd) => Ok(fd),
|
||||
Err(e) if e == Error::new(EXDEV) => {
|
||||
let link_target = read_link_content(&canon, is_relative)?;
|
||||
|
||||
let cwd_guard = CWD.read();
|
||||
let current_abs =
|
||||
canonicalize_using_cwd(cwd_guard.as_ref().map(|c| c.path.as_ref()), &canon)
|
||||
.ok_or(Error::new(ENOENT))?;
|
||||
|
||||
calc_next_abs_path(¤t_abs, &link_target)?
|
||||
let link_path = read_link_content(None, &path, is_relative);
|
||||
let link_path = openat2_path(fcntl::AT_FDCWD, link_path?, 0)?;
|
||||
resolve_sym_links(link_path, flags)
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
|
||||
// Sym reolve loop
|
||||
resolve_sym_links(current_path_string, flags)
|
||||
}
|
||||
|
||||
fn get_parent_path(path: &str) -> Option<String> {
|
||||
let path = path.strip_suffix('/').unwrap_or(path);
|
||||
fn parent_opt(path: &str) -> Option<&str> {
|
||||
path.rfind('/').map(|index| {
|
||||
if index == 0 {
|
||||
// Path is something like "/file.txt" or the root "/".
|
||||
// The parent is the root directory "/".
|
||||
"/"
|
||||
} else {
|
||||
// Path is something like "/a/b/c.txt".
|
||||
// Take the slice from the beginning up to the last '/'.
|
||||
&path[..index]
|
||||
}
|
||||
})
|
||||
}
|
||||
match RedoxPath::from_absolute(path) {
|
||||
Some(path) => {
|
||||
let (scheme, reference) = path.as_parts()?;
|
||||
let parent_ref = parent_opt(reference.as_ref()).unwrap_or("");
|
||||
Some(format!("/scheme/{}/{}", scheme.as_ref(), parent_ref))
|
||||
}
|
||||
None => parent_opt(path).map(String::from),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dir_path_and_fd_path(socket_path: &str) -> Result<(String, String)> {
|
||||
/// Return the directory (or scheme path) and the relative socket path to the scheme
|
||||
pub fn dir_path_and_fd_path(
|
||||
socket_path: RedoxStr<'_>,
|
||||
) -> Result<(RedoxPath<'_>, RedoxReference<'_>)> {
|
||||
let _siglock = tmp_disable_signals();
|
||||
let cwd_guard = CWD.read();
|
||||
let cwd_path = cwd_guard.as_ref().map(|c| c.path.as_ref());
|
||||
let cwd_path = cwd_guard.as_ref().map(|c| &c.redox);
|
||||
let redox_path = openat2_path(fcntl::AT_FDCWD, socket_path, 0)?;
|
||||
|
||||
let full_path = canonicalize_with_cwd_internal(cwd_path, socket_path)?;
|
||||
|
||||
let redox_path = RedoxPath::from_absolute(&full_path).ok_or(Error::new(EINVAL))?;
|
||||
let (_, ref_path) = redox_path.as_parts().ok_or(Error::new(EINVAL))?;
|
||||
let (scheme, ref_path) = redox_path.as_parts().ok_or(Error::new(EINVAL))?;
|
||||
if ref_path.as_ref().is_empty() {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
if redox_path.is_default_scheme() {
|
||||
let dir_to_open = get_parent_path(&full_path).ok_or(Error::new(EINVAL))?;
|
||||
Ok((dir_to_open, ref_path.as_ref().to_string()))
|
||||
} else {
|
||||
let full_path = canonicalize_with_cwd_internal(cwd_path, ref_path.as_ref())?;
|
||||
let redox_path = RedoxPath::from_absolute(&full_path).ok_or(Error::new(EINVAL))?;
|
||||
let (_, path) = redox_path.as_parts().ok_or(Error::new(EINVAL))?;
|
||||
let dir_to_open = get_parent_path(&full_path).ok_or(Error::new(EINVAL))?;
|
||||
Ok((dir_to_open, path.as_ref().to_string()))
|
||||
}
|
||||
let ref_path = RedoxReference::new(ref_path.to_string()).unwrap();
|
||||
let dir_to_open = ref_path.clone().dirname();
|
||||
Ok((scheme.canonicalize_as_scheme(dir_to_open.into()), ref_path))
|
||||
}
|
||||
|
||||
pub struct FileLock(c_int);
|
||||
@@ -465,7 +307,11 @@ impl Drop for FileLock {
|
||||
/// Resolve `path` under `dirfd`.
|
||||
///
|
||||
/// See [`openat2`] for more information.
|
||||
pub(super) fn openat2_path(dirfd: c_int, path: &str, at_flags: c_int) -> Result<String, Errno> {
|
||||
pub(super) fn openat2_path(
|
||||
dirfd: c_int,
|
||||
path: RedoxStr<'_>,
|
||||
at_flags: c_int,
|
||||
) -> Result<RedoxPath<'_>, Errno> {
|
||||
// Ideally, the function calling this fn would check AT_EMPTY_PATH and just call fstat or
|
||||
// whatever with the fd.
|
||||
if path.is_empty() && at_flags & fcntl::AT_EMPTY_PATH != fcntl::AT_EMPTY_PATH {
|
||||
@@ -477,16 +323,23 @@ pub(super) fn openat2_path(dirfd: c_int, path: &str, at_flags: c_int) -> Result<
|
||||
// isn't needed.
|
||||
if dirfd == fcntl::AT_FDCWD {
|
||||
// The special constant AT_FDCWD indicates that we should use the cwd.
|
||||
let cwd_guard = CWD.read();
|
||||
canonicalize_using_cwd(cwd_guard.as_ref().map(|c| c.path.as_ref()), path)
|
||||
.ok_or(Errno(EBADF))
|
||||
let redox_path = match path {
|
||||
RedoxStr::Absolute(redox_path) => redox_path,
|
||||
RedoxStr::Relative(redox_reference) => {
|
||||
let cwd_guard = CWD.read();
|
||||
let cwd_path = cwd_guard.as_ref().map(|c| &c.redox);
|
||||
let cwd_path = cwd_path.ok_or(Error::new(EINVAL))?;
|
||||
cwd_path.canonicalize_as_cwd(redox_reference.into())
|
||||
}
|
||||
};
|
||||
Ok(redox_path)
|
||||
} else {
|
||||
let mut buf = [0; limits::PATH_MAX];
|
||||
let len = Sys::fpath(dirfd, &mut buf)?;
|
||||
// SAFETY: fpath checks then copies valid UTF8.
|
||||
let dir = unsafe { str::from_utf8_unchecked(&buf[..len]) };
|
||||
|
||||
canonicalize_using_cwd(Some(dir), path).ok_or(Errno(EBADF))
|
||||
let dir = RedoxPath::from_absolute(dir).ok_or(Errno(EBADF))?;
|
||||
Ok(dir.canonicalize_as_cwd(path))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -520,12 +373,11 @@ fn at_flags_to_open_flags(at_flags: c_int) -> c_int {
|
||||
/// directory.
|
||||
pub(super) fn openat2(
|
||||
dirfd: c_int,
|
||||
path: &str,
|
||||
path: CStr,
|
||||
at_flags: c_int,
|
||||
oflags: c_int,
|
||||
) -> Result<File, Errno> {
|
||||
// Translate at flags into open flags; openat will do this on its own most likely.
|
||||
let oflags = at_flags_to_open_flags(at_flags) | fcntl::O_CLOEXEC | oflags;
|
||||
let c_path = CString::new(path).map_err(|_| Errno(EINVAL))?;
|
||||
File::openat(dirfd, c_path.as_c_str().into(), oflags)
|
||||
File::openat(dirfd, path, oflags)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use alloc::vec::Vec;
|
||||
use alloc::{borrow::Cow, vec::Vec};
|
||||
use core::{cmp, mem, ptr, slice, str};
|
||||
use redox_path::RedoxStr;
|
||||
use redox_protocols::protocol::{FsCall, O_CLOEXEC, SocketCall};
|
||||
use redox_rt::proc::FdGuard;
|
||||
use syscall::{self, flag::*};
|
||||
@@ -573,18 +574,20 @@ impl PalSocket for Sys {
|
||||
|
||||
let addr =
|
||||
unsafe { slice::from_raw_parts(&data.sun_path as *const _ as *const u8, len) };
|
||||
let path = format!("{}", str::from_utf8(addr).unwrap());
|
||||
let path = str::from_utf8(addr).map_err(|_| Errno(EINVAL))?;
|
||||
log::trace!("bind(): path: {:?}", path);
|
||||
|
||||
let (dir_path, fd_path) = dir_path_and_fd_path(&path)?;
|
||||
let path = RedoxStr::new(path).ok_or(Errno(EINVAL))?;
|
||||
let (dir_path, fd_path) = dir_path_and_fd_path(path)?;
|
||||
|
||||
redox_rt::sys::sys_call_wo(
|
||||
socket as usize,
|
||||
fd_path.as_bytes(),
|
||||
fd_path.as_ref().as_bytes(),
|
||||
CallFlags::empty(),
|
||||
&[SocketCall::Bind as u64],
|
||||
)?;
|
||||
|
||||
let dir_path: Cow<'_, str> = dir_path.into();
|
||||
let fs_bind_result = (|| -> Result<()> {
|
||||
let dirfd = FdGuard::open(
|
||||
&dir_path,
|
||||
@@ -657,12 +660,13 @@ impl PalSocket for Sys {
|
||||
|
||||
let addr =
|
||||
unsafe { slice::from_raw_parts(&data.sun_path as *const _ as *const u8, len) };
|
||||
let path = format!("{}", str::from_utf8(addr).unwrap());
|
||||
log::trace!("connect(): path: {:?}", path);
|
||||
let path = str::from_utf8(addr).map_err(|_| Errno(EINVAL))?;
|
||||
log::trace!("bind(): path: {:?}", path);
|
||||
|
||||
let (_, fd_path) = dir_path_and_fd_path(&path)?;
|
||||
let path = RedoxStr::new(path).ok_or(Errno(EINVAL))?;
|
||||
let (_, fd_path) = dir_path_and_fd_path(path)?;
|
||||
|
||||
let target_path = format!("/{fd_path}");
|
||||
let target_path = format!("/{}", fd_path.as_ref());
|
||||
let socket_file_fd = FdGuard::open(&target_path, syscall::O_RDWR)?;
|
||||
|
||||
const TOKEN_BUF_SIZE: usize = 16;
|
||||
|
||||
Reference in New Issue
Block a user