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  }