github.com/kyleu/dbaudit@v0.0.2-0.20240321155047-ff2f2c940496/app/lib/filesystem/zip.go (about)

     1  // Package filesystem - Content managed by Project Forge, see [projectforge.md] for details.
     2  package filesystem
     3  
     4  import (
     5  	"archive/zip"
     6  	"io"
     7  	"os"
     8  	"path/filepath"
     9  	"strings"
    10  
    11  	"github.com/pkg/errors"
    12  
    13  	"github.com/kyleu/dbaudit/app/util"
    14  )
    15  
    16  func (f *FileSystem) UnzipToDir(src string, dest string) (*util.OrderedMap[int64], error) {
    17  	r, err := f.FileReader(src)
    18  	if err != nil {
    19  		return nil, err
    20  	}
    21  
    22  	zr, err := zip.NewReader(r, int64(f.Size(src)))
    23  	if err != nil {
    24  		return nil, err
    25  	}
    26  
    27  	err = f.CreateDirectory(dest)
    28  	if err != nil {
    29  		return nil, err
    30  	}
    31  
    32  	extractAndWriteFile := func(zf *zip.File) (int64, error) {
    33  		rc, err := zf.Open()
    34  		if err != nil {
    35  			return 0, err
    36  		}
    37  		defer func() {
    38  			if err := rc.Close(); err != nil {
    39  				panic(err)
    40  			}
    41  		}()
    42  
    43  		path := filepath.Join(dest, zf.Name)
    44  
    45  		if !strings.HasPrefix(path, filepath.Clean(dest)+string(os.PathSeparator)) {
    46  			return 0, errors.Errorf("illegal file path: %s", path)
    47  		}
    48  
    49  		var sz int64
    50  		if zf.FileInfo().IsDir() {
    51  			sz = -1
    52  			_ = f.CreateDirectory(path)
    53  		} else {
    54  			_ = f.CreateDirectory(filepath.Dir(path))
    55  			df, err := f.FileWriter(path, true, false)
    56  			if err != nil {
    57  				return 0, err
    58  			}
    59  			defer func() {
    60  				_ = df.Close()
    61  			}()
    62  			sz, err = io.Copy(df, rc)
    63  			if err != nil {
    64  				return 0, err
    65  			}
    66  		}
    67  		return sz, nil
    68  	}
    69  
    70  	ret := util.NewOrderedMap[int64](false, len(zr.File))
    71  	for _, f := range zr.File {
    72  		fsz, err := extractAndWriteFile(f)
    73  		if err != nil {
    74  			return nil, err
    75  		}
    76  		ret.Append(f.Name, fsz)
    77  	}
    78  	return ret, nil
    79  }