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