134 lines
3.4 KiB
Go
134 lines
3.4 KiB
Go
package tsm1
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"reflect"
|
|
"sync"
|
|
"syscall"
|
|
"unsafe"
|
|
)
|
|
|
|
// mmap implementation for Windows
|
|
// Based on: https://github.com/edsrzf/mmap-go
|
|
// Based on: https://github.com/boltdb/bolt/bolt_windows.go
|
|
// Ref: https://groups.google.com/forum/#!topic/golang-nuts/g0nLwQI9www
|
|
|
|
// We keep this map so that we can get back the original handle from the memory address.
|
|
var handleLock sync.Mutex
|
|
var handleMap = map[uintptr]syscall.Handle{}
|
|
var fileMap = map[uintptr]*os.File{}
|
|
|
|
func openSharedFile(f *os.File) (file *os.File, err error) {
|
|
|
|
var access, createmode, sharemode uint32
|
|
var sa *syscall.SecurityAttributes
|
|
|
|
access = syscall.GENERIC_READ
|
|
sharemode = uint32(syscall.FILE_SHARE_READ | syscall.FILE_SHARE_WRITE | syscall.FILE_SHARE_DELETE)
|
|
createmode = syscall.OPEN_EXISTING
|
|
fileName := f.Name()
|
|
|
|
pathp, err := syscall.UTF16PtrFromString(fileName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
h, e := syscall.CreateFile(pathp, access, sharemode, sa, createmode, syscall.FILE_ATTRIBUTE_NORMAL, 0)
|
|
|
|
if e != nil {
|
|
return nil, e
|
|
}
|
|
//NewFile does not add finalizer, need to close this manually
|
|
return os.NewFile(uintptr(h), fileName), nil
|
|
}
|
|
|
|
func mmap(f *os.File, offset int64, length int) (out []byte, err error) {
|
|
// TODO: Add support for anonymous mapping on windows
|
|
if f == nil {
|
|
return make([]byte, length), nil
|
|
}
|
|
|
|
// Open a file mapping handle.
|
|
sizelo := uint32(length >> 32)
|
|
sizehi := uint32(length) & 0xffffffff
|
|
|
|
sharedHandle, errno := openSharedFile(f)
|
|
if errno != nil {
|
|
return nil, os.NewSyscallError("CreateFile", errno)
|
|
}
|
|
|
|
h, errno := syscall.CreateFileMapping(syscall.Handle(sharedHandle.Fd()), nil, syscall.PAGE_READONLY, sizelo, sizehi, nil)
|
|
if h == 0 {
|
|
return nil, os.NewSyscallError("CreateFileMapping", errno)
|
|
}
|
|
|
|
// Create the memory map.
|
|
addr, errno := syscall.MapViewOfFile(h, syscall.FILE_MAP_READ, 0, 0, uintptr(length))
|
|
if addr == 0 {
|
|
return nil, os.NewSyscallError("MapViewOfFile", errno)
|
|
}
|
|
|
|
handleLock.Lock()
|
|
handleMap[addr] = h
|
|
fileMap[addr] = sharedHandle
|
|
handleLock.Unlock()
|
|
|
|
// Convert to a byte array.
|
|
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&out))
|
|
hdr.Data = uintptr(unsafe.Pointer(addr))
|
|
hdr.Len = length
|
|
hdr.Cap = length
|
|
|
|
return
|
|
}
|
|
|
|
// munmap Windows implementation
|
|
// Based on: https://github.com/edsrzf/mmap-go
|
|
// Based on: https://github.com/boltdb/bolt/bolt_windows.go
|
|
func munmap(b []byte) (err error) {
|
|
handleLock.Lock()
|
|
defer handleLock.Unlock()
|
|
|
|
addr := (uintptr)(unsafe.Pointer(&b[0]))
|
|
if err := syscall.UnmapViewOfFile(addr); err != nil {
|
|
return os.NewSyscallError("UnmapViewOfFile", err)
|
|
}
|
|
|
|
handle, ok := handleMap[addr]
|
|
if !ok {
|
|
// should be impossible; we would've seen the error above
|
|
return errors.New("unknown base address")
|
|
}
|
|
delete(handleMap, addr)
|
|
|
|
e := syscall.CloseHandle(syscall.Handle(handle))
|
|
if e != nil {
|
|
return os.NewSyscallError("CloseHandle", e)
|
|
}
|
|
|
|
file, ok := fileMap[addr]
|
|
if !ok {
|
|
// should be impossible; we would've seen the error above
|
|
return errors.New("unknown base address")
|
|
}
|
|
delete(fileMap, addr)
|
|
|
|
e = file.Close()
|
|
if e != nil {
|
|
return errors.New("close file" + e.Error())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// madviseWillNeed is unsupported on Windows.
|
|
func madviseWillNeed(b []byte) error { return nil }
|
|
|
|
// madviseDontNeed is unsupported on Windows.
|
|
func madviseDontNeed(b []byte) error { return nil }
|
|
|
|
func madvise(b []byte, advice int) error {
|
|
// Not implemented
|
|
return nil
|
|
}
|