1package tsm1
2
3import (
4	"errors"
5	"os"
6	"reflect"
7	"sync"
8	"syscall"
9	"unsafe"
10)
11
12// mmap implementation for Windows
13// Based on: https://github.com/edsrzf/mmap-go
14// Based on: https://github.com/boltdb/bolt/bolt_windows.go
15// Ref: https://groups.google.com/forum/#!topic/golang-nuts/g0nLwQI9www
16
17// We keep this map so that we can get back the original handle from the memory address.
18var handleLock sync.Mutex
19var handleMap = map[uintptr]syscall.Handle{}
20var fileMap = map[uintptr]*os.File{}
21
22func openSharedFile(f *os.File) (file *os.File, err error) {
23
24	var access, createmode, sharemode uint32
25	var sa *syscall.SecurityAttributes
26
27	access = syscall.GENERIC_READ
28	sharemode = uint32(syscall.FILE_SHARE_READ | syscall.FILE_SHARE_WRITE | syscall.FILE_SHARE_DELETE)
29	createmode = syscall.OPEN_EXISTING
30	fileName := f.Name()
31
32	pathp, err := syscall.UTF16PtrFromString(fileName)
33	if err != nil {
34		return nil, err
35	}
36
37	h, e := syscall.CreateFile(pathp, access, sharemode, sa, createmode, syscall.FILE_ATTRIBUTE_NORMAL, 0)
38
39	if e != nil {
40		return nil, e
41	}
42	//NewFile does not add finalizer, need to close this manually
43	return os.NewFile(uintptr(h), fileName), nil
44}
45
46func mmap(f *os.File, offset int64, length int) (out []byte, err error) {
47	// TODO: Add support for anonymous mapping on windows
48	if f == nil {
49		return make([]byte, length), nil
50	}
51
52	// Open a file mapping handle.
53	sizelo := uint32(length >> 32)
54	sizehi := uint32(length) & 0xffffffff
55
56	sharedHandle, errno := openSharedFile(f)
57	if errno != nil {
58		return nil, os.NewSyscallError("CreateFile", errno)
59	}
60
61	h, errno := syscall.CreateFileMapping(syscall.Handle(sharedHandle.Fd()), nil, syscall.PAGE_READONLY, sizelo, sizehi, nil)
62	if h == 0 {
63		return nil, os.NewSyscallError("CreateFileMapping", errno)
64	}
65
66	// Create the memory map.
67	addr, errno := syscall.MapViewOfFile(h, syscall.FILE_MAP_READ, 0, 0, uintptr(length))
68	if addr == 0 {
69		return nil, os.NewSyscallError("MapViewOfFile", errno)
70	}
71
72	handleLock.Lock()
73	handleMap[addr] = h
74	fileMap[addr] = sharedHandle
75	handleLock.Unlock()
76
77	// Convert to a byte array.
78	hdr := (*reflect.SliceHeader)(unsafe.Pointer(&out))
79	hdr.Data = uintptr(unsafe.Pointer(addr))
80	hdr.Len = length
81	hdr.Cap = length
82
83	return
84}
85
86// munmap Windows implementation
87// Based on: https://github.com/edsrzf/mmap-go
88// Based on: https://github.com/boltdb/bolt/bolt_windows.go
89func munmap(b []byte) (err error) {
90	handleLock.Lock()
91	defer handleLock.Unlock()
92
93	addr := (uintptr)(unsafe.Pointer(&b[0]))
94	if err := syscall.UnmapViewOfFile(addr); err != nil {
95		return os.NewSyscallError("UnmapViewOfFile", err)
96	}
97
98	handle, ok := handleMap[addr]
99	if !ok {
100		// should be impossible; we would've seen the error above
101		return errors.New("unknown base address")
102	}
103	delete(handleMap, addr)
104
105	e := syscall.CloseHandle(syscall.Handle(handle))
106	if e != nil {
107		return os.NewSyscallError("CloseHandle", e)
108	}
109
110	file, ok := fileMap[addr]
111	if !ok {
112		// should be impossible; we would've seen the error above
113		return errors.New("unknown base address")
114	}
115	delete(fileMap, addr)
116
117	e = file.Close()
118	if e != nil {
119		return errors.New("close file" + e.Error())
120	}
121	return nil
122}
123
124// madviseWillNeed is unsupported on Windows.
125func madviseWillNeed(b []byte) error { return nil }
126
127// madviseDontNeed is unsupported on Windows.
128func madviseDontNeed(b []byte) error { return nil }
129
130func madvise(b []byte, advice int) error {
131	// Not implemented
132	return nil
133}
134