| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 | 
							- // Copyright (C) 2015 The Syncthing Authors.
 
- //
 
- // This Source Code Form is subject to the terms of the Mozilla Public
 
- // License, v. 2.0. If a copy of the MPL was not distributed with this file,
 
- // You can obtain one at https://mozilla.org/MPL/2.0/.
 
- package versioner
 
- import (
 
- 	"context"
 
- 	"errors"
 
- 	"fmt"
 
- 	"os"
 
- 	"os/exec"
 
- 	"strings"
 
- 	"time"
 
- 	"github.com/syncthing/syncthing/lib/build"
 
- 	"github.com/syncthing/syncthing/lib/config"
 
- 	"github.com/syncthing/syncthing/lib/fs"
 
- 	"github.com/kballard/go-shellquote"
 
- )
 
- func init() {
 
- 	// Register the constructor for this type of versioner with the name "external"
 
- 	factories["external"] = newExternal
 
- }
 
- type external struct {
 
- 	command    string
 
- 	filesystem fs.Filesystem
 
- }
 
- func newExternal(cfg config.FolderConfiguration) Versioner {
 
- 	command := cfg.Versioning.Params["command"]
 
- 	if build.IsWindows {
 
- 		command = strings.ReplaceAll(command, `\`, `\\`)
 
- 	}
 
- 	s := external{
 
- 		command:    command,
 
- 		filesystem: cfg.Filesystem(),
 
- 	}
 
- 	l.Debugf("instantiated %#v", s)
 
- 	return s
 
- }
 
- // Archive moves the named file away to a version archive. If this function
 
- // returns nil, the named file does not exist any more (has been archived).
 
- func (v external) Archive(filePath string) error {
 
- 	info, err := v.filesystem.Lstat(filePath)
 
- 	if fs.IsNotExist(err) {
 
- 		l.Debugln("not archiving nonexistent file", filePath)
 
- 		return nil
 
- 	} else if err != nil {
 
- 		return err
 
- 	}
 
- 	if info.IsSymlink() {
 
- 		panic("bug: attempting to version a symlink")
 
- 	}
 
- 	l.Debugln("archiving", filePath)
 
- 	if v.command == "" {
 
- 		return errors.New("command is empty, please enter a valid command")
 
- 	}
 
- 	words, err := shellquote.Split(v.command)
 
- 	if err != nil {
 
- 		return fmt.Errorf("command is invalid: %w", err)
 
- 	}
 
- 	context := map[string]string{
 
- 		"%FOLDER_FILESYSTEM%": string(v.filesystem.Type()),
 
- 		"%FOLDER_PATH%":       v.filesystem.URI(),
 
- 		"%FILE_PATH%":         filePath,
 
- 	}
 
- 	for i, word := range words {
 
- 		for key, val := range context {
 
- 			word = strings.ReplaceAll(word, key, val)
 
- 		}
 
- 		words[i] = word
 
- 	}
 
- 	cmd := exec.Command(words[0], words[1:]...)
 
- 	env := os.Environ()
 
- 	// filter STGUIAUTH and STGUIAPIKEY from environment variables
 
- 	var filteredEnv []string
 
- 	for _, x := range env {
 
- 		if !strings.HasPrefix(x, "STGUIAUTH=") && !strings.HasPrefix(x, "STGUIAPIKEY=") {
 
- 			filteredEnv = append(filteredEnv, x)
 
- 		}
 
- 	}
 
- 	cmd.Env = filteredEnv
 
- 	combinedOutput, err := cmd.CombinedOutput()
 
- 	l.Debugln("external command output:", string(combinedOutput))
 
- 	if err != nil {
 
- 		if eerr, ok := err.(*exec.ExitError); ok && len(eerr.Stderr) > 0 {
 
- 			return fmt.Errorf("%v: %v", err, string(eerr.Stderr))
 
- 		}
 
- 		return err
 
- 	}
 
- 	// return error if the file was not removed
 
- 	if _, err = v.filesystem.Lstat(filePath); fs.IsNotExist(err) {
 
- 		return nil
 
- 	}
 
- 	return errors.New("file was not removed by external script")
 
- }
 
- func (external) GetVersions() (map[string][]FileVersion, error) {
 
- 	return nil, ErrRestorationNotSupported
 
- }
 
- func (external) Restore(_ string, _ time.Time) error {
 
- 	return ErrRestorationNotSupported
 
- }
 
- func (external) Clean(_ context.Context) error {
 
- 	return nil
 
- }
 
 
  |