...
1
2
3
4
5
6 package mmap
7
8 import (
9 "errors"
10 "fmt"
11 "io"
12 "os"
13 "runtime"
14 "syscall"
15 "unsafe"
16 )
17
18
19
20
21
22
23
24
25 const debug = false
26
27
28
29
30
31 type ReaderAt struct {
32 data []byte
33 }
34
35
36 func (r *ReaderAt) Close() error {
37 if r.data == nil {
38 return nil
39 } else if len(r.data) == 0 {
40 r.data = nil
41 return nil
42 }
43 data := r.data
44 r.data = nil
45 if debug {
46 var p *byte
47 if len(data) != 0 {
48 p = &data[0]
49 }
50 println("munmap", r, p)
51 }
52 runtime.SetFinalizer(r, nil)
53 return syscall.UnmapViewOfFile(uintptr(unsafe.Pointer(&data[0])))
54 }
55
56
57 func (r *ReaderAt) Len() int {
58 return len(r.data)
59 }
60
61
62 func (r *ReaderAt) At(i int) byte {
63 return r.data[i]
64 }
65
66
67 func (r *ReaderAt) ReadAt(p []byte, off int64) (int, error) {
68 if r.data == nil {
69 return 0, errors.New("mmap: closed")
70 }
71 if off < 0 || int64(len(r.data)) < off {
72 return 0, fmt.Errorf("mmap: invalid ReadAt offset %d", off)
73 }
74 n := copy(p, r.data[off:])
75 if n < len(p) {
76 return n, io.EOF
77 }
78 return n, nil
79 }
80
81
82 func Open(filename string) (*ReaderAt, error) {
83 f, err := os.Open(filename)
84 if err != nil {
85 return nil, err
86 }
87 defer f.Close()
88 fi, err := f.Stat()
89 if err != nil {
90 return nil, err
91 }
92
93 size := fi.Size()
94 if size == 0 {
95
96
97
98
99
100 return &ReaderAt{
101 data: make([]byte, 0),
102 }, nil
103 }
104 if size < 0 {
105 return nil, fmt.Errorf("mmap: file %q has negative size", filename)
106 }
107 if size != int64(int(size)) {
108 return nil, fmt.Errorf("mmap: file %q is too large", filename)
109 }
110
111 low, high := uint32(size), uint32(size>>32)
112 fmap, err := syscall.CreateFileMapping(syscall.Handle(f.Fd()), nil, syscall.PAGE_READONLY, high, low, nil)
113 if err != nil {
114 return nil, err
115 }
116 defer syscall.CloseHandle(fmap)
117 ptr, err := syscall.MapViewOfFile(fmap, syscall.FILE_MAP_READ, 0, 0, uintptr(size))
118 if err != nil {
119 return nil, err
120 }
121 data := unsafe.Slice((*byte)(unsafe.Pointer(ptr)), size)
122
123 r := &ReaderAt{data: data}
124 if debug {
125 var p *byte
126 if len(data) != 0 {
127 p = &data[0]
128 }
129 println("mmap", r, p)
130 }
131 runtime.SetFinalizer(r, (*ReaderAt).Close)
132 return r, nil
133 }
134
View as plain text