]> git.proxmox.com Git - rustc.git/blame - vendor/memmap2/src/windows.rs
Merge tag 'debian/1.52.1+dfsg1-1_exp2' into proxmox/buster
[rustc.git] / vendor / memmap2 / src / windows.rs
CommitLineData
6a06907d
XL
1#![allow(non_camel_case_types)]
2#![allow(non_snake_case)]
3
4use std::fs::File;
5use std::os::raw::c_void;
6use std::os::windows::io::{AsRawHandle, RawHandle};
7use std::{io, mem, ptr};
8
9type BOOL = i32;
10type WORD = u16;
11type DWORD = u32;
12type WCHAR = u16;
13type HANDLE = *mut c_void;
14type LPVOID = *mut c_void;
15type LPCVOID = *const c_void;
16type ULONG_PTR = usize;
17type SIZE_T = ULONG_PTR;
18type LPCWSTR = *const WCHAR;
19type PDWORD = *mut DWORD;
20type DWORD_PTR = ULONG_PTR;
21type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES;
22type LPSYSTEM_INFO = *mut SYSTEM_INFO;
23
24const INVALID_HANDLE_VALUE: HANDLE = -1isize as HANDLE;
25
26const STANDARD_RIGHTS_REQUIRED: DWORD = 0x000F0000;
27
28const SECTION_QUERY: DWORD = 0x0001;
29const SECTION_MAP_WRITE: DWORD = 0x0002;
30const SECTION_MAP_READ: DWORD = 0x0004;
31const SECTION_MAP_EXECUTE: DWORD = 0x0008;
32const SECTION_EXTEND_SIZE: DWORD = 0x0010;
33const SECTION_MAP_EXECUTE_EXPLICIT: DWORD = 0x0020;
34const SECTION_ALL_ACCESS: DWORD = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY
35 | SECTION_MAP_WRITE | SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_EXTEND_SIZE;
36
37const PAGE_READONLY: DWORD = 0x02;
38const PAGE_READWRITE: DWORD = 0x04;
39const PAGE_WRITECOPY: DWORD = 0x08;
40const PAGE_EXECUTE_READ: DWORD = 0x20;
41const PAGE_EXECUTE_READWRITE: DWORD = 0x40;
42const PAGE_EXECUTE_WRITECOPY: DWORD = 0x80;
43
44const FILE_MAP_WRITE: DWORD = SECTION_MAP_WRITE;
45const FILE_MAP_READ: DWORD = SECTION_MAP_READ;
46const FILE_MAP_ALL_ACCESS: DWORD = SECTION_ALL_ACCESS;
47const FILE_MAP_EXECUTE: DWORD = SECTION_MAP_EXECUTE_EXPLICIT;
48const FILE_MAP_COPY: DWORD = 0x00000001;
49
50#[repr(C)]
51#[derive(Clone, Copy)]
52struct SECURITY_ATTRIBUTES {
53 nLength: DWORD,
54 lpSecurityDescriptor: LPVOID,
55 bInheritHandle: BOOL,
56}
57
58#[repr(C)]
59#[derive(Clone, Copy)]
60struct SYSTEM_INFO_u_s {
61 wProcessorArchitecture: WORD,
62 wReserved: WORD,
63}
64
65#[repr(C)]
66#[derive(Clone, Copy)]
67struct SYSTEM_INFO_u([u32; 1]);
68
69#[repr(C)]
70#[derive(Clone, Copy)]
71struct SYSTEM_INFO {
72 u: SYSTEM_INFO_u,
73 dwPageSize: DWORD,
74 lpMinimumApplicationAddress: LPVOID,
75 lpMaximumApplicationAddress: LPVOID,
76 dwActiveProcessorMask: DWORD_PTR,
77 dwNumberOfProcessors: DWORD,
78 dwProcessorType: DWORD,
79 dwAllocationGranularity: DWORD,
80 wProcessorLevel: WORD,
81 wProcessorRevision: WORD,
82}
83
84extern "system" {
85 fn CloseHandle(
86 hObject: HANDLE,
87 ) -> BOOL;
88
89 fn CreateFileMappingW(
90 hFile: HANDLE,
91 lpFileMappingAttributes: LPSECURITY_ATTRIBUTES,
92 flProtect: DWORD,
93 dwMaximumSizeHigh: DWORD,
94 dwMaximumSizeLow: DWORD,
95 lpName: LPCWSTR,
96 ) -> HANDLE;
97
98 fn FlushViewOfFile(
99 lpBaseAddress: LPCVOID,
100 dwNumberOfBytesToFlush: SIZE_T,
101 ) -> BOOL;
102
103 fn UnmapViewOfFile(
104 lpBaseAddress: LPCVOID,
105 ) -> BOOL;
106
107 fn MapViewOfFile(
108 hFileMappingObject: HANDLE,
109 dwDesiredAccess: DWORD,
110 dwFileOffsetHigh: DWORD,
111 dwFileOffsetLow: DWORD,
112 dwNumberOfBytesToMap: SIZE_T,
113 ) -> LPVOID;
114
115 fn VirtualProtect(
116 lpAddress: LPVOID,
117 dwSize: SIZE_T,
118 flNewProtect: DWORD,
119 lpflOldProtect: PDWORD,
120 ) -> BOOL;
121
122 fn GetSystemInfo(
123 lpSystemInfo: LPSYSTEM_INFO,
124 );
125}
126
127pub struct MmapInner {
128 file: Option<File>,
129 ptr: *mut c_void,
130 len: usize,
131 copy: bool,
132}
133
134impl MmapInner {
135 /// Creates a new `MmapInner`.
136 ///
137 /// This is a thin wrapper around the `CreateFileMappingW` and `MapViewOfFile` system calls.
138 pub fn new(
139 file: &File,
140 protect: DWORD,
141 access: DWORD,
142 offset: u64,
143 len: usize,
144 copy: bool,
145 ) -> io::Result<MmapInner> {
146 let alignment = offset % allocation_granularity() as u64;
147 let aligned_offset = offset - alignment as u64;
148 let aligned_len = len + alignment as usize;
149
150 unsafe {
151 let handle = CreateFileMappingW(
152 file.as_raw_handle(),
153 ptr::null_mut(),
154 protect,
155 0,
156 0,
157 ptr::null(),
158 );
159 if handle == ptr::null_mut() {
160 return Err(io::Error::last_os_error());
161 }
162
163 let ptr = MapViewOfFile(
164 handle,
165 access,
166 (aligned_offset >> 16 >> 16) as DWORD,
167 (aligned_offset & 0xffffffff) as DWORD,
168 aligned_len as SIZE_T,
169 );
170 CloseHandle(handle);
171
172 if ptr == ptr::null_mut() {
173 Err(io::Error::last_os_error())
174 } else {
175 Ok(MmapInner {
176 file: Some(file.try_clone()?),
177 ptr: ptr.offset(alignment as isize),
178 len: len as usize,
179 copy: copy,
180 })
181 }
182 }
183 }
184
185 pub fn map(len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
186 let write = protection_supported(file.as_raw_handle(), PAGE_READWRITE);
187 let exec = protection_supported(file.as_raw_handle(), PAGE_EXECUTE_READ);
188 let mut access = FILE_MAP_READ;
189 let protection = match (write, exec) {
190 (true, true) => {
191 access |= FILE_MAP_WRITE | FILE_MAP_EXECUTE;
192 PAGE_EXECUTE_READWRITE
193 }
194 (true, false) => {
195 access |= FILE_MAP_WRITE;
196 PAGE_READWRITE
197 }
198 (false, true) => {
199 access |= FILE_MAP_EXECUTE;
200 PAGE_EXECUTE_READ
201 }
202 (false, false) => PAGE_READONLY,
203 };
204
205 let mut inner = MmapInner::new(file, protection, access, offset, len, false)?;
206 if write || exec {
207 inner.make_read_only()?;
208 }
209 Ok(inner)
210 }
211
212 pub fn map_exec(len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
213 let write = protection_supported(file.as_raw_handle(), PAGE_READWRITE);
214 let mut access = FILE_MAP_READ | FILE_MAP_EXECUTE;
215 let protection = if write {
216 access |= FILE_MAP_WRITE;
217 PAGE_EXECUTE_READWRITE
218 } else {
219 PAGE_EXECUTE_READ
220 };
221
222 let mut inner = MmapInner::new(file, protection, access, offset, len, false)?;
223 if write {
224 inner.make_exec()?;
225 }
226 Ok(inner)
227 }
228
229 pub fn map_mut(len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
230 let exec = protection_supported(file.as_raw_handle(), PAGE_EXECUTE_READ);
231 let mut access = FILE_MAP_READ | FILE_MAP_WRITE;
232 let protection = if exec {
233 access |= FILE_MAP_EXECUTE;
234 PAGE_EXECUTE_READWRITE
235 } else {
236 PAGE_READWRITE
237 };
238
239 let mut inner = MmapInner::new(file, protection, access, offset, len, false)?;
240 if exec {
241 inner.make_mut()?;
242 }
243 Ok(inner)
244 }
245
246 pub fn map_copy(len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
247 let exec = protection_supported(file.as_raw_handle(), PAGE_EXECUTE_READWRITE);
248 let mut access = FILE_MAP_COPY;
249 let protection = if exec {
250 access |= FILE_MAP_EXECUTE;
251 PAGE_EXECUTE_WRITECOPY
252 } else {
253 PAGE_WRITECOPY
254 };
255
256 let mut inner = MmapInner::new(file, protection, access, offset, len, true)?;
257 if exec {
258 inner.make_mut()?;
259 }
260 Ok(inner)
261 }
262
263 pub fn map_copy_read_only(len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
264 let write = protection_supported(file.as_raw_handle(), PAGE_READWRITE);
265 let exec = protection_supported(file.as_raw_handle(), PAGE_EXECUTE_READ);
266 let mut access = FILE_MAP_COPY;
267 let protection = if exec {
268 access |= FILE_MAP_EXECUTE;
269 PAGE_EXECUTE_WRITECOPY
270 } else {
271 PAGE_WRITECOPY
272 };
273
274 let mut inner = MmapInner::new(file, protection, access, offset, len, true)?;
275 if write || exec {
276 inner.make_read_only()?;
277 }
278 Ok(inner)
279 }
280
281 pub fn map_anon(len: usize, _stack: bool) -> io::Result<MmapInner> {
282 unsafe {
283 // Create a mapping and view with maximum access permissions, then use `VirtualProtect`
284 // to set the actual `Protection`. This way, we can set more permissive protection later
285 // on.
286 // Also see https://msdn.microsoft.com/en-us/library/windows/desktop/aa366537.aspx
287
288 let handle = CreateFileMappingW(
289 INVALID_HANDLE_VALUE,
290 ptr::null_mut(),
291 PAGE_EXECUTE_READWRITE,
292 (len >> 16 >> 16) as DWORD,
293 (len & 0xffffffff) as DWORD,
294 ptr::null(),
295 );
296 if handle == ptr::null_mut() {
297 return Err(io::Error::last_os_error());
298 }
299 let access = FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE;
300 let ptr = MapViewOfFile(handle, access, 0, 0, len as SIZE_T);
301 CloseHandle(handle);
302
303 if ptr == ptr::null_mut() {
304 return Err(io::Error::last_os_error());
305 }
306
307 let mut old = 0;
308 let result = VirtualProtect(ptr, len as SIZE_T, PAGE_READWRITE, &mut old);
309 if result != 0 {
310 Ok(MmapInner {
311 file: None,
312 ptr: ptr,
313 len: len as usize,
314 copy: false,
315 })
316 } else {
317 Err(io::Error::last_os_error())
318 }
319 }
320 }
321
322 pub fn flush(&self, offset: usize, len: usize) -> io::Result<()> {
323 self.flush_async(offset, len)?;
324 if let Some(ref file) = self.file {
325 file.sync_data()?;
326 }
327 Ok(())
328 }
329
330 pub fn flush_async(&self, offset: usize, len: usize) -> io::Result<()> {
331 let result = unsafe { FlushViewOfFile(self.ptr.offset(offset as isize), len as SIZE_T) };
332 if result != 0 {
333 Ok(())
334 } else {
335 Err(io::Error::last_os_error())
336 }
337 }
338
339 fn virtual_protect(&mut self, protect: DWORD) -> io::Result<()> {
340 unsafe {
341 let alignment = self.ptr as usize % allocation_granularity();
342 let ptr = self.ptr.offset(-(alignment as isize));
343 let aligned_len = self.len as SIZE_T + alignment as SIZE_T;
344
345 let mut old = 0;
346 let result = VirtualProtect(ptr, aligned_len, protect, &mut old);
347
348 if result != 0 {
349 Ok(())
350 } else {
351 Err(io::Error::last_os_error())
352 }
353 }
354 }
355
356 pub fn make_read_only(&mut self) -> io::Result<()> {
357 self.virtual_protect(PAGE_READONLY)
358 }
359
360 pub fn make_exec(&mut self) -> io::Result<()> {
361 if self.copy {
362 self.virtual_protect(PAGE_EXECUTE_WRITECOPY)
363 } else {
364 self.virtual_protect(PAGE_EXECUTE_READ)
365 }
366 }
367
368 pub fn make_mut(&mut self) -> io::Result<()> {
369 if self.copy {
370 self.virtual_protect(PAGE_WRITECOPY)
371 } else {
372 self.virtual_protect(PAGE_READWRITE)
373 }
374 }
375
376 #[inline]
377 pub fn ptr(&self) -> *const u8 {
378 self.ptr as *const u8
379 }
380
381 #[inline]
382 pub fn mut_ptr(&mut self) -> *mut u8 {
383 self.ptr as *mut u8
384 }
385
386 #[inline]
387 pub fn len(&self) -> usize {
388 self.len
389 }
390}
391
392impl Drop for MmapInner {
393 fn drop(&mut self) {
394 let alignment = self.ptr as usize % allocation_granularity();
395 unsafe {
396 let ptr = self.ptr.offset(-(alignment as isize));
397 assert!(
398 UnmapViewOfFile(ptr) != 0,
399 "unable to unmap mmap: {}",
400 io::Error::last_os_error()
401 );
402 }
403 }
404}
405
406unsafe impl Sync for MmapInner {}
407unsafe impl Send for MmapInner {}
408
409fn protection_supported(handle: RawHandle, protection: DWORD) -> bool {
410 unsafe {
411 let handle = CreateFileMappingW(handle, ptr::null_mut(), protection, 0, 0, ptr::null());
412 if handle == ptr::null_mut() {
413 return false;
414 }
415 CloseHandle(handle);
416 true
417 }
418}
419
420fn allocation_granularity() -> usize {
421 unsafe {
422 let mut info = mem::zeroed();
423 GetSystemInfo(&mut info);
424 return info.dwAllocationGranularity as usize;
425 }
426}