// Copyright (c) 2020 Proton Technologies AG // // This file is part of ProtonMail Bridge. // // ProtonMail Bridge is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // ProtonMail Bridge is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with ProtonMail Bridge. If not, see . package updates import ( "archive/tar" "compress/gzip" "errors" "io" "os" "os/exec" "path/filepath" "runtime" "github.com/sirupsen/logrus" ) func createTar(tarPath, sourcePath string) error { //nolint[unused] if runtime.GOOS != "linux" { return errors.New("tar not implemented only for linux") } // Check whether it exists and is a directory. if _, err := os.Lstat(sourcePath); err != nil { return err } absPath, err := filepath.Abs(tarPath) if err != nil { return err } cmd := exec.Command("tar", "-zvcf", absPath, filepath.Base(sourcePath)) //nolint[gosec] cmd.Dir = filepath.Dir(sourcePath) cmd.Stderr = log.WriterLevel(logrus.ErrorLevel) cmd.Stdout = log.WriterLevel(logrus.InfoLevel) return cmd.Run() } func untarToDir(tarPath, targetDir string, status *Progress) error { //nolint[funlen] // Check whether it exists and is a directory. if ls, err := os.Lstat(targetDir); err == nil { if !ls.IsDir() { return errors.New("not a dir") } } else { return err } tgzReader, err := os.Open(tarPath) //nolint[gosec] if err != nil { return err } defer tgzReader.Close() //nolint[errcheck] size := uint64(0) if info, err := tgzReader.Stat(); err == nil { size = uint64(info.Size()) } wc := &WriteCounter{ Status: status, Size: size, } tarReader, err := gzip.NewReader(io.TeeReader(tgzReader, wc)) if err != nil { return err } fileReader := tar.NewReader(tarReader) for { header, err := fileReader.Next() if err == io.EOF { break } if err != nil { return err } if header == nil { continue } targetFile := filepath.Join(targetDir, header.Name) info := header.FileInfo() // Create symlink. if header.Typeflag == tar.TypeSymlink { if header.Linkname == "" { return errors.New("missing linkname") } if err := os.Symlink(header.Linkname, targetFile); err != nil { return err } continue } // Handle case that it is a directory. if info.IsDir() { if err := os.MkdirAll(targetFile, info.Mode()); err != nil { return err } continue } // Handle case that it is a regular file. if err := copyToFileTruncate(fileReader, targetFile, info.Mode()); err != nil { return err } } return nil }