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:
greatroar
2024-10-04 10:06:18 +02:00
parent f967a33ccc
commit 8f20d5dcd5
10 changed files with 57 additions and 65 deletions

View File

@@ -292,18 +292,11 @@ func nodeRestoreMetadata(node *restic.Node, path string, warn func(msg string))
}
func nodeRestoreTimestamps(node *restic.Node, path string) error {
var utimes = [...]syscall.Timespec{
syscall.NsecToTimespec(node.AccessTime.UnixNano()),
syscall.NsecToTimespec(node.ModTime.UnixNano()),
}
atime := node.AccessTime.UnixNano()
mtime := node.ModTime.UnixNano()
if node.Type == restic.NodeTypeSymlink {
return nodeRestoreSymlinkTimestamps(path, utimes)
if err := utimesNano(fixpath(path), atime, mtime, node.Type); err != nil {
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
}