Browse Source

Refactor: break out walkSymlink method

Jakob Borg 10 years ago
parent
commit
6dbb072d11
1 changed files with 65 additions and 53 deletions
  1. 65 53
      lib/scanner/walk.go

+ 65 - 53
lib/scanner/walk.go

@@ -263,61 +263,11 @@ func (w *Walker) walkAndHashFiles(fchan, dchan chan protocol.FileInfo) filepath.
 		// Index wise symlinks are always files, regardless of what the target
 		// is, because symlinks carry their target path as their content.
 		if info.Mode()&os.ModeSymlink == os.ModeSymlink {
-			// If the target is a directory, do NOT descend down there. This
-			// will cause files to get tracked, and removing the symlink will
-			// as a result remove files in their real location.
-			if !symlinks.Supported {
+			if shouldSkip, err := w.walkSymlink(absPath, relPath, dchan); err != nil {
+				return err
+			} else if shouldSkip {
 				return skip
 			}
-
-			// We always rehash symlinks as they have no modtime or
-			// permissions. We check if they point to the old target by
-			// checking that their existing blocks match with the blocks in
-			// the index.
-
-			target, targetType, err := symlinks.Read(absPath)
-			if err != nil {
-				l.Debugln("readlink error:", absPath, err)
-				return skip
-			}
-
-			blocks, err := Blocks(strings.NewReader(target), w.BlockSize, 0, nil)
-			if err != nil {
-				l.Debugln("hash link error:", absPath, err)
-				return skip
-			}
-
-			if w.CurrentFiler != nil {
-				// A symlink is "unchanged", if
-				//  - it exists
-				//  - 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 block list (i.e. hash of target) was the same
-				cf, ok = w.CurrentFiler.CurrentFile(relPath)
-				if ok && !cf.IsDeleted() && cf.IsSymlink() && !cf.IsInvalid() && SymlinkTypeEqual(targetType, cf) && BlocksEqual(cf.Blocks, blocks) {
-					return skip
-				}
-			}
-
-			f := protocol.FileInfo{
-				Name:     relPath,
-				Version:  cf.Version.Update(w.ShortID),
-				Flags:    uint32(protocol.FlagSymlink | protocol.FlagNoPermBits | 0666 | SymlinkFlags(targetType)),
-				Modified: 0,
-				Blocks:   blocks,
-			}
-
-			l.Debugln("symlink changedb:", absPath, f)
-
-			select {
-			case dchan <- f:
-			case <-w.Cancel:
-				return errors.New("cancelled")
-			}
-
-			return skip
 		}
 
 		if info.Mode().IsDir() {
@@ -410,6 +360,68 @@ func (w *Walker) walkAndHashFiles(fchan, dchan chan protocol.FileInfo) filepath.
 	}
 }
 
+// walkSymlinks returns true if the symlink should be skipped, or an error if
+// we should stop walking altogether.
+func (w *Walker) walkSymlink(absPath, relPath string, dchan chan protocol.FileInfo) (skip bool, err error) {
+	// If the target is a directory, do NOT descend down there. This
+	// will cause files to get tracked, and removing the symlink will
+	// as a result remove files in their real location.
+	if !symlinks.Supported {
+		return true, nil
+	}
+
+	// We always rehash symlinks as they have no modtime or
+	// permissions. We check if they point to the old target by
+	// checking that their existing blocks match with the blocks in
+	// the index.
+
+	target, targetType, err := symlinks.Read(absPath)
+	if err != nil {
+		l.Debugln("readlink error:", absPath, err)
+		return true, nil
+	}
+
+	blocks, err := Blocks(strings.NewReader(target), w.BlockSize, 0, nil)
+	if err != nil {
+		l.Debugln("hash link error:", absPath, err)
+		return true, nil
+	}
+
+	var currentVersion protocol.Vector
+	if w.CurrentFiler != nil {
+		// A symlink is "unchanged", if
+		//  - it exists
+		//  - 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 block list (i.e. hash of target) was the same
+		cf, ok := w.CurrentFiler.CurrentFile(relPath)
+		if ok && !cf.IsDeleted() && cf.IsSymlink() && !cf.IsInvalid() && SymlinkTypeEqual(targetType, cf) && BlocksEqual(cf.Blocks, blocks) {
+			return true, nil
+		}
+		currentVersion = cf.Version
+	}
+
+	f := protocol.FileInfo{
+		Name:     relPath,
+		Version:  currentVersion.Update(w.ShortID),
+		Flags:    uint32(protocol.FlagSymlink | protocol.FlagNoPermBits | 0666 | SymlinkFlags(targetType)),
+		Modified: 0,
+		Blocks:   blocks,
+	}
+
+	l.Debugln("symlink changedb:", absPath, f)
+
+	select {
+	case dchan <- f:
+	case <-w.Cancel:
+		return false, errors.New("cancelled")
+	}
+
+	return false, nil
+}
+
 // normalizePath returns the normalized relative path (possibly after fixing
 // it on disk), or skip is true.
 func (w *Walker) normalizePath(absPath, relPath string) (normPath string, skip bool) {