2
2
mirror of https://github.com/octoleo/restic.git synced 2024-11-22 21:05:10 +00:00

Merge pull request #2212 from cbane/check-ctime

Examine file ctime when checking if files have changed.
This commit is contained in:
Alexander Neumann 2019-04-25 08:58:27 +02:00
commit a6481b3707
7 changed files with 40 additions and 1 deletions

View File

@ -0,0 +1,15 @@
Enhancement: Use ctime when checking for file changes
Previously, restic only checked a file's mtime (along with other non-timestamp
metadata) to decide if a file has changed. This could cause restic to not notice
that a file has changed (and therefore continue to store the old version, as
opposed to the modified version) if something edits the file and then resets the
timestamp. Restic now also checks the ctime of files, so any modifications to a
file should be noticed, and the modified file will be backed up. The ctime check
will be disabled if the --ignore-inode flag was given.
If this change causes problems for you, please open an issue, and we can look in
to adding a seperate flag to disable just the ctime check.
https://github.com/restic/restic/issues/2179
https://github.com/restic/restic/pull/2212

View File

@ -453,8 +453,13 @@ func fileChanged(fi os.FileInfo, node *restic.Node, ignoreInode bool) bool {
return true return true
} }
// check size // check status change timestamp
extFI := fs.ExtendedStat(fi) extFI := fs.ExtendedStat(fi)
if !ignoreInode && !extFI.ChangeTime.Equal(node.ChangeTime) {
return true
}
// check size
if uint64(fi.Size()) != node.Size || uint64(extFI.Size) != node.Size { if uint64(fi.Size()) != node.Size || uint64(extFI.Size) != node.Size {
return true return true
} }

View File

@ -1,6 +1,7 @@
package archiver package archiver
import ( import (
"bytes"
"context" "context"
"io/ioutil" "io/ioutil"
"os" "os"
@ -576,6 +577,19 @@ func TestFileChanged(t *testing.T) {
save(t, filename, defaultContent) save(t, filename, defaultContent)
}, },
}, },
{
Name: "new-content-same-timestamp",
Modify: func(t testing.TB, filename string) {
fi, err := os.Stat(filename)
if err != nil {
t.Fatal(err)
}
extFI := fs.ExtendedStat(fi)
save(t, filename, bytes.ToUpper(defaultContent))
sleep()
setTimestamp(t, filename, extFI.AccessTime, extFI.ModTime)
},
},
{ {
Name: "other-content", Name: "other-content",
Modify: func(t testing.TB, filename string) { Modify: func(t testing.TB, filename string) {

View File

@ -22,6 +22,7 @@ type ExtendedFileInfo struct {
AccessTime time.Time // last access time stamp AccessTime time.Time // last access time stamp
ModTime time.Time // last (content) modification time stamp ModTime time.Time // last (content) modification time stamp
ChangeTime time.Time // last status change time stamp
} }
// ExtendedStat returns an ExtendedFileInfo constructed from the os.FileInfo. // ExtendedStat returns an ExtendedFileInfo constructed from the os.FileInfo.

View File

@ -30,6 +30,7 @@ func extendedStat(fi os.FileInfo) ExtendedFileInfo {
AccessTime: time.Unix(s.Atimespec.Unix()), AccessTime: time.Unix(s.Atimespec.Unix()),
ModTime: time.Unix(s.Mtimespec.Unix()), ModTime: time.Unix(s.Mtimespec.Unix()),
ChangeTime: time.Unix(s.Ctimespec.Unix()),
} }
return extFI return extFI

View File

@ -30,6 +30,7 @@ func extendedStat(fi os.FileInfo) ExtendedFileInfo {
AccessTime: time.Unix(s.Atim.Unix()), AccessTime: time.Unix(s.Atim.Unix()),
ModTime: time.Unix(s.Mtim.Unix()), ModTime: time.Unix(s.Mtim.Unix()),
ChangeTime: time.Unix(s.Ctim.Unix()),
} }
return extFI return extFI

View File

@ -27,5 +27,7 @@ func extendedStat(fi os.FileInfo) ExtendedFileInfo {
mtime := syscall.NsecToTimespec(s.LastWriteTime.Nanoseconds()) mtime := syscall.NsecToTimespec(s.LastWriteTime.Nanoseconds())
extFI.ModTime = time.Unix(mtime.Unix()) extFI.ModTime = time.Unix(mtime.Unix())
extFI.ChangeTime = extFI.ModTime
return extFI return extFI
} }