1use std::collections::hash_map::*;
2use std::env::current_dir;
3use std::path::{Path, PathBuf};
4use std::fs::File;
5use std::io::{BufRead, BufReader, Read};
6use std::io;
7use super::{Location, RemoteLocation};
8
9#[derive(Debug)]
11pub struct RemoteMounts {
12 map: HashMap<PathBuf, RemoteLocation>,
13}
14impl RemoteMounts {
15 pub fn load_reader<R: Read>(r: R) -> io::Result<RemoteMounts> {
17 let mut line = String::new();
18 let mut reader = BufReader::new(r);
19
20 let mut map = HashMap::new();
21 while try!(reader.read_line(&mut line)) != 0 {
22 {
23 let mut split = line.split_whitespace();
24 let remote = RemoteLocation::new(split.next().unwrap());
25 if let Ok(remote) = remote {
26 let mount = Path::new(split.next().unwrap()).to_path_buf();
27 map.insert(mount, remote);
28 }
29 }
30 line.clear();
31 }
32 Ok(RemoteMounts { map: map })
33 }
34
35 pub fn load() -> io::Result<RemoteMounts> {
37 Self::load_reader(try!(File::open("/etc/mtab")))
38 }
39
40 pub fn into_dir(mut self, p: PathBuf) -> Location {
42 let curr_dir = p;
43 let mut check = curr_dir.clone();
44 loop {
45 match self.map.entry(check.clone()) {
46 Entry::Vacant(_) => {
47 if check.parent().is_none() {
48 return Location::Local;
49 }
50 check.pop();
51 continue;
52 }
53 Entry::Occupied(entry) => {
54 let mut remote = entry.remove();
55 remote.path.push(curr_dir.strip_prefix(&check).unwrap());
56 return Location::Remote(remote);
57 }
58 }
59 }
60 }
61
62 pub fn into_current_dir(self) -> io::Result<Location> {
64 Ok(self.into_dir(try!(current_dir())))
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use std::path::Path;
71 use super::RemoteMounts;
72 use super::super::{Location, RemoteLocation};
73
74 #[test]
75 fn empty_mtab() {
76 let mtab: &[u8] = &[];
77 let dir = Path::new("/").to_path_buf();
78 assert_eq!(RemoteMounts::load_reader(mtab).unwrap().into_dir(dir),
79 Location::Local);
80 }
81
82 #[test]
83 fn local_mtab() {
84 let mtab: &[u8] = b"\
85proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
86sys /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0
87dev /dev devtmpfs rw,nosuid,relatime,size=4046352k,nr_inodes=1011588,mode=755 0 0
88run /run tmpfs rw,nosuid,nodev,relatime,mode=755 0 0
89/dev/sda1 / btrfs rw,relatime,compress=lzo,space_cache 0 0
90tmpfs /dev/shm tmpfs rw,nosuid,nodev 0 0
91devpts /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000 0 0
92tmpfs /sys/fs/cgroup tmpfs ro,nosuid,nodev,noexec,mode=755 0 0
93binfmt_misc /proc/sys/fs/binfmt_misc binfmt_misc rw,relatime 0 0
94tmpfs /tmp tmpfs rw 0 0
95";
96 let dir = Path::new("/").to_path_buf();
97 assert_eq!(RemoteMounts::load_reader(mtab).unwrap().into_dir(dir),
98 Location::Local);
99 }
100
101 #[test]
102 fn remote_mtab() {
103 let mtab: &[u8] = b"\
104proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
105sys /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0
106dev /dev devtmpfs rw,nosuid,relatime,size=4046352k,nr_inodes=1011588,mode=755 0 0
107example:/ /media/example fuse.sshfs rw,nosuid,nodev,relatime,user_id=1000,group_id=100 0 0
108run /run tmpfs rw,nosuid,nodev,relatime,mode=755 0 0
109/dev/sda1 / btrfs rw,relatime,compress=lzo,space_cache 0 0
110example.com:/home/user /run/user/1000/media/example fuse.sshfs rw,nosuid,nodev,relatime,\
111user_id=1000,group_id=100 0 0
112tmpfs /dev/shm tmpfs rw,nosuid,nodev 0 0
113devpts /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000 0 0
114user@example.com:/home/user /mnt fuse.sshfs rw,nosuid,nodev,relatime,user_id=1000,group_id=100 0 0
115tmpfs /sys/fs/cgroup tmpfs ro,nosuid,nodev,noexec,mode=755 0 0
116example.com:/home /mnt fuse.sshfs rw,nosuid,nodev,relatime,user_id=1000,group_id=100 0 0
117binfmt_misc /proc/sys/fs/binfmt_misc binfmt_misc rw,relatime 0 0
118tmpfs /tmp tmpfs rw 0 0
119";
120 let dir1 = Path::new("/").to_path_buf();
121 let dir2 = Path::new("/media/example").to_path_buf();
122 let dir3 = Path::new("/run/media").to_path_buf();
123 let dir4 = Path::new("/mnt/user").to_path_buf();
124 let remote2 = RemoteLocation::new("example:/").unwrap();
125 let remote4 = RemoteLocation::new("example.com:/home/user").unwrap();
126 assert_eq!(RemoteMounts::load_reader(mtab).unwrap().into_dir(dir1),
127 Location::Local);
128 assert_eq!(RemoteMounts::load_reader(mtab).unwrap().into_dir(dir2),
129 Location::Remote(remote2));
130 assert_eq!(RemoteMounts::load_reader(mtab).unwrap().into_dir(dir3),
131 Location::Local);
132 assert_eq!(RemoteMounts::load_reader(mtab).unwrap().into_dir(dir4),
133 Location::Remote(remote4));
134 }
135}