|
|
// +build windows
package storage
import ( "reflect" "syscall" "unsafe"
"golang.org/x/sys/windows" )
type DWORD = uint32 type WORD = uint16
type memory_buffer struct { aligned_length uint64 length uint64 aligned_ptr uintptr ptr uintptr buffer []byte }
type memory_map struct { file_handle windows.Handle file_memory_map_handle windows.Handle write_map_views []memory_buffer max_length uint64 // read_map_views []memory_buffer
}
var ( procGetSystemInfo = syscall.NewLazyDLL("kernel32.dll").NewProc("GetSystemInfo") )
var system_info, err = getSystemInfo()
var chunk_size = uint64(system_info.dwAllocationGranularity) * 512
func CreateMemoryMap(hFile windows.Handle, maxlength uint64) memory_map {
mem_map := memory_map{} maxlength_high := uint32(maxlength >> 32) maxlength_low := uint32(maxlength & 0xFFFFFFFF) file_memory_map_handle, err := windows.CreateFileMapping(hFile, nil, windows.PAGE_READWRITE, maxlength_high, maxlength_low, nil)
if err != nil { mem_map.file_handle = hFile mem_map.file_memory_map_handle = file_memory_map_handle mem_map.max_length = maxlength }
return mem_map }
func DeleteFileAndMemoryMap(mem_map memory_map) { windows.CloseHandle(mem_map.file_memory_map_handle) windows.CloseHandle(mem_map.file_handle)
for _, view := range mem_map.write_map_views { ReleaseMemory(view) }
mem_map.write_map_views = nil mem_map.max_length = 0 }
func min(x, y uint64) uint64 { if x < y { return x } return y }
func WriteMemory(mem_map memory_map, offset uint64, length uint64, data []byte) {
for { if ((offset+length)/chunk_size)+1 > uint64(len(mem_map.write_map_views)) { allocateChunk(mem_map) } else { break } }
remaining_length := length slice_index := offset / chunk_size slice_offset := offset - (slice_index * chunk_size) data_offset := uint64(0)
for { write_end := min(remaining_length, chunk_size) copy(mem_map.write_map_views[slice_index].buffer[slice_offset:write_end], data[data_offset:]) remaining_length -= (write_end - slice_offset) data_offset += (write_end - slice_offset)
if remaining_length > 0 { slice_index += 1 slice_offset = 0 } else { break } } }
func ReadMemory(mem_map memory_map, offset uint64, length uint64) (memory_buffer, error) { return allocate(mem_map.file_memory_map_handle, offset, length, false) }
func ReleaseMemory(mem_buffer memory_buffer) { windows.UnmapViewOfFile(mem_buffer.aligned_ptr)
mem_buffer.ptr = 0 mem_buffer.aligned_ptr = 0 mem_buffer.length = 0 mem_buffer.aligned_length = 0 mem_buffer.buffer = nil }
func allocateChunk(mem_map memory_map) {
start := uint64(len(mem_map.write_map_views)-1) * chunk_size mem_buffer, err := allocate(mem_map.file_memory_map_handle, start, chunk_size, true)
if err == nil { mem_map.write_map_views = append(mem_map.write_map_views, mem_buffer) } }
func allocate(hMapFile windows.Handle, offset uint64, length uint64, write bool) (memory_buffer, error) {
mem_buffer := memory_buffer{}
dwSysGran := system_info.dwAllocationGranularity
start := (offset / uint64(dwSysGran)) * uint64(dwSysGran) diff := offset - start aligned_length := diff + length
offset_high := uint32(start >> 32) offset_low := uint32(start & 0xFFFFFFFF)
access := windows.FILE_MAP_READ
if write { access = windows.FILE_MAP_WRITE }
addr_ptr, errno := windows.MapViewOfFile(hMapFile, uint32(access), // read/write permission
offset_high, offset_low, uintptr(aligned_length))
if addr_ptr == 0 { return mem_buffer, errno }
mem_buffer.aligned_ptr = addr_ptr mem_buffer.aligned_length = aligned_length mem_buffer.ptr = addr_ptr + uintptr(diff) mem_buffer.length = length
slice_header := (*reflect.SliceHeader)(unsafe.Pointer(&mem_buffer.buffer)) slice_header.Data = addr_ptr + uintptr(diff) slice_header.Len = int(length) slice_header.Cap = int(length)
return mem_buffer, nil }
// typedef struct _SYSTEM_INFO {
// union {
// DWORD dwOemId;
// struct {
// WORD wProcessorArchitecture;
// WORD wReserved;
// };
// };
// DWORD dwPageSize;
// LPVOID lpMinimumApplicationAddress;
// LPVOID lpMaximumApplicationAddress;
// DWORD_PTR dwActiveProcessorMask;
// DWORD dwNumberOfProcessors;
// DWORD dwProcessorType;
// DWORD dwAllocationGranularity;
// WORD wProcessorLevel;
// WORD wProcessorRevision;
// } SYSTEM_INFO;
// https://msdn.microsoft.com/en-us/library/ms724958(v=vs.85).aspx
type _SYSTEM_INFO struct { dwOemId DWORD dwPageSize DWORD lpMinimumApplicationAddress uintptr lpMaximumApplicationAddress uintptr dwActiveProcessorMask uintptr dwNumberOfProcessors DWORD dwProcessorType DWORD dwAllocationGranularity DWORD wProcessorLevel WORD wProcessorRevision WORD }
// void WINAPI GetSystemInfo(
// _Out_ LPSYSTEM_INFO lpSystemInfo
// );
// https://msdn.microsoft.com/en-us/library/ms724381(VS.85).aspx
func getSystemInfo() (_SYSTEM_INFO, error) { var si _SYSTEM_INFO _, _, err := procGetSystemInfo.Call( uintptr(unsafe.Pointer(&si)), ) if err != syscall.Errno(0) { return si, err } return si, nil }
|