basicfs_fileinfo_windows.go 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. // Copyright (C) 2017 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package fs
  7. import (
  8. "os"
  9. "path/filepath"
  10. "strings"
  11. "time"
  12. )
  13. var execExts map[string]bool
  14. func init() {
  15. // PATHEXT contains a list of executable file extensions, on Windows
  16. pathext := filepath.SplitList(os.Getenv("PATHEXT"))
  17. // We want the extensions in execExts to be lower case
  18. execExts = make(map[string]bool, len(pathext))
  19. for _, ext := range pathext {
  20. execExts[strings.ToLower(ext)] = true
  21. }
  22. }
  23. // isWindowsExecutable returns true if the given path has an extension that is
  24. // in the list of executable extensions.
  25. func isWindowsExecutable(path string) bool {
  26. return execExts[strings.ToLower(filepath.Ext(path))]
  27. }
  28. func (e basicFileInfo) Mode() FileMode {
  29. m := e.FileInfo.Mode()
  30. if m&os.ModeSymlink != 0 && e.Size() > 0 {
  31. // "Symlinks" with nonzero size are in fact "hard" links, such as
  32. // NTFS deduped files. Remove the symlink bit.
  33. m &^= os.ModeSymlink
  34. }
  35. // Set executable bits on files with executable extensions (.exe, .bat, etc).
  36. if isWindowsExecutable(e.Name()) {
  37. m |= 0111
  38. }
  39. // There is no user/group/others in Windows' read-only attribute, and
  40. // all "w" bits are set if the file is not read-only. Do not send these
  41. // group/others-writable bits to other devices in order to avoid
  42. // unexpected world-writable files on other platforms.
  43. m &^= 0022
  44. return FileMode(m)
  45. }
  46. func (e basicFileInfo) Owner() int {
  47. return -1
  48. }
  49. func (e basicFileInfo) Group() int {
  50. return -1
  51. }
  52. func (basicFileInfo) InodeChangeTime() time.Time {
  53. return time.Time{}
  54. }
  55. // osFileInfo converts e to os.FileInfo that is suitable
  56. // to be passed to os.SameFile.
  57. func (e *basicFileInfo) osFileInfo() os.FileInfo {
  58. fi := e.FileInfo
  59. if fi, ok := fi.(*dirJunctFileInfo); ok {
  60. return fi.FileInfo
  61. }
  62. return fi
  63. }