github.com/LanceLRQ/deer-common@v0.0.9-0.20210319081233-e8222ac018a8/persistence/problems/pack_zip.go (about)

     1  package problems
     2  
     3  import (
     4  	"archive/zip"
     5  	"github.com/LanceLRQ/deer-common/persistence"
     6  	"github.com/pkg/errors"
     7  	"io"
     8  	"os"
     9  	"path"
    10  	"path/filepath"
    11  	"strings"
    12  )
    13  
    14  func packZipFile(rootPath string, targetPath string) error {
    15  	fout, err := os.Create(targetPath)
    16  	if err != nil {
    17  		return errors.Errorf("create problem package file error: %s", err.Error())
    18  	}
    19  	defer fout.Close()
    20  
    21  	zipWriter := zip.NewWriter(fout)
    22  	defer zipWriter.Close()
    23  
    24  	err = filepath.Walk(rootPath, func(path string, info os.FileInfo, err error) error {
    25  		if err != nil {
    26  			return err
    27  		}
    28  
    29  		header, err := zip.FileInfoHeader(info)
    30  		if err != nil {
    31  			return err
    32  		}
    33  
    34  		header.Name = strings.TrimPrefix(path, rootPath+"/")
    35  
    36  		// 排除根目录
    37  		if header.Name == rootPath {
    38  			return nil
    39  		}
    40  		if info.IsDir() {
    41  			header.Name += "/"
    42  		} else {
    43  			header.Method = zip.Deflate
    44  		}
    45  		// 排除bin目录
    46  		if strings.HasPrefix(header.Name, "bin/") {
    47  			return nil
    48  		}
    49  
    50  		writer, err := zipWriter.CreateHeader(header)
    51  		if err != nil {
    52  			return err
    53  		}
    54  
    55  		if !info.IsDir() {
    56  			file, err := os.Open(path)
    57  			if err != nil {
    58  				return err
    59  			}
    60  			defer file.Close()
    61  			_, err = io.Copy(writer, file)
    62  		}
    63  		return err
    64  	})
    65  
    66  	return err
    67  }
    68  
    69  // 执行题目数据表打包操作(打包成zip版本)
    70  func PackProblemsAsZip(options *persistence.ProblemPackageOptions) error {
    71  	// 这边没法支持所有内容的校验了,只能给config签名。
    72  	if options.DigitalSign {
    73  		if options.DigitalPEM.PublicKey == nil || options.DigitalPEM.PrivateKey == nil {
    74  			return errors.Errorf("digital sign need public key and private key")
    75  		}
    76  	}
    77  
    78  	pubkeyFileName := path.Join(options.ConfigDir, ".gpg")
    79  	signFileName := path.Join(options.ConfigDir, ".sign")
    80  
    81  	// clean meta file
    82  	if _, err := os.Stat(pubkeyFileName); os.IsExist(err) {
    83  		_ = os.Remove(pubkeyFileName)
    84  	}
    85  	if _, err := os.Stat(signFileName); os.IsExist(err) {
    86  		_ = os.Remove(signFileName)
    87  	}
    88  
    89  	defer func() {
    90  		_ = os.Remove(pubkeyFileName)
    91  		_ = os.Remove(signFileName)
    92  	}()
    93  
    94  	// Cretea Public Key
    95  	if options.DigitalSign {
    96  		gpgFile, err := os.Create(pubkeyFileName)
    97  		if err != nil {
    98  			return err
    99  		}
   100  		if _, err = gpgFile.Write(options.DigitalPEM.PublicKeyRaw); err != nil {
   101  			return err
   102  		}
   103  		_ = gpgFile.Close()
   104  	}
   105  
   106  	// Create Signature (only for configFile)
   107  	fBody, err := os.Open(options.ConfigFile)
   108  	if err != nil {
   109  		return err
   110  	}
   111  
   112  	hash, err := persistence.SHA256Streams([]io.Reader{fBody})
   113  
   114  	// GPG signature
   115  	if options.DigitalSign {
   116  		hash, err = persistence.RSA2048Sign(hash, options.DigitalPEM.PrivateKey)
   117  		if err != nil {
   118  			return err
   119  		}
   120  	}
   121  
   122  	// Write to .sign file
   123  	signFile, err := os.Create(signFileName)
   124  	if err != nil {
   125  		return err
   126  	}
   127  	if _, err = signFile.Write(hash); err != nil {
   128  		return err
   129  	}
   130  	_ = signFile.Close()
   131  
   132  	// Package Zip
   133  	err = packZipFile(options.ConfigDir, options.OutFile)
   134  
   135  	return err
   136  }