positioned_io/
windows.rs

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}