@@ -5,8 +5,11 @@ import (
5
5
"bytes"
6
6
"errors"
7
7
"fmt"
8
+ "io"
8
9
"net/netip"
10
+ "os"
9
11
"reflect"
12
+ "runtime"
10
13
)
11
14
12
15
const dataSectionSeparatorSize = 16
@@ -45,6 +48,70 @@ type Metadata struct {
45
48
RecordSize uint `maxminddb:"record_size"`
46
49
}
47
50
51
+ // Open takes a string path to a MaxMind DB file and returns a Reader
52
+ // structure or an error. The database file is opened using a memory map
53
+ // on supported platforms. On platforms without memory map support, such
54
+ // as WebAssembly or Google App Engine, the database is loaded into memory.
55
+ // Use the Close method on the Reader object to return the resources to the system.
56
+ func Open (file string ) (* Reader , error ) {
57
+ mapFile , err := os .Open (file )
58
+ if err != nil {
59
+ return nil , err
60
+ }
61
+ defer mapFile .Close ()
62
+
63
+ stats , err := mapFile .Stat ()
64
+ if err != nil {
65
+ return nil , err
66
+ }
67
+
68
+ size64 := stats .Size ()
69
+ size := int (size64 )
70
+ if int64 (size ) != size64 {
71
+ return nil , errors .New ("file too large" )
72
+ }
73
+
74
+ data , err := mmap (int (mapFile .Fd ()), size )
75
+ if err != nil {
76
+ if errors .Is (err , errors .ErrUnsupported ) {
77
+ data , err = openFallback (mapFile , size )
78
+ if err != nil {
79
+ return nil , err
80
+ }
81
+ return FromBytes (data )
82
+ }
83
+ return nil , err
84
+ }
85
+
86
+ reader , err := FromBytes (data )
87
+ if err != nil {
88
+ _ = munmap (data )
89
+ return nil , err
90
+ }
91
+
92
+ reader .hasMappedFile = true
93
+ runtime .SetFinalizer (reader , (* Reader ).Close )
94
+ return reader , nil
95
+ }
96
+
97
+ func openFallback (f * os.File , size int ) (data []byte , err error ) {
98
+ data = make ([]byte , size )
99
+ _ , err = io .ReadFull (f , data )
100
+ return data , err
101
+ }
102
+
103
+ // Close returns the resources used by the database to the system.
104
+ func (r * Reader ) Close () error {
105
+ var err error
106
+ if r .hasMappedFile {
107
+ runtime .SetFinalizer (r , nil )
108
+ r .hasMappedFile = false
109
+ err = munmap (r .buffer )
110
+ }
111
+ r .buffer = nil
112
+ return err
113
+ }
114
+
48
115
// FromBytes takes a byte slice corresponding to a MaxMind DB file and returns
49
116
// a Reader structure or an error.
50
117
func FromBytes (buffer []byte ) (* Reader , error ) {
0 commit comments