From 0084646504d8e8f6ada8566d3ed0d9c9a98430b3 Mon Sep 17 00:00:00 2001 From: Antonio Navarro Perez Date: Wed, 10 Jun 2020 12:52:36 +0200 Subject: [PATCH] Fix error on Next() when skipping files. With this change, we discard remaining bytes for the actual file to avoid errors on partial reads or skipping files calling Next() without reading. Several optimizations are possible, like directly Seek to the next file without reading the previous one, if the underlying reader supports it. Signed-off-by: Antonio Navarro Perez --- reader.go | 9 +++++++++ reader_test.go | 38 +++++++++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/reader.go b/reader.go index a4ce6c5..2579cb0 100644 --- a/reader.go +++ b/reader.go @@ -6,6 +6,7 @@ import ( "fmt" "hash/crc32" "io" + "io/ioutil" "os" "sync" @@ -346,6 +347,14 @@ func (sz *Reader) next() (*headers.FileInfo, error) { return fileInfo, nil } + if sz.folders[sz.folderIndex].sb != nil { + // Discard remainig bytes for current file. + // TODO: we should check if the underlying reader supports Seek to improve performance when possible. + if _, err := io.Copy(ioutil.Discard, sz.folders[sz.folderIndex].sb); err != nil { + return nil, err + } + } + if sz.folders[sz.folderIndex].Next() == io.EOF { sz.folders[sz.folderIndex].Close() sz.folderIndex++ diff --git a/reader_test.go b/reader_test.go index 50098d5..735988e 100644 --- a/reader_test.go +++ b/reader_test.go @@ -5,7 +5,7 @@ import ( "io/ioutil" "testing" - "github.com/saracen/go7z-fixtures" + fixtures "github.com/saracen/go7z-fixtures" ) func TestOpenReader(t *testing.T) { @@ -75,3 +75,39 @@ func TestReader(t *testing.T) { } } } + +func TestSkipFile(t *testing.T) { + fs, closeall := fixtures.Fixtures([]string{"executable", "random"}, []string{}) + defer closeall.Close() + for _, f := range fs { + sz, err := NewReader(f, f.Size) + if err != nil { + t.Fatalf("error reading %v: %v\n", f.Archive, err) + } + + count := 0 + for { + _, err := sz.Next() + if err == io.EOF { + break + } + if err != nil { + t.Fatal(err) + } + + if count%2 == 0 { + count++ + continue + } + + if _, err = io.Copy(ioutil.Discard, sz); err != nil { + t.Fatal(err) + } + count++ + } + + if count != f.Entries { + t.Fatalf("expected %v entries, got %v\n", f.Entries, count) + } + } +}