Merge branch 'redox-path' into 'master'

Use new path format

See merge request redox-os/redoxfs!66
This commit is contained in:
Jeremy Soller
2024-02-09 15:06:51 +00:00
4 changed files with 61 additions and 102 deletions
Generated
+7
View File
@@ -260,6 +260,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384c2842d4e069d5ccacf5fe1dca4ef8d07a5444329715f0fc3c61813502d4d1"
[[package]]
name = "redox-path"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64072665120942deff5fd5425d6c1811b854f4939e7f1c01ce755f64432bbea7"
[[package]]
name = "redox_simple_endian"
version = "0.3.0"
@@ -303,6 +309,7 @@ dependencies = [
"libc",
"log",
"range-tree",
"redox-path",
"redox_simple_endian",
"redox_syscall 0.4.1",
"seahash",
+1
View File
@@ -43,6 +43,7 @@ range-tree = { version = "0.1", optional = true }
seahash = { version = "4.1.0", default-features = false }
termion = { version = "1.5.6", optional = true }
uuid = { version = "1.4", default-features = false }
redox-path = "0.2.0"
# https://github.com/rexlunae/simple-endian-rs/pull/5
[dependencies.redox_simple_endian]
+6 -4
View File
@@ -205,15 +205,17 @@ fn filesystem_by_uuid(
) -> Option<(String, FileSystem<DiskCache<DiskFile>>)> {
use std::fs;
match fs::read_dir(":") {
use redox_path::canonicalize_using_scheme;
match fs::read_dir("/scheme") {
Ok(entries) => {
for entry_res in entries {
if let Ok(entry) = entry_res {
if let Ok(path) = entry.path().into_os_string().into_string() {
let scheme = path.trim_start_matches(':').trim_matches('/');
if let Ok(scheme) = entry.file_name().into_string() {
if scheme.starts_with("disk") {
println!("redoxfs: found scheme {}", scheme);
match fs::read_dir(&format!("{}:", scheme)) {
let scheme_path = canonicalize_using_scheme(&scheme, "")?;
match fs::read_dir(scheme_path) {
Ok(entries) => {
for entry_res in entries {
if let Ok(entry) = entry_res {
+47 -98
View File
@@ -15,6 +15,8 @@ use syscall::flag::{
use syscall::scheme::SchemeMut;
use syscall::{MunmapFlags, EBADFD};
use redox_path::{canonicalize_using_cwd, canonicalize_using_scheme, RedoxPath};
use crate::{Disk, FileSystem, Node, Transaction, TreeData, TreePtr, BLOCK_SIZE};
use super::resource::{DirResource, FileResource, Resource};
@@ -43,15 +45,15 @@ impl<D: Disk> FileScheme<D> {
tx: &mut Transaction<D>,
uid: u32,
gid: u32,
url: &str,
full_path: &str,
node: TreeData<Node>,
nodes: &mut Vec<(TreeData<Node>, String)>,
) -> Result<String> {
let atime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
let scheme = format!("{}:", scheme_name);
let scheme_path = canonicalize_using_scheme(scheme_name, "").ok_or(Error::new(EINVAL))?;
// symbolic link is relative to this part of the url
let mut working_dir = dirname(url).unwrap_or(&scheme).to_string();
let mut working_dir = dirname(full_path).unwrap_or(scheme_path.to_string());
// node of the link
let mut node = node;
@@ -66,22 +68,49 @@ impl<D: Disk> FileScheme<D> {
atime.as_secs(),
atime.subsec_nanos(),
)?;
let target = canonicalize(
&working_dir,
str::from_utf8(&buf[..count]).map_err(|_| Error::new(EINVAL))?,
let target = canonicalize_using_cwd(
Some(&working_dir),
str::from_utf8(&buf[..count]).or(Err(Error::new(EINVAL)))?,
)
.ok_or(Error::new(EINVAL))?;
if !target.starts_with(&scheme) {
return Err(Error::new(EXDEV));
}
let target_path = &target[scheme.len()..];
let target_as_path = RedoxPath::from_absolute(&target).ok_or(Error::new(EINVAL))?;
let target_reference = match target_as_path {
RedoxPath::Standard(_) => {
let (scheme, reference) =
target_as_path.as_parts().ok_or(Error::new(EINVAL))?;
if scheme.as_ref() != scheme_name {
return Err(Error::new(EXDEV));
}
reference.as_ref().to_string()
}
RedoxPath::Legacy(scheme, reference) => {
// Legacy references are not canonicalized because they can contain coded information
// We know this is a `file:` reference, so canonicalize into a Standard path
if scheme.as_ref() != scheme_name {
return Err(Error::new(EXDEV));
}
let target = canonicalize_using_scheme(scheme_name, reference.as_ref())
.ok_or(Error::new(EINVAL))?;
let target_as_path =
RedoxPath::from_absolute(&target).ok_or(Error::new(EINVAL))?;
let (scheme, reference) =
target_as_path.as_parts().ok_or(Error::new(EINVAL))?;
if scheme.as_ref() != scheme_name {
return Err(Error::new(EXDEV));
}
reference.as_ref().to_string()
}
};
nodes.clear();
if let Some((next_node, next_node_name)) =
Self::path_nodes(scheme_name, tx, target_path, uid, gid, nodes)?
Self::path_nodes(scheme_name, tx, &target_reference, uid, gid, nodes)?
{
if !next_node.data().is_symlink() {
nodes.push((next_node, next_node_name));
return Ok(target_path.to_string());
return Ok(target_reference.to_string());
}
node = next_node;
working_dir = dirname(&target).ok_or(Error::new(EINVAL))?.to_string();
@@ -148,91 +177,9 @@ impl<D: Disk> FileScheme<D> {
}
}
/// given a path with a prefix, return the containing directory (or scheme)
fn dirname(path: &str) -> Option<&str> {
if let Some(separator_index) = path.trim_end_matches('/').rfind('/') {
return Some(&path[..=separator_index]);
}
// there was no path separator, just use the scheme
if let Some(scheme) = scheme_with_separator(path) {
return Some(scheme);
}
None
}
/// given a path with a scheme prefix, return the prefix including the separator
fn scheme_with_separator(path: &str) -> Option<&str> {
if let Some(sep_idx) = path.find(':') {
let scheme = &path[..=sep_idx];
if scheme.find('/').is_none() {
return Some(&scheme);
}
}
None
}
/// Make a relative path absolute
/// Given a cwd of "scheme:/path"
/// This 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(current: &str, path: &str) -> Option<String> {
// This function is modified from a version in the kernel
let mut canon = if scheme_with_separator(path).is_none() {
let mut canon = if !path.starts_with('/') {
let mut cwd = current.trim_end_matches('/').to_string();
cwd.push('/');
cwd
} else {
scheme_with_separator(current)?.to_string()
};
canon.push_str(path);
canon
} else {
path.to_string()
};
// 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 == "." {
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
if result.len() == 0 {
canon.truncate(scheme_with_separator(&canon)?.len());
Some(canon)
} else {
Some(result)
}
/// given a path with a scheme, return the containing directory (or scheme)
fn dirname(path: &str) -> Option<String> {
canonicalize_using_cwd(Some(path), "..")
}
impl<D: Disk> SchemeMut for FileScheme<D> {
@@ -296,13 +243,15 @@ impl<D: Disk> SchemeMut for FileScheme<D> {
&& flags & O_SYMLINK != O_SYMLINK
{
let mut resolve_nodes = Vec::new();
let full_path =
canonicalize_using_scheme(scheme_name, url).ok_or(Error::new(EINVAL))?;
let resolved = self.fs.tx(|tx| {
Self::resolve_symlink(
scheme_name,
tx,
uid,
gid,
&format!("{}:/{}", scheme_name, url),
&full_path,
node,
&mut resolve_nodes,
)