1
2
3
4
5 package windows
6
7 import (
8 "syscall"
9 "unsafe"
10 )
11
12
13
14
15
16
17
18
19 const (
20 O_DIRECTORY = 0x100000
21 O_NOFOLLOW_ANY = 0x20000000
22 O_OPEN_REPARSE = 0x40000000
23 )
24
25 func Openat(dirfd syscall.Handle, name string, flag int, perm uint32) (_ syscall.Handle, e1 error) {
26 if len(name) == 0 {
27 return syscall.InvalidHandle, syscall.ERROR_FILE_NOT_FOUND
28 }
29
30 var access, options uint32
31 switch flag & (syscall.O_RDONLY | syscall.O_WRONLY | syscall.O_RDWR) {
32 case syscall.O_RDONLY:
33
34 access = FILE_GENERIC_READ
35 case syscall.O_WRONLY:
36 access = FILE_GENERIC_WRITE
37 options |= FILE_NON_DIRECTORY_FILE
38 case syscall.O_RDWR:
39 access = FILE_GENERIC_READ | FILE_GENERIC_WRITE
40 options |= FILE_NON_DIRECTORY_FILE
41 default:
42
43
44 access = SYNCHRONIZE
45 }
46 if flag&syscall.O_CREAT != 0 {
47 access |= FILE_GENERIC_WRITE
48 }
49 if flag&syscall.O_APPEND != 0 {
50 access |= FILE_APPEND_DATA
51
52
53 if flag&syscall.O_TRUNC == 0 {
54 access &^= FILE_WRITE_DATA
55 }
56 }
57 if flag&O_DIRECTORY != 0 {
58 options |= FILE_DIRECTORY_FILE
59 access |= FILE_LIST_DIRECTORY
60 }
61 if flag&syscall.O_SYNC != 0 {
62 options |= FILE_WRITE_THROUGH
63 }
64
65 access |= STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES | FILE_READ_EA
66
67 objAttrs := &OBJECT_ATTRIBUTES{}
68 if flag&O_NOFOLLOW_ANY != 0 {
69 objAttrs.Attributes |= OBJ_DONT_REPARSE
70 }
71 if flag&syscall.O_CLOEXEC == 0 {
72 objAttrs.Attributes |= OBJ_INHERIT
73 }
74 if err := objAttrs.init(dirfd, name); err != nil {
75 return syscall.InvalidHandle, err
76 }
77
78 if flag&O_OPEN_REPARSE != 0 {
79 options |= FILE_OPEN_REPARSE_POINT
80 }
81
82
83
84
85
86
87 var disposition uint32
88 switch {
89 case flag&(syscall.O_CREAT|syscall.O_EXCL) == (syscall.O_CREAT | syscall.O_EXCL):
90 disposition = FILE_CREATE
91 case flag&syscall.O_CREAT == syscall.O_CREAT:
92 disposition = FILE_OPEN_IF
93 default:
94 disposition = FILE_OPEN
95 }
96
97 fileAttrs := uint32(FILE_ATTRIBUTE_NORMAL)
98 if perm&syscall.S_IWRITE == 0 {
99 fileAttrs = FILE_ATTRIBUTE_READONLY
100 }
101
102 var h syscall.Handle
103 err := NtCreateFile(
104 &h,
105 SYNCHRONIZE|access,
106 objAttrs,
107 &IO_STATUS_BLOCK{},
108 nil,
109 fileAttrs,
110 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
111 disposition,
112 FILE_SYNCHRONOUS_IO_NONALERT|FILE_OPEN_FOR_BACKUP_INTENT|options,
113 0,
114 0,
115 )
116 if err != nil {
117 return h, ntCreateFileError(err, flag)
118 }
119
120 if flag&syscall.O_TRUNC != 0 {
121 err = syscall.Ftruncate(h, 0)
122 if err != nil {
123 syscall.CloseHandle(h)
124 return syscall.InvalidHandle, err
125 }
126 }
127
128 return h, nil
129 }
130
131
132 func ntCreateFileError(err error, flag int) error {
133 s, ok := err.(NTStatus)
134 if !ok {
135
136 return err
137 }
138 switch s {
139 case STATUS_REPARSE_POINT_ENCOUNTERED:
140 return syscall.ELOOP
141 case STATUS_NOT_A_DIRECTORY:
142
143
144
145
146
147
148
149
150 if flag&O_DIRECTORY != 0 {
151 return syscall.ENOTDIR
152 }
153 case STATUS_FILE_IS_A_DIRECTORY:
154 return syscall.EISDIR
155 }
156 return s.Errno()
157 }
158
159 func Mkdirat(dirfd syscall.Handle, name string, mode uint32) error {
160 objAttrs := &OBJECT_ATTRIBUTES{}
161 if err := objAttrs.init(dirfd, name); err != nil {
162 return err
163 }
164 var h syscall.Handle
165 err := NtCreateFile(
166 &h,
167 FILE_GENERIC_READ,
168 objAttrs,
169 &IO_STATUS_BLOCK{},
170 nil,
171 syscall.FILE_ATTRIBUTE_NORMAL,
172 syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
173 FILE_CREATE,
174 FILE_DIRECTORY_FILE,
175 0,
176 0,
177 )
178 if err != nil {
179 return ntCreateFileError(err, 0)
180 }
181 syscall.CloseHandle(h)
182 return nil
183 }
184
185 func Deleteat(dirfd syscall.Handle, name string) error {
186 objAttrs := &OBJECT_ATTRIBUTES{}
187 if err := objAttrs.init(dirfd, name); err != nil {
188 return err
189 }
190 var h syscall.Handle
191 err := NtOpenFile(
192 &h,
193 DELETE,
194 objAttrs,
195 &IO_STATUS_BLOCK{},
196 FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,
197 FILE_OPEN_REPARSE_POINT|FILE_OPEN_FOR_BACKUP_INTENT,
198 )
199 if err != nil {
200 return ntCreateFileError(err, 0)
201 }
202 defer syscall.CloseHandle(h)
203
204 const (
205 FileDispositionInformation = 13
206 FileDispositionInformationEx = 64
207 )
208
209
210
211
212 err = NtSetInformationFile(
213 h,
214 &IO_STATUS_BLOCK{},
215 uintptr(unsafe.Pointer(&FILE_DISPOSITION_INFORMATION_EX{
216 Flags: FILE_DISPOSITION_DELETE |
217 FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK |
218 FILE_DISPOSITION_POSIX_SEMANTICS |
219
220
221
222 FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE,
223 })),
224 uint32(unsafe.Sizeof(FILE_DISPOSITION_INFORMATION_EX{})),
225 FileDispositionInformationEx,
226 )
227 switch err {
228 case nil:
229 return nil
230 case STATUS_CANNOT_DELETE, STATUS_DIRECTORY_NOT_EMPTY:
231 return err.(NTStatus).Errno()
232 }
233
234
235
236
237
238
239 err = NtSetInformationFile(
240 h,
241 &IO_STATUS_BLOCK{},
242 uintptr(unsafe.Pointer(&FILE_DISPOSITION_INFORMATION{
243 DeleteFile: true,
244 })),
245 uint32(unsafe.Sizeof(FILE_DISPOSITION_INFORMATION{})),
246 FileDispositionInformation,
247 )
248 if st, ok := err.(NTStatus); ok {
249 return st.Errno()
250 }
251 return err
252 }
253
View as plain text