github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/tools/zip/unzip.go (about) 1 package unzip 2 3 import ( 4 "archive/zip" 5 "io" 6 "os" 7 "path/filepath" 8 ) 9 10 func Unzip(src, dest string) error { 11 r, err := zip.OpenReader(src) 12 if err != nil { 13 return err 14 } 15 defer func() { 16 if err := r.Close(); err != nil { 17 panic(err) 18 } 19 }() 20 21 if err := os.MkdirAll(dest, 0755); err != nil { 22 return err 23 } 24 25 // Closure to address file descriptors issue with all the deferred .Close() methods 26 extractAndWriteFile := func(f *zip.File) error { 27 rc, err := f.Open() 28 if err != nil { 29 return err 30 } 31 defer func() { 32 if err := rc.Close(); err != nil { 33 panic(err) 34 } 35 }() 36 37 filePath := filepath.Join(dest, f.Name) 38 fileInfo := f.FileInfo() 39 40 if fileInfo.IsDir() { 41 err := os.MkdirAll(filePath, fileInfo.Mode()) 42 if err != nil { 43 return err 44 } 45 } else { 46 err := os.MkdirAll(filepath.Dir(filePath), 0755) 47 if err != nil { 48 return err 49 } 50 51 if fileInfo.Mode()&os.ModeSymlink != 0 { 52 linkName, err := io.ReadAll(rc) 53 if err != nil { 54 return err 55 } 56 return os.Symlink(string(linkName), filePath) 57 } 58 59 fileCopy, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, fileInfo.Mode()) 60 if err != nil { 61 return err 62 } 63 defer fileCopy.Close() 64 65 _, err = io.Copy(fileCopy, rc) 66 if err != nil { 67 return err 68 } 69 } 70 71 return nil 72 } 73 74 for _, f := range r.File { 75 err := extractAndWriteFile(f) 76 if err != nil { 77 return err 78 } 79 } 80 81 return nil 82 }