You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

93 lines
2.7 KiB

  1. // Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
  2. // +build windows
  3. package winfile
  4. import (
  5. "os"
  6. "syscall"
  7. "unsafe"
  8. )
  9. // issue also described here
  10. //https://codereview.appspot.com/8203043/
  11. // https://github.com/jnwhiteh/golang/blob/master/src/pkg/syscall/syscall_windows.go#L218
  12. func Open(path string, mode int, perm uint32) (fd syscall.Handle, err error) {
  13. if len(path) == 0 {
  14. return syscall.InvalidHandle, syscall.ERROR_FILE_NOT_FOUND
  15. }
  16. pathp, err := syscall.UTF16PtrFromString(path)
  17. if err != nil {
  18. return syscall.InvalidHandle, err
  19. }
  20. var access uint32
  21. switch mode & (syscall.O_RDONLY | syscall.O_WRONLY | syscall.O_RDWR) {
  22. case syscall.O_RDONLY:
  23. access = syscall.GENERIC_READ
  24. case syscall.O_WRONLY:
  25. access = syscall.GENERIC_WRITE
  26. case syscall.O_RDWR:
  27. access = syscall.GENERIC_READ | syscall.GENERIC_WRITE
  28. }
  29. if mode&syscall.O_CREAT != 0 {
  30. access |= syscall.GENERIC_WRITE
  31. }
  32. if mode&syscall.O_APPEND != 0 {
  33. access &^= syscall.GENERIC_WRITE
  34. access |= syscall.FILE_APPEND_DATA
  35. }
  36. sharemode := uint32(syscall.FILE_SHARE_READ | syscall.FILE_SHARE_WRITE | syscall.FILE_SHARE_DELETE)
  37. var sa *syscall.SecurityAttributes
  38. if mode&syscall.O_CLOEXEC == 0 {
  39. sa = makeInheritSa()
  40. }
  41. var createmode uint32
  42. switch {
  43. case mode&(syscall.O_CREAT|syscall.O_EXCL) == (syscall.O_CREAT | syscall.O_EXCL):
  44. createmode = syscall.CREATE_NEW
  45. case mode&(syscall.O_CREAT|syscall.O_TRUNC) == (syscall.O_CREAT | syscall.O_TRUNC):
  46. createmode = syscall.CREATE_ALWAYS
  47. case mode&syscall.O_CREAT == syscall.O_CREAT:
  48. createmode = syscall.OPEN_ALWAYS
  49. case mode&syscall.O_TRUNC == syscall.O_TRUNC:
  50. createmode = syscall.TRUNCATE_EXISTING
  51. default:
  52. createmode = syscall.OPEN_EXISTING
  53. }
  54. h, e := syscall.CreateFile(pathp, access, sharemode, sa, createmode, syscall.FILE_ATTRIBUTE_NORMAL, 0)
  55. return h, e
  56. }
  57. // https://github.com/jnwhiteh/golang/blob/master/src/pkg/syscall/syscall_windows.go#L211
  58. func makeInheritSa() *syscall.SecurityAttributes {
  59. var sa syscall.SecurityAttributes
  60. sa.Length = uint32(unsafe.Sizeof(sa))
  61. sa.InheritHandle = 1
  62. return &sa
  63. }
  64. // https://github.com/jnwhiteh/golang/blob/master/src/pkg/os/file_windows.go#L133
  65. func OpenFile(name string, flag int, perm os.FileMode) (file *os.File, err error) {
  66. r, e := Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm))
  67. if e != nil {
  68. return nil, e
  69. }
  70. return os.NewFile(uintptr(r), name), nil
  71. }
  72. // https://github.com/jnwhiteh/golang/blob/master/src/pkg/os/file_posix.go#L61
  73. func syscallMode(i os.FileMode) (o uint32) {
  74. o |= uint32(i.Perm())
  75. if i&os.ModeSetuid != 0 {
  76. o |= syscall.S_ISUID
  77. }
  78. if i&os.ModeSetgid != 0 {
  79. o |= syscall.S_ISGID
  80. }
  81. if i&os.ModeSticky != 0 {
  82. o |= syscall.S_ISVTX
  83. }
  84. // No mapping for Go's ModeTemporary (plan9 only).
  85. return
  86. }