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 options |= FILE_OPEN_REPARSE_POINT
92 case flag&syscall.O_CREAT == syscall.O_CREAT:
93 disposition = FILE_OPEN_IF
94 default:
95 disposition = FILE_OPEN
96 }
97
98 fileAttrs := uint32(FILE_ATTRIBUTE_NORMAL)
99 if perm&syscall.S_IWRITE == 0 {
100 fileAttrs = FILE_ATTRIBUTE_READONLY
101 }
102
103 var h syscall.Handle
104 err := NtCreateFile(
105 &h,
106 SYNCHRONIZE|access,
107 objAttrs,
108 &IO_STATUS_BLOCK{},
109 nil,
110 fileAttrs,
111 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
112 disposition,
113 FILE_SYNCHRONOUS_IO_NONALERT|FILE_OPEN_FOR_BACKUP_INTENT|options,
114 0,
115 0,
116 )
117 if err != nil {
118 return h, ntCreateFileError(err, flag)
119 }
120
121 if flag&syscall.O_TRUNC != 0 {
122 err = syscall.Ftruncate(h, 0)
123 if err != nil {
124 syscall.CloseHandle(h)
125 return syscall.InvalidHandle, err
126 }
127 }
128
129 return h, nil
130 }
131
132
133 func ntCreateFileError(err error, flag int) error {
134 s, ok := err.(NTStatus)
135 if !ok {
136
137 return err
138 }
139 switch s {
140 case STATUS_REPARSE_POINT_ENCOUNTERED:
141 return syscall.ELOOP
142 case STATUS_NOT_A_DIRECTORY:
143
144
145
146
147
148
149
150
151 if flag&O_DIRECTORY != 0 {
152 return syscall.ENOTDIR
153 }
154 case STATUS_FILE_IS_A_DIRECTORY:
155 return syscall.EISDIR
156 }
157 return s.Errno()
158 }
159
160 func Mkdirat(dirfd syscall.Handle, name string, mode uint32) error {
161 objAttrs := &OBJECT_ATTRIBUTES{}
162 if err := objAttrs.init(dirfd, name); err != nil {
163 return err
164 }
165 var h syscall.Handle
166 err := NtCreateFile(
167 &h,
168 FILE_GENERIC_READ,
169 objAttrs,
170 &IO_STATUS_BLOCK{},
171 nil,
172 syscall.FILE_ATTRIBUTE_NORMAL,
173 syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
174 FILE_CREATE,
175 FILE_DIRECTORY_FILE,
176 0,
177 0,
178 )
179 if err != nil {
180 return ntCreateFileError(err, 0)
181 }
182 syscall.CloseHandle(h)
183 return nil
184 }
185
186 func Deleteat(dirfd syscall.Handle, name string) error {
187 objAttrs := &OBJECT_ATTRIBUTES{}
188 if err := objAttrs.init(dirfd, name); err != nil {
189 return err
190 }
191 var h syscall.Handle
192 err := NtOpenFile(
193 &h,
194 DELETE,
195 objAttrs,
196 &IO_STATUS_BLOCK{},
197 FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,
198 FILE_OPEN_REPARSE_POINT|FILE_OPEN_FOR_BACKUP_INTENT,
199 )
200 if err != nil {
201 return ntCreateFileError(err, 0)
202 }
203 defer syscall.CloseHandle(h)
204
205 const (
206 FileDispositionInformation = 13
207 FileDispositionInformationEx = 64
208 )
209
210
211
212
213 err = NtSetInformationFile(
214 h,
215 &IO_STATUS_BLOCK{},
216 uintptr(unsafe.Pointer(&FILE_DISPOSITION_INFORMATION_EX{
217 Flags: FILE_DISPOSITION_DELETE |
218 FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK |
219 FILE_DISPOSITION_POSIX_SEMANTICS |
220
221
222
223 FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE,
224 })),
225 uint32(unsafe.Sizeof(FILE_DISPOSITION_INFORMATION_EX{})),
226 FileDispositionInformationEx,
227 )
228 switch err {
229 case nil:
230 return nil
231 case STATUS_CANNOT_DELETE, STATUS_DIRECTORY_NOT_EMPTY:
232 return err.(NTStatus).Errno()
233 }
234
235
236
237
238
239
240 err = NtSetInformationFile(
241 h,
242 &IO_STATUS_BLOCK{},
243 uintptr(unsafe.Pointer(&FILE_DISPOSITION_INFORMATION{
244 DeleteFile: true,
245 })),
246 uint32(unsafe.Sizeof(FILE_DISPOSITION_INFORMATION{})),
247 FileDispositionInformation,
248 )
249 if st, ok := err.(NTStatus); ok {
250 return st.Errno()
251 }
252 return err
253 }
254
View as plain text