Merge branch 'redox-path' into 'master'
Use new path format See merge request redox-os/redoxfs!66
This commit is contained in:
Generated
+7
@@ -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",
|
||||
|
||||
@@ -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
@@ -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
@@ -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,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user