Implement EXDEV symlink resolution.

This commit is contained in:
4lDO2
2022-08-12 13:00:12 +02:00
parent 54b3f873f8
commit 36775eeb1b
2 changed files with 46 additions and 10 deletions
+14 -7
View File
@@ -1,10 +1,11 @@
use core::{mem, ptr, result::Result as CoreResult, slice, str};
use core::convert::TryFrom;
use core::arch::asm;
use syscall::{
self,
data::{Map, Stat as redox_stat, StatVfs as redox_statvfs, TimeSpec as redox_timespec},
PtraceEvent, Result,
PtraceEvent, Result, Error, EMFILE,
};
use crate::{
@@ -705,12 +706,18 @@ impl Pal for Sys {
fn open(path: &CStr, oflag: c_int, mode: mode_t) -> c_int {
let path = path_from_c_str!(path);
e(canonicalize(path).and_then(|canon| {
syscall::open(
&canon,
((oflag as usize) & 0xFFFF_0000) | ((mode as usize) & 0xFFFF),
)
})) as c_int
match path::open(path, ((oflag as usize) & 0xFFFF_0000) | ((mode as usize) & 0xFFFF)) {
Ok(fd) => {
match c_int::try_from(fd) {
Ok(c_fd) => c_fd,
Err(_) => {
let _ = syscall::close(fd);
e(Err(Error::new(EMFILE))) as c_int
}
}
}
Err(error) => e(Err(error)) as c_int,
}
}
fn pipe2(fds: &mut [c_int], flags: c_int) -> c_int {
+32 -3
View File
@@ -1,11 +1,12 @@
use syscall::error::*;
use syscall::flag::*;
use alloc::borrow::ToOwned;
use alloc::borrow::{Cow, ToOwned};
use alloc::boxed::Box;
use alloc::string::String;
use alloc::vec::Vec;
use super::FdGuard;
use crate::sync::Mutex;
// TODO: Define in syscall
@@ -16,7 +17,7 @@ const PATH_MAX: usize = 4096;
/// Given a cwd of "scheme:/path", this his function will turn "foo" into "scheme:/path/foo".
/// "/foo" will turn into "scheme:/foo". "bar:/foo" will be used directly, as it is already
/// absolute
pub fn canonicalize_using_cwd(cwd_opt: Option<&str>, path: &str) -> Option<String> {
pub fn canonicalize_using_cwd<'a>(cwd_opt: Option<&str>, path: &'a str) -> Option<String> {
let mut canon = if path.find(':').is_none() {
let cwd = cwd_opt?;
let path_start = cwd.find(':')? + 1;
@@ -99,7 +100,6 @@ pub fn chdir(path: &str) -> Result<()> {
// TODO: Check that the dir exists and is a directory.
Ok(())
}
pub fn clone_cwd() -> Option<Box<str>> {
@@ -154,3 +154,32 @@ impl Drop for SignalMask {
let _ = syscall::sigprocmask(syscall::SIG_SETMASK, Some(&self.oldset), None);
}
}
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;
for _ in 0..MAX_LEVEL {
let canon = canonicalize(path)?;
match syscall::open(&*canon, flags) {
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(syscall::open(&*canon, resolve_flags)?);
let bytes_read = syscall::read(*resolve_fd, &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))?;
}
Err(other_error) => return Err(other_error),
}
}
Err(Error::new(ELOOP))
}