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