mirror of
https://github.com/octoleo/restic.git
synced 2024-11-27 07:16:40 +00:00
fs: Refactor UtimesNano replacements
Previously, nodeRestoreTimestamps would do something like if node.Type == restic.NodeTypeSymlink { return nodeRestoreSymlinkTimestamps(...) } return syscall.UtimesNano(...) where nodeRestoreSymlinkTimestamps was either a no-op or a reimplementation of syscall.UtimesNano that handles symlinks, with some repeated converting between timestamp types. The Linux implementation was a bit clumsy, requiring three syscalls to set the timestamps. In this new setup, there is a function utimesNano that has three implementations: * on Linux, it's a modified syscall.UtimesNano that uses AT_SYMLINK_NOFOLLOW and AT_FDCWD so it can handle any type in a single call; * on other Unix platforms, it just calls the syscall function after skipping symlinks; * on Windows, it's the modified UtimesNano that was previously called nodeRestoreSymlinkTimestamps, except with different arguments.
This commit is contained in:
parent
f967a33ccc
commit
8f20d5dcd5
@ -292,18 +292,11 @@ func nodeRestoreMetadata(node *restic.Node, path string, warn func(msg string))
|
|||||||
}
|
}
|
||||||
|
|
||||||
func nodeRestoreTimestamps(node *restic.Node, path string) error {
|
func nodeRestoreTimestamps(node *restic.Node, path string) error {
|
||||||
var utimes = [...]syscall.Timespec{
|
atime := node.AccessTime.UnixNano()
|
||||||
syscall.NsecToTimespec(node.AccessTime.UnixNano()),
|
mtime := node.ModTime.UnixNano()
|
||||||
syscall.NsecToTimespec(node.ModTime.UnixNano()),
|
|
||||||
}
|
|
||||||
|
|
||||||
if node.Type == restic.NodeTypeSymlink {
|
if err := utimesNano(fixpath(path), atime, mtime, node.Type); err != nil {
|
||||||
return nodeRestoreSymlinkTimestamps(path, utimes)
|
return &os.PathError{Op: "UtimesNano", Path: path, Err: err}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := syscall.UtimesNano(fixpath(path), utimes[:]); err != nil {
|
|
||||||
return errors.Wrap(err, "UtimesNano")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -3,15 +3,7 @@
|
|||||||
|
|
||||||
package fs
|
package fs
|
||||||
|
|
||||||
import (
|
import "github.com/restic/restic/internal/restic"
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/restic/restic/internal/restic"
|
|
||||||
)
|
|
||||||
|
|
||||||
func nodeRestoreSymlinkTimestamps(_ string, _ [2]syscall.Timespec) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// nodeRestoreExtendedAttributes is a no-op on AIX.
|
// nodeRestoreExtendedAttributes is a no-op on AIX.
|
||||||
func nodeRestoreExtendedAttributes(_ *restic.Node, _ string) error {
|
func nodeRestoreExtendedAttributes(_ *restic.Node, _ string) error {
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
package fs
|
|
||||||
|
|
||||||
import "syscall"
|
|
||||||
|
|
||||||
func nodeRestoreSymlinkTimestamps(path string, utimes [2]syscall.Timespec) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,18 +1,15 @@
|
|||||||
package fs
|
package fs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"syscall"
|
"github.com/restic/restic/internal/restic"
|
||||||
|
|
||||||
"github.com/restic/restic/internal/errors"
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
func nodeRestoreSymlinkTimestamps(path string, utimes [2]syscall.Timespec) error {
|
// utimesNano is like syscall.UtimesNano, except that it does not follow symlinks.
|
||||||
|
func utimesNano(path string, atime, mtime int64, _ restic.NodeType) error {
|
||||||
times := []unix.Timespec{
|
times := []unix.Timespec{
|
||||||
{Sec: utimes[0].Sec, Nsec: utimes[0].Nsec},
|
unix.NsecToTimespec(atime),
|
||||||
{Sec: utimes[1].Sec, Nsec: utimes[1].Nsec},
|
unix.NsecToTimespec(mtime),
|
||||||
}
|
}
|
||||||
|
return unix.UtimesNanoAt(unix.AT_FDCWD, path, times, unix.AT_SYMLINK_NOFOLLOW)
|
||||||
err := unix.UtimesNanoAt(unix.AT_FDCWD, path, times, unix.AT_SYMLINK_NOFOLLOW)
|
|
||||||
return errors.Wrap(err, "UtimesNanoAt")
|
|
||||||
}
|
}
|
||||||
|
19
internal/fs/node_linux_test.go
Normal file
19
internal/fs/node_linux_test.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package fs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/fs"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/restic/restic/internal/errors"
|
||||||
|
"github.com/restic/restic/internal/restic"
|
||||||
|
rtest "github.com/restic/restic/internal/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRestoreSymlinkTimestampsError(t *testing.T) {
|
||||||
|
d := t.TempDir()
|
||||||
|
node := restic.Node{Type: restic.NodeTypeSymlink}
|
||||||
|
err := nodeRestoreTimestamps(&node, d+"/nosuchfile")
|
||||||
|
rtest.Assert(t, errors.Is(err, fs.ErrNotExist), "want ErrNotExist, got %q", err)
|
||||||
|
rtest.Assert(t, strings.Contains(err.Error(), d), "filename not in %q", err)
|
||||||
|
}
|
@ -1,14 +1,6 @@
|
|||||||
package fs
|
package fs
|
||||||
|
|
||||||
import (
|
import "github.com/restic/restic/internal/restic"
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/restic/restic/internal/restic"
|
|
||||||
)
|
|
||||||
|
|
||||||
func nodeRestoreSymlinkTimestamps(_ string, _ [2]syscall.Timespec) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// nodeRestoreExtendedAttributes is a no-op on netbsd.
|
// nodeRestoreExtendedAttributes is a no-op on netbsd.
|
||||||
func nodeRestoreExtendedAttributes(_ *restic.Node, _ string) error {
|
func nodeRestoreExtendedAttributes(_ *restic.Node, _ string) error {
|
||||||
|
@ -1,14 +1,6 @@
|
|||||||
package fs
|
package fs
|
||||||
|
|
||||||
import (
|
import "github.com/restic/restic/internal/restic"
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/restic/restic/internal/restic"
|
|
||||||
)
|
|
||||||
|
|
||||||
func nodeRestoreSymlinkTimestamps(_ string, _ [2]syscall.Timespec) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// nodeRestoreExtendedAttributes is a no-op on openbsd.
|
// nodeRestoreExtendedAttributes is a no-op on openbsd.
|
||||||
func nodeRestoreExtendedAttributes(_ *restic.Node, _ string) error {
|
func nodeRestoreExtendedAttributes(_ *restic.Node, _ string) error {
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
package fs
|
|
||||||
|
|
||||||
import "syscall"
|
|
||||||
|
|
||||||
func nodeRestoreSymlinkTimestamps(path string, utimes [2]syscall.Timespec) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
21
internal/fs/node_unix_notlinux.go
Normal file
21
internal/fs/node_unix_notlinux.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
//go:build !linux && unix
|
||||||
|
|
||||||
|
package fs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/restic/restic/internal/restic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// utimesNano is like syscall.UtimesNano, except that it skips symlinks.
|
||||||
|
func utimesNano(path string, atime, mtime int64, typ restic.NodeType) error {
|
||||||
|
if typ == restic.NodeTypeSymlink {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return syscall.UtimesNano(path, []syscall.Timespec{
|
||||||
|
syscall.NsecToTimespec(atime),
|
||||||
|
syscall.NsecToTimespec(mtime),
|
||||||
|
})
|
||||||
|
}
|
@ -42,8 +42,8 @@ func lchown(_ string, _ int, _ int) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// restoreSymlinkTimestamps restores timestamps for symlinks
|
// utimesNano is like syscall.UtimesNano, except that it sets FILE_FLAG_OPEN_REPARSE_POINT.
|
||||||
func nodeRestoreSymlinkTimestamps(path string, utimes [2]syscall.Timespec) error {
|
func utimesNano(path string, atime, mtime int64, _ restic.NodeType) error {
|
||||||
// tweaked version of UtimesNano from go/src/syscall/syscall_windows.go
|
// tweaked version of UtimesNano from go/src/syscall/syscall_windows.go
|
||||||
pathp, e := syscall.UTF16PtrFromString(fixpath(path))
|
pathp, e := syscall.UTF16PtrFromString(fixpath(path))
|
||||||
if e != nil {
|
if e != nil {
|
||||||
@ -63,8 +63,8 @@ func nodeRestoreSymlinkTimestamps(path string, utimes [2]syscall.Timespec) error
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
a := syscall.NsecToFiletime(syscall.TimespecToNsec(utimes[0]))
|
a := syscall.NsecToFiletime(atime)
|
||||||
w := syscall.NsecToFiletime(syscall.TimespecToNsec(utimes[1]))
|
w := syscall.NsecToFiletime(mtime)
|
||||||
return syscall.SetFileTime(h, nil, &a, &w)
|
return syscall.SetFileTime(h, nil, &a, &w)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user