33
44package maxminddb
55
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-
336import (
347 "errors"
358 "os"
36- "sync"
379 "unsafe"
3810
3911 "golang.org/x/sys/windows"
4012)
4113
42- // Windows
43- var (
44- handleLock sync.Mutex
45- handleMap = map [uintptr ]windows.Handle {}
46- )
47-
4814// mmap maps a file into memory and returns a byte slice.
4915func mmap (fd int , length int ) ([]byte , error ) {
5016 // Create a file mapping
@@ -53,74 +19,54 @@ func mmap(fd int, length int) ([]byte, error) {
5319 nil ,
5420 windows .PAGE_READONLY ,
5521 0 ,
56- uint32 ( length ) ,
22+ 0 ,
5723 nil ,
5824 )
5925 if err != nil {
6026 return nil , os .NewSyscallError ("CreateFileMapping" , err )
6127 }
28+ defer windows .CloseHandle (handle )
6229
6330 // Map the file into memory
64- addr , err := windows .MapViewOfFile (
31+ addrUintptr , err := windows .MapViewOfFile (
6532 handle ,
6633 windows .FILE_MAP_READ ,
6734 0 ,
6835 0 ,
69- uintptr ( length ) ,
36+ 0 ,
7037 )
7138 if err != nil {
72- windows .CloseHandle (handle )
7339 return nil , os .NewSyscallError ("MapViewOfFile" , err )
7440 }
7541
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 )
9049 }
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
9259}
9360
9461// munmap unmaps a memory-mapped file and releases associated resources.
9562func munmap (b []byte ) error {
9663 // Convert slice to base address and length
9764 data := unsafe .SliceData (b )
9865 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- }
10566
10667 // Unmap the memory
10768 if err := windows .UnmapViewOfFile (addr ); err != nil {
10869 return os .NewSyscallError ("UnmapViewOfFile" , err )
10970 }
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- }
12571 return nil
12672}
0 commit comments