...
1 package sysfs
2
3 import (
4 "io/fs"
5 "os"
6 "strings"
7 "syscall"
8 "unsafe"
9
10 "github.com/tetratelabs/wazero/experimental/sys"
11 "github.com/tetratelabs/wazero/internal/platform"
12 )
13
14 func openFile(path string, oflag sys.Oflag, perm fs.FileMode) (*os.File, sys.Errno) {
15 isDir := oflag&sys.O_DIRECTORY > 0
16 flag := toOsOpenFlag(oflag)
17
18
19 fd, err := open(path, flag|syscall.O_CLOEXEC, uint32(perm))
20 if err == nil {
21 return os.NewFile(uintptr(fd), path), 0
22 }
23
24
25 f, err := os.OpenFile(path, flag, perm)
26 errno := sys.UnwrapOSError(err)
27 if errno == 0 {
28 return f, 0
29 }
30
31 switch errno {
32 case sys.EINVAL:
33
34 if strings.HasSuffix(path, "/") {
35 errno = sys.ENOTDIR
36 }
37
38
39 case sys.ENOTDIR:
40 errno = sys.ENOENT
41 case sys.ENOENT:
42 if isSymlink(path) {
43
44
45
46 if isDir {
47
48 errno = sys.ENOTDIR
49 } else {
50 errno = sys.ELOOP
51 }
52 }
53 }
54 return f, errno
55 }
56
57 const supportedSyscallOflag = sys.O_NONBLOCK
58
59
60 func withSyscallOflag(oflag sys.Oflag, flag int) int {
61
62
63
64 if oflag&sys.O_NONBLOCK != 0 {
65 flag |= syscall.O_NONBLOCK
66 }
67
68 return flag
69 }
70
71 func isSymlink(path string) bool {
72 if st, e := os.Lstat(path); e == nil && st.Mode()&os.ModeSymlink != 0 {
73 return true
74 }
75 return false
76 }
77
78
79
80
81
82
83
84
85
86 func open(path string, mode int, perm uint32) (fd syscall.Handle, err error) {
87 if len(path) == 0 {
88 return syscall.InvalidHandle, syscall.ERROR_FILE_NOT_FOUND
89 }
90 pathp, err := syscall.UTF16PtrFromString(path)
91 if err != nil {
92 return syscall.InvalidHandle, err
93 }
94 var access uint32
95 switch mode & (syscall.O_RDONLY | syscall.O_WRONLY | syscall.O_RDWR) {
96 case syscall.O_RDONLY:
97 access = syscall.GENERIC_READ
98 case syscall.O_WRONLY:
99 access = syscall.GENERIC_WRITE
100 case syscall.O_RDWR:
101 access = syscall.GENERIC_READ | syscall.GENERIC_WRITE
102 }
103 if mode&syscall.O_APPEND != 0 {
104 access &^= syscall.GENERIC_WRITE
105 access |= syscall.FILE_APPEND_DATA
106 }
107 sharemode := uint32(syscall.FILE_SHARE_READ | syscall.FILE_SHARE_WRITE | syscall.FILE_SHARE_DELETE)
108 var sa *syscall.SecurityAttributes
109 if mode&syscall.O_CLOEXEC == 0 {
110 var _sa syscall.SecurityAttributes
111 _sa.Length = uint32(unsafe.Sizeof(sa))
112 _sa.InheritHandle = 1
113 sa = &_sa
114 }
115 var createmode uint32
116 switch {
117 case mode&(syscall.O_CREAT|syscall.O_EXCL) == (syscall.O_CREAT | syscall.O_EXCL):
118 createmode = syscall.CREATE_NEW
119 case mode&(syscall.O_CREAT|syscall.O_TRUNC) == (syscall.O_CREAT | syscall.O_TRUNC):
120 createmode = syscall.CREATE_ALWAYS
121 case mode&syscall.O_CREAT == syscall.O_CREAT:
122 createmode = syscall.OPEN_ALWAYS
123 case mode&syscall.O_TRUNC == syscall.O_TRUNC:
124 createmode = syscall.TRUNCATE_EXISTING
125 default:
126 createmode = syscall.OPEN_EXISTING
127 }
128 var attrs uint32 = syscall.FILE_ATTRIBUTE_NORMAL
129 if perm&syscall.S_IWRITE == 0 {
130 attrs = syscall.FILE_ATTRIBUTE_READONLY
131 if createmode == syscall.CREATE_ALWAYS {
132
133
134
135
136
137
138
139
140 h, e := syscall.CreateFile(pathp, access, sharemode, sa, syscall.TRUNCATE_EXISTING, syscall.FILE_ATTRIBUTE_NORMAL, 0)
141 switch e {
142 case syscall.ERROR_FILE_NOT_FOUND, syscall.ERROR_PATH_NOT_FOUND:
143
144
145
146 default:
147
148 return h, e
149 }
150 }
151 }
152
153 if platform.IsAtLeastGo120 {
154
155
156 if createmode == syscall.OPEN_EXISTING && access == syscall.GENERIC_READ {
157
158 attrs |= syscall.FILE_FLAG_BACKUP_SEMANTICS
159 }
160 }
161
162 h, e := syscall.CreateFile(pathp, access, sharemode, sa, createmode, attrs, 0)
163 return h, e
164 }
165
View as plain text