3
3
4
4
package maxminddb
5
5
6
- // Windows support largely borrowed from mmap-go.
7
- //
8
- // Copyright (c) 2011, Evan Shaw <[email protected] >
9
- // All rights reserved.
10
-
11
- // Redistribution and use in source and binary forms, with or without
12
- // modification, are permitted provided that the following conditions are met:
13
- // * Redistributions of source code must retain the above copyright
14
- // notice, this list of conditions and the following disclaimer.
15
- // * Redistributions in binary form must reproduce the above copyright
16
- // notice, this list of conditions and the following disclaimer in the
17
- // documentation and/or other materials provided with the distribution.
18
- // * Neither the name of the copyright holder nor the
19
- // names of its contributors may be used to endorse or promote products
20
- // derived from this software without specific prior written permission.
21
-
22
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
23
- // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24
- // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25
- // DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
26
- // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27
- // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28
- // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29
- // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31
- // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
-
33
6
import (
34
7
"errors"
35
8
"os"
36
- "sync"
37
9
"unsafe"
38
10
39
11
"golang.org/x/sys/windows"
40
12
)
41
13
42
- // Windows
43
- var (
44
- handleLock sync.Mutex
45
- handleMap = map [uintptr ]windows.Handle {}
46
- )
47
-
48
14
// mmap maps a file into memory and returns a byte slice.
49
15
func mmap (fd int , length int ) ([]byte , error ) {
50
16
// Create a file mapping
@@ -53,74 +19,54 @@ func mmap(fd int, length int) ([]byte, error) {
53
19
nil ,
54
20
windows .PAGE_READONLY ,
55
21
0 ,
56
- uint32 ( length ) ,
22
+ 0 ,
57
23
nil ,
58
24
)
59
25
if err != nil {
60
26
return nil , os .NewSyscallError ("CreateFileMapping" , err )
61
27
}
28
+ defer windows .CloseHandle (handle )
62
29
63
30
// Map the file into memory
64
- addr , err := windows .MapViewOfFile (
31
+ addrUintptr , err := windows .MapViewOfFile (
65
32
handle ,
66
33
windows .FILE_MAP_READ ,
67
34
0 ,
68
35
0 ,
69
- uintptr ( length ) ,
36
+ 0 ,
70
37
)
71
38
if err != nil {
72
- windows .CloseHandle (handle )
73
39
return nil , os .NewSyscallError ("MapViewOfFile" , err )
74
40
}
75
41
76
- // Store the handle in the map
77
- handleLock .Lock ()
78
- handleMap [addr ] = handle
79
- handleLock .Unlock ()
80
-
81
- data := unsafe .Slice ((* byte )(unsafe .Pointer (addr )), length )
82
- return data , nil
83
- }
84
-
85
- // flush ensures changes to a memory-mapped region are written to disk.
86
- func flush (addr , length uintptr ) error {
87
- err := windows .FlushViewOfFile (addr , length )
88
- if err != nil {
89
- return os .NewSyscallError ("FlushViewOfFile" , err )
42
+ // When there's not enough address space for the whole file (e.g. large
43
+ // files on 32-bit systems), MapViewOfFile may return a partial mapping.
44
+ // Query the region size and fail on partial mappings.
45
+ var info windows.MemoryBasicInformation
46
+ if err := windows .VirtualQuery (addrUintptr , & info , unsafe .Sizeof (info )); err != nil {
47
+ _ = windows .UnmapViewOfFile (addrUintptr )
48
+ return nil , os .NewSyscallError ("VirtualQuery" , err )
90
49
}
91
- return nil
50
+ if info .RegionSize < uintptr (length ) {
51
+ _ = windows .UnmapViewOfFile (addrUintptr )
52
+ return nil , errors .New ("file too large" )
53
+ }
54
+
55
+ // Workaround for unsafeptr check in go vet, see
56
+ // https://github.com/golang/go/issues/58625
57
+ addr := * (* unsafe .Pointer )(unsafe .Pointer (& addrUintptr ))
58
+ return unsafe .Slice ((* byte )(addr ), length ), nil
92
59
}
93
60
94
61
// munmap unmaps a memory-mapped file and releases associated resources.
95
62
func munmap (b []byte ) error {
96
63
// Convert slice to base address and length
97
64
data := unsafe .SliceData (b )
98
65
addr := uintptr (unsafe .Pointer (data ))
99
- length := uintptr (len (b ))
100
-
101
- // Flush the memory region
102
- if err := flush (addr , length ); err != nil {
103
- return err
104
- }
105
66
106
67
// Unmap the memory
107
68
if err := windows .UnmapViewOfFile (addr ); err != nil {
108
69
return os .NewSyscallError ("UnmapViewOfFile" , err )
109
70
}
110
-
111
- // Remove the handle from the map and close it
112
- handleLock .Lock ()
113
- defer handleLock .Unlock ()
114
-
115
- handle , ok := handleMap [addr ]
116
- if ! ok {
117
- // should be impossible; we would've errored above
118
- return errors .New ("unknown base address" )
119
- }
120
- delete (handleMap , addr )
121
-
122
- if err := windows .CloseHandle (handle ); err != nil {
123
- return os .NewSyscallError ("CloseHandle" , err )
124
- }
125
71
return nil
126
72
}
0 commit comments