From f49cb6281202125a6e1166bfa12f1052c08b4dd9 Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Sun, 20 Dec 2015 19:45:36 +0100 Subject: [PATCH] Backup and restore setuid/setgid/sticky bits A user discovered that restic does not restore setuid/setgid/sticky file attributes. This commit fixes that. The mode is stored in the Go format as an uint32: https://golang.org/pkg/os/#FileMode --- node.go | 3 ++- node_test.go | 39 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/node.go b/node.go index 4690f1333..579027b87 100644 --- a/node.go +++ b/node.go @@ -67,10 +67,11 @@ func (node Node) Tree() *Tree { // NodeFromFileInfo returns a new node from the given path and FileInfo. func NodeFromFileInfo(path string, fi os.FileInfo) (*Node, error) { + mask := os.ModePerm | os.ModeType | os.ModeSetuid | os.ModeSetgid | os.ModeSticky node := &Node{ path: path, Name: fi.Name(), - Mode: fi.Mode() & (os.ModePerm | os.ModeType), + Mode: fi.Mode() & mask, ModTime: fi.ModTime(), } diff --git a/node_test.go b/node_test.go index e43354bbc..ffb347e45 100644 --- a/node_test.go +++ b/node_test.go @@ -83,13 +83,46 @@ var nodeTests = []restic.Node{ AccessTime: parseTime("2015-05-14 21:07:24.222"), ChangeTime: parseTime("2015-05-14 21:07:25.333"), }, + restic.Node{ + Name: "testSuidFile", + Type: "file", + Content: []backend.ID{}, + UID: uint32(os.Getuid()), + GID: uint32(os.Getgid()), + Mode: 0755 | os.ModeSetuid, + ModTime: parseTime("2015-05-14 21:07:23.111"), + AccessTime: parseTime("2015-05-14 21:07:24.222"), + ChangeTime: parseTime("2015-05-14 21:07:25.333"), + }, + restic.Node{ + Name: "testSuidFile2", + Type: "file", + Content: []backend.ID{}, + UID: uint32(os.Getuid()), + GID: uint32(os.Getgid()), + Mode: 0755 | os.ModeSetgid, + ModTime: parseTime("2015-05-14 21:07:23.111"), + AccessTime: parseTime("2015-05-14 21:07:24.222"), + ChangeTime: parseTime("2015-05-14 21:07:25.333"), + }, + restic.Node{ + Name: "testSticky", + Type: "file", + Content: []backend.ID{}, + UID: uint32(os.Getuid()), + GID: uint32(os.Getgid()), + Mode: 0755 | os.ModeSticky, + ModTime: parseTime("2015-05-14 21:07:23.111"), + AccessTime: parseTime("2015-05-14 21:07:24.222"), + ChangeTime: parseTime("2015-05-14 21:07:25.333"), + }, restic.Node{ Name: "testDir", Type: "dir", Subtree: nil, UID: uint32(os.Getuid()), GID: uint32(os.Getgid()), - Mode: 020000000750, + Mode: 0750 | os.ModeDir, ModTime: parseTime("2015-05-14 21:07:23.111"), AccessTime: parseTime("2015-05-14 21:07:24.222"), ChangeTime: parseTime("2015-05-14 21:07:25.333"), @@ -100,7 +133,7 @@ var nodeTests = []restic.Node{ LinkTarget: "invalid", UID: uint32(os.Getuid()), GID: uint32(os.Getgid()), - Mode: 01000000777, + Mode: 0777 | os.ModeSymlink, ModTime: parseTime("2015-05-14 21:07:23.111"), AccessTime: parseTime("2015-05-14 21:07:24.222"), ChangeTime: parseTime("2015-05-14 21:07:25.333"), @@ -150,7 +183,7 @@ func TestNodeRestoreAt(t *testing.T) { "%v: GID doesn't match (%v != %v)", test.Type, test.GID, n2.GID) if test.Type != "symlink" { Assert(t, test.Mode == n2.Mode, - "%v: mode doesn't match (%v != %v)", test.Type, test.Mode, n2.Mode) + "%v: mode doesn't match (0%o != 0%o)", test.Type, test.Mode, n2.Mode) } }