github.com/kyma-project/kyma/components/asset-store-controller-manager@v0.0.0-20191203152857-3792b5df17c5/internal/loader/package_loader.go (about) 1 package loader 2 3 import ( 4 "archive/tar" 5 "archive/zip" 6 "compress/gzip" 7 "fmt" 8 "io" 9 "io/ioutil" 10 "os" 11 "path/filepath" 12 "regexp" 13 "strings" 14 15 "github.com/pkg/errors" 16 ) 17 18 type matcher interface { 19 MatchString(s string) bool 20 } 21 22 func (l *loader) loadPackage(src, name, filter string) (string, []string, error) { 23 basePath, err := ioutil.TempDir(l.temporaryDir, name) 24 if err != nil { 25 return "", nil, err 26 } 27 28 archiveDir, err := ioutil.TempDir(l.temporaryDir, name) 29 if err != nil { 30 return "", nil, err 31 } 32 defer l.Clean(archiveDir) 33 34 fileName := l.fileName(src) 35 archivePath := filepath.Join(archiveDir, fileName) 36 filterRegexp, err := regexp.Compile(filter) 37 if err != nil { 38 return "", nil, errors.Wrapf(err, "while compiling filter") 39 } 40 41 unpack, err := l.selectEngine(fileName) 42 if err != nil { 43 return "", nil, err 44 } 45 46 if err := l.download(archivePath, src); err != nil { 47 return "", nil, err 48 } 49 50 files, err := unpack(archivePath, basePath, filterRegexp) 51 if err != nil { 52 return "", nil, err 53 } 54 55 return basePath, files, nil 56 } 57 58 func (l *loader) selectEngine(filename string) (func(src, dst string, filter matcher) ([]string, error), error) { 59 extension := strings.ToLower(filepath.Ext(filename)) 60 61 switch { 62 case extension == ".zip": 63 return l.unpackZIP, nil 64 case extension == ".tar" || extension == ".tgz" || strings.HasSuffix(strings.ToLower(filename), ".tar.gz"): 65 return l.unpackTAR, nil 66 } 67 68 return nil, fmt.Errorf("not supported file type %s", extension) 69 } 70 71 func (l *loader) unpackTAR(src, dst string, filter matcher) ([]string, error) { 72 var filenames []string 73 file, err := os.Open(src) 74 if err != nil { 75 return nil, errors.Wrap(err, "while opening archive") 76 } 77 defer file.Close() 78 79 var reader io.Reader 80 extension := strings.ToLower(filepath.Ext(src)) 81 if extension == ".gz" || extension == ".gzip" || extension == ".tgz" { 82 reader, err = gzip.NewReader(file) 83 if err != nil { 84 return nil, errors.Wrap(err, "while creating GZIP reader") 85 } 86 } else { 87 reader = file 88 } 89 90 tarReader := tar.NewReader(reader) 91 92 unpack: 93 for { 94 header, err := tarReader.Next() 95 switch { 96 case err == io.EOF: 97 break unpack 98 case err != nil: 99 return nil, errors.Wrap(err, "while unpacking archive") 100 } 101 102 target := filepath.Join(dst, header.Name) 103 104 switch { 105 case !filter.MatchString(header.Name): 106 continue 107 case header.Typeflag == tar.TypeDir: 108 if err := l.createDir(target); err != nil { 109 return nil, errors.Wrap(err, "while creating directory") 110 } 111 case header.Typeflag == tar.TypeReg: 112 filenames = append(filenames, header.Name) 113 114 if err := l.createFile(tarReader, target, header.Mode); err != nil { 115 return nil, err 116 } 117 } 118 } 119 120 return filenames, nil 121 } 122 123 func (l *loader) unpackZIP(src, dest string, filter matcher) ([]string, error) { 124 var filenames []string 125 126 zipReader, err := zip.OpenReader(src) 127 if err != nil { 128 return nil, errors.Wrap(err, "while opening archive") 129 } 130 defer zipReader.Close() 131 132 for _, file := range zipReader.File { 133 if !filter.MatchString(file.Name) { 134 continue 135 } 136 137 path, isDir, err := l.handleZIPEntry(file, dest) 138 if err != nil { 139 return nil, errors.Wrap(err, "while handling ZIP entry") 140 } 141 142 if !isDir { 143 filenames = append(filenames, path) 144 } 145 } 146 147 return filenames, nil 148 } 149 150 func (l *loader) handleZIPEntry(file *zip.File, dst string) (string, bool, error) { 151 fileReader, err := file.Open() 152 if err != nil { 153 return "", false, err 154 } 155 defer fileReader.Close() 156 157 path := filepath.Join(dst, file.Name) 158 159 if !strings.HasPrefix(path, filepath.Clean(dst)+string(os.PathSeparator)) { 160 return "", false, fmt.Errorf("%s: illegal file path", path) 161 } 162 163 if file.FileInfo().IsDir() { 164 if err := l.createDir(path); err != nil { 165 return "", false, errors.Wrap(err, "while creating directory") 166 } 167 } else { 168 if err := l.createFile(fileReader, path, int64(file.Mode())); err != nil { 169 return "", false, err 170 } 171 } 172 173 return file.Name, file.FileInfo().IsDir(), nil 174 } 175 176 func (l *loader) createFile(src io.Reader, dst string, mode int64) error { 177 if err := l.createDir(filepath.Dir(dst)); err != nil { 178 return errors.Wrap(err, "while creating directory") 179 } 180 181 outFile, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.FileMode(mode)) 182 if err != nil { 183 return errors.Wrap(err, "while opening file") 184 } 185 defer outFile.Close() 186 187 _, err = io.Copy(outFile, src) 188 if err != nil { 189 return errors.Wrap(err, "while copying data to file") 190 } 191 192 return nil 193 } 194 195 func (l *loader) createDir(dst string) error { 196 return os.MkdirAll(dst, os.ModePerm) 197 }