1// Copyright (C) 2014 The Syncthing Authors.
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this file,
5// You can obtain one at https://mozilla.org/MPL/2.0/.
6
7package versioner
8
9import (
10	"context"
11	"strconv"
12	"time"
13
14	"github.com/syncthing/syncthing/lib/config"
15	"github.com/syncthing/syncthing/lib/fs"
16)
17
18func init() {
19	// Register the constructor for this type of versioner with the name "simple"
20	factories["simple"] = newSimple
21}
22
23type simple struct {
24	keep            int
25	cleanoutDays    int
26	folderFs        fs.Filesystem
27	versionsFs      fs.Filesystem
28	copyRangeMethod fs.CopyRangeMethod
29}
30
31func newSimple(cfg config.FolderConfiguration) Versioner {
32	var keep, err = strconv.Atoi(cfg.Versioning.Params["keep"])
33	cleanoutDays, _ := strconv.Atoi(cfg.Versioning.Params["cleanoutDays"])
34	// On error we default to 0, "do not clean out the trash can"
35
36	if err != nil {
37		keep = 5 // A reasonable default
38	}
39
40	s := simple{
41		keep:            keep,
42		cleanoutDays:    cleanoutDays,
43		folderFs:        cfg.Filesystem(),
44		versionsFs:      versionerFsFromFolderCfg(cfg),
45		copyRangeMethod: cfg.CopyRangeMethod,
46	}
47
48	l.Debugf("instantiated %#v", s)
49	return s
50}
51
52// Archive moves the named file away to a version archive. If this function
53// returns nil, the named file does not exist any more (has been archived).
54func (v simple) Archive(filePath string) error {
55	err := archiveFile(v.copyRangeMethod, v.folderFs, v.versionsFs, filePath, TagFilename)
56	if err != nil {
57		return err
58	}
59
60	// Versions are sorted by timestamp in the file name, oldest first.
61	versions := findAllVersions(v.versionsFs, filePath)
62	if len(versions) > v.keep {
63		for _, toRemove := range versions[:len(versions)-v.keep] {
64			l.Debugln("cleaning out", toRemove)
65			err = v.versionsFs.Remove(toRemove)
66			if err != nil {
67				l.Warnln("removing old version:", err)
68			}
69		}
70	}
71
72	return nil
73}
74
75func (v simple) GetVersions() (map[string][]FileVersion, error) {
76	return retrieveVersions(v.versionsFs)
77}
78
79func (v simple) Restore(filepath string, versionTime time.Time) error {
80	return restoreFile(v.copyRangeMethod, v.versionsFs, v.folderFs, filepath, versionTime, TagFilename)
81}
82
83func (v simple) Clean(ctx context.Context) error {
84	return cleanByDay(ctx, v.versionsFs, v.cleanoutDays)
85}
86