basicfs_windows.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. // Copyright (C) 2014 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. // +build windows
  7. package fs
  8. import (
  9. "bytes"
  10. "errors"
  11. "fmt"
  12. "os"
  13. "path/filepath"
  14. "syscall"
  15. "unsafe"
  16. )
  17. var errNotSupported = errors.New("symlinks not supported")
  18. func (BasicFilesystem) SymlinksSupported() bool {
  19. return false
  20. }
  21. func (BasicFilesystem) ReadSymlink(path string) (string, error) {
  22. return "", errNotSupported
  23. }
  24. func (BasicFilesystem) CreateSymlink(path, target string) error {
  25. return errNotSupported
  26. }
  27. // MkdirAll creates a directory named path, along with any necessary parents,
  28. // and returns nil, or else returns an error.
  29. // The permission bits perm are used for all directories that MkdirAll creates.
  30. // If path is already a directory, MkdirAll does nothing and returns nil.
  31. func (f *BasicFilesystem) MkdirAll(path string, perm FileMode) error {
  32. path, err := f.rooted(path)
  33. if err != nil {
  34. return err
  35. }
  36. return f.mkdirAll(path, os.FileMode(perm))
  37. }
  38. // Required due to https://github.com/golang/go/issues/10900
  39. func (f *BasicFilesystem) mkdirAll(path string, perm os.FileMode) error {
  40. // Fast path: if we can tell whether path is a directory or file, stop with success or error.
  41. dir, err := os.Stat(path)
  42. if err == nil {
  43. if dir.IsDir() {
  44. return nil
  45. }
  46. return &os.PathError{
  47. Op: "mkdir",
  48. Path: path,
  49. Err: syscall.ENOTDIR,
  50. }
  51. }
  52. // Slow path: make sure parent exists and then call Mkdir for path.
  53. i := len(path)
  54. for i > 0 && IsPathSeparator(path[i-1]) { // Skip trailing path separator.
  55. i--
  56. }
  57. j := i
  58. for j > 0 && !IsPathSeparator(path[j-1]) { // Scan backward over element.
  59. j--
  60. }
  61. if j > 1 {
  62. // Create parent
  63. parent := path[0 : j-1]
  64. if parent != filepath.VolumeName(parent) {
  65. err = os.MkdirAll(parent, perm)
  66. if err != nil {
  67. return err
  68. }
  69. }
  70. }
  71. // Parent now exists; invoke Mkdir and use its result.
  72. err = os.Mkdir(path, perm)
  73. if err != nil {
  74. // Handle arguments like "foo/." by
  75. // double-checking that directory doesn't exist.
  76. dir, err1 := os.Lstat(path)
  77. if err1 == nil && dir.IsDir() {
  78. return nil
  79. }
  80. return err
  81. }
  82. return nil
  83. }
  84. func (f *BasicFilesystem) Unhide(name string) error {
  85. name, err := f.rooted(name)
  86. if err != nil {
  87. return err
  88. }
  89. p, err := syscall.UTF16PtrFromString(name)
  90. if err != nil {
  91. return err
  92. }
  93. attrs, err := syscall.GetFileAttributes(p)
  94. if err != nil {
  95. return err
  96. }
  97. attrs &^= syscall.FILE_ATTRIBUTE_HIDDEN
  98. return syscall.SetFileAttributes(p, attrs)
  99. }
  100. func (f *BasicFilesystem) Hide(name string) error {
  101. name, err := f.rooted(name)
  102. if err != nil {
  103. return err
  104. }
  105. p, err := syscall.UTF16PtrFromString(name)
  106. if err != nil {
  107. return err
  108. }
  109. attrs, err := syscall.GetFileAttributes(p)
  110. if err != nil {
  111. return err
  112. }
  113. attrs |= syscall.FILE_ATTRIBUTE_HIDDEN
  114. return syscall.SetFileAttributes(p, attrs)
  115. }
  116. func (f *BasicFilesystem) Roots() ([]string, error) {
  117. kernel32, err := syscall.LoadDLL("kernel32.dll")
  118. if err != nil {
  119. return nil, err
  120. }
  121. getLogicalDriveStringsHandle, err := kernel32.FindProc("GetLogicalDriveStringsA")
  122. if err != nil {
  123. return nil, err
  124. }
  125. buffer := [1024]byte{}
  126. bufferSize := uint32(len(buffer))
  127. hr, _, _ := getLogicalDriveStringsHandle.Call(uintptr(unsafe.Pointer(&bufferSize)), uintptr(unsafe.Pointer(&buffer)))
  128. if hr == 0 {
  129. return nil, fmt.Errorf("Syscall failed")
  130. }
  131. var drives []string
  132. parts := bytes.Split(buffer[:], []byte{0})
  133. for _, part := range parts {
  134. if len(part) == 0 {
  135. break
  136. }
  137. drives = append(drives, string(part))
  138. }
  139. return drives, nil
  140. }