winfile.go

 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}