From 2b65e1062ecd002ae79b0cd19c2ed94bd3b817bf Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Mon, 13 Nov 2017 06:57:07 +0000 Subject: [PATCH] lib/model: Fix rescan detection (fixes #4505, fixes #4506) Diff is large due to comment reformatting and indentation but all it does is wrap the file mtime/size/permissions check in an "if stat.IsRegular()". GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4507 --- lib/model/rwfolder.go | 48 +++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/lib/model/rwfolder.go b/lib/model/rwfolder.go index 85b4f5aa6..9cadc525b 100644 --- a/lib/model/rwfolder.go +++ b/lib/model/rwfolder.go @@ -1384,29 +1384,33 @@ func (f *sendReceiveFolder) performFinish(state *sharedPullerState) error { curMode |= 0111 } - // Check that the file on disk is what we expect it to be according to - // the database. If there's a mismatch here, there might be local + // Check that the file on disk is what we expect it to be according + // to the database. If there's a mismatch here, there might be local // changes that we don't know about yet and we should scan before - // touching the file. - // There is also a case where we think the file should be there, but - // it was removed, which is a conflict, yet creations always wins when - // competing with a deletion, so no need to handle that specially. - switch { - // The file reappeared from nowhere, or mtime/size has changed, fallthrough -> rescan. - case !state.hasCurFile || !stat.ModTime().Equal(state.curFile.ModTime()) || stat.Size() != state.curFile.Size: - fallthrough - // Permissions have changed, means the file has changed, rescan. - case !f.ignorePermissions(state.curFile) && state.curFile.HasPermissionBits() && !scanner.PermsEqual(state.curFile.Permissions, curMode): - l.Debugln("file modified but not rescanned; not finishing:", state.curFile.Name) - // Scan() is synchronous (i.e. blocks until the scan is - // completed and returns an error), but a scan can't happen - // while we're in the puller routine. Request the scan in the - // background and it'll be handled when the current pulling - // sweep is complete. As we do retries, we'll queue the scan - // for this file up to ten times, but the last nine of those - // scans will be cheap... - go f.Scan([]string{state.curFile.Name}) - return fmt.Errorf("file modified but not rescanned; will try again later") + // touching the file. There is also a case where we think the file + // should be there, but it was removed, which is a conflict, yet + // creations always wins when competing with a deletion, so no need + // to handle that specially. + if stat.IsRegular() { + switch { + // The file reappeared from nowhere or the modification or size + // has changed, rescan. + case !state.hasCurFile || !stat.ModTime().Equal(state.curFile.ModTime()) || stat.Size() != state.curFile.Size: + fallthrough + + // Permissions have changed, means the file has changed, rescan. + case !f.ignorePermissions(state.curFile) && state.curFile.HasPermissionBits() && !scanner.PermsEqual(state.curFile.Permissions, curMode): + l.Debugln("file modified but not rescanned; not finishing:", state.curFile.Name) + // Scan() is synchronous (i.e. blocks until the scan is + // completed and returns an error), but a scan can't happen + // while we're in the puller routine. Request the scan in the + // background and it'll be handled when the current pulling + // sweep is complete. As we do retries, we'll queue the scan + // for this file up to ten times, but the last nine of those + // scans will be cheap... + go f.Scan([]string{state.curFile.Name}) + return fmt.Errorf("file modified but not rescanned; will try again later") + } } switch {