From 272fb3b4442d4c1e14d1a24f93d9020dc818f9cd Mon Sep 17 00:00:00 2001 From: Simon Frei Date: Sun, 16 Sep 2018 16:09:56 +0200 Subject: [PATCH] all: Adjust windows perms in fs package (#5200) --- lib/fs/fsfileinfo_windows.go | 29 +++++++++++++++++++++++++++++ lib/model/folder_sendrecv.go | 3 --- lib/osutil/osutil.go | 19 ------------------- lib/scanner/walk.go | 36 +++++++----------------------------- 4 files changed, 36 insertions(+), 51 deletions(-) diff --git a/lib/fs/fsfileinfo_windows.go b/lib/fs/fsfileinfo_windows.go index fdd524d1..d66332c7 100644 --- a/lib/fs/fsfileinfo_windows.go +++ b/lib/fs/fsfileinfo_windows.go @@ -8,8 +8,28 @@ package fs import ( "os" + "path/filepath" + "strings" ) +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))] +} + func (e fsFileInfo) Mode() FileMode { m := e.FileInfo.Mode() if m&os.ModeSymlink != 0 && e.Size() > 0 { @@ -17,5 +37,14 @@ func (e fsFileInfo) Mode() FileMode { // NTFS deduped files. Remove the symlink bit. m &^= os.ModeSymlink } + // Set executable bits on files with executable extenions (.exe, .bat, etc). + if isWindowsExecutable(e.Name()) { + m |= 0111 + } + // There is no user/group/others in Windows' read-only attribute, and + // all "w" bits are set if the file is not read-only. Do not send these + // group/others-writable bits to other devices in order to avoid + // unexpected world-writable files on other platforms. + m &^= 0022 return FileMode(m) } diff --git a/lib/model/folder_sendrecv.go b/lib/model/folder_sendrecv.go index 8cc37078..2cf094bc 100644 --- a/lib/model/folder_sendrecv.go +++ b/lib/model/folder_sendrecv.go @@ -1453,9 +1453,6 @@ func (f *sendReceiveFolder) performFinish(ignores *ignore.Matcher, file, curFile // handle that. curMode := uint32(stat.Mode()) - if runtime.GOOS == "windows" && osutil.IsWindowsExecutable(file.Name) { - curMode |= 0111 - } // Check that the file on disk is what we expect it to be according // to the database. If there's a mismatch here, there might be local diff --git a/lib/osutil/osutil.go b/lib/osutil/osutil.go index 45b5f3b1..256ca1da 100644 --- a/lib/osutil/osutil.go +++ b/lib/osutil/osutil.go @@ -10,7 +10,6 @@ package osutil import ( "errors" "io" - "os" "path/filepath" "runtime" "strings" @@ -136,24 +135,6 @@ func copyFileContents(filesystem fs.Filesystem, src, dst string) (err error) { 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))] -} - func IsDeleted(ffs fs.Filesystem, name string) bool { if _, err := ffs.Lstat(name); fs.IsNotExist(err) { return true diff --git a/lib/scanner/walk.go b/lib/scanner/walk.go index 35cb7b2a..d3284358 100644 --- a/lib/scanner/walk.go +++ b/lib/scanner/walk.go @@ -19,26 +19,10 @@ import ( "github.com/syncthing/syncthing/lib/events" "github.com/syncthing/syncthing/lib/fs" "github.com/syncthing/syncthing/lib/ignore" - "github.com/syncthing/syncthing/lib/osutil" "github.com/syncthing/syncthing/lib/protocol" "golang.org/x/text/unicode/norm" ) -var maskModePerm fs.FileMode - -func init() { - if runtime.GOOS == "windows" { - // There is no user/group/others in Windows' read-only - // attribute, and all "w" bits are set in fs.FileMode - // if the file is not read-only. Do not send these - // group/others-writable bits to other devices in order to - // avoid unexpected world-writable files on other platforms. - maskModePerm = fs.ModePerm & 0755 - } else { - maskModePerm = fs.ModePerm - } -} - type Config struct { // Folder for which the walker has been created Folder string @@ -326,16 +310,10 @@ func (w *walker) walkRegular(ctx context.Context, relPath string, info fs.FileIn curFile, hasCurFile := w.CurrentFiler.CurrentFile(relPath) newMode := uint32(info.Mode()) - if runtime.GOOS == "windows" { - if osutil.IsWindowsExecutable(relPath) { - // Set executable bits on files with executable extenions (.exe, - // .bat, etc). - newMode |= 0111 - } else if hasCurFile { - // If we have an existing index entry, copy the executable bits - // from there. - newMode |= (curFile.Permissions & 0111) - } + if runtime.GOOS == "windows" && hasCurFile { + // If we have an existing index entry, copy the executable bits + // from there. + newMode |= (curFile.Permissions & 0111) } blockSize := protocol.MinBlockSize @@ -362,7 +340,7 @@ func (w *walker) walkRegular(ctx context.Context, relPath string, info fs.FileIn Name: relPath, Type: protocol.FileInfoTypeFile, Version: curFile.Version.Update(w.ShortID), - Permissions: newMode & uint32(maskModePerm), + Permissions: newMode & uint32(fs.ModePerm), NoPermissions: w.IgnorePerms, ModifiedS: info.ModTime().Unix(), ModifiedNs: int32(info.ModTime().Nanosecond()), @@ -405,7 +383,7 @@ func (w *walker) walkDir(ctx context.Context, relPath string, info fs.FileInfo, Name: relPath, Type: protocol.FileInfoTypeDirectory, Version: cf.Version.Update(w.ShortID), - Permissions: uint32(info.Mode() & maskModePerm), + Permissions: uint32(info.Mode() & fs.ModePerm), NoPermissions: w.IgnorePerms, ModifiedS: info.ModTime().Unix(), ModifiedNs: int32(info.ModTime().Nanosecond()), @@ -615,7 +593,7 @@ func CreateFileInfo(fi fs.FileInfo, name string, filesystem fs.Filesystem) (prot f := protocol.FileInfo{ Name: name, Type: protocol.FileInfoTypeFile, - Permissions: uint32(fi.Mode()), + Permissions: uint32(fi.Mode() & fs.ModePerm), ModifiedS: fi.ModTime().Unix(), ModifiedNs: int32(fi.ModTime().Nanosecond()), Size: fi.Size(),