This commit is contained in:
Jim Minter 2026-04-01 06:32:08 -07:00 committed by GitHub
commit 3934f7bc90
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 113 additions and 0 deletions

View file

@ -85,6 +85,7 @@ type BackupOptions struct {
ExcludeCaches bool
ExcludeLargerThan string
ExcludeCloudFiles bool
ExcludeNoDump bool
Stdin bool
StdinFilename string
StdinCommand bool
@ -143,6 +144,9 @@ func (opts *BackupOptions) AddFlags(f *pflag.FlagSet) {
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
f.BoolVar(&opts.ExcludeCloudFiles, "exclude-cloud-files", false, "excludes online-only cloud files (such as OneDrive, iCloud drive, …)")
}
if runtime.GOOS == "linux" {
f.BoolVar(&opts.ExcludeNoDump, "exclude-no-dump", false, "excludes directories and files marked with the `no dump` attribute)")
}
f.BoolVar(&opts.SkipIfUnchanged, "skip-if-unchanged", false, "skip snapshot creation if identical to parent snapshot")
// parse read concurrency from env, on error the default value will be used
@ -380,6 +384,14 @@ func collectRejectFuncs(opts BackupOptions, targets []string, fs fs.FS, warnf fu
funcs = append(funcs, f)
}
if opts.ExcludeNoDump {
f, err := archiver.RejectByNoDump(warnf)
if err != nil {
return nil, err
}
funcs = append(funcs, f)
}
return funcs, nil
}

View file

@ -0,0 +1,19 @@
//go:build linux
package archiver
import (
"golang.org/x/sys/unix"
)
// isNoDump returns whether the "no dump" Linux file attribute is set on path.
// See CHATTR(1) for more information about Linux file attributes.
func isNoDump(path string) (bool, error) {
statx := &unix.Statx_t{}
if err := unix.Statx(0, path, unix.AT_NO_AUTOMOUNT|unix.AT_SYMLINK_NOFOLLOW, 0, statx); err != nil {
return false, err
}
return statx.Attributes&unix.STATX_ATTR_NODUMP != 0, nil
}

View file

@ -0,0 +1,9 @@
//go:build !linux
package archiver
// isNoDump returns whether the "no dump" Linux file attribute is set on path.
// See CHATTR(1) for more information about Linux file attributes.
func isNoDump(path string) (bool, error) {
return false, nil
}

View file

@ -334,3 +334,16 @@ func RejectCloudFiles(warnf func(msg string, args ...interface{})) (RejectFunc,
return false
}, nil
}
// RejectByNoDump returns a func which on Linux rejects files with the "no dump"
// Linux file attribute is set. On other OSes it rejects no files.
func RejectByNoDump(warnf func(string, ...any)) (RejectFunc, error) {
return func(item string, _ *fs.ExtendedFileInfo, _ fs.FS) bool {
rv, err := isNoDump(item)
if err != nil {
warnf("item %v: error getting attributes: %v", item, err)
}
return rv
}, nil
}

View file

@ -0,0 +1,60 @@
//go:build linux
package archiver
import (
"os"
"testing"
"golang.org/x/sys/unix"
"github.com/restic/restic/internal/test"
)
func TestRejectByNoDump(t *testing.T) {
tempDir := test.TempDir(t)
items := []struct {
path string
dir bool
noDump bool
}{
{"/no-dump", true, true},
{"/normal", true, false},
{"/normal/no-dump", false, true},
{"/normal/normal", false, false},
}
for _, item := range items {
if item.dir {
test.OK(t, os.Mkdir(tempDir+item.path, 0700))
} else {
test.OK(t, os.WriteFile(tempDir+item.path, nil, 0600))
}
if item.noDump {
test.OK(t, setNoDump(tempDir+item.path))
}
}
reject, err := RejectByNoDump(nil)
test.OK(t, err)
for _, item := range items {
rejected := reject(tempDir+item.path, nil, nil)
if rejected != item.noDump {
t.Errorf("inclusion status of %s is wrong: want %v, got %v", item.path, item.noDump, rejected)
}
}
}
// setNoDump sets the "no dump" Linux file attribute on path (file or directory).
func setNoDump(path string) error {
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close()
return unix.IoctlSetPointerInt(int(f.Fd()), unix.FS_IOC_SETFLAGS, 0x40 /* FS_NODUMP_FL */)
}