github.com/e154/smart-home@v0.17.2-0.20240311175135-e530a6e5cd45/system/backup/zip.go (about)

     1  // This file is part of the Smart Home
     2  // Program complex distribution https://github.com/e154/smart-home
     3  // Copyright (C) 2016-2023, Filippov Alex
     4  //
     5  // This library is free software: you can redistribute it and/or
     6  // modify it under the terms of the GNU Lesser General Public
     7  // License as published by the Free Software Foundation; either
     8  // version 3 of the License, or (at your option) any later version.
     9  //
    10  // This library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13  // Library General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public
    16  // License along with this library.  If not, see
    17  // <https://www.gnu.org/licenses/>.
    18  
    19  package backup
    20  
    21  import (
    22  	"archive/zip"
    23  	"io"
    24  	"os"
    25  	"path/filepath"
    26  	"strings"
    27  )
    28  
    29  func unzip(archive, target string) error {
    30  	reader, err := zip.OpenReader(archive)
    31  	if err != nil {
    32  		return err
    33  	}
    34  	defer reader.Close()
    35  
    36  	if err := os.MkdirAll(target, 0755); err != nil {
    37  		return err
    38  	}
    39  
    40  	for _, file := range reader.File {
    41  		path := filepath.Join(target, file.Name)
    42  		if file.FileInfo().IsDir() {
    43  			_ = os.MkdirAll(path, file.Mode())
    44  			continue
    45  		}
    46  
    47  		fileReader, err := file.Open()
    48  		if err != nil {
    49  			return err
    50  		}
    51  		defer fileReader.Close()
    52  
    53  		targetFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, file.Mode())
    54  		if err != nil {
    55  			return err
    56  		}
    57  		defer targetFile.Close()
    58  
    59  		if _, err := io.Copy(targetFile, fileReader); err != nil {
    60  			return err
    61  		}
    62  	}
    63  
    64  	return nil
    65  }
    66  
    67  func zipit(sources []string, target string) error {
    68  	zipfile, err := os.Create(target)
    69  	if err != nil {
    70  		return err
    71  	}
    72  	defer zipfile.Close()
    73  
    74  	archive := zip.NewWriter(zipfile)
    75  	defer archive.Close()
    76  
    77  	for _, source := range sources {
    78  		info, err := os.Stat(source)
    79  		if err != nil {
    80  			return nil
    81  		}
    82  
    83  		var baseDir string
    84  		if info.IsDir() {
    85  			baseDir = filepath.Base(source)
    86  		}
    87  
    88  		_ = filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
    89  			if err != nil {
    90  				return err
    91  			}
    92  
    93  			header, err := zip.FileInfoHeader(info)
    94  			if err != nil {
    95  				return err
    96  			}
    97  
    98  			if baseDir != "" {
    99  				header.Name = filepath.Join(baseDir, strings.TrimPrefix(path, source))
   100  			}
   101  
   102  			if info.IsDir() {
   103  				header.Name += string(filepath.Separator)
   104  			} else {
   105  				header.Method = zip.Deflate
   106  			}
   107  
   108  			writer, err := archive.CreateHeader(header)
   109  			if err != nil {
   110  				return err
   111  			}
   112  
   113  			if info.IsDir() {
   114  				return nil
   115  			}
   116  
   117  			file, err := os.Open(path)
   118  			if err != nil {
   119  				return err
   120  			}
   121  			defer file.Close()
   122  			_, err = io.Copy(writer, file)
   123  			return err
   124  		})
   125  
   126  	}
   127  
   128  	return err
   129  }
   130  
   131  func checkZip(archive string) (ok bool, err error) {
   132  	var reader *zip.ReadCloser
   133  	reader, err = zip.OpenReader(archive)
   134  	if err != nil {
   135  		return
   136  	}
   137  	defer reader.Close()
   138  	ok = len(reader.File) > 0
   139  	return
   140  }