diff --git a/mount/redox/scheme.rs b/mount/redox/scheme.rs index 014865fb9923ef3828e4df55946df446ee855abe..8b89f547973735ef27d1e511e1da90632393c114 100644 --- a/mount/redox/scheme.rs +++ b/mount/redox/scheme.rs @@ -31,59 +31,73 @@ 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)); +impl FileScheme { + fn resolve_symlink(&self, fs: &mut FileSystem, uid: u32, gid: u32, url: &[u8], node: (u64, Node), nodes: &mut Vec<(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)?; + 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('/'); + nodes.clear(); + if let Some(next_node) = self.path_nodes(fs, path, uid, gid, nodes)? { + if !next_node.1.is_symlink() { + if canon.starts_with(scheme.as_bytes()) { + nodes.push(next_node); + 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)); } - node = next_node; - } else { - return Err(Error::new(ENOENT)); } + Err(Error::new(ELOOP)) } - 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; - let mut block = fs.header.1.root; - loop { - let node_res = match part_opt { - None => fs.node(block), - Some(part) => fs.find_node(part, block), - }; - - part_opt = parts.next(); - if part_opt.is_some() { - let node = node_res?; - if ! node.1.permission(uid, gid, Node::MODE_EXEC) { - return Err(Error::new(EACCES)); - } - if ! node.1.is_dir() { - return Err(Error::new(ENOTDIR)); - } - block = node.0; - nodes.push(node); - } else { - match node_res { - Ok(node) => return Ok(Some(node)), - Err(err) => match err.errno { - ENOENT => return Ok(None), - _ => return Err(err) + fn path_nodes(&self, 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; + let mut block = fs.header.1.root; + loop { + let node_res = match part_opt { + None => fs.node(block), + Some(part) => fs.find_node(part, block), + }; + + part_opt = parts.next(); + if part_opt.is_some() { + let node = node_res?; + if ! node.1.permission(uid, gid, Node::MODE_EXEC) { + return Err(Error::new(EACCES)); + } + if node.1.is_symlink() { + let mut url = Vec::new(); + url.extend_from_slice(self.name.as_bytes()); + url.push(b':'); + for i in nodes.iter() { + url.push(b'/'); + url.extend_from_slice(&i.1.name); + } + self.resolve_symlink(fs, uid, gid, &url, node, nodes)?; + block = nodes.last().unwrap().0; + } else if ! node.1.is_dir() { + return Err(Error::new(ENOTDIR)); + } else { + block = node.0; + nodes.push(node); + } + } else { + match node_res { + Ok(node) => return Ok(Some(node)), + Err(err) => match err.errno { + ENOENT => return Ok(None), + _ => return Err(err) + } } } } @@ -170,7 +184,7 @@ impl Scheme for FileScheme { let mut fs = self.fs.borrow_mut(); let mut nodes = Vec::new(); - let node_opt = path_nodes(&mut fs, path, uid, gid, &mut nodes)?; + let node_opt = self.path_nodes(&mut fs, path, uid, gid, &mut nodes)?; let resource: Box<Resource> = match node_opt { Some(node) => if flags & (O_CREAT | O_EXCL) == O_CREAT | O_EXCL { return Err(Error::new(EEXIST)); @@ -206,8 +220,9 @@ impl Scheme for FileScheme { // println!("dir not opened with O_RDONLY"); 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 resolved = resolve_symlink(&mut fs, &self.name, uid, gid, &mut nodes, url, node)?; + } else if node.1.is_symlink() && !(flags & O_STAT == O_STAT && flags & O_NOFOLLOW == O_NOFOLLOW) && flags & O_SYMLINK != O_SYMLINK { + let mut resolve_nodes = Vec::new(); + let resolved = self.resolve_symlink(&mut fs, uid, gid, url, node, &mut resolve_nodes)?; drop(fs); return self.open(&resolved, flags, uid, gid); } else if !node.1.is_symlink() && flags & O_SYMLINK == O_SYMLINK { @@ -310,7 +325,7 @@ impl Scheme for FileScheme { let mut fs = self.fs.borrow_mut(); let mut nodes = Vec::new(); - if let Some(mut node) = path_nodes(&mut fs, path, uid, gid, &mut nodes)? { + if let Some(mut node) = self.path_nodes(&mut fs, path, uid, gid, &mut nodes)? { if node.1.uid == uid || uid == 0 { node.1.mode = (node.1.mode & ! MODE_PERM) | (mode & MODE_PERM); fs.write_at(node.0, &node.1)?; @@ -331,7 +346,7 @@ impl Scheme for FileScheme { let mut fs = self.fs.borrow_mut(); let mut nodes = Vec::new(); - if let Some(child) = path_nodes(&mut fs, path, uid, gid, &mut nodes)? { + if let Some(child) = self.path_nodes(&mut fs, path, uid, gid, &mut nodes)? { if let Some(parent) = nodes.last() { if ! parent.1.permission(uid, gid, Node::MODE_WRITE) { // println!("dir not writable {:o}", parent.1.mode); @@ -368,7 +383,7 @@ impl Scheme for FileScheme { let mut fs = self.fs.borrow_mut(); let mut nodes = Vec::new(); - if let Some(child) = path_nodes(&mut fs, path, uid, gid, &mut nodes)? { + if let Some(child) = self.path_nodes(&mut fs, path, uid, gid, &mut nodes)? { if let Some(parent) = nodes.last() { if ! parent.1.permission(uid, gid, Node::MODE_WRITE) { // println!("dir not writable {:o}", parent.1.mode);