diff --git a/mount/redox/scheme.rs b/mount/redox/scheme.rs index 576b102efa6c9390e2abab01eca1b642efa3ab3c..014865fb9923ef3828e4df55946df446ee855abe 100644 --- a/mount/redox/scheme.rs +++ b/mount/redox/scheme.rs @@ -31,6 +31,32 @@ impl FileScheme { } } +fn resolve_symlink(fs: &mut FileSystem, name: &str, uid: u32, gid: u32, nodes: &mut Vec<(u64, Node)>, url: &[u8], node: (u64, Node)) -> Result<Vec<u8>> { + let mut node = node; + for _ in 1..10 { // XXX What should the limit be? + let mut buf = [0; 4096]; + let count = fs.read_node(node.0, 0, &mut buf)?; + // XXX Relative paths + let scheme = format!("{}:", name); + let canon = canonicalize(format!("{}{}", scheme, str::from_utf8(url).unwrap()).as_bytes(), &buf[0..count]); + let path = str::from_utf8(&canon[scheme.len()..]).unwrap_or("").trim_matches('/'); + if let Some(next_node) = path_nodes(fs, path, uid, gid, nodes)? { + if !next_node.1.is_symlink() { + if canon.starts_with(scheme.as_bytes()) { + return Ok(canon[scheme.len()..].to_vec()); + } else { + // TODO: Find way to support symlink to another scheme + return Err(Error::new(ENOENT)); + } + } + node = next_node; + } else { + return Err(Error::new(ENOENT)); + } + } + Err(Error::new(ELOOP)) +} + fn path_nodes(fs: &mut FileSystem, path: &str, uid: u32, gid: u32, nodes: &mut Vec<(u64, Node)>) -> Result<Option<(u64, Node)>> { let mut parts = path.split('/').filter(|part| ! part.is_empty()); let mut part_opt = None; @@ -181,30 +207,9 @@ impl Scheme for FileScheme { return Err(Error::new(EACCES)); } } else if node.1.is_symlink() && !(flags & O_STAT == O_STAT && flags & O_NOFOLLOW == O_NOFOLLOW) && flags & O_SYMLINK != O_SYMLINK { - let mut node = node; - for _ in 1..10 { // XXX What should the limit be? - let mut buf = [0; 4096]; - let count = fs.read_node(node.0, 0, &mut buf)?; - // XXX Relative paths - let scheme = format!("{}:", self.name); - let canon = canonicalize(format!("{}{}", scheme, str::from_utf8(url).unwrap()).as_bytes(), &buf[0..count]); - let path = str::from_utf8(&canon[scheme.len()..]).unwrap_or("").trim_matches('/'); - if let Some(next_node) = path_nodes(&mut fs, path, uid, gid, &mut nodes)? { - if !next_node.1.is_symlink() { - if canon.starts_with(scheme.as_bytes()) { - drop(fs); - return self.open(&canon[scheme.len()..], flags, uid, gid); - } else { - // TODO: Find way to support symlink to another scheme - return Err(Error::new(ENOENT)); - } - } - node = next_node; - } else { - return Err(Error::new(ENOENT)); - } - } - return Err(Error::new(ELOOP)); + let resolved = resolve_symlink(&mut fs, &self.name, uid, gid, &mut nodes, url, node)?; + drop(fs); + return self.open(&resolved, flags, uid, gid); } else if !node.1.is_symlink() && flags & O_SYMLINK == O_SYMLINK { return Err(Error::new(EINVAL)); } else {