From 46a143e80e13e2fface4ac22d6b0beaf21c2e2ed Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Fri, 2 Sep 2016 13:23:24 +0000 Subject: [PATCH] lib/model: Handle deleted-then-ignored files (fixes #3502) When files that were previously marked as deleted became ignored, we used to do nothing at all. This changes that behavior to set the Invalid bit (that we should rename to Ignored). This then becomes an update to other devices that they should not trust our knowledge about the file in question. Read this diff without whitespace... Tested by - creating a bunch of files on s1 - letting them sync to s2 - shutting down s2 - deleting the files on s1 and rescanning - adding the files to .stignore on s1 and rescanning - starting up s2 and letting it sync - observing the files are not deleted on s2, and it considers itself up to date. GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3557 --- lib/model/model.go | 57 +++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/lib/model/model.go b/lib/model/model.go index 0eab34c3..5adb147a 100644 --- a/lib/model/model.go +++ b/lib/model/model.go @@ -1735,41 +1735,46 @@ func (m *Model) internalScanFolderSubdirs(folder string, subDirs []string) error subDirs = []string{""} } - // Do a scan of the database for each prefix, to check for deleted files. + // Do a scan of the database for each prefix, to check for deleted and + // ignored files. batch = batch[:0] for _, sub := range subDirs { var iterError error fs.WithPrefixedHaveTruncated(protocol.LocalDeviceID, sub, func(fi db.FileIntf) bool { f := fi.(db.FileInfoTruncated) - if !f.IsDeleted() { - if len(batch) == batchSizeFiles { - if err := m.CheckFolderHealth(folder); err != nil { - iterError = err - return false - } - m.updateLocalsFromScanning(folder, batch) - batch = batch[:0] + if len(batch) == batchSizeFiles { + if err := m.CheckFolderHealth(folder); err != nil { + iterError = err + return false } + m.updateLocalsFromScanning(folder, batch) + batch = batch[:0] + } - if !f.IsInvalid() && (ignores.Match(f.Name).IsIgnored() || symlinkInvalid(folder, f)) { - // File has been ignored or an unsupported symlink. Set invalid bit. - l.Debugln("setting invalid bit on ignored", f) - nf := protocol.FileInfo{ - Name: f.Name, - Type: f.Type, - Size: f.Size, - ModifiedS: f.ModifiedS, - ModifiedNs: f.ModifiedNs, - Permissions: f.Permissions, - NoPermissions: f.NoPermissions, - Invalid: true, - Version: f.Version, // The file is still the same, so don't bump version - } - batch = append(batch, nf) - } else if _, err := mtimefs.Lstat(filepath.Join(folderCfg.Path(), f.Name)); err != nil { - // File has been deleted. + switch { + case !f.IsInvalid() && (ignores.Match(f.Name).IsIgnored() || symlinkInvalid(folder, f)): + // File was valid at last pass but has been ignored or is an + // unsupported symlink. Set invalid bit. + l.Debugln("setting invalid bit on ignored", f) + nf := protocol.FileInfo{ + Name: f.Name, + Type: f.Type, + Size: f.Size, + ModifiedS: f.ModifiedS, + ModifiedNs: f.ModifiedNs, + Permissions: f.Permissions, + NoPermissions: f.NoPermissions, + Invalid: true, + Version: f.Version, // The file is still the same, so don't bump version + } + batch = append(batch, nf) + case !f.IsInvalid() && !f.IsDeleted(): + // The file is valid and not deleted. Lets check if it's + // still here. + + if _, err := mtimefs.Lstat(filepath.Join(folderCfg.Path(), f.Name)); err != nil { // We don't specifically verify that the error is // os.IsNotExist because there is a corner case when a // directory is suddenly transformed into a file. When that