1 #![allow(non_camel_case_types)]
2 #![allow(non_snake_case)]
5 use std
::os
::raw
::c_void
;
6 use std
::os
::windows
::io
::{AsRawHandle, RawHandle}
;
7 use std
::{io, mem, ptr}
;
13 type HANDLE
= *mut c_void
;
14 type LPVOID
= *mut c_void
;
15 type LPCVOID
= *const c_void
;
16 type ULONG_PTR
= usize;
17 type SIZE_T
= ULONG_PTR
;
18 type LPCWSTR
= *const WCHAR
;
19 type PDWORD
= *mut DWORD
;
20 type DWORD_PTR
= ULONG_PTR
;
21 type LPSECURITY_ATTRIBUTES
= *mut SECURITY_ATTRIBUTES
;
22 type LPSYSTEM_INFO
= *mut SYSTEM_INFO
;
24 const INVALID_HANDLE_VALUE
: HANDLE
= -1isize
as HANDLE
;
26 const STANDARD_RIGHTS_REQUIRED
: DWORD
= 0x000F0000;
28 const SECTION_QUERY
: DWORD
= 0x0001;
29 const SECTION_MAP_WRITE
: DWORD
= 0x0002;
30 const SECTION_MAP_READ
: DWORD
= 0x0004;
31 const SECTION_MAP_EXECUTE
: DWORD
= 0x0008;
32 const SECTION_EXTEND_SIZE
: DWORD
= 0x0010;
33 const SECTION_MAP_EXECUTE_EXPLICIT
: DWORD
= 0x0020;
34 const SECTION_ALL_ACCESS
: DWORD
= STANDARD_RIGHTS_REQUIRED
| SECTION_QUERY
35 | SECTION_MAP_WRITE
| SECTION_MAP_READ
| SECTION_MAP_EXECUTE
| SECTION_EXTEND_SIZE
;
37 const PAGE_READONLY
: DWORD
= 0x02;
38 const PAGE_READWRITE
: DWORD
= 0x04;
39 const PAGE_WRITECOPY
: DWORD
= 0x08;
40 const PAGE_EXECUTE_READ
: DWORD
= 0x20;
41 const PAGE_EXECUTE_READWRITE
: DWORD
= 0x40;
42 const PAGE_EXECUTE_WRITECOPY
: DWORD
= 0x80;
44 const FILE_MAP_WRITE
: DWORD
= SECTION_MAP_WRITE
;
45 const FILE_MAP_READ
: DWORD
= SECTION_MAP_READ
;
46 const FILE_MAP_ALL_ACCESS
: DWORD
= SECTION_ALL_ACCESS
;
47 const FILE_MAP_EXECUTE
: DWORD
= SECTION_MAP_EXECUTE_EXPLICIT
;
48 const FILE_MAP_COPY
: DWORD
= 0x00000001;
51 #[derive(Clone, Copy)]
52 struct SECURITY_ATTRIBUTES
{
54 lpSecurityDescriptor
: LPVOID
,
59 #[derive(Clone, Copy)]
60 struct SYSTEM_INFO_u_s
{
61 wProcessorArchitecture
: WORD
,
66 #[derive(Clone, Copy)]
67 struct SYSTEM_INFO_u([u32; 1]);
70 #[derive(Clone, Copy)]
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
,
89 fn CreateFileMappingW(
91 lpFileMappingAttributes
: LPSECURITY_ATTRIBUTES
,
93 dwMaximumSizeHigh
: DWORD
,
94 dwMaximumSizeLow
: DWORD
,
99 lpBaseAddress
: LPCVOID
,
100 dwNumberOfBytesToFlush
: SIZE_T
,
104 lpBaseAddress
: LPCVOID
,
108 hFileMappingObject
: HANDLE
,
109 dwDesiredAccess
: DWORD
,
110 dwFileOffsetHigh
: DWORD
,
111 dwFileOffsetLow
: DWORD
,
112 dwNumberOfBytesToMap
: SIZE_T
,
119 lpflOldProtect
: PDWORD
,
123 lpSystemInfo
: LPSYSTEM_INFO
,
127 pub struct MmapInner
{
135 /// Creates a new `MmapInner`.
137 /// This is a thin wrapper around the `CreateFileMappingW` and `MapViewOfFile` system calls.
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;
151 let handle
= CreateFileMappingW(
152 file
.as_raw_handle(),
159 if handle
== ptr
::null_mut() {
160 return Err(io
::Error
::last_os_error());
163 let ptr
= MapViewOfFile(
166 (aligned_offset
>> 16 >> 16) as DWORD
,
167 (aligned_offset
& 0xffffffff) as DWORD
,
168 aligned_len
as SIZE_T
,
172 if ptr
== ptr
::null_mut() {
173 Err(io
::Error
::last_os_error())
176 file
: Some(file
.try_clone()?
),
177 ptr
: ptr
.offset(alignment
as isize),
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
) {
191 access
|= FILE_MAP_WRITE
| FILE_MAP_EXECUTE
;
192 PAGE_EXECUTE_READWRITE
195 access
|= FILE_MAP_WRITE
;
199 access
|= FILE_MAP_EXECUTE
;
202 (false, false) => PAGE_READONLY
,
205 let mut inner
= MmapInner
::new(file
, protection
, access
, offset
, len
, false)?
;
207 inner
.make_read_only()?
;
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
222 let mut inner
= MmapInner
::new(file
, protection
, access
, offset
, len
, false)?
;
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
239 let mut inner
= MmapInner
::new(file
, protection
, access
, offset
, len
, false)?
;
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
256 let mut inner
= MmapInner
::new(file
, protection
, access
, offset
, len
, true)?
;
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
274 let mut inner
= MmapInner
::new(file
, protection
, access
, offset
, len
, true)?
;
276 inner
.make_read_only()?
;
281 pub fn map_anon(len
: usize, _stack
: bool
) -> io
::Result
<MmapInner
> {
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
286 // Also see https://msdn.microsoft.com/en-us/library/windows/desktop/aa366537.aspx
288 let handle
= CreateFileMappingW(
289 INVALID_HANDLE_VALUE
,
291 PAGE_EXECUTE_READWRITE
,
292 (len
>> 16 >> 16) as DWORD
,
293 (len
& 0xffffffff) as DWORD
,
296 if handle
== ptr
::null_mut() {
297 return Err(io
::Error
::last_os_error());
299 let access
= FILE_MAP_ALL_ACCESS
| FILE_MAP_EXECUTE
;
300 let ptr
= MapViewOfFile(handle
, access
, 0, 0, len
as SIZE_T
);
303 if ptr
== ptr
::null_mut() {
304 return Err(io
::Error
::last_os_error());
308 let result
= VirtualProtect(ptr
, len
as SIZE_T
, PAGE_READWRITE
, &mut old
);
317 Err(io
::Error
::last_os_error())
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
{
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) }
;
335 Err(io
::Error
::last_os_error())
339 fn virtual_protect(&mut self, protect
: DWORD
) -> io
::Result
<()> {
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
;
346 let result
= VirtualProtect(ptr
, aligned_len
, protect
, &mut old
);
351 Err(io
::Error
::last_os_error())
356 pub fn make_read_only(&mut self) -> io
::Result
<()> {
357 self.virtual_protect(PAGE_READONLY
)
360 pub fn make_exec(&mut self) -> io
::Result
<()> {
362 self.virtual_protect(PAGE_EXECUTE_WRITECOPY
)
364 self.virtual_protect(PAGE_EXECUTE_READ
)
368 pub fn make_mut(&mut self) -> io
::Result
<()> {
370 self.virtual_protect(PAGE_WRITECOPY
)
372 self.virtual_protect(PAGE_READWRITE
)
377 pub fn ptr(&self) -> *const u8 {
378 self.ptr
as *const u8
382 pub fn mut_ptr(&mut self) -> *mut u8 {
387 pub fn len(&self) -> usize {
392 impl Drop
for MmapInner
{
394 let alignment
= self.ptr
as usize % allocation_granularity();
396 let ptr
= self.ptr
.offset(-(alignment
as isize));
398 UnmapViewOfFile(ptr
) != 0,
399 "unable to unmap mmap: {}",
400 io
::Error
::last_os_error()
406 unsafe impl Sync
for MmapInner {}
407 unsafe impl Send
for MmapInner {}
409 fn protection_supported(handle
: RawHandle
, protection
: DWORD
) -> bool
{
411 let handle
= CreateFileMappingW(handle
, ptr
::null_mut(), protection
, 0, 0, ptr
::null());
412 if handle
== ptr
::null_mut() {
420 fn allocation_granularity() -> usize {
422 let mut info
= mem
::zeroed();
423 GetSystemInfo(&mut info
);
424 return info
.dwAllocationGranularity
as usize;