Skip to main content

simple_unc/
simple_unc.rs

1#![cfg_attr(not(target_os = "windows"), allow(unused))]
2#[cfg(windows)]
3use crate::{Drives, PathExt};
4use std::{
5    borrow::Cow,
6    fs,
7    path::{Path, PathBuf},
8};
9
10#[derive(Default)]
11pub struct SimpleUnc {
12    /// Map to the network share drive when possible.
13    /// ```
14    /// # use simple_unc::SimpleUnc;
15    /// let path = "file.txt";
16    /// let unc = SimpleUnc { map_to_drive: true, ..Default::default() };
17    /// let canonicalized = unc.canonicalize(path);
18    /// ```
19    /// If the `file.txt` is in a network drive,
20    /// the result should be `Z:\dir\file.txt`
21    /// instead of `\\server\share\dir\file.txt`.
22    pub map_to_drive: bool,
23}
24
25impl SimpleUnc {
26    pub fn canonicalize(&self, path: impl AsRef<Path>) -> anyhow::Result<PathBuf> {
27        let canonicalized = fs::canonicalize(path)?;
28        #[cfg(windows)]
29        if let Some(simplified) = self.simplify(&canonicalized)? {
30            return Ok(simplified.into_owned());
31        }
32        Ok(canonicalized)
33    }
34
35    pub fn simplify<'a>(&self, path: &'a Path) -> anyhow::Result<Option<Cow<'a, Path>>> {
36        #[cfg(windows)]
37        {
38            // Try mapped network share drives.
39            if let Some(drive_path) = Drives::drive_path(path)? {
40                if self.map_to_drive {
41                    return Ok(Some(Cow::Owned(drive_path.to_path_buf())));
42                }
43                if let Some(stripped) = path.strip_win32_file_namespace_unc() {
44                    return Ok(Some(Cow::Owned(stripped)));
45                }
46            }
47
48            // Try `dunce::simplified`.
49            let simplified = dunce::simplified(path);
50            if !std::ptr::eq(path, simplified) {
51                return Ok(Some(Cow::Borrowed(simplified)));
52            }
53        }
54        Ok(None)
55    }
56
57    /// Refreshes the cached information.
58    pub fn refresh() -> anyhow::Result<()> {
59        #[cfg(windows)]
60        Drives::refresh()?;
61        Ok(())
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn simplify_none() {
71        let unc = SimpleUnc::default();
72        assert_eq!(unc.simplify(Path::new(r"C:\foo")).unwrap(), None);
73    }
74
75    #[cfg(windows)]
76    #[test]
77    fn simplify_dunce() {
78        let unc = SimpleUnc::default();
79        assert_eq!(
80            unc.simplify(Path::new(r"\\?\C:\foo")).unwrap(),
81            Some(Cow::Borrowed(Path::new(r"C:\foo")))
82        );
83    }
84}