io.go 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. package internal
  2. import (
  3. "bufio"
  4. "compress/gzip"
  5. "errors"
  6. "io"
  7. "os"
  8. )
  9. // NewBufferedSectionReader wraps an io.ReaderAt in an appropriately-sized
  10. // buffered reader. It is a convenience function for reading subsections of
  11. // ELF sections while minimizing the amount of read() syscalls made.
  12. //
  13. // Syscall overhead is non-negligible in continuous integration context
  14. // where ELFs might be accessed over virtual filesystems with poor random
  15. // access performance. Buffering reads makes sense because (sub)sections
  16. // end up being read completely anyway.
  17. //
  18. // Use instead of the r.Seek() + io.LimitReader() pattern.
  19. func NewBufferedSectionReader(ra io.ReaderAt, off, n int64) *bufio.Reader {
  20. // Clamp the size of the buffer to one page to avoid slurping large parts
  21. // of a file into memory. bufio.NewReader uses a hardcoded default buffer
  22. // of 4096. Allow arches with larger pages to allocate more, but don't
  23. // allocate a fixed 4k buffer if we only need to read a small segment.
  24. buf := n
  25. if ps := int64(os.Getpagesize()); n > ps {
  26. buf = ps
  27. }
  28. return bufio.NewReaderSize(io.NewSectionReader(ra, off, n), int(buf))
  29. }
  30. // DiscardZeroes makes sure that all written bytes are zero
  31. // before discarding them.
  32. type DiscardZeroes struct{}
  33. func (DiscardZeroes) Write(p []byte) (int, error) {
  34. for _, b := range p {
  35. if b != 0 {
  36. return 0, errors.New("encountered non-zero byte")
  37. }
  38. }
  39. return len(p), nil
  40. }
  41. // ReadAllCompressed decompresses a gzipped file into memory.
  42. func ReadAllCompressed(file string) ([]byte, error) {
  43. fh, err := os.Open(file)
  44. if err != nil {
  45. return nil, err
  46. }
  47. defer fh.Close()
  48. gz, err := gzip.NewReader(fh)
  49. if err != nil {
  50. return nil, err
  51. }
  52. defer gz.Close()
  53. return io.ReadAll(gz)
  54. }