winfile.go 2.6 KB

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