diff options
Diffstat (limited to 'libpod/logs/reversereader/reversereader.go')
-rw-r--r-- | libpod/logs/reversereader/reversereader.go | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/libpod/logs/reversereader/reversereader.go b/libpod/logs/reversereader/reversereader.go new file mode 100644 index 000000000..72d9ad975 --- /dev/null +++ b/libpod/logs/reversereader/reversereader.go @@ -0,0 +1,66 @@ +package reversereader + +import ( + "io" + "os" + + "github.com/pkg/errors" +) + +// ReverseReader structure for reading a file backwards +type ReverseReader struct { + reader *os.File + offset int64 + readSize int64 +} + +// NewReverseReader returns a reader that reads from the end of a file +// rather than the beginning. It sets the readsize to pagesize and determines +// the first offset using using modulus. +func NewReverseReader(reader *os.File) (*ReverseReader, error) { + // pagesize should be safe for memory use and file reads should be on page + // boundaries as well + pageSize := int64(os.Getpagesize()) + stat, err := reader.Stat() + if err != nil { + return nil, err + } + // figure out the last page boundary + remainder := stat.Size() % pageSize + end, err := reader.Seek(0, 2) + if err != nil { + return nil, err + } + // set offset (starting position) to the last page boundary or + // zero if fits in one page + startOffset := end - remainder + if startOffset < 0 { + startOffset = 0 + } + rr := ReverseReader{ + reader: reader, + offset: startOffset, + readSize: pageSize, + } + return &rr, nil +} + +// ReverseReader reads from a given offset to the previous offset and +// then sets the newoff set one pagesize less than the previous read. +func (r *ReverseReader) Read() (string, error) { + if r.offset < 0 { + return "", errors.Wrap(io.EOF, "at beginning of file") + } + // Read from given offset + b := make([]byte, r.readSize) + n, err := r.reader.ReadAt(b, r.offset) + if err != nil && errors.Cause(err) != io.EOF { + return "", err + } + if int64(n) < r.readSize { + b = b[0:n] + } + // Set to the next page boundary + r.offset = -r.readSize + return string(b), nil +} |