From 4f0f038e0bfc54b4eb58b4958ec5661be5c1677f Mon Sep 17 00:00:00 2001 From: Jesse Hallam Date: Tue, 25 May 2021 22:00:57 -0300 Subject: [PATCH] MM-35945: handle lots of files in ExtractTarGz (#17669) * MM-35945: handle lots of files in ExtractTarGz `ExtractTarGz` can fail on archives with a largish number or files, complaining about too many open file handles. Clean up as we go to avoid this. Fixes: https://mattermost.atlassian.net/browse/MM-35945 * use closure to allow defer --- app/extract_plugin_tar.go | 18 +++++++++++++----- app/extract_plugin_tar_test.go | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/app/extract_plugin_tar.go b/app/extract_plugin_tar.go index b81a4552cb..65c8646a7e 100644 --- a/app/extract_plugin_tar.go +++ b/app/extract_plugin_tar.go @@ -68,12 +68,20 @@ func extractTarGz(gzipStream io.Reader, dst string) error { return err } - outFile, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, os.FileMode(header.Mode)) - if err != nil { - return err + copyFile := func() error { + outFile, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, os.FileMode(header.Mode)) + if err != nil { + return err + } + defer outFile.Close() + if _, err := io.Copy(outFile, tarReader); err != nil { + return err + } + + return nil } - defer outFile.Close() - if _, err := io.Copy(outFile, tarReader); err != nil { + + if err := copyFile(); err != nil { return err } } diff --git a/app/extract_plugin_tar_test.go b/app/extract_plugin_tar_test.go index 8fba0ef4d7..3cacff7272 100644 --- a/app/extract_plugin_tar_test.go +++ b/app/extract_plugin_tar_test.go @@ -72,6 +72,24 @@ func TestExtractTarGz(t *testing.T) { require.Error(t, err) }) + t.Run("huge tar", func(t *testing.T) { + files := make([]*tar.Header, 0, 10000) + for i := 0; i < 10000; i++ { + files = append(files, &tar.Header{ + Name: fmt.Sprintf("%d.txt", i), + Typeflag: tar.TypeReg, + }) + } + + dst, err := ioutil.TempDir("", "TestExtractTarGz") + require.NoError(t, err) + defer os.RemoveAll(dst) + + archive := makeArchive(t, files) + err = extractTarGz(&archive, dst) + require.NoError(t, err) + }) + testCases := []struct { Files []*tar.Header ExpectedError bool