j.laycock
5 years ago
1 changed files with 216 additions and 0 deletions
@ -0,0 +1,216 @@ |
|||||
|
// +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 |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue