From 6dbb072d11e5e13a60d3353374f3d608b6a18067 Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Fri, 20 Nov 2015 09:50:46 +0100 Subject: [PATCH] Refactor: break out walkSymlink method --- lib/scanner/walk.go | 118 ++++++++++++++++++++++++-------------------- 1 file changed, 65 insertions(+), 53 deletions(-) diff --git a/lib/scanner/walk.go b/lib/scanner/walk.go index de5059ee..a05690bf 100644 --- a/lib/scanner/walk.go +++ b/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) {