github.com/remind101/go-getter@v0.0.0-20180809191950-4bda8fa99001/decompress_zip.go (about)

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