1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
use crate::fs::{errors, OpenOptions};
use crate::AmbientAuthority;
use std::ffi::OsString;
use std::ops::Deref;
use std::os::windows::ffi::{OsStrExt, OsStringExt};
use std::os::windows::fs::OpenOptionsExt;
use std::path::{Path, PathBuf};
use std::{fs, io};
use windows_sys::Win32::Storage::FileSystem::{
FILE_FLAG_BACKUP_SEMANTICS, FILE_SHARE_READ, FILE_SHARE_WRITE,
};
pub(crate) fn path_requires_dir(path: &Path) -> bool {
let wide: Vec<u16> = path.as_os_str().encode_wide().collect();
wide.ends_with(&['/' as u16])
|| wide.ends_with(&['/' as u16, '.' as _])
|| wide.ends_with(&['\\' as u16])
|| wide.ends_with(&['\\' as u16, '.' as _])
}
pub(crate) fn path_has_trailing_dot(_path: &Path) -> bool {
false
}
pub(crate) fn path_really_has_trailing_dot(path: &Path) -> bool {
let wide: Vec<u16> = path.as_os_str().encode_wide().collect();
wide.ends_with(&['/' as u16, '.' as u16]) || wide.ends_with(&['\\' as u16, '.' as u16])
}
pub(crate) fn path_has_trailing_slash(path: &Path) -> bool {
let wide: Vec<u16> = path.as_os_str().encode_wide().collect();
wide.ends_with(&['/' as u16]) || wide.ends_with(&['\\' as u16])
}
pub(crate) fn strip_dir_suffix(path: &Path) -> impl Deref<Target = Path> + '_ {
let mut wide: Vec<u16> = path.as_os_str().encode_wide().collect();
while wide.len() > 1
&& (*wide.last().unwrap() == '/' as u16 || *wide.last().unwrap() == '\\' as u16)
{
wide.pop();
}
PathBuf::from(OsString::from_wide(&wide))
}
pub(crate) fn dir_options() -> OpenOptions {
OpenOptions::new()
.read(true)
.dir_required(true)
.custom_flags(FILE_FLAG_BACKUP_SEMANTICS)
.share_mode(FILE_SHARE_READ | FILE_SHARE_WRITE)
.clone()
}
pub(crate) fn readdir_options() -> OpenOptions {
dir_options().readdir_required(true).clone()
}
pub(crate) fn canonicalize_options() -> OpenOptions {
OpenOptions::new()
.read(true)
.custom_flags(FILE_FLAG_BACKUP_SEMANTICS)
.clone()
}
pub(crate) fn open_ambient_dir_impl(path: &Path, _: AmbientAuthority) -> io::Result<fs::File> {
let dir = fs::OpenOptions::new()
.read(true)
.custom_flags(FILE_FLAG_BACKUP_SEMANTICS)
.share_mode(FILE_SHARE_READ | FILE_SHARE_WRITE)
.open(&path)?;
if !dir.metadata()?.is_dir() {
return Err(errors::is_not_directory());
}
Ok(dir)
}
#[test]
fn strip_dir_suffix_tests() {
assert_eq!(&*strip_dir_suffix(Path::new("/foo//")), Path::new("/foo"));
assert_eq!(&*strip_dir_suffix(Path::new("/foo/")), Path::new("/foo"));
assert_eq!(&*strip_dir_suffix(Path::new("foo/")), Path::new("foo"));
assert_eq!(&*strip_dir_suffix(Path::new("foo")), Path::new("foo"));
assert_eq!(&*strip_dir_suffix(Path::new("/")), Path::new("/"));
assert_eq!(&*strip_dir_suffix(Path::new("//")), Path::new("/"));
assert_eq!(
&*strip_dir_suffix(Path::new("\\foo\\\\")),
Path::new("\\foo")
);
assert_eq!(&*strip_dir_suffix(Path::new("\\foo\\")), Path::new("\\foo"));
assert_eq!(&*strip_dir_suffix(Path::new("foo\\")), Path::new("foo"));
assert_eq!(&*strip_dir_suffix(Path::new("foo")), Path::new("foo"));
assert_eq!(&*strip_dir_suffix(Path::new("\\")), Path::new("\\"));
assert_eq!(&*strip_dir_suffix(Path::new("\\\\")), Path::new("\\"));
}
#[test]
fn test_path_requires_dir() {
assert!(!path_requires_dir(Path::new(".")));
assert!(path_requires_dir(Path::new("/")));
assert!(path_requires_dir(Path::new("//")));
assert!(path_requires_dir(Path::new("/./.")));
assert!(path_requires_dir(Path::new("foo/")));
assert!(path_requires_dir(Path::new("foo//")));
assert!(path_requires_dir(Path::new("foo//.")));
assert!(path_requires_dir(Path::new("foo/./.")));
assert!(path_requires_dir(Path::new("foo/./")));
assert!(path_requires_dir(Path::new("foo/.//")));
assert!(path_requires_dir(Path::new("\\")));
assert!(path_requires_dir(Path::new("\\\\")));
assert!(path_requires_dir(Path::new("\\.\\.")));
assert!(path_requires_dir(Path::new("foo\\")));
assert!(path_requires_dir(Path::new("foo\\\\")));
assert!(path_requires_dir(Path::new("foo\\\\.")));
assert!(path_requires_dir(Path::new("foo\\.\\.")));
assert!(path_requires_dir(Path::new("foo\\.\\")));
assert!(path_requires_dir(Path::new("foo\\.\\\\")));
}
#[test]
fn test_path_has_trailing_slash() {
assert!(path_has_trailing_slash(Path::new("/")));
assert!(path_has_trailing_slash(Path::new("//")));
assert!(path_has_trailing_slash(Path::new("foo/")));
assert!(path_has_trailing_slash(Path::new("foo//")));
assert!(path_has_trailing_slash(Path::new("foo/./")));
assert!(path_has_trailing_slash(Path::new("foo/.//")));
assert!(path_has_trailing_slash(Path::new("\\")));
assert!(path_has_trailing_slash(Path::new("\\\\")));
assert!(path_has_trailing_slash(Path::new("foo\\")));
assert!(path_has_trailing_slash(Path::new("foo\\\\")));
assert!(path_has_trailing_slash(Path::new("foo\\.\\")));
assert!(path_has_trailing_slash(Path::new("foo\\.\\\\")));
assert!(!path_has_trailing_slash(Path::new("foo")));
assert!(!path_has_trailing_slash(Path::new("foo.")));
assert!(!path_has_trailing_slash(Path::new("/./foo")));
assert!(!path_has_trailing_slash(Path::new("..")));
assert!(!path_has_trailing_slash(Path::new("/..")));
assert!(!path_has_trailing_slash(Path::new("\\.\\foo")));
assert!(!path_has_trailing_slash(Path::new("..")));
assert!(!path_has_trailing_slash(Path::new("\\..")));
assert!(!path_has_trailing_slash(Path::new("/./.")));
assert!(!path_has_trailing_slash(Path::new("foo//.")));
assert!(!path_has_trailing_slash(Path::new("foo/./.")));
assert!(!path_has_trailing_slash(Path::new(".")));
assert!(!path_has_trailing_slash(Path::new("\\.\\.")));
assert!(!path_has_trailing_slash(Path::new("foo\\\\.")));
assert!(!path_has_trailing_slash(Path::new("foo\\.\\.")));
}