refactor: Make processes have cwd as a capability
This commit is contained in:
committed by
Jeremy Soller
parent
98e8716f48
commit
bd9c6f1440
+2
-3
@@ -265,15 +265,14 @@ pub fn current_proc_fd() -> &'static FdGuardUpper {
|
||||
info.proc_fd.as_ref().unwrap()
|
||||
}
|
||||
#[inline]
|
||||
pub fn current_namespace_fd() -> usize {
|
||||
pub fn current_namespace_fd() -> syscall::Result<usize> {
|
||||
DYNAMIC_PROC_INFO
|
||||
.lock()
|
||||
.ns_fd
|
||||
.as_ref()
|
||||
.map(|g| g.as_raw_fd())
|
||||
.unwrap_or(usize::MAX)
|
||||
.ok_or(syscall::Error::new(syscall::ENOENT))
|
||||
}
|
||||
|
||||
struct ChildHookCommonArgs {
|
||||
new_thr_fd: FdGuard,
|
||||
new_proc_fd: Option<FdGuard>,
|
||||
|
||||
@@ -61,6 +61,8 @@ pub struct ExtraInfo<'a> {
|
||||
pub proc_fd: usize,
|
||||
/// Namespace handle
|
||||
pub ns_fd: Option<usize>,
|
||||
/// CWD handle
|
||||
pub cwd_fd: Option<usize>,
|
||||
}
|
||||
|
||||
pub fn fexec_impl(
|
||||
@@ -393,6 +395,8 @@ pub fn fexec_impl(
|
||||
push(AT_REDOX_PROC_FD)?;
|
||||
push(extrainfo.ns_fd.unwrap_or(usize::MAX))?;
|
||||
push(AT_REDOX_NS_FD)?;
|
||||
push(extrainfo.cwd_fd.unwrap_or(usize::MAX))?;
|
||||
push(AT_REDOX_CWD_FD)?;
|
||||
|
||||
push(0)?;
|
||||
|
||||
@@ -773,6 +777,15 @@ impl FdGuard<false> {
|
||||
}
|
||||
}
|
||||
impl<const UPPER: bool> FdGuard<UPPER> {
|
||||
#[inline]
|
||||
pub fn openat<T: AsRef<str>>(
|
||||
&self,
|
||||
path: T,
|
||||
flags: usize,
|
||||
fcntl_flags: usize,
|
||||
) -> Result<FdGuard<false>> {
|
||||
syscall::openat(self.fd, path, flags, fcntl_flags).map(FdGuard::new)
|
||||
}
|
||||
#[inline]
|
||||
pub fn dup(&self, buf: &[u8]) -> Result<FdGuard<false>> {
|
||||
syscall::dup(self.fd, buf).map(FdGuard::new)
|
||||
|
||||
+22
-4
@@ -445,7 +445,7 @@ pub fn setns(fd: usize) -> Option<FdGuardUpper> {
|
||||
old_fd_guard
|
||||
}
|
||||
pub fn getns() -> Result<usize> {
|
||||
let cur_ns = crate::current_namespace_fd();
|
||||
let cur_ns = crate::current_namespace_fd()?;
|
||||
if cur_ns == usize::MAX {
|
||||
Err(Error::new(ENODEV))
|
||||
} else {
|
||||
@@ -458,7 +458,25 @@ pub fn open<T: AsRef<str>>(path: T, flags: usize) -> Result<usize> {
|
||||
unsafe {
|
||||
syscall::syscall5(
|
||||
syscall::SYS_OPENAT,
|
||||
crate::current_namespace_fd(),
|
||||
crate::current_namespace_fd()?,
|
||||
path.as_ptr() as usize,
|
||||
path.len(),
|
||||
flags,
|
||||
fcntl_flags,
|
||||
)
|
||||
}
|
||||
}
|
||||
pub fn openat<T: AsRef<str>>(
|
||||
fd: usize,
|
||||
path: T,
|
||||
flags: usize,
|
||||
fcntl_flags: usize,
|
||||
) -> Result<usize> {
|
||||
let path = path.as_ref();
|
||||
unsafe {
|
||||
syscall::syscall5(
|
||||
syscall::SYS_OPENAT,
|
||||
fd,
|
||||
path.as_ptr() as usize,
|
||||
path.len(),
|
||||
flags,
|
||||
@@ -471,7 +489,7 @@ pub fn unlink<T: AsRef<str>>(path: T, flags: usize) -> Result<usize> {
|
||||
unsafe {
|
||||
syscall::syscall4(
|
||||
syscall::SYS_UNLINKAT,
|
||||
crate::current_namespace_fd(),
|
||||
crate::current_namespace_fd()?,
|
||||
path.as_ptr() as usize,
|
||||
path.len(),
|
||||
flags,
|
||||
@@ -487,7 +505,7 @@ pub fn mkns(names: &[IoSlice]) -> Result<FdGuardUpper> {
|
||||
buf.extend_from_slice(&len.to_ne_bytes());
|
||||
buf.extend_from_slice(name_bytes);
|
||||
}
|
||||
FdGuard::new(syscall::dup(crate::current_namespace_fd(), &buf)?).to_upper()
|
||||
FdGuard::new(syscall::dup(crate::current_namespace_fd()?, &buf)?).to_upper()
|
||||
}
|
||||
pub fn register_scheme_to_ns(ns_fd: usize, name: &str, cap_fd: usize) -> Result<()> {
|
||||
let mut buf = alloc::vec::Vec::from((NsDup::IssueRegister as usize).to_ne_bytes());
|
||||
|
||||
@@ -55,3 +55,6 @@ pub const AT_REDOX_THR_FD: usize = 42;
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
pub const AT_REDOX_NS_FD: usize = 43;
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
pub const AT_REDOX_CWD_FD: usize = 44;
|
||||
|
||||
+12
-3
@@ -352,6 +352,7 @@ pub unsafe fn init(auxvs: Box<[[usize; 2]]>) {
|
||||
pub unsafe fn init_inner(auxvs: Box<[[usize; 2]]>) {
|
||||
use self::auxv_defs::*;
|
||||
use crate::header::sys_stat::S_ISVTX;
|
||||
use redox_rt::proc::FdGuard;
|
||||
use syscall::MODE_PERM;
|
||||
|
||||
// TODO: Is it safe to assume setup_sighandler has been called at this point?
|
||||
@@ -362,14 +363,22 @@ pub unsafe fn init_inner(auxvs: Box<[[usize; 2]]>) {
|
||||
)
|
||||
.expect("failed to sync signal pctl");
|
||||
|
||||
if let (Some(cwd_ptr), Some(cwd_len)) = (
|
||||
if let (Some(cwd_ptr), Some(cwd_len), Some(cwd_fd)) = (
|
||||
get_auxv(&auxvs, AT_REDOX_INITIAL_CWD_PTR),
|
||||
get_auxv(&auxvs, AT_REDOX_INITIAL_CWD_LEN),
|
||||
get_auxv(&auxvs, AT_REDOX_CWD_FD),
|
||||
) {
|
||||
let cwd_bytes: &'static [u8] =
|
||||
unsafe { core::slice::from_raw_parts(cwd_ptr as *const u8, cwd_len) };
|
||||
if let Ok(cwd) = core::str::from_utf8(cwd_bytes) {
|
||||
self::sys::path::set_cwd_manual(cwd.into());
|
||||
if let (Ok(cwd_path), Some(cwd_fd)) = (
|
||||
core::str::from_utf8(cwd_bytes),
|
||||
(cwd_fd != usize::MAX).then(|| {
|
||||
FdGuard::new(cwd_fd)
|
||||
.to_upper()
|
||||
.expect("failed to move cwd fd to upper table")
|
||||
}),
|
||||
) {
|
||||
self::sys::path::set_cwd_manual(cwd_path.into(), cwd_fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -201,7 +201,10 @@ pub fn execve(
|
||||
umask: redox_rt::sys::get_umask(),
|
||||
thr_fd: RtTcb::current().thread_fd().as_raw_fd(),
|
||||
proc_fd: redox_rt::current_proc_fd().as_raw_fd(),
|
||||
ns_fd: Some(redox_rt::current_namespace_fd()),
|
||||
ns_fd: redox_rt::current_namespace_fd().ok(),
|
||||
cwd_fd: super::path::current_dir()
|
||||
.ok()
|
||||
.map(|fd| fd.as_ref().unwrap().fd.as_raw_fd()),
|
||||
};
|
||||
|
||||
fexec_impl(
|
||||
|
||||
@@ -29,7 +29,7 @@ use crate::{
|
||||
bits_time::timespec,
|
||||
errno::{
|
||||
EBADF, EBADFD, EBADR, EEXIST, EFAULT, EFBIG, EINTR, EINVAL, EIO, ENAMETOOLONG, ENOENT,
|
||||
ENOMEM, ENOSYS, EOPNOTSUPP, EPERM, ERANGE,
|
||||
ENOMEM, ENOSYS, EOPNOTSUPP, EPERM,
|
||||
},
|
||||
fcntl::{
|
||||
self, AT_EMPTY_PATH, AT_FDCWD, AT_SYMLINK_NOFOLLOW, F_GETLK, F_OFD_GETLK, F_OFD_SETLK,
|
||||
@@ -265,11 +265,7 @@ impl Pal for Sys {
|
||||
}
|
||||
|
||||
fn fchdir(fd: c_int) -> Result<()> {
|
||||
let mut buf = [0; 4096];
|
||||
let res = syscall::fpath(fd as usize, &mut buf)?;
|
||||
|
||||
let path = str::from_utf8(&buf[..res]).map_err(|_| Errno(EINVAL))?;
|
||||
path::chdir(path)?;
|
||||
path::fchdir(fd)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -522,7 +518,7 @@ impl Pal for Sys {
|
||||
}
|
||||
|
||||
fn getcwd(buf: Out<[u8]>) -> Result<()> {
|
||||
path::getcwd(buf).ok_or(Errno(ERANGE))?;
|
||||
path::getcwd(buf)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
+255
-60
@@ -1,10 +1,12 @@
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
collections::btree_set::BTreeSet,
|
||||
ffi::CString,
|
||||
string::{String, ToString},
|
||||
vec::Vec,
|
||||
};
|
||||
use core::{ffi::c_int, str};
|
||||
use redox_rt::signal::tmp_disable_signals;
|
||||
use redox_rt::{proc::FdGuardUpper, signal::tmp_disable_signals};
|
||||
use syscall::{data::Stat, error::*, flag::*};
|
||||
|
||||
use super::{FdGuard, Pal, Sys, libcscheme};
|
||||
@@ -13,11 +15,74 @@ use crate::{
|
||||
fs::File,
|
||||
header::{fcntl, limits, sys_file},
|
||||
out::Out,
|
||||
sync::Mutex,
|
||||
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("/"),
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: Define in syscall
|
||||
const PATH_MAX: usize = 4096;
|
||||
|
||||
@@ -25,41 +90,94 @@ const PATH_MAX: usize = 4096;
|
||||
// same time forbid signal handlers from running in the meantime, to avoid reentrant deadlock.
|
||||
pub fn chdir(path: &str) -> Result<()> {
|
||||
let _siglock = tmp_disable_signals();
|
||||
let mut cwd_guard = CWD.lock();
|
||||
let mut cwd_guard = CWD.write();
|
||||
let (is_relative, path) = normalize_path(path).ok_or(Error::new(ENOENT))?;
|
||||
if is_relative {
|
||||
let fd = current_dir()?
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.fd
|
||||
.openat(&path, O_STAT, 0)?
|
||||
.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));
|
||||
}
|
||||
|
||||
let canon = canonicalize_using_cwd(cwd_guard.as_deref(), path).ok_or(Error::new(ENOENT))?;
|
||||
let canon_with_scheme = canonicalize_with_cwd_internal(cwd_guard.as_deref(), path)?;
|
||||
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: canon.into_boxed_str(),
|
||||
fd,
|
||||
});
|
||||
} else {
|
||||
let canon_with_scheme = scheme_rooted_path(&path)?;
|
||||
|
||||
let fd = redox_rt::sys::open(&canon_with_scheme, O_STAT | O_CLOEXEC)?;
|
||||
let mut stat = Stat::default();
|
||||
if syscall::fstat(fd, &mut stat).is_err() || (stat.st_mode & MODE_TYPE) != MODE_DIR {
|
||||
return Err(Error::new(ENOTDIR));
|
||||
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));
|
||||
}
|
||||
|
||||
*cwd_guard = Some(Cwd {
|
||||
path: path.into_boxed_str(),
|
||||
fd,
|
||||
});
|
||||
}
|
||||
let _ = syscall::close(fd);
|
||||
|
||||
*cwd_guard = Some(canon.into_boxed_str());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// getcwd is similarly both thread-safe and signal-safe.
|
||||
pub fn getcwd(mut buf: Out<[u8]>) -> Option<usize> {
|
||||
let _siglock = tmp_disable_signals();
|
||||
let cwd_guard = CWD.lock();
|
||||
let cwd = cwd_guard.as_deref().unwrap_or("").as_bytes();
|
||||
pub fn fchdir(fd: c_int) -> Result<()> {
|
||||
let mut buf = [0; PATH_MAX];
|
||||
let res = syscall::fpath(fd as usize, &mut buf)?;
|
||||
|
||||
let [mut before, mut after] = buf.split_at_checked(cwd.len())?;
|
||||
|
||||
before.copy_from_slice(&cwd);
|
||||
after.zero();
|
||||
|
||||
Some(cwd.len())
|
||||
let path = core::str::from_utf8(&buf[..res])
|
||||
.map_err(|_| Errno(EINVAL))?
|
||||
.to_string();
|
||||
let fd = FdGuard::new(syscall::fcntl(
|
||||
fd as usize,
|
||||
syscall::F_DUPFD,
|
||||
syscall::UPPER_FDTBL_TAG,
|
||||
)?)
|
||||
.to_upper()
|
||||
.unwrap();
|
||||
set_cwd_manual(path.into_boxed_str(), fd);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// 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))?;
|
||||
// getcwd is similarly both thread-safe and signal-safe.
|
||||
pub fn getcwd(mut buf: Out<[u8]>) -> Result<usize> {
|
||||
let _siglock = tmp_disable_signals();
|
||||
let guard = CWD.read();
|
||||
let cwd = guard.as_ref().ok_or(Error::new(ENOENT))?;
|
||||
let path_bytes = cwd.path.as_bytes();
|
||||
|
||||
let [mut before, mut after] = buf
|
||||
.split_at_checked(path_bytes.len())
|
||||
.ok_or(Error::new(ERANGE))?;
|
||||
|
||||
before.copy_from_slice(path_bytes);
|
||||
after.zero();
|
||||
|
||||
Ok(path_bytes.len())
|
||||
}
|
||||
|
||||
// Get Cwd object
|
||||
pub fn current_dir() -> Result<ReadGuard<'static, Option<Cwd>>> {
|
||||
let guard = CWD.read();
|
||||
|
||||
if guard.as_ref().is_none() {
|
||||
return Err(Error::new(ENOENT));
|
||||
}
|
||||
|
||||
Ok(guard)
|
||||
}
|
||||
|
||||
fn scheme_rooted_path(path: &str) -> Result<String> {
|
||||
let standard_scheme = path == "/scheme" || path.starts_with("/scheme/");
|
||||
let legacy_scheme = path
|
||||
.split("/")
|
||||
@@ -68,7 +186,7 @@ fn canonicalize_with_cwd_internal(cwd: Option<&str>, path: &str) -> Result<Strin
|
||||
.unwrap_or(false);
|
||||
|
||||
Ok(if standard_scheme || legacy_scheme {
|
||||
path
|
||||
path.to_string()
|
||||
} else {
|
||||
let mut result = format!("/scheme/file{}", path);
|
||||
|
||||
@@ -81,23 +199,34 @@ fn canonicalize_with_cwd_internal(cwd: Option<&str>, path: &str) -> Result<Strin
|
||||
})
|
||||
}
|
||||
|
||||
// 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.lock();
|
||||
canonicalize_with_cwd_internal(cwd_guard.as_deref(), path)
|
||||
let cwd_guard = CWD.read();
|
||||
canonicalize_with_cwd_internal(cwd_guard.as_ref().map(|c| c.path.as_ref()), path)
|
||||
}
|
||||
|
||||
pub struct Cwd {
|
||||
pub path: Box<str>,
|
||||
pub fd: FdGuardUpper,
|
||||
}
|
||||
|
||||
// TODO: arraystring?
|
||||
static CWD: Mutex<Option<Box<str>>> = Mutex::new(None);
|
||||
static CWD: RwLock<Option<Cwd>> = RwLock::new(None);
|
||||
|
||||
pub fn set_cwd_manual(cwd: Box<str>) {
|
||||
pub fn set_cwd_manual(path: Box<str>, fd: FdGuardUpper) {
|
||||
let _siglock = tmp_disable_signals();
|
||||
*CWD.lock() = Some(cwd);
|
||||
*CWD.write() = Some(Cwd { path, fd });
|
||||
}
|
||||
|
||||
pub fn clone_cwd() -> Option<Box<str>> {
|
||||
let _siglock = tmp_disable_signals();
|
||||
CWD.lock().clone()
|
||||
CWD.read().as_ref().map(|cwd| cwd.path.clone())
|
||||
}
|
||||
|
||||
// TODO: Move to redox-rt, or maybe part of it?
|
||||
@@ -105,46 +234,106 @@ pub fn open(path: &str, flags: usize) -> Result<usize> {
|
||||
// TODO: SYMLOOP_MAX
|
||||
const MAX_LEVEL: usize = 64;
|
||||
|
||||
let mut resolve_buf = [0_u8; 4096];
|
||||
let mut path = path;
|
||||
if path == "" {
|
||||
return Err(Error::new(ENOENT));
|
||||
}
|
||||
|
||||
for _ in 0..MAX_LEVEL {
|
||||
let canon = canonicalize_with_cwd_internal(CWD.lock().as_deref(), path)?;
|
||||
|
||||
let open_res = if canon.starts_with(libcscheme::LIBC_SCHEME) {
|
||||
libcscheme::open(&canon, flags)
|
||||
let open_absolute = |path: &str| -> Result<usize> {
|
||||
if path.starts_with(libcscheme::LIBC_SCHEME) {
|
||||
libcscheme::open(path, flags)
|
||||
} else {
|
||||
redox_rt::sys::open(&*canon, flags)
|
||||
redox_rt::sys::open(path, flags)
|
||||
}
|
||||
};
|
||||
|
||||
let read_link_content = |path: &str, is_relative: bool| -> Result<String> {
|
||||
let mut resolve_buf = [0_u8; 4096];
|
||||
let resolve_flags = O_CLOEXEC | O_SYMLINK | O_RDONLY;
|
||||
|
||||
let fd = if is_relative {
|
||||
let fcntl_flags = resolve_flags & syscall::O_FCNTL_MASK;
|
||||
current_dir()?
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.fd
|
||||
.openat(path, resolve_flags, fcntl_flags)?
|
||||
} else {
|
||||
FdGuard::open(path, resolve_flags)?
|
||||
};
|
||||
|
||||
match open_res {
|
||||
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())
|
||||
};
|
||||
|
||||
let calc_next_abs_path = |current_abs: &str, link_target: &str| -> Result<String> {
|
||||
let _siglock = tmp_disable_signals();
|
||||
let parent = get_parent_path(current_abs).ok_or(Error::new(ENOENT))?;
|
||||
|
||||
canonicalize_using_cwd(Some(parent), link_target).ok_or(Error::new(ENOENT))
|
||||
};
|
||||
|
||||
let (is_relative, canon) = normalize_scheme_rooted_path(path).ok_or(Error::new(ENOENT))?;
|
||||
let mut current_path_string: String;
|
||||
|
||||
// First try
|
||||
let initial_res = if is_relative {
|
||||
let fcntl_flags = flags & syscall::O_FCNTL_MASK;
|
||||
current_dir()?
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.fd
|
||||
.openat(&canon, flags, fcntl_flags)
|
||||
.map(|fd: FdGuard| fd.take())
|
||||
} else {
|
||||
open_absolute(&canon)
|
||||
};
|
||||
|
||||
match initial_res {
|
||||
Ok(fd) => return Ok(fd),
|
||||
Err(e) if e == Error::new(EXDEV) => {
|
||||
let link_target = read_link_content(&canon, is_relative)?;
|
||||
|
||||
let _siglock = tmp_disable_signals();
|
||||
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))?;
|
||||
|
||||
current_path_string = calc_next_abs_path(¤t_abs, &link_target)?;
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
|
||||
// Sym reolve loop
|
||||
for _ in 0..(MAX_LEVEL - 1) {
|
||||
match open_absolute(¤t_path_string) {
|
||||
Ok(fd) => return Ok(fd),
|
||||
Err(error) if error == Error::new(EXDEV) => {
|
||||
let resolve_flags = O_CLOEXEC | O_SYMLINK | O_RDONLY;
|
||||
let resolve_fd = FdGuard::new(redox_rt::sys::open(&*canon, resolve_flags)?);
|
||||
Err(e) if e == Error::new(EXDEV) => {
|
||||
let link_target = read_link_content(¤t_path_string, false)?;
|
||||
|
||||
let bytes_read = resolve_fd.read(&mut resolve_buf)?;
|
||||
// TODO: make resolve_buf PATH_MAX + 1 bytes?
|
||||
if bytes_read == 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".
|
||||
path = core::str::from_utf8(&resolve_buf[..bytes_read])
|
||||
.map_err(|_| Error::new(ENOENT))?;
|
||||
current_path_string = calc_next_abs_path(¤t_path_string, &link_target)?;
|
||||
}
|
||||
Err(other_error) => return Err(other_error),
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::new(ELOOP))
|
||||
}
|
||||
|
||||
pub fn dir_path_and_fd_path(socket_path: &str) -> Result<(String, String)> {
|
||||
let _siglock = tmp_disable_signals();
|
||||
let cwd_guard = CWD.lock();
|
||||
let cwd_guard = CWD.read();
|
||||
let cwd_path = cwd_guard.as_ref().map(|c| c.path.as_ref());
|
||||
|
||||
let full_path = canonicalize_with_cwd_internal(cwd_guard.as_deref(), socket_path)?;
|
||||
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))?;
|
||||
@@ -155,7 +344,7 @@ pub fn dir_path_and_fd_path(socket_path: &str) -> Result<(String, String)> {
|
||||
let dir_to_open = String::from(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_guard.as_deref(), ref_path.as_ref())?;
|
||||
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 = String::from(get_parent_path(&full_path).ok_or(Error::new(EINVAL))?);
|
||||
@@ -217,7 +406,13 @@ pub(super) fn openat2_path(dirfd: c_int, path: &str, at_flags: c_int) -> Result<
|
||||
if dirfd == fcntl::AT_FDCWD {
|
||||
// The special constant AT_FDCWD indicates that we should use the cwd.
|
||||
let mut buf = [0; limits::PATH_MAX];
|
||||
let len = getcwd(Out::from_mut(&mut buf)).ok_or(Errno(ENAMETOOLONG))?;
|
||||
let len = match getcwd(Out::from_mut(&mut buf)) {
|
||||
Ok(len) => len,
|
||||
Err(e) if e.errno == ERANGE => {
|
||||
return Err(Errno(ENAMETOOLONG));
|
||||
}
|
||||
Err(e) => return Err(Errno(e.errno)),
|
||||
};
|
||||
// SAFETY: Redox's cwd is stored as a str.
|
||||
let cwd = unsafe { str::from_utf8_unchecked(&buf[..len]) };
|
||||
|
||||
|
||||
Reference in New Issue
Block a user