src/archive/zip/reader.go | 11 ++++++++++- src/archive/zip/reader_test.go | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/src/archive/zip/reader.go b/src/archive/zip/reader.go index 6b57f767fc849d7cd47428fb566f5a922a874aab..b2a4ed6042d5d579bd819093662144d6b13ab6d5 100644 --- a/src/archive/zip/reader.go +++ b/src/archive/zip/reader.go @@ -834,7 +834,16 @@ r.fileList[idx].isDup = true continue } - for dir := path.Dir(name); dir != "."; dir = path.Dir(dir) { + dir := name + for { + if idx := strings.LastIndex(dir, "/"); idx < 0 { + break + } else { + dir = dir[:idx] + } + if dirs[dir] { + break + } dirs[dir] = true } diff --git a/src/archive/zip/reader_test.go b/src/archive/zip/reader_test.go index 410b2d037e44d5671fdb6b35de9a3e1fa61cfbc8..4b1122269e007d7ab67c4b8de82db2af51c0310b 100644 --- a/src/archive/zip/reader_test.go +++ b/src/archive/zip/reader_test.go @@ -9,6 +9,7 @@ "bytes" "encoding/binary" "encoding/hex" "errors" + "fmt" "internal/obscuretestdata" "io" "io/fs" @@ -1876,3 +1877,83 @@ // an io.SectionReader which would access a slice at a negative offset // as the section reader offset & size were < 0. NewReader(bytes.NewReader(data), int64(len(data))+1875) } + +func BenchmarkReaderOneDeepDir(b *testing.B) { + var buf bytes.Buffer + zw := NewWriter(&buf) + + for i := range 4000 { + name := strings.Repeat("a/", i) + "data" + zw.CreateHeader(&FileHeader{ + Name: name, + Method: Store, + }) + } + + if err := zw.Close(); err != nil { + b.Fatal(err) + } + data := buf.Bytes() + + for b.Loop() { + zr, err := NewReader(bytes.NewReader(data), int64(len(data))) + if err != nil { + b.Fatal(err) + } + zr.Open("does-not-exist") + } +} + +func BenchmarkReaderManyDeepDirs(b *testing.B) { + var buf bytes.Buffer + zw := NewWriter(&buf) + + for i := range 2850 { + name := fmt.Sprintf("%x", i) + name = strings.Repeat("/"+name, i+1)[1:] + + zw.CreateHeader(&FileHeader{ + Name: name, + Method: Store, + }) + } + + if err := zw.Close(); err != nil { + b.Fatal(err) + } + data := buf.Bytes() + + for b.Loop() { + zr, err := NewReader(bytes.NewReader(data), int64(len(data))) + if err != nil { + b.Fatal(err) + } + zr.Open("does-not-exist") + } +} + +func BenchmarkReaderManyShallowFiles(b *testing.B) { + var buf bytes.Buffer + zw := NewWriter(&buf) + + for i := range 310000 { + name := fmt.Sprintf("%v", i) + zw.CreateHeader(&FileHeader{ + Name: name, + Method: Store, + }) + } + + if err := zw.Close(); err != nil { + b.Fatal(err) + } + data := buf.Bytes() + + for b.Loop() { + zr, err := NewReader(bytes.NewReader(data), int64(len(data))) + if err != nil { + b.Fatal(err) + } + zr.Open("does-not-exist") + } +}