std\sys\pal\windows/
os.rs1#![allow(nonstandard_style)]
4
5#[cfg(test)]
6mod tests;
7
8use super::api;
9#[cfg(not(target_vendor = "uwp"))]
10use super::api::WinError;
11use crate::ffi::{OsStr, OsString};
12use crate::os::windows::ffi::EncodeWide;
13use crate::os::windows::prelude::*;
14use crate::path::{self, PathBuf};
15use crate::sys::pal::{c, cvt};
16use crate::{fmt, io, ptr};
17
18pub struct SplitPaths<'a> {
19 data: EncodeWide<'a>,
20 must_yield: bool,
21}
22
23pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> {
24 SplitPaths { data: unparsed.encode_wide(), must_yield: true }
25}
26
27impl<'a> Iterator for SplitPaths<'a> {
28 type Item = PathBuf;
29 fn next(&mut self) -> Option<PathBuf> {
30 let must_yield = self.must_yield;
44 self.must_yield = false;
45
46 let mut in_progress = Vec::new();
47 let mut in_quote = false;
48 for b in self.data.by_ref() {
49 if b == '"' as u16 {
50 in_quote = !in_quote;
51 } else if b == ';' as u16 && !in_quote {
52 self.must_yield = true;
53 break;
54 } else {
55 in_progress.push(b)
56 }
57 }
58
59 if !must_yield && in_progress.is_empty() {
60 None
61 } else {
62 Some(super::os2path(&in_progress))
63 }
64 }
65}
66
67#[derive(Debug)]
68pub struct JoinPathsError;
69
70pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
71where
72 I: Iterator<Item = T>,
73 T: AsRef<OsStr>,
74{
75 let mut joined = Vec::new();
76 let sep = b';' as u16;
77
78 for (i, path) in paths.enumerate() {
79 let path = path.as_ref();
80 if i > 0 {
81 joined.push(sep)
82 }
83 let v = path.encode_wide().collect::<Vec<u16>>();
84 if v.contains(&(b'"' as u16)) {
85 return Err(JoinPathsError);
86 } else if v.contains(&sep) {
87 joined.push(b'"' as u16);
88 joined.extend_from_slice(&v[..]);
89 joined.push(b'"' as u16);
90 } else {
91 joined.extend_from_slice(&v[..]);
92 }
93 }
94
95 Ok(OsStringExt::from_wide(&joined[..]))
96}
97
98impl fmt::Display for JoinPathsError {
99 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100 "path segment contains `\"`".fmt(f)
101 }
102}
103
104impl crate::error::Error for JoinPathsError {}
105
106pub fn current_exe() -> io::Result<PathBuf> {
107 super::fill_utf16_buf(
108 |buf, sz| unsafe { c::GetModuleFileNameW(ptr::null_mut(), buf, sz) },
109 super::os2path,
110 )
111}
112
113pub fn getcwd() -> io::Result<PathBuf> {
114 super::fill_utf16_buf(|buf, sz| unsafe { c::GetCurrentDirectoryW(sz, buf) }, super::os2path)
115}
116
117pub fn chdir(p: &path::Path) -> io::Result<()> {
118 let p: &OsStr = p.as_ref();
119 let mut p = p.encode_wide().collect::<Vec<_>>();
120 p.push(0);
121
122 cvt(unsafe { c::SetCurrentDirectoryW(p.as_ptr()) }).map(drop)
123}
124
125pub fn temp_dir() -> PathBuf {
126 super::fill_utf16_buf(|buf, sz| unsafe { c::GetTempPath2W(sz, buf) }, super::os2path).unwrap()
127}
128
129#[cfg(all(not(target_vendor = "uwp"), not(target_vendor = "win7")))]
130fn home_dir_crt() -> Option<PathBuf> {
131 unsafe {
132 const CURRENT_PROCESS_TOKEN: usize = -4_isize as usize;
134
135 super::fill_utf16_buf(
136 |buf, mut sz| {
137 match c::GetUserProfileDirectoryW(
140 ptr::without_provenance_mut(CURRENT_PROCESS_TOKEN),
141 buf,
142 &mut sz,
143 ) {
144 0 if api::get_last_error() != WinError::INSUFFICIENT_BUFFER => 0,
145 0 => sz,
146 _ => sz - 1, }
148 },
149 super::os2path,
150 )
151 .ok()
152 }
153}
154
155#[cfg(target_vendor = "win7")]
156fn home_dir_crt() -> Option<PathBuf> {
157 unsafe {
158 use crate::sys::handle::Handle;
159
160 let me = c::GetCurrentProcess();
161 let mut token = ptr::null_mut();
162 if c::OpenProcessToken(me, c::TOKEN_READ, &mut token) == 0 {
163 return None;
164 }
165 let _handle = Handle::from_raw_handle(token);
166 super::fill_utf16_buf(
167 |buf, mut sz| {
168 match c::GetUserProfileDirectoryW(token, buf, &mut sz) {
169 0 if api::get_last_error() != WinError::INSUFFICIENT_BUFFER => 0,
170 0 => sz,
171 _ => sz - 1, }
173 },
174 super::os2path,
175 )
176 .ok()
177 }
178}
179
180#[cfg(target_vendor = "uwp")]
181fn home_dir_crt() -> Option<PathBuf> {
182 None
183}
184
185pub fn home_dir() -> Option<PathBuf> {
186 crate::env::var_os("USERPROFILE")
187 .filter(|s| !s.is_empty())
188 .map(PathBuf::from)
189 .or_else(home_dir_crt)
190}
191
192pub fn exit(code: i32) -> ! {
193 unsafe { c::ExitProcess(code as u32) }
194}
195
196pub fn getpid() -> u32 {
197 unsafe { c::GetCurrentProcessId() }
198}