forked from TrueCloudLab/restic
Merge pull request #2212 from cbane/check-ctime
Examine file ctime when checking if files have changed.
This commit is contained in:
commit
a6481b3707
7 changed files with 40 additions and 1 deletions
15
changelog/0.9.5_2019-04-23/issue-2179
Normal file
15
changelog/0.9.5_2019-04-23/issue-2179
Normal 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
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue