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

     1  // This file is part of the Smart Home
     2  // Program complex distribution https://github.com/e154/smart-home
     3  // Copyright (C) 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  	"fmt"
    23  	"io"
    24  	"os"
    25  	"path"
    26  	"path/filepath"
    27  	"sort"
    28  	"strings"
    29  
    30  	"github.com/pkg/errors"
    31  )
    32  
    33  func splitFile(inputPath string, chunkSize int64) ([]string, error) {
    34  	inputFile, err := os.Open(inputPath)
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  	defer inputFile.Close()
    39  
    40  	chunkSize = 1024 * 1024 * chunkSize
    41  
    42  	fileInfo, err := os.Stat(inputPath)
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  
    47  	fileSize := fileInfo.Size()
    48  	numChunks := (fileSize + chunkSize - 1) / chunkSize
    49  
    50  	tmpDir := path.Join(os.TempDir(), "smart_home")
    51  	if err = os.MkdirAll(tmpDir, 0755); err != nil {
    52  		return nil, err
    53  	}
    54  
    55  	var fileList []string
    56  	fileName := strings.ReplaceAll(fileInfo.Name(), ".zip", "")
    57  	for i := int64(0); i < numChunks; i++ {
    58  		outputPath := fmt.Sprintf("%s_part%d.dat", fileName, i+1)
    59  		outputPath = path.Join(tmpDir, outputPath)
    60  
    61  		// Создаем новый файл для части
    62  		outputFile, err := os.Create(outputPath)
    63  		if err != nil {
    64  			return nil, err
    65  		}
    66  		defer outputFile.Close()
    67  
    68  		// Читаем кусок данных из исходного файла
    69  		bufferSize := chunkSize
    70  		if i == numChunks-1 {
    71  			bufferSize = fileSize - i*chunkSize
    72  		}
    73  
    74  		buffer := make([]byte, bufferSize)
    75  		_, err = inputFile.Read(buffer)
    76  		if err != nil && err != io.EOF {
    77  			return nil, err
    78  		}
    79  
    80  		// Записываем кусок в новый файл
    81  		_, err = outputFile.Write(buffer)
    82  		if err != nil {
    83  			return nil, err
    84  		}
    85  
    86  		fileList = append(fileList, outputPath)
    87  	}
    88  
    89  	return fileList, nil
    90  }
    91  
    92  func joinFiles(inputPattern, dir string) (string, error) {
    93  
    94  	matches, err := filepath.Glob(inputPattern)
    95  	if err != nil {
    96  		return "", err
    97  	}
    98  
    99  	if len(matches) == 0 || len(matches) == 1 {
   100  		return "", errors.New("no matches or less then 2")
   101  	}
   102  
   103  	sort.Strings(matches)
   104  
   105  	fmt.Println(matches)
   106  
   107  	params := strings.Split(matches[0], "_part")
   108  	if len(params) < 2 {
   109  		return "", err
   110  	}
   111  
   112  	fileName := path.Join(dir, filepath.Base(fmt.Sprintf("%s.zip", params[0])))
   113  	outputFile, err := os.Create(fileName)
   114  	if err != nil {
   115  		return "", err
   116  	}
   117  	defer outputFile.Close()
   118  
   119  	for _, match := range matches {
   120  		inputFile, err := os.Open(match)
   121  		if err != nil {
   122  			return "", err
   123  		}
   124  		defer inputFile.Close()
   125  
   126  		_, err = io.Copy(outputFile, inputFile)
   127  		if err != nil {
   128  			return "", err
   129  		}
   130  	}
   131  
   132  	return fileName, nil
   133  }