1// +build windows,!appengine
2
3package maxminddb
4
5// Windows support largely borrowed from mmap-go.
6//
7// Copyright 2011 Evan Shaw. All rights reserved.
8// Use of this source code is governed by a BSD-style
9// license that can be found in the LICENSE file.
10
11import (
12	"errors"
13	"os"
14	"reflect"
15	"sync"
16	"unsafe"
17
18	"github.com/ooni/psiphon/oopsi/golang.org/x/sys/windows"
19)
20
21type memoryMap []byte
22
23// Windows
24var handleLock sync.Mutex
25var handleMap = map[uintptr]windows.Handle{}
26
27func mmap(fd int, length int) (data []byte, err error) {
28	h, errno := windows.CreateFileMapping(windows.Handle(fd), nil,
29		uint32(windows.PAGE_READONLY), 0, uint32(length), nil)
30	if h == 0 {
31		return nil, os.NewSyscallError("CreateFileMapping", errno)
32	}
33
34	addr, errno := windows.MapViewOfFile(h, uint32(windows.FILE_MAP_READ), 0,
35		0, uintptr(length))
36	if addr == 0 {
37		return nil, os.NewSyscallError("MapViewOfFile", errno)
38	}
39	handleLock.Lock()
40	handleMap[addr] = h
41	handleLock.Unlock()
42
43	m := memoryMap{}
44	dh := m.header()
45	dh.Data = addr
46	dh.Len = length
47	dh.Cap = dh.Len
48
49	return m, nil
50}
51
52func (m *memoryMap) header() *reflect.SliceHeader {
53	return (*reflect.SliceHeader)(unsafe.Pointer(m))
54}
55
56func flush(addr, len uintptr) error {
57	errno := windows.FlushViewOfFile(addr, len)
58	return os.NewSyscallError("FlushViewOfFile", errno)
59}
60
61func munmap(b []byte) (err error) {
62	m := memoryMap(b)
63	dh := m.header()
64
65	addr := dh.Data
66	length := uintptr(dh.Len)
67
68	flush(addr, length)
69	err = windows.UnmapViewOfFile(addr)
70	if err != nil {
71		return err
72	}
73
74	handleLock.Lock()
75	defer handleLock.Unlock()
76	handle, ok := handleMap[addr]
77	if !ok {
78		// should be impossible; we would've errored above
79		return errors.New("unknown base address")
80	}
81	delete(handleMap, addr)
82
83	e := windows.CloseHandle(windows.Handle(handle))
84	return os.NewSyscallError("CloseHandle", e)
85}
86