浏览代码

lib/model: Handle type changes when pulling (ref #4505 #4506 #4507)

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4509
LGTM: AudriusButkevicius, calmh
Simon Frei 8 年之前
父节点
当前提交
fa12a18190
共有 2 个文件被更改,包括 37 次插入19 次删除
  1. 37 18
      lib/model/rwfolder.go
  2. 0 1
      lib/scanner/walk.go

+ 37 - 18
lib/model/rwfolder.go

@@ -1391,28 +1391,47 @@ func (f *sendReceiveFolder) performFinish(state *sharedPullerState) error {
 		// 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):
+		changed := false
+		switch {
+		case !state.hasCurFile:
+			// The file appeared from nowhere
+			l.Debugln("file exists but not scanned; not finishing:", state.file.Name)
+			changed = true
+
+		case stat.IsDir() != state.curFile.IsDirectory() || stat.IsSymlink() != state.curFile.IsSymlink():
+			// The file changed type. IsRegular is implicitly tested in the condition above
+			l.Debugln("file type changed but not rescanned; not finishing:", state.curFile.Name)
+			changed = true
+
+		case stat.IsRegular():
+			if !stat.ModTime().Equal(state.curFile.ModTime()) || stat.Size() != state.curFile.Size {
 				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")
+				changed = true
+				break
+			}
+			// check permissions
+			fallthrough
+
+		case stat.IsDir():
+			// Dirs only have perm, no modetime/size
+			if !f.ignorePermissions(state.curFile) && state.curFile.HasPermissionBits() && !scanner.PermsEqual(state.curFile.Permissions, curMode) {
+				l.Debugln("file permission modified but not rescanned; not finishing:", state.curFile.Name)
+				changed = true
 			}
 		}
 
+		if changed {
+			// 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 {
 		case stat.IsDir() || stat.IsSymlink():
 			// It's a directory or a symlink. These are not versioned or

+ 0 - 1
lib/scanner/walk.go

@@ -392,7 +392,6 @@ func (w *walker) walkSymlink(ctx context.Context, relPath string, dchan chan pro
 	//  - it wasn't deleted (because it isn't now)
 	//  - it was a symlink
 	//  - it wasn't invalid
-	//  - the symlink type (file/dir) was the same
 	//  - the target was the same
 	cf, ok := w.CurrentFiler.CurrentFile(relPath)
 	if ok && !cf.IsDeleted() && cf.IsSymlink() && !cf.IsInvalid() && cf.SymlinkTarget == target {