use std::collections::hash_map::*;
use std::env::current_dir;
use std::path::{Path, PathBuf};
use std::fs::File;
use std::io::{BufRead, BufReader, Read};
use std::io;
use super::{Location, RemoteLocation};
#[derive(Debug)]
pub struct RemoteMounts {
map: HashMap<PathBuf, RemoteLocation>,
}
impl RemoteMounts {
pub fn load_reader<R: Read>(r: R) -> io::Result<RemoteMounts> {
let mut line = String::new();
let mut reader = BufReader::new(r);
let mut map = HashMap::new();
while try!(reader.read_line(&mut line)) != 0 {
{
let mut split = line.split_whitespace();
let remote = RemoteLocation::new(split.next().unwrap());
if let Ok(remote) = remote {
let mount = Path::new(split.next().unwrap()).to_path_buf();
map.insert(mount, remote);
}
}
line.clear();
}
Ok(RemoteMounts { map: map })
}
pub fn load() -> io::Result<RemoteMounts> {
Self::load_reader(try!(File::open("/etc/mtab")))
}
pub fn into_dir(mut self, p: PathBuf) -> Location {
let curr_dir = p;
let mut check = curr_dir.clone();
loop {
match self.map.entry(check.clone()) {
Entry::Vacant(_) => {
if check.parent().is_none() {
return Location::Local;
}
check.pop();
continue;
}
Entry::Occupied(entry) => {
let mut remote = entry.remove();
remote.path.push(curr_dir.strip_prefix(&check).unwrap());
return Location::Remote(remote);
}
}
}
}
pub fn into_current_dir(self) -> io::Result<Location> {
Ok(self.into_dir(try!(current_dir())))
}
}
#[cfg(test)]
mod tests {
use std::path::Path;
use super::RemoteMounts;
use super::super::{Location, RemoteLocation};
#[test]
fn empty_mtab() {
let mtab: &[u8] = &[];
let dir = Path::new("/").to_path_buf();
assert_eq!(RemoteMounts::load_reader(mtab).unwrap().into_dir(dir),
Location::Local);
}
#[test]
fn local_mtab() {
let mtab: &[u8] = b"\
proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
sys /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0
dev /dev devtmpfs rw,nosuid,relatime,size=4046352k,nr_inodes=1011588,mode=755 0 0
run /run tmpfs rw,nosuid,nodev,relatime,mode=755 0 0
/dev/sda1 / btrfs rw,relatime,compress=lzo,space_cache 0 0
tmpfs /dev/shm tmpfs rw,nosuid,nodev 0 0
devpts /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000 0 0
tmpfs /sys/fs/cgroup tmpfs ro,nosuid,nodev,noexec,mode=755 0 0
binfmt_misc /proc/sys/fs/binfmt_misc binfmt_misc rw,relatime 0 0
tmpfs /tmp tmpfs rw 0 0
";
let dir = Path::new("/").to_path_buf();
assert_eq!(RemoteMounts::load_reader(mtab).unwrap().into_dir(dir),
Location::Local);
}
#[test]
fn remote_mtab() {
let mtab: &[u8] = b"\
proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
sys /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0
dev /dev devtmpfs rw,nosuid,relatime,size=4046352k,nr_inodes=1011588,mode=755 0 0
example:/ /media/example fuse.sshfs rw,nosuid,nodev,relatime,user_id=1000,group_id=100 0 0
run /run tmpfs rw,nosuid,nodev,relatime,mode=755 0 0
/dev/sda1 / btrfs rw,relatime,compress=lzo,space_cache 0 0
example.com:/home/user /run/user/1000/media/example fuse.sshfs rw,nosuid,nodev,relatime,\
user_id=1000,group_id=100 0 0
tmpfs /dev/shm tmpfs rw,nosuid,nodev 0 0
devpts /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000 0 0
user@example.com:/home/user /mnt fuse.sshfs rw,nosuid,nodev,relatime,user_id=1000,group_id=100 0 0
tmpfs /sys/fs/cgroup tmpfs ro,nosuid,nodev,noexec,mode=755 0 0
example.com:/home /mnt fuse.sshfs rw,nosuid,nodev,relatime,user_id=1000,group_id=100 0 0
binfmt_misc /proc/sys/fs/binfmt_misc binfmt_misc rw,relatime 0 0
tmpfs /tmp tmpfs rw 0 0
";
let dir1 = Path::new("/").to_path_buf();
let dir2 = Path::new("/media/example").to_path_buf();
let dir3 = Path::new("/run/media").to_path_buf();
let dir4 = Path::new("/mnt/user").to_path_buf();
let remote2 = RemoteLocation::new("example:/").unwrap();
let remote4 = RemoteLocation::new("example.com:/home/user").unwrap();
assert_eq!(RemoteMounts::load_reader(mtab).unwrap().into_dir(dir1),
Location::Local);
assert_eq!(RemoteMounts::load_reader(mtab).unwrap().into_dir(dir2),
Location::Remote(remote2));
assert_eq!(RemoteMounts::load_reader(mtab).unwrap().into_dir(dir3),
Location::Local);
assert_eq!(RemoteMounts::load_reader(mtab).unwrap().into_dir(dir4),
Location::Remote(remote4));
}
}