github.com/ungtb10d/cli/v2@v2.0.0-20221110210412-98537dd9d6a1/pkg/cmd/run/download/zip.go (about) 1 package download 2 3 import ( 4 "archive/zip" 5 "fmt" 6 "io" 7 "os" 8 "path/filepath" 9 "strings" 10 ) 11 12 const ( 13 dirMode os.FileMode = 0755 14 fileMode os.FileMode = 0644 15 execMode os.FileMode = 0755 16 ) 17 18 func extractZip(zr *zip.Reader, destDir string) error { 19 for _, zf := range zr.File { 20 fpath := filepath.Join(destDir, filepath.FromSlash(zf.Name)) 21 if !filepathDescendsFrom(fpath, destDir) { 22 continue 23 } 24 if err := extractZipFile(zf, fpath); err != nil { 25 return fmt.Errorf("error extracting %q: %w", zf.Name, err) 26 } 27 } 28 return nil 29 } 30 31 func extractZipFile(zf *zip.File, dest string) error { 32 zm := zf.Mode() 33 if zm.IsDir() { 34 return os.MkdirAll(dest, dirMode) 35 } 36 37 f, err := zf.Open() 38 if err != nil { 39 return err 40 } 41 defer f.Close() 42 43 if dir := filepath.Dir(dest); dir != "." { 44 if err := os.MkdirAll(dir, dirMode); err != nil { 45 return err 46 } 47 } 48 49 df, err := os.OpenFile(dest, os.O_WRONLY|os.O_CREATE|os.O_EXCL, getPerm(zm)) 50 if err != nil { 51 return err 52 } 53 defer df.Close() 54 55 _, err = io.Copy(df, f) 56 return err 57 } 58 59 func getPerm(m os.FileMode) os.FileMode { 60 if m&0111 == 0 { 61 return fileMode 62 } 63 return execMode 64 } 65 66 func filepathDescendsFrom(p, dir string) bool { 67 p = filepath.Clean(p) 68 dir = filepath.Clean(dir) 69 if dir == "." && !filepath.IsAbs(p) { 70 return !strings.HasPrefix(p, ".."+string(filepath.Separator)) 71 } 72 if !strings.HasSuffix(dir, string(filepath.Separator)) { 73 dir += string(filepath.Separator) 74 } 75 return strings.HasPrefix(p, dir) 76 }