github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/exp/mmap/mmap_windows.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package mmap provides a way to memory-map a file. 6 package mmap 7 8 import ( 9 "errors" 10 "fmt" 11 "io" 12 "os" 13 "runtime" 14 "syscall" 15 "unsafe" 16 ) 17 18 // debug is whether to print debugging messages for manual testing. 19 // 20 // The runtime.SetFinalizer documentation says that, "The finalizer for x is 21 // scheduled to run at some arbitrary time after x becomes unreachable. There 22 // is no guarantee that finalizers will run before a program exits", so we 23 // cannot automatically test that the finalizer runs. Instead, set this to true 24 // when running the manual test. 25 const debug = false 26 27 // ReaderAt reads a memory-mapped file. 28 // 29 // Like any io.ReaderAt, clients can execute parallel ReadAt calls, but it is 30 // not safe to call Close and reading methods concurrently. 31 type ReaderAt struct { 32 data []byte 33 } 34 35 // Close closes the reader. 36 func (r *ReaderAt) Close() error { 37 if r.data == nil { 38 return nil 39 } 40 data := r.data 41 r.data = nil 42 if debug { 43 var p *byte 44 if len(data) != 0 { 45 p = &data[0] 46 } 47 println("munmap", r, p) 48 } 49 runtime.SetFinalizer(r, nil) 50 return syscall.UnmapViewOfFile(uintptr(unsafe.Pointer(&data[0]))) 51 } 52 53 // Len returns the length of the underlying memory-mapped file. 54 func (r *ReaderAt) Len() int { 55 return len(r.data) 56 } 57 58 // At returns the byte at index i. 59 func (r *ReaderAt) At(i int) byte { 60 return r.data[i] 61 } 62 63 // ReadAt implements the io.ReaderAt interface. 64 func (r *ReaderAt) ReadAt(p []byte, off int64) (int, error) { 65 if r.data == nil { 66 return 0, errors.New("mmap: closed") 67 } 68 if off < 0 || int64(len(r.data)) < off { 69 return 0, fmt.Errorf("mmap: invalid ReadAt offset %d", off) 70 } 71 n := copy(p, r.data[off:]) 72 if n < len(p) { 73 return n, io.EOF 74 } 75 return n, nil 76 } 77 78 // Open memory-maps the named file for reading. 79 func Open(filename string) (*ReaderAt, error) { 80 f, err := os.Open(filename) 81 if err != nil { 82 return nil, err 83 } 84 defer f.Close() 85 fi, err := f.Stat() 86 if err != nil { 87 return nil, err 88 } 89 90 size := fi.Size() 91 if size == 0 { 92 return &ReaderAt{}, nil 93 } 94 if size < 0 { 95 return nil, fmt.Errorf("mmap: file %q has negative size", filename) 96 } 97 if size != int64(int(size)) { 98 return nil, fmt.Errorf("mmap: file %q is too large", filename) 99 } 100 101 low, high := uint32(size), uint32(size>>32) 102 fmap, err := syscall.CreateFileMapping(syscall.Handle(f.Fd()), nil, syscall.PAGE_READONLY, high, low, nil) 103 if err != nil { 104 return nil, err 105 } 106 defer syscall.CloseHandle(fmap) 107 ptr, err := syscall.MapViewOfFile(fmap, syscall.FILE_MAP_READ, 0, 0, uintptr(size)) 108 if err != nil { 109 return nil, err 110 } 111 data := (*[1 << 30]byte)(unsafe.Pointer(ptr))[:size] 112 113 r := &ReaderAt{data: data} 114 if debug { 115 var p *byte 116 if len(data) != 0 { 117 p = &data[0] 118 } 119 println("mmap", r, p) 120 } 121 runtime.SetFinalizer(r, (*ReaderAt).Close) 122 return r, nil 123 }