1// Copyright 2022 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 5package cov 6 7import ( 8 "cmd/internal/bio" 9 "io" 10 "os" 11) 12 13// This file contains the helper "MReader", a wrapper around bio plus 14// an "mmap'd read-only" view of the file obtained from bio.SliceRO(). 15// MReader is designed to implement the io.ReaderSeeker interface. 16// Since bio.SliceOS() is not guaranteed to succeed, MReader falls back 17// on explicit reads + seeks provided by bio.Reader if needed. 18 19type MReader struct { 20 f *os.File 21 rdr *bio.Reader 22 fileView []byte 23 off int64 24} 25 26func NewMreader(f *os.File) (*MReader, error) { 27 rdr := bio.NewReader(f) 28 fi, err := f.Stat() 29 if err != nil { 30 return nil, err 31 } 32 r := MReader{ 33 f: f, 34 rdr: rdr, 35 fileView: rdr.SliceRO(uint64(fi.Size())), 36 } 37 return &r, nil 38} 39 40func (r *MReader) Read(p []byte) (int, error) { 41 if r.fileView != nil { 42 amt := len(p) 43 toread := r.fileView[r.off:] 44 if len(toread) < 1 { 45 return 0, io.EOF 46 } 47 if len(toread) < amt { 48 amt = len(toread) 49 } 50 copy(p, toread) 51 r.off += int64(amt) 52 return amt, nil 53 } 54 return io.ReadFull(r.rdr, p) 55} 56 57func (r *MReader) ReadByte() (byte, error) { 58 if r.fileView != nil { 59 toread := r.fileView[r.off:] 60 if len(toread) < 1 { 61 return 0, io.EOF 62 } 63 rv := toread[0] 64 r.off++ 65 return rv, nil 66 } 67 return r.rdr.ReadByte() 68} 69 70func (r *MReader) Seek(offset int64, whence int) (int64, error) { 71 if r.fileView == nil { 72 return r.rdr.MustSeek(offset, whence), nil 73 } 74 switch whence { 75 case io.SeekStart: 76 r.off = offset 77 return offset, nil 78 case io.SeekCurrent: 79 return r.off, nil 80 case io.SeekEnd: 81 r.off = int64(len(r.fileView)) + offset 82 return r.off, nil 83 } 84 panic("other modes not implemented") 85} 86