github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/exp/mmap/mmap_linux.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  )
    16  
    17  // debug is whether to print debugging messages for manual testing.
    18  //
    19  // The runtime.SetFinalizer documentation says that, "The finalizer for x is
    20  // scheduled to run at some arbitrary time after x becomes unreachable. There
    21  // is no guarantee that finalizers will run before a program exits", so we
    22  // cannot automatically test that the finalizer runs. Instead, set this to true
    23  // when running the manual test.
    24  const debug = false
    25  
    26  // ReaderAt reads a memory-mapped file.
    27  //
    28  // Like any io.ReaderAt, clients can execute parallel ReadAt calls, but it is
    29  // not safe to call Close and reading methods concurrently.
    30  type ReaderAt struct {
    31  	data []byte
    32  }
    33  
    34  // Close closes the reader.
    35  func (r *ReaderAt) Close() error {
    36  	if r.data == nil {
    37  		return nil
    38  	}
    39  	data := r.data
    40  	r.data = nil
    41  	if debug {
    42  		var p *byte
    43  		if len(data) != 0 {
    44  			p = &data[0]
    45  		}
    46  		println("munmap", r, p)
    47  	}
    48  	runtime.SetFinalizer(r, nil)
    49  	return syscall.Munmap(data)
    50  }
    51  
    52  // Len returns the length of the underlying memory-mapped file.
    53  func (r *ReaderAt) Len() int {
    54  	return len(r.data)
    55  }
    56  
    57  // At returns the byte at index i.
    58  func (r *ReaderAt) At(i int) byte {
    59  	return r.data[i]
    60  }
    61  
    62  // ReadAt implements the io.ReaderAt interface.
    63  func (r *ReaderAt) ReadAt(p []byte, off int64) (int, error) {
    64  	if r.data == nil {
    65  		return 0, errors.New("mmap: closed")
    66  	}
    67  	if off < 0 || int64(len(r.data)) < off {
    68  		return 0, fmt.Errorf("mmap: invalid ReadAt offset %d", off)
    69  	}
    70  	n := copy(p, r.data[off:])
    71  	if n < len(p) {
    72  		return n, io.EOF
    73  	}
    74  	return n, nil
    75  }
    76  
    77  // Open memory-maps the named file for reading.
    78  func Open(filename string) (*ReaderAt, error) {
    79  	f, err := os.Open(filename)
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  	defer f.Close()
    84  	fi, err := f.Stat()
    85  	if err != nil {
    86  		return nil, err
    87  	}
    88  
    89  	size := fi.Size()
    90  	if size == 0 {
    91  		return &ReaderAt{}, nil
    92  	}
    93  	if size < 0 {
    94  		return nil, fmt.Errorf("mmap: file %q has negative size", filename)
    95  	}
    96  	if size != int64(int(size)) {
    97  		return nil, fmt.Errorf("mmap: file %q is too large", filename)
    98  	}
    99  
   100  	data, err := syscall.Mmap(int(f.Fd()), 0, int(size), syscall.PROT_READ, syscall.MAP_SHARED)
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  	r := &ReaderAt{data}
   105  	if debug {
   106  		var p *byte
   107  		if len(data) != 0 {
   108  			p = &data[0]
   109  		}
   110  		println("mmap", r, p)
   111  	}
   112  	runtime.SetFinalizer(r, (*ReaderAt).Close)
   113  	return r, nil
   114  }