Move redox path handling to redox-path crate
This commit is contained in:
Generated
+5
@@ -198,6 +198,10 @@ dependencies = [
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox-path"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.4.1"
|
||||
@@ -224,6 +228,7 @@ dependencies = [
|
||||
"rand_jitter",
|
||||
"rand_xorshift",
|
||||
"redox-exec",
|
||||
"redox-path",
|
||||
"redox_syscall",
|
||||
"sc",
|
||||
"unicode-width",
|
||||
|
||||
+9
-1
@@ -9,7 +9,14 @@ name = "relibc"
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[workspace]
|
||||
members = ["src/crt0", "src/crti", "src/crtn", "src/ld_so", "src/platform/redox/redox-exec"]
|
||||
members = [
|
||||
"src/crt0",
|
||||
"src/crti",
|
||||
"src/crtn",
|
||||
"src/ld_so",
|
||||
"src/platform/redox/redox-exec",
|
||||
"src/platform/redox/redox-path",
|
||||
]
|
||||
exclude = ["tests", "dlmalloc-rs"]
|
||||
|
||||
[build-dependencies]
|
||||
@@ -47,6 +54,7 @@ sc = "0.2.3"
|
||||
[target.'cfg(target_os = "redox")'.dependencies]
|
||||
redox_syscall = "0.4"
|
||||
redox-exec = { path = "src/platform/redox/redox-exec" }
|
||||
redox-path = { path = "src/platform/redox/redox-path" }
|
||||
|
||||
[features]
|
||||
default = ["check_against_libc_crate"]
|
||||
|
||||
@@ -1,78 +1,14 @@
|
||||
use syscall::{data::Stat, error::*, flag::*};
|
||||
|
||||
use alloc::{borrow::ToOwned, boxed::Box, string::String, vec::Vec};
|
||||
use syscall::{data::Stat, error::*, flag::*};
|
||||
|
||||
use super::{libcscheme, FdGuard};
|
||||
use crate::sync::Mutex;
|
||||
|
||||
pub use redox_path::canonicalize_using_cwd;
|
||||
|
||||
// TODO: Define in syscall
|
||||
const PATH_MAX: usize = 4096;
|
||||
|
||||
/// Make a relative path absolute.
|
||||
///
|
||||
/// Given a cwd of "scheme:/path", this his function will turn "foo" into "scheme:/path/foo".
|
||||
/// "/foo" will turn into "file:/foo". "bar:/foo" will be used directly, as it is already
|
||||
/// absolute
|
||||
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 mut canon = if !path.starts_with('/') {
|
||||
let mut c = cwd.to_owned();
|
||||
if !c.ends_with('/') {
|
||||
c.push('/');
|
||||
}
|
||||
c
|
||||
} else {
|
||||
// Fall back to the file scheme if no scheme provided
|
||||
"file:".to_owned()
|
||||
};
|
||||
|
||||
canon.push_str(&path);
|
||||
canon
|
||||
} else {
|
||||
path.to_owned()
|
||||
};
|
||||
|
||||
// NOTE: assumes the scheme does not include anything like "../" or "./"
|
||||
let mut result = {
|
||||
let parts = canon
|
||||
.split('/')
|
||||
.rev()
|
||||
.scan(0, |nskip, part| {
|
||||
if part == "." {
|
||||
Some(None)
|
||||
} else if part == ".." {
|
||||
*nskip += 1;
|
||||
Some(None)
|
||||
} else if *nskip > 0 {
|
||||
*nskip -= 1;
|
||||
Some(None)
|
||||
} else {
|
||||
Some(Some(part))
|
||||
}
|
||||
})
|
||||
.filter_map(|x| x)
|
||||
.filter(|x| !x.is_empty())
|
||||
.collect::<Vec<_>>();
|
||||
parts.iter().rev().fold(String::new(), |mut string, &part| {
|
||||
string.push_str(part);
|
||||
string.push('/');
|
||||
string
|
||||
})
|
||||
};
|
||||
result.pop(); // remove extra '/'
|
||||
|
||||
// replace with the root of the scheme if it's empty
|
||||
Some(if result.is_empty() {
|
||||
let pos = canon.find(':').map_or(canon.len(), |p| p + 1);
|
||||
canon.truncate(pos);
|
||||
canon
|
||||
} else {
|
||||
result
|
||||
})
|
||||
}
|
||||
|
||||
// XXX: chdir is not marked thread-safe (MT-safe) by POSIX. But on Linux it is simply run as a
|
||||
// syscall and is therefore atomic, which is presumably why Rust's libstd doesn't synchronize
|
||||
// access to this.
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "redox-path"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
@@ -0,0 +1,171 @@
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::{borrow::ToOwned, format, string::String, vec::Vec};
|
||||
|
||||
pub fn split_path<'a>(path: &'a str) -> Option<(&'a str, &'a str)> {
|
||||
let mut parts = path.splitn(2, ':');
|
||||
let scheme = parts.next()?;
|
||||
let reference = parts.next()?;
|
||||
Some((scheme, reference))
|
||||
}
|
||||
|
||||
/// Make a relative path absolute.
|
||||
///
|
||||
/// Given a cwd of "scheme:/path", this his function will turn "foo" into "scheme:/path/foo".
|
||||
/// "/foo" will turn into "file:/foo". "bar:/foo" will be used directly, as it is already
|
||||
/// absolute
|
||||
pub fn canonicalize_using_cwd<'a>(cwd_opt: Option<&str>, path: &'a str) -> Option<String> {
|
||||
let (scheme, reference) = match split_path(path) {
|
||||
Some((scheme, reference)) => (scheme, reference.to_owned()),
|
||||
None => {
|
||||
let cwd = cwd_opt?;
|
||||
let (scheme, reference) = split_path(cwd)?;
|
||||
if path.starts_with('/') {
|
||||
(scheme, path.to_owned())
|
||||
} else {
|
||||
let mut reference = reference.to_owned();
|
||||
if !reference.ends_with('/') {
|
||||
reference.push('/');
|
||||
}
|
||||
reference.push_str(path);
|
||||
(scheme, reference)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let mut canonical = {
|
||||
let parts = reference
|
||||
.split('/')
|
||||
.rev()
|
||||
.scan(0, |nskip, part| {
|
||||
if part == "." {
|
||||
Some(None)
|
||||
} else if part == ".." {
|
||||
*nskip += 1;
|
||||
Some(None)
|
||||
} else if *nskip > 0 {
|
||||
*nskip -= 1;
|
||||
Some(None)
|
||||
} else {
|
||||
Some(Some(part))
|
||||
}
|
||||
})
|
||||
.filter_map(|x| x)
|
||||
.filter(|x| !x.is_empty())
|
||||
.collect::<Vec<_>>();
|
||||
parts.iter().rev().fold(String::new(), |mut string, &part| {
|
||||
string.push_str(part);
|
||||
string.push('/');
|
||||
string
|
||||
})
|
||||
};
|
||||
canonical.pop(); // remove extra '/'
|
||||
|
||||
Some(format!("{}:{}", scheme, canonical))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use alloc::string::ToString;
|
||||
|
||||
// Tests absolute paths without scheme
|
||||
#[test]
|
||||
fn test_absolute() {
|
||||
let cwd_opt = Some("foo:");
|
||||
assert_eq!(
|
||||
canonicalize_using_cwd(cwd_opt, "/"),
|
||||
Some("foo:".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
canonicalize_using_cwd(cwd_opt, "/file"),
|
||||
Some("foo:file".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
canonicalize_using_cwd(cwd_opt, "/folder/file"),
|
||||
Some("foo:folder/file".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
canonicalize_using_cwd(cwd_opt, "/folder/../file"),
|
||||
Some("foo:file".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
canonicalize_using_cwd(cwd_opt, "/folder/../.."),
|
||||
Some("foo:".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
canonicalize_using_cwd(cwd_opt, "/folder/../../../.."),
|
||||
Some("foo:".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
canonicalize_using_cwd(cwd_opt, "/.."),
|
||||
Some("foo:".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
// Test relative paths
|
||||
#[test]
|
||||
fn test_relative() {
|
||||
let cwd_opt = Some("foo:");
|
||||
assert_eq!(
|
||||
canonicalize_using_cwd(cwd_opt, "file"),
|
||||
Some("foo:file".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
canonicalize_using_cwd(cwd_opt, "folder/file"),
|
||||
Some("foo:folder/file".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
canonicalize_using_cwd(cwd_opt, "folder/../file"),
|
||||
Some("foo:file".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
canonicalize_using_cwd(cwd_opt, "folder/../.."),
|
||||
Some("foo:".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
canonicalize_using_cwd(cwd_opt, "folder/../../../.."),
|
||||
Some("foo:".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
canonicalize_using_cwd(cwd_opt, ".."),
|
||||
Some("foo:".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
// Tests paths prefixed with scheme
|
||||
#[test]
|
||||
fn test_scheme() {
|
||||
let cwd_opt = Some("foo:");
|
||||
assert_eq!(
|
||||
canonicalize_using_cwd(cwd_opt, "bar:"),
|
||||
Some("bar:".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
canonicalize_using_cwd(cwd_opt, "bar:file"),
|
||||
Some("bar:file".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
canonicalize_using_cwd(cwd_opt, "bar:folder/file"),
|
||||
Some("bar:folder/file".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
canonicalize_using_cwd(cwd_opt, "bar:folder/../file"),
|
||||
Some("bar:file".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
canonicalize_using_cwd(cwd_opt, "bar:folder/../.."),
|
||||
Some("bar:".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
canonicalize_using_cwd(cwd_opt, "bar:folder/../../../.."),
|
||||
Some("bar:".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
canonicalize_using_cwd(cwd_opt, "bar:.."),
|
||||
Some("bar:".to_string())
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user