2023-01-17 20:59:04 +00:00
|
|
|
package internal
|
|
|
|
|
2023-04-03 09:16:17 +00:00
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"compress/gzip"
|
|
|
|
"errors"
|
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
)
|
|
|
|
|
|
|
|
// NewBufferedSectionReader wraps an io.ReaderAt in an appropriately-sized
|
|
|
|
// buffered reader. It is a convenience function for reading subsections of
|
|
|
|
// ELF sections while minimizing the amount of read() syscalls made.
|
|
|
|
//
|
|
|
|
// Syscall overhead is non-negligible in continuous integration context
|
|
|
|
// where ELFs might be accessed over virtual filesystems with poor random
|
|
|
|
// access performance. Buffering reads makes sense because (sub)sections
|
|
|
|
// end up being read completely anyway.
|
|
|
|
//
|
|
|
|
// Use instead of the r.Seek() + io.LimitReader() pattern.
|
|
|
|
func NewBufferedSectionReader(ra io.ReaderAt, off, n int64) *bufio.Reader {
|
|
|
|
// Clamp the size of the buffer to one page to avoid slurping large parts
|
|
|
|
// of a file into memory. bufio.NewReader uses a hardcoded default buffer
|
|
|
|
// of 4096. Allow arches with larger pages to allocate more, but don't
|
|
|
|
// allocate a fixed 4k buffer if we only need to read a small segment.
|
|
|
|
buf := n
|
|
|
|
if ps := int64(os.Getpagesize()); n > ps {
|
|
|
|
buf = ps
|
|
|
|
}
|
|
|
|
|
|
|
|
return bufio.NewReaderSize(io.NewSectionReader(ra, off, n), int(buf))
|
|
|
|
}
|
2023-01-17 20:59:04 +00:00
|
|
|
|
|
|
|
// DiscardZeroes makes sure that all written bytes are zero
|
|
|
|
// before discarding them.
|
|
|
|
type DiscardZeroes struct{}
|
|
|
|
|
|
|
|
func (DiscardZeroes) Write(p []byte) (int, error) {
|
|
|
|
for _, b := range p {
|
|
|
|
if b != 0 {
|
|
|
|
return 0, errors.New("encountered non-zero byte")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return len(p), nil
|
|
|
|
}
|
2023-04-03 09:16:17 +00:00
|
|
|
|
|
|
|
// ReadAllCompressed decompresses a gzipped file into memory.
|
|
|
|
func ReadAllCompressed(file string) ([]byte, error) {
|
|
|
|
fh, err := os.Open(file)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer fh.Close()
|
|
|
|
|
|
|
|
gz, err := gzip.NewReader(fh)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer gz.Close()
|
|
|
|
|
|
|
|
return io.ReadAll(gz)
|
|
|
|
}
|