github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/libpod/logs/reversereader/reversereader.go (about) 1 package reversereader 2 3 import ( 4 "io" 5 "os" 6 7 "github.com/pkg/errors" 8 ) 9 10 // ReverseReader structure for reading a file backwards 11 type ReverseReader struct { 12 reader *os.File 13 offset int64 14 readSize int64 15 } 16 17 // NewReverseReader returns a reader that reads from the end of a file 18 // rather than the beginning. It sets the readsize to pagesize and determines 19 // the first offset using using modulus. 20 func NewReverseReader(reader *os.File) (*ReverseReader, error) { 21 // pagesize should be safe for memory use and file reads should be on page 22 // boundaries as well 23 pageSize := int64(os.Getpagesize()) 24 stat, err := reader.Stat() 25 if err != nil { 26 return nil, err 27 } 28 // figure out the last page boundary 29 remainder := stat.Size() % pageSize 30 end, err := reader.Seek(0, 2) 31 if err != nil { 32 return nil, err 33 } 34 // set offset (starting position) to the last page boundary or 35 // zero if fits in one page 36 startOffset := end - remainder 37 if startOffset < 0 { 38 startOffset = 0 39 } 40 rr := ReverseReader{ 41 reader: reader, 42 offset: startOffset, 43 readSize: pageSize, 44 } 45 return &rr, nil 46 } 47 48 // ReverseReader reads from a given offset to the previous offset and 49 // then sets the newoff set one pagesize less than the previous read. 50 func (r *ReverseReader) Read() (string, error) { 51 if r.offset < 0 { 52 return "", errors.Wrap(io.EOF, "at beginning of file") 53 } 54 // Read from given offset 55 b := make([]byte, r.readSize) 56 n, err := r.reader.ReadAt(b, r.offset) 57 if err != nil && errors.Cause(err) != io.EOF { 58 return "", err 59 } 60 if int64(n) < r.readSize { 61 b = b[0:n] 62 } 63 // Move the offset one pagesize up 64 r.offset -= r.readSize 65 return string(b), nil 66 }