diff --git a/archiver.go b/archiver.go index 7e68f30d..f89410e2 100644 --- a/archiver.go +++ b/archiver.go @@ -264,6 +264,26 @@ func isSymlink(info fs.FileInfo) bool { return info.Mode()&os.ModeSymlink != 0 } +// streamSizeBySeeking determines the size of the stream by +// seeking to the end, then back again, so the resulting +// seek position upon returning is the same as when called +// (assuming no errors). +func streamSizeBySeeking(s io.Seeker) (int64, error) { + currentPosition, err := s.Seek(0, io.SeekCurrent) + if err != nil { + return 0, fmt.Errorf("getting current offset: %w", err) + } + maxPosition, err := s.Seek(0, io.SeekEnd) + if err != nil { + return 0, fmt.Errorf("fast-forwarding to end: %w", err) + } + _, err = s.Seek(currentPosition, io.SeekStart) + if err != nil { + return 0, fmt.Errorf("returning to prior offset %d: %w", currentPosition, err) + } + return maxPosition, nil +} + // skipList keeps a list of non-intersecting paths // as long as its add method is used. Identical // elements are rejected, more specific paths are diff --git a/fs.go b/fs.go index 560727b5..a2c7510a 100644 --- a/fs.go +++ b/fs.go @@ -98,14 +98,10 @@ func FileSystem(ctx context.Context, filename string, stream ReaderAtSeeker) (fs // determine size -- we know that the stream value we get back from // Identify is the same type as what we input because it is a Seeker - size, err := stream.Seek(0, io.SeekEnd) + size, err := streamSizeBySeeking(stream) if err != nil { return nil, fmt.Errorf("seeking for size: %w", err) } - _, err = stream.Seek(0, io.SeekStart) - if err != nil { - return nil, fmt.Errorf("seeking back to beginning: %w", err) - } sr := io.NewSectionReader(stream, 0, size) diff --git a/zip.go b/zip.go index c012c080..73361d8b 100644 --- a/zip.go +++ b/zip.go @@ -337,22 +337,6 @@ type seekReaderAt interface { io.Seeker } -func streamSizeBySeeking(s io.Seeker) (int64, error) { - currentPosition, err := s.Seek(0, io.SeekCurrent) - if err != nil { - return 0, fmt.Errorf("getting current offset: %w", err) - } - maxPosition, err := s.Seek(0, io.SeekEnd) - if err != nil { - return 0, fmt.Errorf("fast-forwarding to end: %w", err) - } - _, err = s.Seek(currentPosition, io.SeekStart) - if err != nil { - return 0, fmt.Errorf("returning to prior offset %d: %w", currentPosition, err) - } - return maxPosition, nil -} - // Additional compression methods not offered by archive/zip. // See https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT section 4.4.5. const (