1extern crate winapi;
2
3use std::{
4 cmp::min,
5 fs::File,
6 io,
7 io::{Seek, SeekFrom, Write},
8 mem,
9 os::windows::{fs::FileExt, io::AsRawHandle},
10 ptr,
11};
12
13use self::winapi::{
14 shared::{
15 basetsd::SIZE_T,
16 minwindef::{BOOL, DWORD},
17 },
18 um::{
19 handleapi::CloseHandle,
20 memoryapi::{CreateFileMappingW, MapViewOfFile, UnmapViewOfFile, FILE_MAP_READ},
21 sysinfoapi::GetSystemInfo,
22 winnt::{HANDLE, PAGE_READONLY},
23 },
24};
25use super::{ReadAt, WriteAt};
26
27fn result(e: BOOL) -> io::Result<()> {
28 if e == 0 {
29 Err(io::Error::last_os_error())
30 } else {
31 Ok(())
32 }
33}
34
35fn allocation_granularity() -> usize {
36 unsafe {
37 let mut info = mem::zeroed();
38 GetSystemInfo(&mut info);
39 info.dwAllocationGranularity as usize
40 }
41}
42
43impl ReadAt for File {
44 fn read_at(&self, pos: u64, buf: &mut [u8]) -> io::Result<usize> {
45 let file_len = self.metadata()?.len();
46
47 if buf.is_empty() || pos >= file_len {
48 return Ok(0);
49 }
50
51 let len = min(file_len - pos, buf.len() as u64) as usize;
52
53 unsafe {
54 let alignment = pos % allocation_granularity() as u64;
55 let aligned_pos = pos - alignment;
56 let aligned_len = len + alignment as usize;
57
58 let mapping = CreateFileMappingW(
59 self.as_raw_handle() as HANDLE,
60 ptr::null_mut(),
61 PAGE_READONLY,
62 0,
63 0,
64 ptr::null(),
65 );
66
67 if mapping.is_null() {
68 return Err(io::Error::last_os_error());
69 }
70
71 let aligned_ptr = MapViewOfFile(
72 mapping,
73 FILE_MAP_READ,
74 (aligned_pos >> 32) as DWORD,
75 (aligned_pos & 0xffff_ffff) as DWORD,
76 aligned_len as SIZE_T,
77 );
78
79 CloseHandle(mapping);
80
81 if aligned_ptr.is_null() {
82 return Err(io::Error::last_os_error());
83 }
84
85 let ptr = (aligned_ptr as *const u8).offset(alignment as isize);
86 ptr::copy_nonoverlapping(ptr, buf.as_mut_ptr(), len);
87
88 result(UnmapViewOfFile(aligned_ptr))?;
89 }
90
91 Ok(len)
92 }
93}
94
95impl WriteAt for File {
96 fn write_at(&mut self, pos: u64, buf: &[u8]) -> io::Result<usize> {
97 let cursor = self.seek(SeekFrom::Current(0))?;
98 let result = self.seek_write(buf, pos)?;
99 self.seek(SeekFrom::Start(cursor))?;
100 Ok(result)
101 }
102
103 fn flush(&mut self) -> io::Result<()> {
104 Write::flush(self)
105 }
106}