]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/windows/path.rs
Format libstd/sys with rustfmt
[rust.git] / src / libstd / sys / windows / path.rs
1 use crate::ffi::OsStr;
2 use crate::mem;
3 use crate::path::Prefix;
4
5 fn os_str_as_u8_slice(s: &OsStr) -> &[u8] {
6     unsafe { mem::transmute(s) }
7 }
8 unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr {
9     mem::transmute(s)
10 }
11
12 #[inline]
13 pub fn is_sep_byte(b: u8) -> bool {
14     b == b'/' || b == b'\\'
15 }
16
17 #[inline]
18 pub fn is_verbatim_sep(b: u8) -> bool {
19     b == b'\\'
20 }
21
22 pub fn parse_prefix(path: &OsStr) -> Option<Prefix<'_>> {
23     use crate::path::Prefix::*;
24     unsafe {
25         // The unsafety here stems from converting between &OsStr and &[u8]
26         // and back. This is safe to do because (1) we only look at ASCII
27         // contents of the encoding and (2) new &OsStr values are produced
28         // only from ASCII-bounded slices of existing &OsStr values.
29         let mut path = os_str_as_u8_slice(path);
30
31         if path.starts_with(br"\\") {
32             // \\
33             path = &path[2..];
34             if path.starts_with(br"?\") {
35                 // \\?\
36                 path = &path[2..];
37                 if path.starts_with(br"UNC\") {
38                     // \\?\UNC\server\share
39                     path = &path[4..];
40                     let (server, share) = match parse_two_comps(path, is_verbatim_sep) {
41                         Some((server, share)) => {
42                             (u8_slice_as_os_str(server), u8_slice_as_os_str(share))
43                         }
44                         None => (u8_slice_as_os_str(path), u8_slice_as_os_str(&[])),
45                     };
46                     return Some(VerbatimUNC(server, share));
47                 } else {
48                     // \\?\path
49                     let idx = path.iter().position(|&b| b == b'\\');
50                     if idx == Some(2) && path[1] == b':' {
51                         let c = path[0];
52                         if c.is_ascii() && (c as char).is_alphabetic() {
53                             // \\?\C:\ path
54                             return Some(VerbatimDisk(c.to_ascii_uppercase()));
55                         }
56                     }
57                     let slice = &path[..idx.unwrap_or(path.len())];
58                     return Some(Verbatim(u8_slice_as_os_str(slice)));
59                 }
60             } else if path.starts_with(b".\\") {
61                 // \\.\path
62                 path = &path[2..];
63                 let pos = path.iter().position(|&b| b == b'\\');
64                 let slice = &path[..pos.unwrap_or(path.len())];
65                 return Some(DeviceNS(u8_slice_as_os_str(slice)));
66             }
67             match parse_two_comps(path, is_sep_byte) {
68                 Some((server, share)) if !server.is_empty() && !share.is_empty() => {
69                     // \\server\share
70                     return Some(UNC(u8_slice_as_os_str(server), u8_slice_as_os_str(share)));
71                 }
72                 _ => (),
73             }
74         } else if path.get(1) == Some(&b':') {
75             // C:
76             let c = path[0];
77             if c.is_ascii() && (c as char).is_alphabetic() {
78                 return Some(Disk(c.to_ascii_uppercase()));
79             }
80         }
81         return None;
82     }
83
84     fn parse_two_comps(mut path: &[u8], f: fn(u8) -> bool) -> Option<(&[u8], &[u8])> {
85         let first = &path[..path.iter().position(|x| f(*x))?];
86         path = &path[(first.len() + 1)..];
87         let idx = path.iter().position(|x| f(*x));
88         let second = &path[..idx.unwrap_or(path.len())];
89         Some((first, second))
90     }
91 }
92
93 pub const MAIN_SEP_STR: &str = "\\";
94 pub const MAIN_SEP: char = '\\';