github.com/containers/podman/v4@v4.9.4/libpod/logs/reversereader/reversereader.go (about) 1 package reversereader 2 3 import ( 4 "errors" 5 "fmt" 6 "io" 7 "os" 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 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 "", fmt.Errorf("at beginning of file: %w", io.EOF) 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.Is(err, io.EOF) { 58 return "", err 59 } 60 // Move the offset one pagesize up 61 r.offset -= r.readSize 62 return string(b[:n]), nil 63 }