vss: Implement VSS support for Windows

The VSS support works for 32 and 64-bit windows, this includes a check that
the restic version matches the OS architecture as required by VSS. The backup
operation will fail the user has not sufficient permissions to use VSS.

Snapshotting volumes also covers mountpoints but skips UNC paths.
This commit is contained in:
fgma
2020-10-24 11:35:57 +02:00
committed by Michael Eischer
parent 5fd3dbccb7
commit 5695f9ebd2
10 changed files with 1373 additions and 2 deletions
+24
View File
@@ -10,6 +10,7 @@ import (
"os"
"path"
"path/filepath"
"runtime"
"strconv"
"strings"
"time"
@@ -96,6 +97,7 @@ type BackupOptions struct {
TimeStamp string
WithAtime bool
IgnoreInode bool
UseFsSnapshot bool
}
var backupOptions BackupOptions
@@ -129,6 +131,9 @@ func init() {
f.StringVar(&backupOptions.TimeStamp, "time", "", "`time` of the backup (ex. '2012-11-01 22:08:41') (default: now)")
f.BoolVar(&backupOptions.WithAtime, "with-atime", false, "store the atime for all files and directories")
f.BoolVar(&backupOptions.IgnoreInode, "ignore-inode", false, "ignore inode number changes when checking for modified files")
if runtime.GOOS == "windows" {
f.BoolVar(&backupOptions.UseFsSnapshot, "use-fs-snapshot", false, "use filesystem snapshot where possible (currently only Windows VSS)")
}
}
// filterExisting returns a slice of all existing items, or an error if no
@@ -550,6 +555,25 @@ func runBackup(opts BackupOptions, gopts GlobalOptions, term *termstatus.Termina
}
var targetFS fs.FS = fs.Local{}
if runtime.GOOS == "windows" && opts.UseFsSnapshot {
if !fs.HasSufficientPrivilegesForVSS() {
return errors.Fatal("user doesn't have sufficient privileges to use VSS snapshots\n")
}
errorHandler := func(item string, err error) error {
return p.Error(item, nil, err)
}
messageHandler := func(msg string, args ...interface{}) {
if !gopts.JSON {
p.P(msg, args...)
}
}
localVss := fs.NewLocalVss(errorHandler, messageHandler)
defer localVss.DeleteSnapshots()
targetFS = localVss
}
if opts.Stdin {
if !gopts.JSON {
p.V("read data from stdin")
+12 -1
View File
@@ -21,6 +21,7 @@ import (
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/filter"
"github.com/restic/restic/internal/fs"
"github.com/restic/restic/internal/repository"
"github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test"
@@ -281,11 +282,21 @@ func testSetupBackupData(t testing.TB, env *testEnvironment) string {
}
func TestBackup(t *testing.T) {
testBackup(t, false)
}
func TestBackupWithFilesystemSnapshots(t *testing.T) {
if runtime.GOOS == "windows" && fs.HasSufficientPrivilegesForVSS() {
testBackup(t, true)
}
}
func testBackup(t *testing.T, useFsSnapshot bool) {
env, cleanup := withTestEnvironment(t)
defer cleanup()
testSetupBackupData(t, env)
opts := BackupOptions{}
opts := BackupOptions{UseFsSnapshot: useFsSnapshot}
// first backup
testRunBackup(t, filepath.Dir(env.testdata), []string{"testdata"}, opts, env.gopts)