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