mirror of
https://github.com/restic/restic.git
synced 2026-05-30 22:05:24 +00:00
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:
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user