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