github.com/levb/mattermost-server@v5.3.1+incompatible/utils/extract.go (about) 1 // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package utils 5 6 import ( 7 "archive/tar" 8 "compress/gzip" 9 "fmt" 10 "io" 11 "os" 12 "path/filepath" 13 ) 14 15 // ExtractTarGz takes in an io.Reader containing the bytes for a .tar.gz file and 16 // a destination string to extract to. 17 func ExtractTarGz(gzipStream io.Reader, dst string) error { 18 uncompressedStream, err := gzip.NewReader(gzipStream) 19 if err != nil { 20 return fmt.Errorf("ExtractTarGz: NewReader failed: %s", err.Error()) 21 } 22 defer uncompressedStream.Close() 23 24 tarReader := tar.NewReader(uncompressedStream) 25 26 for { 27 header, err := tarReader.Next() 28 29 if err == io.EOF { 30 break 31 } 32 33 if err != nil { 34 return fmt.Errorf("ExtractTarGz: Next() failed: %s", err.Error()) 35 } 36 37 switch header.Typeflag { 38 case tar.TypeDir: 39 if PathTraversesUpward(header.Name) { 40 return fmt.Errorf("ExtractTarGz: path attempts to traverse upwards") 41 } 42 43 path := filepath.Join(dst, header.Name) 44 if err := os.Mkdir(path, 0744); err != nil && !os.IsExist(err) { 45 return fmt.Errorf("ExtractTarGz: Mkdir() failed: %s", err.Error()) 46 } 47 case tar.TypeReg: 48 if PathTraversesUpward(header.Name) { 49 return fmt.Errorf("ExtractTarGz: path attempts to traverse upwards") 50 } 51 52 path := filepath.Join(dst, header.Name) 53 dir := filepath.Dir(path) 54 55 if err := os.MkdirAll(dir, 0744); err != nil { 56 return fmt.Errorf("ExtractTarGz: MkdirAll() failed: %s", err.Error()) 57 } 58 59 outFile, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, os.FileMode(header.Mode)) 60 if err != nil { 61 return fmt.Errorf("ExtractTarGz: Create() failed: %s", err.Error()) 62 } 63 defer outFile.Close() 64 if _, err := io.Copy(outFile, tarReader); err != nil { 65 return fmt.Errorf("ExtractTarGz: Copy() failed: %s", err.Error()) 66 } 67 default: 68 return fmt.Errorf( 69 "ExtractTarGz: unknown type: %v in %v", 70 header.Typeflag, 71 header.Name) 72 } 73 } 74 75 return nil 76 }