You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

216 lines
5.2 KiB

  1. // +build windows
  2. package storage
  3. import (
  4. "reflect"
  5. "syscall"
  6. "unsafe"
  7. "golang.org/x/sys/windows"
  8. )
  9. type DWORD = uint32
  10. type WORD = uint16
  11. type memory_buffer struct {
  12. aligned_length uint64
  13. length uint64
  14. aligned_ptr uintptr
  15. ptr uintptr
  16. buffer []byte
  17. }
  18. type memory_map struct {
  19. file_handle windows.Handle
  20. file_memory_map_handle windows.Handle
  21. write_map_views []memory_buffer
  22. max_length uint64
  23. // read_map_views []memory_buffer
  24. }
  25. var (
  26. procGetSystemInfo = syscall.NewLazyDLL("kernel32.dll").NewProc("GetSystemInfo")
  27. )
  28. var system_info, err = getSystemInfo()
  29. var chunk_size = uint64(system_info.dwAllocationGranularity) * 512
  30. func CreateMemoryMap(hFile windows.Handle, maxlength uint64) memory_map {
  31. mem_map := memory_map{}
  32. maxlength_high := uint32(maxlength >> 32)
  33. maxlength_low := uint32(maxlength & 0xFFFFFFFF)
  34. file_memory_map_handle, err := windows.CreateFileMapping(hFile, nil, windows.PAGE_READWRITE, maxlength_high, maxlength_low, nil)
  35. if err != nil {
  36. mem_map.file_handle = hFile
  37. mem_map.file_memory_map_handle = file_memory_map_handle
  38. mem_map.max_length = maxlength
  39. }
  40. return mem_map
  41. }
  42. func DeleteFileAndMemoryMap(mem_map memory_map) {
  43. windows.CloseHandle(mem_map.file_memory_map_handle)
  44. windows.CloseHandle(mem_map.file_handle)
  45. for _, view := range mem_map.write_map_views {
  46. ReleaseMemory(view)
  47. }
  48. mem_map.write_map_views = nil
  49. mem_map.max_length = 0
  50. }
  51. func min(x, y uint64) uint64 {
  52. if x < y {
  53. return x
  54. }
  55. return y
  56. }
  57. func WriteMemory(mem_map memory_map, offset uint64, length uint64, data []byte) {
  58. for {
  59. if ((offset+length)/chunk_size)+1 > uint64(len(mem_map.write_map_views)) {
  60. allocateChunk(mem_map)
  61. } else {
  62. break
  63. }
  64. }
  65. remaining_length := length
  66. slice_index := offset / chunk_size
  67. slice_offset := offset - (slice_index * chunk_size)
  68. data_offset := uint64(0)
  69. for {
  70. write_end := min(remaining_length, chunk_size)
  71. copy(mem_map.write_map_views[slice_index].buffer[slice_offset:write_end], data[data_offset:])
  72. remaining_length -= (write_end - slice_offset)
  73. data_offset += (write_end - slice_offset)
  74. if remaining_length > 0 {
  75. slice_index += 1
  76. slice_offset = 0
  77. } else {
  78. break
  79. }
  80. }
  81. }
  82. func ReadMemory(mem_map memory_map, offset uint64, length uint64) (memory_buffer, error) {
  83. return allocate(mem_map.file_memory_map_handle, offset, length, false)
  84. }
  85. func ReleaseMemory(mem_buffer memory_buffer) {
  86. windows.UnmapViewOfFile(mem_buffer.aligned_ptr)
  87. mem_buffer.ptr = 0
  88. mem_buffer.aligned_ptr = 0
  89. mem_buffer.length = 0
  90. mem_buffer.aligned_length = 0
  91. mem_buffer.buffer = nil
  92. }
  93. func allocateChunk(mem_map memory_map) {
  94. start := uint64(len(mem_map.write_map_views)-1) * chunk_size
  95. mem_buffer, err := allocate(mem_map.file_memory_map_handle, start, chunk_size, true)
  96. if err == nil {
  97. mem_map.write_map_views = append(mem_map.write_map_views, mem_buffer)
  98. }
  99. }
  100. func allocate(hMapFile windows.Handle, offset uint64, length uint64, write bool) (memory_buffer, error) {
  101. mem_buffer := memory_buffer{}
  102. dwSysGran := system_info.dwAllocationGranularity
  103. start := (offset / uint64(dwSysGran)) * uint64(dwSysGran)
  104. diff := offset - start
  105. aligned_length := diff + length
  106. offset_high := uint32(start >> 32)
  107. offset_low := uint32(start & 0xFFFFFFFF)
  108. access := windows.FILE_MAP_READ
  109. if write {
  110. access = windows.FILE_MAP_WRITE
  111. }
  112. addr_ptr, errno := windows.MapViewOfFile(hMapFile,
  113. uint32(access), // read/write permission
  114. offset_high,
  115. offset_low,
  116. uintptr(aligned_length))
  117. if addr_ptr == 0 {
  118. return mem_buffer, errno
  119. }
  120. mem_buffer.aligned_ptr = addr_ptr
  121. mem_buffer.aligned_length = aligned_length
  122. mem_buffer.ptr = addr_ptr + uintptr(diff)
  123. mem_buffer.length = length
  124. slice_header := (*reflect.SliceHeader)(unsafe.Pointer(&mem_buffer.buffer))
  125. slice_header.Data = addr_ptr + uintptr(diff)
  126. slice_header.Len = int(length)
  127. slice_header.Cap = int(length)
  128. return mem_buffer, nil
  129. }
  130. // typedef struct _SYSTEM_INFO {
  131. // union {
  132. // DWORD dwOemId;
  133. // struct {
  134. // WORD wProcessorArchitecture;
  135. // WORD wReserved;
  136. // };
  137. // };
  138. // DWORD dwPageSize;
  139. // LPVOID lpMinimumApplicationAddress;
  140. // LPVOID lpMaximumApplicationAddress;
  141. // DWORD_PTR dwActiveProcessorMask;
  142. // DWORD dwNumberOfProcessors;
  143. // DWORD dwProcessorType;
  144. // DWORD dwAllocationGranularity;
  145. // WORD wProcessorLevel;
  146. // WORD wProcessorRevision;
  147. // } SYSTEM_INFO;
  148. // https://msdn.microsoft.com/en-us/library/ms724958(v=vs.85).aspx
  149. type _SYSTEM_INFO struct {
  150. dwOemId DWORD
  151. dwPageSize DWORD
  152. lpMinimumApplicationAddress uintptr
  153. lpMaximumApplicationAddress uintptr
  154. dwActiveProcessorMask uintptr
  155. dwNumberOfProcessors DWORD
  156. dwProcessorType DWORD
  157. dwAllocationGranularity DWORD
  158. wProcessorLevel WORD
  159. wProcessorRevision WORD
  160. }
  161. // void WINAPI GetSystemInfo(
  162. // _Out_ LPSYSTEM_INFO lpSystemInfo
  163. // );
  164. // https://msdn.microsoft.com/en-us/library/ms724381(VS.85).aspx
  165. func getSystemInfo() (_SYSTEM_INFO, error) {
  166. var si _SYSTEM_INFO
  167. _, _, err := procGetSystemInfo.Call(
  168. uintptr(unsafe.Pointer(&si)),
  169. )
  170. if err != syscall.Errno(0) {
  171. return si, err
  172. }
  173. return si, nil
  174. }