|
@@ -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))
|
|
|
+}
|