diff --git a/internal/osutil/osutil.go b/internal/osutil/osutil.go index 7b0fa43f9..03e3473e9 100644 --- a/internal/osutil/osutil.go +++ b/internal/osutil/osutil.go @@ -192,3 +192,21 @@ func copyFileContents(src, dst string) (err error) { err = out.Sync() return } + +var execExts map[string]bool + +func init() { + // PATHEXT contains a list of executable file extensions, on Windows + pathext := filepath.SplitList(os.Getenv("PATHEXT")) + // We want the extensions in execExts to be lower case + execExts = make(map[string]bool, len(pathext)) + for _, ext := range pathext { + execExts[strings.ToLower(ext)] = true + } +} + +// IsWindowsExecutable returns true if the given path has an extension that is +// in the list of executable extensions. +func IsWindowsExecutable(path string) bool { + return execExts[strings.ToLower(filepath.Ext(path))] +} diff --git a/internal/scanner/walk.go b/internal/scanner/walk.go index 55f79a0a4..95a74d935 100644 --- a/internal/scanner/walk.go +++ b/internal/scanner/walk.go @@ -308,6 +308,11 @@ func (w *Walker) walkAndHashFiles(fchan chan protocol.FileInfo) filepath.WalkFun } if info.Mode().IsRegular() { + curMode := uint32(info.Mode()) + if runtime.GOOS == "windows" && osutil.IsWindowsExecutable(rn) { + curMode |= 0111 + } + if w.CurrentFiler != nil { // A file is "unchanged", if it // - exists @@ -319,7 +324,7 @@ func (w *Walker) walkAndHashFiles(fchan chan protocol.FileInfo) filepath.WalkFun // - was not invalid (since it looks valid now) // - has the same size as previously cf, ok = w.CurrentFiler.CurrentFile(rn) - permUnchanged := w.IgnorePerms || !cf.HasPermissionBits() || PermsEqual(cf.Flags, uint32(info.Mode())) + permUnchanged := w.IgnorePerms || !cf.HasPermissionBits() || PermsEqual(cf.Flags, curMode) if ok && permUnchanged && !cf.IsDeleted() && cf.Modified == info.ModTime().Unix() && !cf.IsDirectory() && !cf.IsSymlink() && !cf.IsInvalid() && cf.Size() == info.Size() { return nil @@ -330,7 +335,7 @@ func (w *Walker) walkAndHashFiles(fchan chan protocol.FileInfo) filepath.WalkFun } } - var flags = uint32(info.Mode() & maskModePerm) + var flags = curMode & uint32(maskModePerm) if w.IgnorePerms { flags = protocol.FlagNoPermBits | 0666 } @@ -387,5 +392,4 @@ func SymlinkTypeEqual(disk, index uint32) bool { return true } return disk&protocol.SymlinkTypeMask == index&protocol.SymlinkTypeMask - }