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  }