github.com/remind101/go-getter@v0.0.0-20180809191950-4bda8fa99001/decompress_zip.go (about) 1 package getter 2 3 import ( 4 "archive/zip" 5 "fmt" 6 "io" 7 "os" 8 "path/filepath" 9 ) 10 11 // ZipDecompressor is an implementation of Decompressor that can 12 // decompress tar.gzip files. 13 type ZipDecompressor struct{} 14 15 func (d *ZipDecompressor) Decompress(dst, src string, dir bool) error { 16 // If we're going into a directory we should make that first 17 mkdir := dst 18 if !dir { 19 mkdir = filepath.Dir(dst) 20 } 21 if err := os.MkdirAll(mkdir, 0755); err != nil { 22 return err 23 } 24 25 // Open the zip 26 zipR, err := zip.OpenReader(src) 27 if err != nil { 28 return err 29 } 30 defer zipR.Close() 31 32 // Check the zip integrity 33 if len(zipR.File) == 0 { 34 // Empty archive 35 return fmt.Errorf("empty archive: %s", src) 36 } 37 if !dir && len(zipR.File) > 1 { 38 return fmt.Errorf("expected a single file: %s", src) 39 } 40 41 // Go through and unarchive 42 for _, f := range zipR.File { 43 path := dst 44 if dir { 45 // Disallow parent traversal 46 if containsDotDot(f.Name) { 47 return fmt.Errorf("entry contains '..': %s", f.Name) 48 } 49 50 path = filepath.Join(path, f.Name) 51 } 52 53 if f.FileInfo().IsDir() { 54 if !dir { 55 return fmt.Errorf("expected a single file: %s", src) 56 } 57 58 // A directory, just make the directory and continue unarchiving... 59 if err := os.MkdirAll(path, 0755); err != nil { 60 return err 61 } 62 63 continue 64 } 65 66 // Create the enclosing directories if we must. ZIP files aren't 67 // required to contain entries for just the directories so this 68 // can happen. 69 if dir { 70 if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { 71 return err 72 } 73 } 74 75 // Open the file for reading 76 srcF, err := f.Open() 77 if err != nil { 78 return err 79 } 80 81 // Open the file for writing 82 dstF, err := os.Create(path) 83 if err != nil { 84 srcF.Close() 85 return err 86 } 87 _, err = io.Copy(dstF, srcF) 88 srcF.Close() 89 dstF.Close() 90 if err != nil { 91 return err 92 } 93 94 // Chmod the file 95 if err := os.Chmod(path, f.Mode()); err != nil { 96 return err 97 } 98 } 99 100 return nil 101 }