]>
Commit | Line | Data |
---|---|---|
1fd5e000 CF |
1 | /* fhandler.cc. See console.cc for fhandler_console functions. |
2 | ||
3fd68a6a | 3 | Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, |
7bef7db5 | 4 | 2005, 2006, 2007 Red Hat, Inc. |
1fd5e000 CF |
5 | |
6 | This file is part of Cygwin. | |
7 | ||
8 | This software is a copyrighted work licensed under the terms of the | |
9 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
10 | details. */ | |
11 | ||
4c8d72de | 12 | #include "winsup.h" |
1fd5e000 CF |
13 | #include <unistd.h> |
14 | #include <stdlib.h> | |
f0338f54 | 15 | #include <sys/cygwin.h> |
ab7f9b93 | 16 | #include <sys/uio.h> |
e3d1d515 | 17 | #include <sys/acl.h> |
3323df7e | 18 | #include <sys/statvfs.h> |
f0338f54 | 19 | #include <signal.h> |
9e2baf8d | 20 | #include "cygerrno.h" |
95a8465b | 21 | #include "perprocess.h" |
6b91b8d5 | 22 | #include "security.h" |
96a3f4ae | 23 | #include "cygwin/version.h" |
47063f00 | 24 | #include "path.h" |
7ac61736 | 25 | #include "fhandler.h" |
0381fec6 CF |
26 | #include "dtable.h" |
27 | #include "cygheap.h" | |
29ac7f89 | 28 | #include "shared_info.h" |
8d817b0f | 29 | #include "pinfo.h" |
47063f00 | 30 | #include <assert.h> |
acb56175 | 31 | #include <limits.h> |
fac297d5 | 32 | #include <winioctl.h> |
e8597065 CV |
33 | #include <ntdef.h> |
34 | #include "ntdll.h" | |
d9c0e3ec CF |
35 | #include "cygtls.h" |
36 | #include "sigproc.h" | |
1fd5e000 CF |
37 | |
38 | static NO_COPY const int CHUNK_SIZE = 1024; /* Used for crlf conversions */ | |
39 | ||
08b78edf | 40 | struct __cygwin_perfile *perfile_table; |
bd4ec496 | 41 | |
08b78edf | 42 | DWORD binmode; |
14a3bc2f | 43 | |
b0e82b74 | 44 | inline fhandler_base& |
7ac61736 | 45 | fhandler_base::operator =(fhandler_base& x) |
b0e82b74 CF |
46 | { |
47 | memcpy (this, &x, sizeof *this); | |
19afaa1a | 48 | pc = x.pc; |
b0e82b74 CF |
49 | rabuf = NULL; |
50 | ralen = 0; | |
51 | raixget = 0; | |
52 | raixput = 0; | |
53 | rabuflen = 0; | |
54 | return *this; | |
55 | } | |
56 | ||
1fd5e000 | 57 | int |
aa6df8d7 | 58 | fhandler_base::puts_readahead (const char *s, size_t len) |
1fd5e000 CF |
59 | { |
60 | int success = 1; | |
3020ba83 | 61 | while ((len == (size_t) -1 ? *s : len--) |
b0e82b74 | 62 | && (success = put_readahead (*s++) > 0)) |
1fd5e000 CF |
63 | continue; |
64 | return success; | |
65 | } | |
66 | ||
67 | int | |
68 | fhandler_base::put_readahead (char value) | |
69 | { | |
70 | char *newrabuf; | |
71 | if (raixput < rabuflen) | |
72 | /* Nothing to do */; | |
73 | else if ((newrabuf = (char *) realloc (rabuf, rabuflen += 32))) | |
74 | rabuf = newrabuf; | |
75 | else | |
76 | return 0; | |
77 | ||
78 | rabuf[raixput++] = value; | |
79 | ralen++; | |
80 | return 1; | |
81 | } | |
82 | ||
83 | int | |
84 | fhandler_base::get_readahead () | |
85 | { | |
86 | int chret = -1; | |
87 | if (raixget < ralen) | |
0381fec6 | 88 | chret = ((unsigned char) rabuf[raixget++]) & 0xff; |
1fd5e000 CF |
89 | /* FIXME - not thread safe */ |
90 | if (raixget >= ralen) | |
91 | raixget = raixput = ralen = 0; | |
92 | return chret; | |
93 | } | |
94 | ||
95 | int | |
96 | fhandler_base::peek_readahead (int queryput) | |
97 | { | |
98 | int chret = -1; | |
99 | if (!queryput && raixget < ralen) | |
100 | chret = ((unsigned char) rabuf[raixget]) & 0xff; | |
101 | else if (queryput && raixput > 0) | |
102 | chret = ((unsigned char) rabuf[raixput - 1]) & 0xff; | |
103 | return chret; | |
104 | } | |
105 | ||
106 | void | |
aa6df8d7 | 107 | fhandler_base::set_readahead_valid (int val, int ch) |
1fd5e000 CF |
108 | { |
109 | if (!val) | |
110 | ralen = raixget = raixput = 0; | |
111 | if (ch != -1) | |
c90e1cf1 | 112 | put_readahead (ch); |
1fd5e000 CF |
113 | } |
114 | ||
115 | int | |
116 | fhandler_base::eat_readahead (int n) | |
117 | { | |
118 | int oralen = ralen; | |
119 | if (n < 0) | |
120 | n = ralen; | |
121 | if (n > 0 && ralen) | |
122 | { | |
9cec3d45 | 123 | if ((int) (ralen -= n) < 0) |
1fd5e000 CF |
124 | ralen = 0; |
125 | ||
126 | if (raixget >= ralen) | |
127 | raixget = raixput = ralen = 0; | |
128 | else if (raixput > ralen) | |
129 | raixput = ralen; | |
130 | } | |
131 | ||
132 | return oralen; | |
133 | } | |
134 | ||
3f0b4935 CF |
135 | int |
136 | fhandler_base::get_readahead_into_buffer (char *buf, size_t buflen) | |
137 | { | |
138 | int ch; | |
139 | int copied_chars = 0; | |
140 | ||
141 | while (buflen) | |
142 | if ((ch = get_readahead ()) < 0) | |
143 | break; | |
144 | else | |
145 | { | |
146 | buf[copied_chars++] = (unsigned char)(ch & 0xff); | |
147 | buflen--; | |
148 | } | |
149 | ||
150 | return copied_chars; | |
151 | } | |
152 | ||
7ac61736 CF |
153 | /* Record the file name. and name hash */ |
154 | void | |
155 | fhandler_base::set_name (path_conv &in_pc) | |
1fd5e000 | 156 | { |
19afaa1a | 157 | pc = in_pc; |
47063f00 CF |
158 | } |
159 | ||
4f27e288 CV |
160 | char *fhandler_base::get_proc_fd_name (char *buf) |
161 | { | |
162 | if (get_name ()) | |
163 | return strcpy (buf, get_name ()); | |
164 | if (dev ().name) | |
165 | return strcpy (buf, dev ().name); | |
e8309efd | 166 | return strcpy (buf, ""); |
4f27e288 CV |
167 | } |
168 | ||
fe1c7fe7 CF |
169 | /* Detect if we are sitting at EOF for conditions where Windows |
170 | returns an error but UNIX doesn't. */ | |
171 | static int __stdcall | |
172 | is_at_eof (HANDLE h, DWORD err) | |
173 | { | |
6ce2c241 CV |
174 | IO_STATUS_BLOCK io; |
175 | FILE_POSITION_INFORMATION fpi; | |
176 | FILE_STANDARD_INFORMATION fsi; | |
177 | ||
178 | if (NT_SUCCESS (NtQueryInformationFile (h, &io, &fsi, sizeof fsi, | |
179 | FileStandardInformation)) | |
180 | && NT_SUCCESS (NtQueryInformationFile (h, &io, &fpi, sizeof fpi, | |
181 | FilePositionInformation)) | |
182 | && fsi.EndOfFile.QuadPart == fpi.CurrentByteOffset.QuadPart) | |
183 | return 1; | |
fe1c7fe7 CF |
184 | SetLastError (err); |
185 | return 0; | |
186 | } | |
187 | ||
c25ebbaf CF |
188 | void |
189 | fhandler_base::set_flags (int flags, int supplied_bin) | |
190 | { | |
191 | int bin; | |
192 | int fmode; | |
193 | debug_printf ("flags %p, supplied_bin %p", flags, supplied_bin); | |
194 | if ((bin = flags & (O_BINARY | O_TEXT))) | |
195 | debug_printf ("O_TEXT/O_BINARY set in flags %p", bin); | |
56551a9b CV |
196 | else if (rbinset () && wbinset ()) |
197 | bin = rbinary () ? O_BINARY : O_TEXT; // FIXME: Not quite right | |
c25ebbaf CF |
198 | else if ((fmode = get_default_fmode (flags)) & O_BINARY) |
199 | bin = O_BINARY; | |
200 | else if (fmode & O_TEXT) | |
201 | bin = O_TEXT; | |
202 | else if (supplied_bin) | |
203 | bin = supplied_bin; | |
204 | else | |
56551a9b | 205 | bin = wbinary () || rbinary () || (binmode != O_TEXT) |
5bf785a0 | 206 | ? O_BINARY : O_TEXT; |
c25ebbaf CF |
207 | |
208 | openflags = flags | bin; | |
209 | ||
210 | bin &= O_BINARY; | |
56551a9b CV |
211 | rbinary (bin ? true : false); |
212 | wbinary (bin ? true : false); | |
c25ebbaf CF |
213 | syscall_printf ("filemode set to %s", bin ? "binary" : "text"); |
214 | } | |
215 | ||
1fd5e000 CF |
216 | /* Normal file i/o handlers. */ |
217 | ||
218 | /* Cover function to ReadFile to achieve (as much as possible) Posix style | |
219 | semantics and use of errno. */ | |
8bce0d72 CF |
220 | void |
221 | fhandler_base::raw_read (void *ptr, size_t& ulen) | |
1fd5e000 | 222 | { |
6cce721b | 223 | #define bytes_read ulen |
8bce0d72 | 224 | |
2f98d8bd | 225 | int try_noreserve = 1; |
8bce0d72 | 226 | DWORD len = ulen; |
3627f682 | 227 | |
2f98d8bd | 228 | retry: |
c0a9bffd | 229 | ulen = (size_t) -1; |
d9c0e3ec | 230 | BOOL res = ReadFile (get_handle (), ptr, len, (DWORD *) &ulen, NULL); |
8bce0d72 | 231 | if (!res) |
1fd5e000 | 232 | { |
1fd5e000 CF |
233 | /* Some errors are not really errors. Detect such cases here. */ |
234 | ||
8bce0d72 | 235 | DWORD errcode = GetLastError (); |
1fd5e000 CF |
236 | switch (errcode) |
237 | { | |
238 | case ERROR_BROKEN_PIPE: | |
239 | /* This is really EOF. */ | |
240 | bytes_read = 0; | |
241 | break; | |
242 | case ERROR_MORE_DATA: | |
243 | /* `bytes_read' is supposedly valid. */ | |
244 | break; | |
fe1c7fe7 CF |
245 | case ERROR_NOACCESS: |
246 | if (is_at_eof (get_handle (), errcode)) | |
8bce0d72 CF |
247 | { |
248 | bytes_read = 0; | |
249 | break; | |
250 | } | |
2f98d8bd CF |
251 | if (try_noreserve) |
252 | { | |
253 | try_noreserve = 0; | |
254 | switch (mmap_is_attached_or_noreserve (ptr, len)) | |
255 | { | |
256 | case MMAP_NORESERVE_COMMITED: | |
257 | goto retry; | |
258 | case MMAP_RAISE_SIGBUS: | |
259 | raise(SIGBUS); | |
260 | case MMAP_NONE: | |
261 | break; | |
262 | } | |
263 | } | |
70e476d2 | 264 | /*FALLTHRU*/ |
47063f00 CF |
265 | case ERROR_INVALID_FUNCTION: |
266 | case ERROR_INVALID_PARAMETER: | |
5bf785a0 | 267 | case ERROR_INVALID_HANDLE: |
e8bf2329 | 268 | if (pc.isdir ()) |
47063f00 CF |
269 | { |
270 | set_errno (EISDIR); | |
6cce721b | 271 | bytes_read = (size_t) -1; |
8bce0d72 | 272 | break; |
47063f00 | 273 | } |
1fd5e000 | 274 | default: |
b739751d | 275 | syscall_printf ("ReadFile %s(%p) failed, %E", get_name (), get_handle ()); |
b0e82b74 | 276 | __seterrno_from_win_error (errcode); |
6cce721b | 277 | bytes_read = (size_t) -1; |
1fd5e000 CF |
278 | break; |
279 | } | |
280 | } | |
8bce0d72 | 281 | #undef bytes_read |
1fd5e000 CF |
282 | } |
283 | ||
1fd5e000 CF |
284 | /* Cover function to WriteFile to provide Posix interface and semantics |
285 | (as much as possible). */ | |
6ce2c241 CV |
286 | static LARGE_INTEGER off_current = { QuadPart:FILE_USE_FILE_POINTER_POSITION }; |
287 | static LARGE_INTEGER off_append = { QuadPart:FILE_WRITE_TO_END_OF_FILE }; | |
288 | ||
1fd5e000 CF |
289 | int |
290 | fhandler_base::raw_write (const void *ptr, size_t len) | |
291 | { | |
6ce2c241 CV |
292 | NTSTATUS status; |
293 | IO_STATUS_BLOCK io; | |
1fd5e000 | 294 | |
6ce2c241 CV |
295 | status = NtWriteFile (get_output_handle (), NULL, NULL, NULL, &io, |
296 | (PVOID) ptr, len, | |
297 | (get_flags () & O_APPEND) ? &off_append : &off_current, | |
298 | NULL); | |
299 | if (!NT_SUCCESS (status)) | |
1fd5e000 | 300 | { |
6ce2c241 | 301 | if (status == STATUS_DISK_FULL && io.Information > 0) |
8be730bb | 302 | goto written; |
6ce2c241 | 303 | __seterrno_from_nt_status (status); |
1fd5e000 CF |
304 | if (get_errno () == EPIPE) |
305 | raise (SIGPIPE); | |
306 | return -1; | |
307 | } | |
8be730bb | 308 | written: |
6ce2c241 | 309 | return io.Information; |
1fd5e000 CF |
310 | } |
311 | ||
bd4ec496 CF |
312 | int |
313 | fhandler_base::get_default_fmode (int flags) | |
314 | { | |
0301bfd0 | 315 | int fmode = __fmode; |
bd4ec496 CF |
316 | if (perfile_table) |
317 | { | |
318 | size_t nlen = strlen (get_name ()); | |
ba31e832 | 319 | unsigned accflags = (flags & O_ACCMODE); |
bd4ec496 | 320 | for (__cygwin_perfile *pf = perfile_table; pf->name; pf++) |
ba31e832 | 321 | if (!*pf->name && (pf->flags & O_ACCMODE) == accflags) |
0301bfd0 | 322 | { |
ba31e832 | 323 | fmode = pf->flags & ~O_ACCMODE; |
0301bfd0 CF |
324 | break; |
325 | } | |
bb5d559a CF |
326 | else |
327 | { | |
328 | size_t pflen = strlen (pf->name); | |
329 | const char *stem = get_name () + nlen - pflen; | |
330 | if (pflen > nlen || (stem != get_name () && !isdirsep (stem[-1]))) | |
331 | continue; | |
ba31e832 CV |
332 | else if ((pf->flags & O_ACCMODE) == accflags |
333 | && strcasematch (stem, pf->name)) | |
0301bfd0 | 334 | { |
ba31e832 | 335 | fmode = pf->flags & ~O_ACCMODE; |
0301bfd0 CF |
336 | break; |
337 | } | |
bb5d559a | 338 | } |
bd4ec496 | 339 | } |
0301bfd0 | 340 | return fmode; |
bd4ec496 CF |
341 | } |
342 | ||
7ac61736 CF |
343 | bool |
344 | fhandler_base::device_access_denied (int flags) | |
345 | { | |
346 | int mode = 0; | |
7ac61736 CF |
347 | |
348 | if (flags & O_RDWR) | |
349 | mode |= R_OK | W_OK; | |
350 | if (flags & (O_WRONLY | O_APPEND)) | |
351 | mode |= W_OK; | |
352 | if (!mode) | |
353 | mode |= R_OK; | |
354 | ||
f4e815bc CF |
355 | return fhaccess (mode); |
356 | } | |
357 | ||
9157f0f3 | 358 | int |
f4e815bc CF |
359 | fhandler_base::fhaccess (int flags) |
360 | { | |
9157f0f3 | 361 | int res = -1; |
f4e815bc CF |
362 | if (error ()) |
363 | { | |
364 | set_errno (error ()); | |
9157f0f3 | 365 | goto done; |
f4e815bc CF |
366 | } |
367 | ||
368 | if (!exists ()) | |
369 | { | |
370 | set_errno (ENOENT); | |
9157f0f3 | 371 | goto done; |
f4e815bc CF |
372 | } |
373 | ||
374 | if (!(flags & (R_OK | W_OK | X_OK))) | |
375 | return 0; | |
376 | ||
377 | if (is_fs_special ()) | |
378 | /* short circuit */; | |
101f07b9 CV |
379 | else if (has_attribute (FILE_ATTRIBUTE_READONLY) && (flags & W_OK) |
380 | && !pc.isdir ()) | |
d7231d72 CF |
381 | goto eaccess_done; |
382 | else if (has_acls () && allow_ntsec) | |
f4e815bc | 383 | { |
eea4e482 | 384 | res = check_file_access (pc, flags); |
9157f0f3 | 385 | goto done; |
f4e815bc | 386 | } |
2b26c2fc CV |
387 | else if (get_device () == FH_REGISTRY && allow_ntsec && open (O_RDONLY, 0) |
388 | && get_handle ()) | |
1b4153db CV |
389 | { |
390 | res = check_registry_access (get_handle (), flags); | |
391 | close (); | |
392 | return res; | |
393 | } | |
f4e815bc CF |
394 | |
395 | struct __stat64 st; | |
9157f0f3 CF |
396 | if (fstat (&st)) |
397 | goto done; | |
398 | ||
f4e815bc CF |
399 | if (flags & R_OK) |
400 | { | |
401 | if (st.st_uid == myself->uid) | |
402 | { | |
403 | if (!(st.st_mode & S_IRUSR)) | |
d7231d72 | 404 | goto eaccess_done; |
f4e815bc CF |
405 | } |
406 | else if (st.st_gid == myself->gid) | |
407 | { | |
408 | if (!(st.st_mode & S_IRGRP)) | |
d7231d72 | 409 | goto eaccess_done; |
f4e815bc CF |
410 | } |
411 | else if (!(st.st_mode & S_IROTH)) | |
d7231d72 | 412 | goto eaccess_done; |
f4e815bc | 413 | } |
9157f0f3 | 414 | |
f4e815bc CF |
415 | if (flags & W_OK) |
416 | { | |
417 | if (st.st_uid == myself->uid) | |
418 | { | |
419 | if (!(st.st_mode & S_IWUSR)) | |
d7231d72 | 420 | goto eaccess_done; |
f4e815bc CF |
421 | } |
422 | else if (st.st_gid == myself->gid) | |
423 | { | |
424 | if (!(st.st_mode & S_IWGRP)) | |
d7231d72 | 425 | goto eaccess_done; |
f4e815bc CF |
426 | } |
427 | else if (!(st.st_mode & S_IWOTH)) | |
d7231d72 | 428 | goto eaccess_done; |
f4e815bc | 429 | } |
9157f0f3 | 430 | |
f4e815bc CF |
431 | if (flags & X_OK) |
432 | { | |
433 | if (st.st_uid == myself->uid) | |
434 | { | |
435 | if (!(st.st_mode & S_IXUSR)) | |
d7231d72 | 436 | goto eaccess_done; |
f4e815bc CF |
437 | } |
438 | else if (st.st_gid == myself->gid) | |
439 | { | |
440 | if (!(st.st_mode & S_IXGRP)) | |
d7231d72 | 441 | goto eaccess_done; |
f4e815bc CF |
442 | } |
443 | else if (!(st.st_mode & S_IXOTH)) | |
d7231d72 | 444 | goto eaccess_done; |
f4e815bc | 445 | } |
d7231d72 | 446 | |
9157f0f3 | 447 | res = 0; |
d7231d72 CF |
448 | goto done; |
449 | ||
450 | eaccess_done: | |
451 | set_errno (EACCES); | |
f4e815bc | 452 | done: |
52a6e6d8 CV |
453 | if (!res && (flags & W_OK) && get_device () == FH_FS |
454 | && (pc.fs_flags () & FILE_READ_ONLY_VOLUME)) | |
455 | { | |
456 | set_errno (EROFS); | |
457 | res = -1; | |
458 | } | |
9157f0f3 CF |
459 | debug_printf ("returning %d", res); |
460 | return res; | |
7ac61736 CF |
461 | } |
462 | ||
e8597065 CV |
463 | /* Open system call handler function. */ |
464 | int | |
465 | fhandler_base::open (int flags, mode_t mode) | |
466 | { | |
e8597065 CV |
467 | int res = 0; |
468 | HANDLE x; | |
469 | ULONG file_attributes = 0; | |
bd8f891e | 470 | ULONG shared = (get_major () == DEV_TAPE_MAJOR ? 0 : FILE_SHARE_VALID_FLAGS); |
e8597065 CV |
471 | ULONG create_disposition; |
472 | ULONG create_options; | |
473 | SECURITY_ATTRIBUTES sa = sec_none; | |
474 | security_descriptor sd; | |
e8597065 CV |
475 | OBJECT_ATTRIBUTES attr; |
476 | IO_STATUS_BLOCK io; | |
477 | NTSTATUS status; | |
478 | ||
19afaa1a | 479 | syscall_printf ("(%S, %p)", pc.get_nt_native_path (), flags); |
e6b21daf | 480 | |
91d2f6ee | 481 | pc.get_object_attr (attr, sa); |
e8597065 CV |
482 | |
483 | switch (query_open ()) | |
484 | { | |
485 | case query_read_control: | |
3323df7e CV |
486 | access = READ_CONTROL; |
487 | create_options = FILE_OPEN_FOR_BACKUP_INTENT; | |
488 | break; | |
489 | case query_read_attributes: | |
b65479ca | 490 | access = READ_CONTROL | FILE_READ_ATTRIBUTES; |
e3778517 CF |
491 | create_options = FILE_OPEN_FOR_BACKUP_INTENT; |
492 | break; | |
e8597065 | 493 | case query_write_control: |
6e070c25 | 494 | access = READ_CONTROL | WRITE_OWNER | WRITE_DAC | FILE_WRITE_ATTRIBUTES; |
e3778517 CF |
495 | create_options = FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_FOR_RECOVERY; |
496 | break; | |
2b09be25 CV |
497 | case query_write_attributes: |
498 | access = READ_CONTROL | FILE_WRITE_ATTRIBUTES; | |
499 | create_options = FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_FOR_RECOVERY; | |
500 | break; | |
e8597065 | 501 | default: |
ba31e832 | 502 | if ((flags & O_ACCMODE) == O_RDONLY) |
2c1ffdbf CV |
503 | { |
504 | access = GENERIC_READ; | |
505 | create_options = FILE_OPEN_FOR_BACKUP_INTENT; | |
506 | } | |
ba31e832 | 507 | else if ((flags & O_ACCMODE) == O_WRONLY) |
2c1ffdbf | 508 | { |
fe7bbe15 CV |
509 | access = GENERIC_WRITE | READ_CONTROL | FILE_READ_ATTRIBUTES; |
510 | create_options = FILE_OPEN_FOR_BACKUP_INTENT | |
511 | | FILE_OPEN_FOR_RECOVERY; | |
2c1ffdbf | 512 | } |
e8597065 | 513 | else |
2c1ffdbf CV |
514 | { |
515 | access = GENERIC_READ | GENERIC_WRITE; | |
516 | create_options = FILE_OPEN_FOR_BACKUP_INTENT | |
517 | | FILE_OPEN_FOR_RECOVERY; | |
518 | } | |
e3d14af1 CV |
519 | if (flags & O_SYNC) |
520 | create_options |= FILE_WRITE_THROUGH; | |
521 | if (flags & O_DIRECT) | |
522 | create_options |= FILE_NO_INTERMEDIATE_BUFFERING; | |
1b557b43 | 523 | if (get_major () != DEV_SERIAL_MAJOR && get_major () != DEV_TAPE_MAJOR) |
e8597065 CV |
524 | { |
525 | create_options |= FILE_SYNCHRONOUS_IO_NONALERT; | |
526 | access |= SYNCHRONIZE; | |
527 | } | |
528 | break; | |
529 | } | |
530 | ||
531 | if ((flags & O_TRUNC) && ((flags & O_ACCMODE) != O_RDONLY)) | |
532 | { | |
533 | if (flags & O_CREAT) | |
f6d9664b | 534 | create_disposition = FILE_OVERWRITE_IF; |
e8597065 CV |
535 | else |
536 | create_disposition = FILE_OVERWRITE; | |
537 | } | |
538 | else if (flags & O_CREAT) | |
539 | create_disposition = FILE_OPEN_IF; | |
540 | else | |
541 | create_disposition = FILE_OPEN; | |
542 | ||
543 | if ((flags & O_EXCL) && (flags & O_CREAT)) | |
544 | create_disposition = FILE_CREATE; | |
545 | ||
f3257492 | 546 | if (get_device () == FH_FS) |
e8597065 | 547 | { |
f3257492 CV |
548 | /* Add the reparse point flag to native symlinks, otherwise we open the |
549 | target, not the symlink. This would break lstat. */ | |
550 | if (pc.is_rep_symlink ()) | |
551 | create_options |= FILE_OPEN_REPARSE_POINT; | |
552 | ||
553 | if (flags & O_CREAT) | |
e8597065 | 554 | { |
f3257492 CV |
555 | file_attributes = FILE_ATTRIBUTE_NORMAL; |
556 | /* If mode has no write bits set, we set the R/O attribute. */ | |
557 | if (!(mode & (S_IWUSR | S_IWGRP | S_IWOTH))) | |
558 | file_attributes |= FILE_ATTRIBUTE_READONLY; | |
559 | /* Starting with Windows 2000, when trying to overwrite an already | |
560 | existing file with FILE_ATTRIBUTE_HIDDEN and/or FILE_ATTRIBUTE_SYSTEM | |
561 | attribute set, CreateFile fails with ERROR_ACCESS_DENIED. | |
562 | Per MSDN you have to create the file with the same attributes as | |
563 | already specified for the file. */ | |
564 | if (has_attribute (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) | |
565 | file_attributes |= pc.file_attributes (); | |
566 | ||
567 | /* If the file should actually be created and ntsec is on, | |
568 | set files attributes. */ | |
569 | /* TODO: Don't remove the call to has_acls() unless there's a | |
570 | solution for the security descriptor problem on remote samba | |
571 | drives. The local user SID is used in set_security_attribute, | |
572 | but the actual owner on the Samba share is the SID of the Unix | |
573 | account. There's no transparent mapping between these accounts. | |
574 | And Samba has a strange behaviour when creating a file. Apparently | |
575 | it *first* creates the file, *then* it looks if the security | |
576 | descriptor matches. The result is that the file gets created, but | |
577 | then NtCreateFile doesn't return a handle to the file and fails | |
578 | with STATUS_ACCESS_DENIED. Go figure! */ | |
579 | if (allow_ntsec && has_acls ()) | |
580 | { | |
581 | set_security_attribute (mode, &sa, sd); | |
582 | attr.SecurityDescriptor = sa.lpSecurityDescriptor; | |
583 | } | |
584 | /* The file attributes are needed for later use in, e.g. fchmod. */ | |
585 | pc.file_attributes (file_attributes); | |
e8597065 CV |
586 | } |
587 | } | |
588 | ||
589 | status = NtCreateFile (&x, access, &attr, &io, NULL, file_attributes, shared, | |
e3778517 | 590 | create_disposition, create_options, NULL, 0); |
e8597065 CV |
591 | if (!NT_SUCCESS (status)) |
592 | { | |
7460bfd3 | 593 | __seterrno_from_nt_status (status); |
e8597065 CV |
594 | if (!nohandle ()) |
595 | goto done; | |
596 | } | |
597 | ||
e8597065 CV |
598 | set_io_handle (x); |
599 | set_flags (flags, pc.binmode ()); | |
600 | ||
601 | res = 1; | |
602 | set_open_status (); | |
603 | done: | |
bd0e9c7a | 604 | debug_printf ("%x = NtCreateFile " |
19afaa1a CV |
605 | "(%p, %x, %S, io, NULL, %x, %x, %x, %x, NULL, 0)", |
606 | status, x, access, pc.get_nt_native_path (), file_attributes, | |
607 | shared, create_disposition, create_options); | |
bd0e9c7a | 608 | |
19afaa1a CV |
609 | syscall_printf ("%d = fhandler_base::open (%s, %p)", |
610 | res, pc.get_nt_native_path (), flags); | |
e8597065 CV |
611 | return res; |
612 | } | |
613 | ||
1fd5e000 CF |
614 | /* states: |
615 | open buffer in binary mode? Just do the read. | |
616 | ||
617 | open buffer in text mode? Scan buffer for control zs and handle | |
618 | the first one found. Then scan buffer, converting every \r\n into | |
619 | an \n. If last char is an \r, look ahead one more char, if \n then | |
620 | modify \r, if not, remember char. | |
621 | */ | |
8bce0d72 CF |
622 | void |
623 | fhandler_base::read (void *in_ptr, size_t& len) | |
1fd5e000 | 624 | { |
1fd5e000 | 625 | char *ptr = (char *) in_ptr; |
5ecd1ea6 | 626 | ssize_t copied_chars = get_readahead_into_buffer (ptr, len); |
1fd5e000 | 627 | |
c4157069 | 628 | if (copied_chars && is_slow ()) |
8bce0d72 CF |
629 | { |
630 | len = (size_t) copied_chars; | |
3627f682 | 631 | goto out; |
8bce0d72 | 632 | } |
c4157069 | 633 | |
5ecd1ea6 | 634 | len -= copied_chars; |
3627f682 | 635 | if (!len) |
8bce0d72 CF |
636 | { |
637 | len = (size_t) copied_chars; | |
3627f682 | 638 | goto out; |
57bf29e8 | 639 | } |
1fd5e000 | 640 | |
85a798d6 | 641 | raw_read (ptr + copied_chars, len); |
3627f682 CF |
642 | if (!copied_chars) |
643 | /* nothing */; | |
644 | else if ((ssize_t) len > 0) | |
645 | len += copied_chars; | |
646 | else | |
647 | len = copied_chars; | |
1fd5e000 | 648 | |
56551a9b | 649 | if (rbinary () || len <= 0) |
3627f682 | 650 | goto out; |
1fd5e000 CF |
651 | |
652 | /* Scan buffer and turn \r\n into \n */ | |
3627f682 CF |
653 | char *src, *dst, *end; |
654 | src = (char *) ptr; | |
655 | dst = (char *) ptr; | |
656 | end = src + len - 1; | |
1fd5e000 CF |
657 | |
658 | /* Read up to the last but one char - the last char needs special handling */ | |
659 | while (src < end) | |
660 | { | |
8bce0d72 CF |
661 | if (*src == '\r' && src[1] == '\n') |
662 | src++; | |
663 | *dst++ = *src++; | |
1fd5e000 CF |
664 | } |
665 | ||
3627f682 CF |
666 | /* If not beyond end and last char is a '\r' then read one more |
667 | to see if we should translate this one too */ | |
668 | if (src > end) | |
669 | /* nothing */; | |
670 | else if (*src != '\r') | |
671 | *dst++ = *src; | |
672 | else | |
1fd5e000 | 673 | { |
3627f682 CF |
674 | char c1; |
675 | size_t c1len = 1; | |
676 | raw_read (&c1, c1len); | |
677 | if (c1len <= 0) | |
1fd5e000 | 678 | /* nothing */; |
3627f682 CF |
679 | else if (c1 == '\n') |
680 | *dst++ = '\n'; | |
1fd5e000 | 681 | else |
8bce0d72 | 682 | { |
3627f682 CF |
683 | set_readahead_valid (1, c1); |
684 | *dst++ = *src; | |
8bce0d72 | 685 | } |
1fd5e000 CF |
686 | } |
687 | ||
3627f682 | 688 | len = dst - (char *) ptr; |
1fd5e000 | 689 | |
1fd5e000 | 690 | #ifndef NOSTRACE |
5d970405 | 691 | if (strace.active ()) |
1fd5e000 CF |
692 | { |
693 | char buf[16 * 6 + 1]; | |
694 | char *p = buf; | |
695 | ||
696 | for (int i = 0; i < copied_chars && i < 16; ++i) | |
697 | { | |
698 | unsigned char c = ((unsigned char *) ptr)[i]; | |
d54b79d3 | 699 | __small_sprintf (p, " %c", c); |
1fd5e000 CF |
700 | p += strlen (p); |
701 | } | |
8b6d0723 | 702 | *p = '\0'; |
1fd5e000 CF |
703 | debug_printf ("read %d bytes (%s%s)", copied_chars, buf, |
704 | copied_chars > 16 ? " ..." : ""); | |
705 | } | |
706 | #endif | |
707 | ||
3627f682 | 708 | out: |
56551a9b | 709 | debug_printf ("returning %d, %s mode", len, rbinary () ? "binary" : "text"); |
1fd5e000 CF |
710 | } |
711 | ||
712 | int | |
713 | fhandler_base::write (const void *ptr, size_t len) | |
714 | { | |
715 | int res; | |
6ce2c241 CV |
716 | IO_STATUS_BLOCK io; |
717 | FILE_POSITION_INFORMATION fpi; | |
718 | FILE_STANDARD_INFORMATION fsi; | |
1fd5e000 | 719 | |
6ce2c241 | 720 | if (did_lseek ()) |
1fd5e000 | 721 | { |
56551a9b | 722 | did_lseek (false); /* don't do it again */ |
fac297d5 | 723 | |
6ce2c241 CV |
724 | if (!(get_flags () & O_APPEND) |
725 | && NT_SUCCESS (NtQueryInformationFile (get_output_handle (), | |
726 | &io, &fsi, sizeof fsi, | |
727 | FileStandardInformation)) | |
728 | && NT_SUCCESS (NtQueryInformationFile (get_output_handle (), | |
729 | &io, &fpi, sizeof fpi, | |
730 | FilePositionInformation)) | |
731 | && fpi.CurrentByteOffset.QuadPart | |
732 | >= fsi.EndOfFile.QuadPart + (128 * 1024) | |
e9095199 | 733 | && get_fs_flags (FILE_SUPPORTS_SPARSE_FILES)) |
1fd5e000 | 734 | { |
e9095199 CV |
735 | /* If the file system supports sparse files and the application |
736 | is writing after a long seek beyond EOF, convert the file to | |
737 | a sparse file. */ | |
6ce2c241 CV |
738 | NTSTATUS status; |
739 | status = NtFsControlFile (get_output_handle (), NULL, NULL, NULL, | |
740 | &io, FSCTL_SET_SPARSE, NULL, 0, NULL, 0); | |
741 | syscall_printf ("%p = NtFsControlFile(%S, FSCTL_SET_SPARSE)", | |
742 | status, pc.get_nt_native_path ()); | |
1fd5e000 CF |
743 | } |
744 | } | |
745 | ||
56551a9b | 746 | if (wbinary ()) |
1fd5e000 | 747 | { |
57bf29e8 | 748 | debug_printf ("binary write"); |
1fd5e000 CF |
749 | res = raw_write (ptr, len); |
750 | } | |
751 | else | |
752 | { | |
57bf29e8 | 753 | debug_printf ("text write"); |
1fd5e000 | 754 | /* This is the Microsoft/DJGPP way. Still not ideal, but it's |
57bf29e8 CF |
755 | compatible. |
756 | Modified slightly by CGF 2000-10-07 */ | |
1fd5e000 CF |
757 | |
758 | int left_in_data = len; | |
759 | char *data = (char *)ptr; | |
57bf29e8 | 760 | res = 0; |
1fd5e000 CF |
761 | |
762 | while (left_in_data > 0) | |
763 | { | |
57bf29e8 | 764 | char buf[CHUNK_SIZE + 1], *buf_ptr = buf; |
1fd5e000 CF |
765 | int left_in_buf = CHUNK_SIZE; |
766 | ||
767 | while (left_in_buf > 0 && left_in_data > 0) | |
768 | { | |
57bf29e8 CF |
769 | char ch = *data++; |
770 | if (ch == '\n') | |
1fd5e000 | 771 | { |
1fd5e000 CF |
772 | *buf_ptr++ = '\r'; |
773 | left_in_buf--; | |
774 | } | |
57bf29e8 | 775 | *buf_ptr++ = ch; |
1fd5e000 CF |
776 | left_in_buf--; |
777 | left_in_data--; | |
57bf29e8 CF |
778 | if (left_in_data > 0 && ch == '\r' && *data == '\n') |
779 | { | |
780 | *buf_ptr++ = *data++; | |
781 | left_in_buf--; | |
782 | left_in_data--; | |
783 | } | |
1fd5e000 CF |
784 | } |
785 | ||
786 | /* We've got a buffer-full, or we're out of data. Write it out */ | |
57bf29e8 | 787 | int nbytes; |
1fd5e000 | 788 | int want = buf_ptr - buf; |
57bf29e8 | 789 | if ((nbytes = raw_write (buf, want)) == want) |
1fd5e000 | 790 | { |
57bf29e8 CF |
791 | /* Keep track of how much written not counting additional \r's */ |
792 | res = data - (char *)ptr; | |
793 | continue; | |
1fd5e000 | 794 | } |
1fd5e000 | 795 | |
57bf29e8 CF |
796 | if (nbytes == -1) |
797 | res = -1; /* Error */ | |
798 | else | |
799 | res += nbytes; /* Partial write. Return total bytes written. */ | |
800 | break; /* All done */ | |
801 | } | |
1fd5e000 | 802 | } |
57bf29e8 | 803 | |
1fd5e000 CF |
804 | return res; |
805 | } | |
806 | ||
ab7f9b93 CF |
807 | ssize_t |
808 | fhandler_base::readv (const struct iovec *const iov, const int iovcnt, | |
809 | ssize_t tot) | |
810 | { | |
811 | assert (iov); | |
812 | assert (iovcnt >= 1); | |
813 | ||
d2466c7a | 814 | size_t len = tot; |
ab7f9b93 | 815 | if (iovcnt == 1) |
8bce0d72 | 816 | { |
d2466c7a | 817 | len = iov->iov_len; |
8bce0d72 CF |
818 | read (iov->iov_base, len); |
819 | return len; | |
820 | } | |
ab7f9b93 CF |
821 | |
822 | if (tot == -1) // i.e. if not pre-calculated by the caller. | |
823 | { | |
d2466c7a | 824 | len = 0; |
ab7f9b93 | 825 | const struct iovec *iovptr = iov + iovcnt; |
5bf785a0 | 826 | do |
ab7f9b93 CF |
827 | { |
828 | iovptr -= 1; | |
d2466c7a | 829 | len += iovptr->iov_len; |
ab7f9b93 CF |
830 | } |
831 | while (iovptr != iov); | |
832 | } | |
833 | ||
d2466c7a | 834 | if (!len) |
ab7f9b93 CF |
835 | return 0; |
836 | ||
8eb445cf | 837 | char *buf = (char *) malloc (len); |
ab7f9b93 CF |
838 | |
839 | if (!buf) | |
840 | { | |
841 | set_errno (ENOMEM); | |
842 | return -1; | |
843 | } | |
844 | ||
d2466c7a CF |
845 | read (buf, len); |
846 | ssize_t nbytes = (ssize_t) len; | |
ab7f9b93 CF |
847 | |
848 | const struct iovec *iovptr = iov; | |
ab7f9b93 | 849 | |
8eb445cf | 850 | char *p = buf; |
ab7f9b93 CF |
851 | while (nbytes > 0) |
852 | { | |
853 | const int frag = min (nbytes, (ssize_t) iovptr->iov_len); | |
8eb445cf CF |
854 | memcpy (iovptr->iov_base, p, frag); |
855 | p += frag; | |
ab7f9b93 CF |
856 | iovptr += 1; |
857 | nbytes -= frag; | |
858 | } | |
859 | ||
f2abf317 | 860 | free (buf); |
d2466c7a | 861 | return len; |
ab7f9b93 CF |
862 | } |
863 | ||
864 | ssize_t | |
865 | fhandler_base::writev (const struct iovec *const iov, const int iovcnt, | |
866 | ssize_t tot) | |
867 | { | |
868 | assert (iov); | |
869 | assert (iovcnt >= 1); | |
870 | ||
871 | if (iovcnt == 1) | |
872 | return write (iov->iov_base, iov->iov_len); | |
873 | ||
874 | if (tot == -1) // i.e. if not pre-calculated by the caller. | |
875 | { | |
876 | tot = 0; | |
877 | const struct iovec *iovptr = iov + iovcnt; | |
5bf785a0 | 878 | do |
ab7f9b93 CF |
879 | { |
880 | iovptr -= 1; | |
881 | tot += iovptr->iov_len; | |
882 | } | |
883 | while (iovptr != iov); | |
884 | } | |
885 | ||
886 | assert (tot >= 0); | |
887 | ||
888 | if (tot == 0) | |
889 | return 0; | |
890 | ||
f2abf317 | 891 | char *const buf = (char *) malloc (tot); |
ab7f9b93 CF |
892 | |
893 | if (!buf) | |
894 | { | |
895 | set_errno (ENOMEM); | |
896 | return -1; | |
897 | } | |
898 | ||
899 | char *bufptr = buf; | |
900 | const struct iovec *iovptr = iov; | |
901 | int nbytes = tot; | |
902 | ||
903 | while (nbytes != 0) | |
904 | { | |
905 | const int frag = min (nbytes, (ssize_t) iovptr->iov_len); | |
906 | memcpy (bufptr, iovptr->iov_base, frag); | |
907 | bufptr += frag; | |
908 | iovptr += 1; | |
909 | nbytes -= frag; | |
910 | } | |
f2abf317 CV |
911 | ssize_t ret = write (buf, tot); |
912 | free (buf); | |
913 | return ret; | |
ab7f9b93 CF |
914 | } |
915 | ||
1727fba0 CV |
916 | _off64_t |
917 | fhandler_base::lseek (_off64_t offset, int whence) | |
1fd5e000 | 918 | { |
6ce2c241 CV |
919 | NTSTATUS status; |
920 | IO_STATUS_BLOCK io; | |
921 | FILE_POSITION_INFORMATION fpi; | |
922 | FILE_STANDARD_INFORMATION fsi; | |
acb56175 | 923 | |
1fd5e000 CF |
924 | /* Seeks on text files is tough, we rewind and read till we get to the |
925 | right place. */ | |
926 | ||
927 | if (whence != SEEK_CUR || offset != 0) | |
928 | { | |
929 | if (whence == SEEK_CUR) | |
930 | offset -= ralen - raixget; | |
931 | set_readahead_valid (0); | |
932 | } | |
933 | ||
6ce2c241 | 934 | switch (whence) |
1fd5e000 | 935 | { |
6ce2c241 CV |
936 | case SEEK_SET: |
937 | fpi.CurrentByteOffset.QuadPart = offset; | |
938 | break; | |
939 | case SEEK_CUR: | |
940 | status = NtQueryInformationFile (get_handle (), &io, &fpi, sizeof fpi, | |
941 | FilePositionInformation); | |
942 | if (!NT_SUCCESS (status)) | |
70300fdb | 943 | { |
6ce2c241 CV |
944 | __seterrno_from_nt_status (status); |
945 | return -1; | |
946 | } | |
947 | fpi.CurrentByteOffset.QuadPart += offset; | |
948 | break; | |
949 | default: /* SEEK_END */ | |
950 | status = NtQueryInformationFile (get_handle (), &io, &fsi, sizeof fsi, | |
951 | FileStandardInformation); | |
952 | if (!NT_SUCCESS (status)) | |
70300fdb | 953 | { |
6ce2c241 CV |
954 | __seterrno_from_nt_status (status); |
955 | return -1; | |
956 | } | |
957 | fpi.CurrentByteOffset.QuadPart = fsi.EndOfFile.QuadPart + offset; | |
958 | break; | |
1fd5e000 | 959 | } |
6ce2c241 CV |
960 | |
961 | debug_printf ("setting file pointer to %U", fpi.CurrentByteOffset.QuadPart); | |
962 | status = NtSetInformationFile (get_handle (), &io, &fpi, sizeof fpi, | |
963 | FilePositionInformation); | |
964 | if (!NT_SUCCESS (status)) | |
1fd5e000 | 965 | { |
6ce2c241 CV |
966 | __seterrno_from_nt_status (status); |
967 | return -1; | |
968 | } | |
969 | _off64_t res = fpi.CurrentByteOffset.QuadPart; | |
8f4dfcaa | 970 | |
6ce2c241 CV |
971 | /* When next we write(), we will check to see if *this* seek went beyond |
972 | the end of the file and if so, potentially sparsify the file. */ | |
973 | did_lseek (true); | |
1fd5e000 | 974 | |
6ce2c241 CV |
975 | /* If this was a SEEK_CUR with offset 0, we still might have |
976 | readahead that we have to take into account when calculating | |
977 | the actual position for the application. */ | |
978 | if (whence == SEEK_CUR) | |
979 | res -= ralen - raixget; | |
1fd5e000 CF |
980 | |
981 | return res; | |
982 | } | |
983 | ||
7d7d09ae CF |
984 | ssize_t __stdcall |
985 | fhandler_base::pread (void *, size_t, _off64_t) | |
986 | { | |
987 | set_errno (ESPIPE); | |
988 | return -1; | |
989 | } | |
990 | ||
991 | ssize_t __stdcall | |
992 | fhandler_base::pwrite (void *, size_t, _off64_t) | |
993 | { | |
994 | set_errno (ESPIPE); | |
995 | return -1; | |
996 | } | |
997 | ||
1fd5e000 | 998 | int |
e62ac9e8 | 999 | fhandler_base::close () |
1fd5e000 CF |
1000 | { |
1001 | int res = -1; | |
1002 | ||
c90e1cf1 | 1003 | syscall_printf ("closing '%s' handle %p", get_name (), get_handle ()); |
56551a9b | 1004 | if (nohandle () || CloseHandle (get_handle ())) |
1fd5e000 CF |
1005 | res = 0; |
1006 | else | |
1007 | { | |
c90e1cf1 | 1008 | paranoid_printf ("CloseHandle (%d <%s>) failed", get_handle (), |
1fd5e000 CF |
1009 | get_name ()); |
1010 | ||
1011 | __seterrno (); | |
1012 | } | |
d9c0e3ec | 1013 | destroy_overlapped (); |
1fd5e000 CF |
1014 | return res; |
1015 | } | |
1016 | ||
1017 | int | |
1018 | fhandler_base::ioctl (unsigned int cmd, void *buf) | |
1019 | { | |
89256ff1 | 1020 | int res; |
1fd5e000 | 1021 | |
89256ff1 CV |
1022 | switch (cmd) |
1023 | { | |
1024 | case FIONBIO: | |
1025 | set_nonblocking (*(int *) buf); | |
1026 | res = 0; | |
1027 | break; | |
1028 | default: | |
1029 | set_errno (EINVAL); | |
1030 | res = -1; | |
1031 | break; | |
1032 | } | |
1033 | ||
1034 | syscall_printf ("%d = ioctl (%x, %p)", res, cmd, buf); | |
1035 | return res; | |
1fd5e000 CF |
1036 | } |
1037 | ||
1038 | int | |
dc399868 | 1039 | fhandler_base::lock (int, struct __flock64 *) |
1fd5e000 | 1040 | { |
5bf785a0 | 1041 | set_errno (EINVAL); |
1fd5e000 CF |
1042 | return -1; |
1043 | } | |
1044 | ||
8d817b0f | 1045 | int __stdcall |
7ac61736 | 1046 | fhandler_base::fstat (struct __stat64 *buf) |
8d817b0f | 1047 | { |
0301bfd0 | 1048 | debug_printf ("here"); |
7ac61736 CF |
1049 | |
1050 | if (is_fs_special ()) | |
1051 | return fstat_fs (buf); | |
1052 | ||
8d817b0f CF |
1053 | switch (get_device ()) |
1054 | { | |
035bfbdd | 1055 | case FH_PIPE: |
5ef61dd0 | 1056 | buf->st_mode = S_IFIFO | S_IRUSR | S_IWUSR; |
035bfbdd | 1057 | break; |
8d817b0f | 1058 | case FH_PIPEW: |
5ef61dd0 | 1059 | buf->st_mode = S_IFIFO | S_IWUSR; |
8d817b0f CF |
1060 | break; |
1061 | case FH_PIPER: | |
5ef61dd0 | 1062 | buf->st_mode = S_IFIFO | S_IRUSR; |
035bfbdd | 1063 | break; |
e5ef74df CV |
1064 | case FH_FULL: |
1065 | buf->st_mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH; | |
1066 | break; | |
8d817b0f | 1067 | default: |
035bfbdd | 1068 | buf->st_mode = S_IFCHR | STD_RBITS | STD_WBITS | S_IWGRP | S_IWOTH; |
8d817b0f CF |
1069 | break; |
1070 | } | |
1071 | ||
2d388e43 CV |
1072 | buf->st_uid = geteuid32 (); |
1073 | buf->st_gid = getegid32 (); | |
8d817b0f | 1074 | buf->st_nlink = 1; |
7bef7db5 | 1075 | buf->st_blksize = PREFERRED_IO_BLKSIZE; |
13965483 CV |
1076 | buf->st_ctim.tv_sec = 1164931200L; /* Arbitrary value: 2006-12-01 */ |
1077 | buf->st_ctim.tv_nsec = 0L; | |
70de8290 | 1078 | buf->st_atim = buf->st_mtim = buf->st_birthtim = buf->st_ctim; |
8d817b0f CF |
1079 | return 0; |
1080 | } | |
1081 | ||
3323df7e CV |
1082 | int __stdcall |
1083 | fhandler_base::fstatvfs (struct statvfs *sfs) | |
1084 | { | |
1085 | /* If we hit this base implementation, it's some device in /dev. | |
1086 | Just call statvfs on /dev for simplicity. */ | |
1087 | path_conv pc ("/dev"); | |
1088 | fhandler_disk_file fh (pc); | |
1089 | return fh.fstatvfs (sfs); | |
1090 | } | |
1091 | ||
1fd5e000 CF |
1092 | void |
1093 | fhandler_base::init (HANDLE f, DWORD a, mode_t bin) | |
1094 | { | |
1095 | set_io_handle (f); | |
f3ea62a8 | 1096 | access = a; |
1fd5e000 | 1097 | a &= GENERIC_READ | GENERIC_WRITE; |
e35f391f | 1098 | int flags = 0; |
1fd5e000 | 1099 | if (a == GENERIC_READ) |
e35f391f | 1100 | flags = O_RDONLY; |
8461f41e | 1101 | else if (a == GENERIC_WRITE) |
e35f391f | 1102 | flags = O_WRONLY; |
8461f41e | 1103 | else if (a == (GENERIC_READ | GENERIC_WRITE)) |
e35f391f | 1104 | flags = O_RDWR; |
58b43c8d | 1105 | set_flags (flags | bin); |
f3ea62a8 | 1106 | set_open_status (); |
56551a9b | 1107 | debug_printf ("created new fhandler_base for handle %p, bin %d", f, rbinary ()); |
1fd5e000 CF |
1108 | } |
1109 | ||
1fd5e000 | 1110 | int |
dcb091ca | 1111 | fhandler_base::dup (fhandler_base *child) |
1fd5e000 CF |
1112 | { |
1113 | debug_printf ("in fhandler_base dup"); | |
1114 | ||
1115 | HANDLE nh; | |
56551a9b | 1116 | if (!nohandle ()) |
1fd5e000 | 1117 | { |
dcb091ca | 1118 | if (!DuplicateHandle (hMainProc, get_handle (), hMainProc, &nh, 0, TRUE, |
c90e1cf1 CF |
1119 | DUPLICATE_SAME_ACCESS)) |
1120 | { | |
d495ee9f CV |
1121 | debug_printf ("dup(%s) failed, handle %x, %E", |
1122 | get_name (), get_handle ()); | |
c90e1cf1 CF |
1123 | __seterrno (); |
1124 | return -1; | |
1125 | } | |
1fd5e000 | 1126 | |
f7239090 | 1127 | VerifyHandle (nh); |
c90e1cf1 CF |
1128 | child->set_io_handle (nh); |
1129 | } | |
d9c0e3ec CF |
1130 | if (get_overlapped ()) |
1131 | child->setup_overlapped (); | |
dcb091ca | 1132 | set_flags (child->get_flags ()); |
1fd5e000 CF |
1133 | return 0; |
1134 | } | |
1135 | ||
1eb14bae CV |
1136 | int fhandler_base::fcntl (int cmd, void *arg) |
1137 | { | |
1138 | int res; | |
1139 | ||
1eb14bae CV |
1140 | switch (cmd) |
1141 | { | |
1142 | case F_GETFD: | |
56551a9b | 1143 | res = close_on_exec () ? FD_CLOEXEC : 0; |
1eb14bae CV |
1144 | break; |
1145 | case F_SETFD: | |
56551a9b | 1146 | set_close_on_exec (((int) arg & FD_CLOEXEC) ? 1 : 0); |
1eb14bae CV |
1147 | res = 0; |
1148 | break; | |
1149 | case F_GETFL: | |
1150 | res = get_flags (); | |
81010d21 | 1151 | debug_printf ("GETFL: %p", res); |
1eb14bae CV |
1152 | break; |
1153 | case F_SETFL: | |
38a17986 CV |
1154 | { |
1155 | /* | |
90bb77dd | 1156 | * Only O_APPEND, O_ASYNC and O_NONBLOCK/O_NDELAY are allowed. |
38a17986 CV |
1157 | * Each other flag will be ignored. |
1158 | * Since O_ASYNC isn't defined in fcntl.h it's currently | |
1159 | * ignored as well. | |
38a17986 | 1160 | */ |
1ff9f4b9 | 1161 | const int allowed_flags = O_APPEND | O_NONBLOCK_MASK; |
96a3f4ae | 1162 | int new_flags = (int) arg & allowed_flags; |
1ff9f4b9 | 1163 | /* Carefully test for the O_NONBLOCK or deprecated OLD_O_NDELAY flag. |
96a3f4ae CF |
1164 | Set only the flag that has been passed in. If both are set, just |
1165 | record O_NONBLOCK. */ | |
1166 | if ((new_flags & OLD_O_NDELAY) && (new_flags & O_NONBLOCK)) | |
2b7dcf79 | 1167 | new_flags &= ~OLD_O_NDELAY; |
96a3f4ae | 1168 | set_flags ((get_flags () & ~allowed_flags) | new_flags); |
38a17986 | 1169 | } |
1eb14bae CV |
1170 | res = 0; |
1171 | break; | |
1172 | case F_GETLK: | |
1173 | case F_SETLK: | |
1174 | case F_SETLKW: | |
dc399868 | 1175 | res = lock (cmd, (struct __flock64 *) arg); |
1eb14bae CV |
1176 | break; |
1177 | default: | |
1178 | set_errno (EINVAL); | |
1179 | res = -1; | |
1180 | break; | |
1181 | } | |
1182 | return res; | |
1183 | } | |
1184 | ||
1fd5e000 CF |
1185 | /* Base terminal handlers. These just return errors. */ |
1186 | ||
1187 | int | |
9cec3d45 | 1188 | fhandler_base::tcflush (int) |
1fd5e000 CF |
1189 | { |
1190 | set_errno (ENOTTY); | |
1191 | return -1; | |
1192 | } | |
1193 | ||
1194 | int | |
9cec3d45 | 1195 | fhandler_base::tcsendbreak (int) |
1fd5e000 CF |
1196 | { |
1197 | set_errno (ENOTTY); | |
1198 | return -1; | |
1199 | } | |
1200 | ||
1201 | int | |
2f9ae2ed | 1202 | fhandler_base::tcdrain () |
1fd5e000 CF |
1203 | { |
1204 | set_errno (ENOTTY); | |
1205 | return -1; | |
1206 | } | |
1207 | ||
1208 | int | |
9cec3d45 | 1209 | fhandler_base::tcflow (int) |
1fd5e000 CF |
1210 | { |
1211 | set_errno (ENOTTY); | |
1212 | return -1; | |
1213 | } | |
1214 | ||
1215 | int | |
9cec3d45 | 1216 | fhandler_base::tcsetattr (int, const struct termios *) |
1fd5e000 CF |
1217 | { |
1218 | set_errno (ENOTTY); | |
1219 | return -1; | |
1220 | } | |
1221 | ||
1222 | int | |
9cec3d45 | 1223 | fhandler_base::tcgetattr (struct termios *) |
1fd5e000 CF |
1224 | { |
1225 | set_errno (ENOTTY); | |
1226 | return -1; | |
1227 | } | |
1228 | ||
1229 | int | |
9cec3d45 | 1230 | fhandler_base::tcsetpgrp (const pid_t) |
1fd5e000 CF |
1231 | { |
1232 | set_errno (ENOTTY); | |
1233 | return -1; | |
1234 | } | |
1235 | ||
1236 | int | |
2f9ae2ed | 1237 | fhandler_base::tcgetpgrp () |
1fd5e000 CF |
1238 | { |
1239 | set_errno (ENOTTY); | |
1240 | return -1; | |
1241 | } | |
1242 | ||
b0e82b74 CF |
1243 | void |
1244 | fhandler_base::operator delete (void *p) | |
1245 | { | |
1246 | cfree (p); | |
b0e82b74 CF |
1247 | } |
1248 | ||
1fd5e000 | 1249 | /* Normal I/O constructor */ |
b79f85c2 CV |
1250 | fhandler_base::fhandler_base () : |
1251 | status (), | |
1252 | open_status (), | |
f3ea62a8 | 1253 | access (0), |
1fd5e000 | 1254 | io_handle (NULL), |
f3ea62a8 CF |
1255 | namehash (0), |
1256 | openflags (0), | |
1fd5e000 CF |
1257 | rabuf (NULL), |
1258 | ralen (0), | |
1259 | raixget (0), | |
1260 | raixput (0), | |
f3ea62a8 | 1261 | rabuflen (0), |
fac297d5 | 1262 | fs_flags (0), |
8e10c431 CF |
1263 | archetype (NULL), |
1264 | usecount (0) | |
1fd5e000 | 1265 | { |
1fd5e000 CF |
1266 | } |
1267 | ||
1268 | /* Normal I/O destructor */ | |
2f9ae2ed | 1269 | fhandler_base::~fhandler_base () |
1fd5e000 | 1270 | { |
b0e82b74 CF |
1271 | if (rabuf) |
1272 | free (rabuf); | |
1fd5e000 CF |
1273 | } |
1274 | ||
1fd5e000 CF |
1275 | /**********************************************************************/ |
1276 | /* /dev/null */ | |
1277 | ||
0476bae5 | 1278 | fhandler_dev_null::fhandler_dev_null () : |
7ac61736 | 1279 | fhandler_base () |
1fd5e000 | 1280 | { |
1fd5e000 CF |
1281 | } |
1282 | ||
d7aac2ac | 1283 | void |
c16548b2 | 1284 | fhandler_base::set_no_inheritance (HANDLE &h, bool not_inheriting) |
1fd5e000 | 1285 | { |
eef57fe1 CV |
1286 | if (!SetHandleInformation (h, HANDLE_FLAG_INHERIT, |
1287 | not_inheriting ? 0 : HANDLE_FLAG_INHERIT)) | |
1288 | debug_printf ("SetHandleInformation failed, %E"); | |
3d0ba393 | 1289 | #ifdef DEBUGGING_AND_FDS_PROTECTED |
a0626ebe | 1290 | if (h) |
0301bfd0 | 1291 | setclexec (oh, h, not_inheriting); |
1fd5e000 CF |
1292 | #endif |
1293 | } | |
1294 | ||
3cd94e0c | 1295 | bool |
1fd5e000 CF |
1296 | fhandler_base::fork_fixup (HANDLE parent, HANDLE &h, const char *name) |
1297 | { | |
f7239090 | 1298 | HANDLE oh = h; |
3cd94e0c | 1299 | bool res = false; |
56551a9b | 1300 | if (/* !is_socket () && */ !close_on_exec ()) |
a7670c1e | 1301 | debug_printf ("handle %p already opened", h); |
56551a9b | 1302 | else if (!DuplicateHandle (parent, h, hMainProc, &h, 0, !close_on_exec (), |
a448b8cf | 1303 | DUPLICATE_SAME_ACCESS)) |
1fd5e000 | 1304 | system_printf ("%s - %E, handle %s<%p>", get_name (), name, h); |
3cd94e0c CF |
1305 | else |
1306 | { | |
1307 | if (oh != h) | |
1308 | VerifyHandle (h); | |
1309 | res = true; | |
1310 | } | |
d9c0e3ec CF |
1311 | if (get_overlapped ()) |
1312 | setup_overlapped (); | |
3cd94e0c | 1313 | return res; |
1fd5e000 CF |
1314 | } |
1315 | ||
1316 | void | |
56551a9b | 1317 | fhandler_base::set_close_on_exec (bool val) |
1fd5e000 | 1318 | { |
56551a9b | 1319 | if (!nohandle ()) |
6027d26d | 1320 | set_no_inheritance (io_handle, val); |
56551a9b | 1321 | close_on_exec (val); |
1fd5e000 CF |
1322 | debug_printf ("set close_on_exec for %s to %d", get_name (), val); |
1323 | } | |
1324 | ||
1325 | void | |
1326 | fhandler_base::fixup_after_fork (HANDLE parent) | |
1327 | { | |
1328 | debug_printf ("inheriting '%s' from parent", get_name ()); | |
56551a9b | 1329 | if (!nohandle ()) |
5bf785a0 | 1330 | fork_fixup (parent, io_handle, "io_handle"); |
d9c0e3ec CF |
1331 | if (get_overlapped ()) |
1332 | setup_overlapped (); | |
1fd5e000 | 1333 | } |
5fd12fb0 | 1334 | |
3378bdfc CF |
1335 | void |
1336 | fhandler_base::fixup_after_exec () | |
1337 | { | |
1338 | debug_printf ("here for '%s'", get_name ()); | |
d9c0e3ec CF |
1339 | if (get_overlapped ()) |
1340 | setup_overlapped (); | |
3378bdfc CF |
1341 | } |
1342 | ||
5a64d869 | 1343 | bool |
5fd12fb0 CV |
1344 | fhandler_base::is_nonblocking () |
1345 | { | |
1346 | return (openflags & O_NONBLOCK_MASK) != 0; | |
1347 | } | |
1348 | ||
1349 | void | |
1350 | fhandler_base::set_nonblocking (int yes) | |
1351 | { | |
1352 | int current = openflags & O_NONBLOCK_MASK; | |
1353 | int new_flags = yes ? (!current ? O_NONBLOCK : current) : 0; | |
1354 | openflags = (openflags & ~O_NONBLOCK_MASK) | new_flags; | |
1355 | } | |
7903ee69 | 1356 | |
125b724d CF |
1357 | int |
1358 | fhandler_base::mkdir (mode_t) | |
1359 | { | |
1360 | if (exists ()) | |
1361 | set_errno (EEXIST); | |
1362 | else | |
1363 | set_errno (EROFS); | |
1364 | return -1; | |
1365 | } | |
1366 | ||
1367 | int | |
1368 | fhandler_base::rmdir () | |
1369 | { | |
1370 | if (!exists ()) | |
1371 | set_errno (ENOENT); | |
1372 | else if (!pc.isdir ()) | |
1373 | set_errno (ENOTDIR); | |
1374 | else | |
1375 | set_errno (EROFS); | |
1376 | return -1; | |
1377 | } | |
1378 | ||
7903ee69 | 1379 | DIR * |
40570a82 | 1380 | fhandler_base::opendir (int fd) |
7903ee69 CF |
1381 | { |
1382 | set_errno (ENOTDIR); | |
1383 | return NULL; | |
1384 | } | |
1385 | ||
d9a22764 CF |
1386 | int |
1387 | fhandler_base::readdir (DIR *, dirent *) | |
7903ee69 | 1388 | { |
d9a22764 | 1389 | return ENOTDIR; |
7903ee69 CF |
1390 | } |
1391 | ||
1727fba0 | 1392 | _off64_t |
7903ee69 CF |
1393 | fhandler_base::telldir (DIR *) |
1394 | { | |
1395 | set_errno (ENOTDIR); | |
1396 | return -1; | |
1397 | } | |
1398 | ||
1399 | void | |
1727fba0 | 1400 | fhandler_base::seekdir (DIR *, _off64_t) |
7903ee69 CF |
1401 | { |
1402 | set_errno (ENOTDIR); | |
7903ee69 CF |
1403 | } |
1404 | ||
1405 | void | |
1406 | fhandler_base::rewinddir (DIR *) | |
1407 | { | |
1408 | set_errno (ENOTDIR); | |
7903ee69 CF |
1409 | } |
1410 | ||
1411 | int | |
1412 | fhandler_base::closedir (DIR *) | |
1413 | { | |
1414 | set_errno (ENOTDIR); | |
1415 | return -1; | |
1416 | } | |
854c8700 CV |
1417 | |
1418 | int | |
1419 | fhandler_base::fchmod (mode_t mode) | |
1420 | { | |
8711eddd CF |
1421 | extern int chmod_device (path_conv& pc, mode_t mode); |
1422 | if (pc.is_fs_special ()) | |
1423 | return chmod_device (pc, mode); | |
854c8700 CV |
1424 | /* By default, just succeeds. */ |
1425 | return 0; | |
1426 | } | |
ddf9c4a7 CV |
1427 | |
1428 | int | |
1429 | fhandler_base::fchown (__uid32_t uid, __gid32_t gid) | |
1430 | { | |
8711eddd CF |
1431 | if (pc.is_fs_special ()) |
1432 | return ((fhandler_disk_file *) this)->fhandler_disk_file::fchown (uid, gid); | |
ddf9c4a7 CV |
1433 | /* By default, just succeeds. */ |
1434 | return 0; | |
1435 | } | |
e3d1d515 CV |
1436 | |
1437 | int | |
1438 | fhandler_base::facl (int cmd, int nentries, __aclent32_t *aclbufp) | |
1439 | { | |
aafdf30f CV |
1440 | int res = -1; |
1441 | switch (cmd) | |
1442 | { | |
1443 | case SETACL: | |
1444 | /* By default, just succeeds. */ | |
1445 | res = 0; | |
1446 | break; | |
1447 | case GETACL: | |
1448 | if (!aclbufp) | |
1449 | set_errno(EFAULT); | |
1450 | else if (nentries < MIN_ACL_ENTRIES) | |
1451 | set_errno (ENOSPC); | |
1452 | else | |
1453 | { | |
1454 | aclbufp[0].a_type = USER_OBJ; | |
1455 | aclbufp[0].a_id = myself->uid; | |
1456 | aclbufp[0].a_perm = (S_IRUSR | S_IWUSR) >> 6; | |
1457 | aclbufp[1].a_type = GROUP_OBJ; | |
1458 | aclbufp[1].a_id = myself->gid; | |
1459 | aclbufp[1].a_perm = (S_IRGRP | S_IWGRP) >> 3; | |
1460 | aclbufp[2].a_type = OTHER_OBJ; | |
1461 | aclbufp[2].a_id = ILLEGAL_GID; | |
1462 | aclbufp[2].a_perm = S_IROTH | S_IWOTH; | |
1463 | aclbufp[3].a_type = CLASS_OBJ; | |
1464 | aclbufp[3].a_id = ILLEGAL_GID; | |
1465 | aclbufp[3].a_perm = S_IRWXU | S_IRWXG | S_IRWXO; | |
1466 | res = MIN_ACL_ENTRIES; | |
1467 | } | |
1468 | break; | |
1469 | case GETACLCNT: | |
1470 | res = MIN_ACL_ENTRIES; | |
1471 | break; | |
1472 | default: | |
1473 | set_errno (EINVAL); | |
1474 | break; | |
1475 | } | |
1476 | return res; | |
e3d1d515 | 1477 | } |
3fd68a6a | 1478 | |
50450dcc CV |
1479 | ssize_t |
1480 | fhandler_base::fgetxattr (const char *name, void *value, size_t size) | |
1481 | { | |
1482 | set_errno (ENOTSUP); | |
1483 | return -1; | |
1484 | } | |
1485 | ||
1486 | int | |
1487 | fhandler_base::fsetxattr (const char *name, const void *value, size_t size, | |
1488 | int flags) | |
1489 | { | |
1490 | set_errno (ENOTSUP); | |
1491 | return -1; | |
1492 | } | |
1493 | ||
3fd68a6a | 1494 | int |
7636b585 CV |
1495 | fhandler_base::fadvise (_off64_t offset, _off64_t length, int advice) |
1496 | { | |
1497 | set_errno (EINVAL); | |
1498 | return -1; | |
1499 | } | |
1500 | ||
1501 | int | |
1502 | fhandler_base::ftruncate (_off64_t length, bool allow_truncate) | |
3fd68a6a CV |
1503 | { |
1504 | set_errno (EINVAL); | |
1505 | return -1; | |
1506 | } | |
0d75ce96 CV |
1507 | |
1508 | int | |
1509 | fhandler_base::link (const char *newpath) | |
1510 | { | |
1511 | set_errno (EINVAL); | |
1512 | return -1; | |
1513 | } | |
2b09be25 CV |
1514 | |
1515 | int | |
1516 | fhandler_base::utimes (const struct timeval *tvp) | |
1517 | { | |
f134945d CF |
1518 | if (is_fs_special ()) |
1519 | return utimes_fs (tvp); | |
1520 | ||
2b09be25 CV |
1521 | set_errno (EINVAL); |
1522 | return -1; | |
1523 | } | |
4944ca2f CV |
1524 | |
1525 | int | |
1526 | fhandler_base::fsync () | |
1527 | { | |
a62f6b80 CV |
1528 | if (!get_handle () || nohandle ()) |
1529 | { | |
1530 | set_errno (EINVAL); | |
1531 | return -1; | |
1532 | } | |
4944ca2f CV |
1533 | if (pc.isdir ()) /* Just succeed. */ |
1534 | return 0; | |
1535 | if (FlushFileBuffers (get_handle ())) | |
1536 | return 0; | |
1537 | __seterrno (); | |
1538 | return -1; | |
1539 | } | |
86bc8fad | 1540 | |
86bc8fad CV |
1541 | int |
1542 | fhandler_base::fpathconf (int v) | |
1543 | { | |
e2108ce0 CV |
1544 | int ret; |
1545 | ||
86bc8fad CV |
1546 | switch (v) |
1547 | { | |
1548 | case _PC_LINK_MAX: | |
1549 | return pc.fs_is_ntfs () || pc.fs_is_samba () || pc.fs_is_nfs () | |
1550 | ? LINK_MAX : 1; | |
1551 | case _PC_MAX_CANON: | |
1552 | if (is_tty ()) | |
510a85cb | 1553 | return MAX_CANON; |
86bc8fad CV |
1554 | set_errno (EINVAL); |
1555 | break; | |
1556 | case _PC_MAX_INPUT: | |
1557 | if (is_tty ()) | |
510a85cb | 1558 | return MAX_INPUT; |
86bc8fad CV |
1559 | set_errno (EINVAL); |
1560 | break; | |
1561 | case _PC_NAME_MAX: | |
1562 | /* NAME_MAX is without trailing \0 */ | |
e2108ce0 CV |
1563 | if (!pc.isdir ()) |
1564 | return NAME_MAX; | |
1565 | ret = NT_MAX_PATH - strlen (get_name ()) - 2; | |
1566 | return ret < 0 ? 0 : ret > NAME_MAX ? NAME_MAX : ret; | |
86bc8fad CV |
1567 | case _PC_PATH_MAX: |
1568 | /* PATH_MAX is with trailing \0 */ | |
e2108ce0 CV |
1569 | if (!pc.isdir ()) |
1570 | return PATH_MAX; | |
1571 | ret = NT_MAX_PATH - strlen (get_name ()) - 1; | |
1572 | return ret < 0 ? 0 : ret > PATH_MAX ? PATH_MAX : ret; | |
86bc8fad CV |
1573 | case _PC_PIPE_BUF: |
1574 | if (pc.isdir () | |
1575 | || get_device () == FH_FIFO || get_device () == FH_PIPE | |
1576 | || get_device () == FH_PIPER || get_device () == FH_PIPEW) | |
510a85cb | 1577 | return PIPE_BUF; |
86bc8fad CV |
1578 | set_errno (EINVAL); |
1579 | break; | |
1580 | case _PC_CHOWN_RESTRICTED: | |
1581 | return 1; | |
1582 | case _PC_NO_TRUNC: | |
1583 | return 1; | |
1584 | case _PC_VDISABLE: | |
59e3b6ca | 1585 | if (is_tty ()) |
510a85cb | 1586 | return _POSIX_VDISABLE; |
59e3b6ca | 1587 | set_errno (EINVAL); |
86bc8fad CV |
1588 | break; |
1589 | case _PC_ASYNC_IO: | |
1590 | case _PC_PRIO_IO: | |
86bc8fad | 1591 | break; |
59e3b6ca CV |
1592 | case _PC_SYNC_IO: |
1593 | return 1; | |
86bc8fad CV |
1594 | case _PC_FILESIZEBITS: |
1595 | return FILESIZEBITS; | |
1596 | case _PC_2_SYMLINKS: | |
1597 | return 1; | |
1598 | case _PC_SYMLINK_MAX: | |
59e3b6ca | 1599 | return SYMLINK_MAX; |
86bc8fad CV |
1600 | case _PC_POSIX_PERMISSIONS: |
1601 | case _PC_POSIX_SECURITY: | |
1602 | if (get_device () == FH_FS) | |
67629eb2 | 1603 | return pc.has_acls (); |
86bc8fad CV |
1604 | set_errno (EINVAL); |
1605 | break; | |
1606 | default: | |
1607 | set_errno (EINVAL); | |
1608 | break; | |
1609 | } | |
1610 | return -1; | |
1611 | } | |
d9c0e3ec CF |
1612 | |
1613 | /* Overlapped I/O */ | |
1614 | ||
1615 | bool | |
1616 | fhandler_base::setup_overlapped () | |
1617 | { | |
1618 | OVERLAPPED *ov = get_overlapped (); | |
1619 | memset (ov, 0, sizeof (*ov)); | |
1620 | return ov->hEvent = CreateEvent (&sec_none_nih, true, false, NULL); | |
1621 | } | |
1622 | ||
1623 | void | |
1624 | fhandler_base::destroy_overlapped () | |
1625 | { | |
1626 | OVERLAPPED *ov = get_overlapped (); | |
1627 | if (ov && ov->hEvent) | |
1628 | { | |
1629 | CloseHandle (ov->hEvent); | |
1630 | ov->hEvent = NULL; | |
1631 | } | |
1632 | } | |
1633 | ||
ee298432 CF |
1634 | int |
1635 | fhandler_base::wait_overlapped (bool& res, bool writing, DWORD *bytes) | |
d9c0e3ec | 1636 | { |
ee298432 CF |
1637 | if (bytes) |
1638 | *bytes = (DWORD) -1; | |
5990b339 CF |
1639 | DWORD err = GetLastError (); |
1640 | if (!res && err != ERROR_IO_PENDING) | |
1641 | { | |
1642 | if (err != ERROR_HANDLE_EOF && err != ERROR_BROKEN_PIPE) | |
1643 | goto err; | |
1644 | res = 1; | |
1645 | if (*bytes) | |
1646 | *bytes = 0; | |
1647 | } | |
d9c0e3ec CF |
1648 | else |
1649 | { | |
1650 | #ifdef DEBUGGING | |
1651 | if (!get_overlapped ()) | |
1652 | system_printf ("get_overlapped is zero?"); | |
1653 | if (!get_overlapped ()->hEvent) | |
1654 | system_printf ("hEvent is zero?"); | |
1655 | #endif | |
1656 | DWORD n = 1; | |
1657 | HANDLE w4[2]; | |
1658 | w4[0] = get_overlapped ()->hEvent; | |
1659 | if (&_my_tls == _main_tls) | |
1660 | w4[n++] = signal_arrived; | |
ee298432 | 1661 | HANDLE h = writing ? get_output_handle () : get_handle (); |
d9c0e3ec CF |
1662 | switch (WaitForMultipleObjects (n, w4, false, INFINITE)) |
1663 | { | |
1664 | case WAIT_OBJECT_0: | |
634a4140 | 1665 | debug_printf ("normal read"); |
ee298432 CF |
1666 | if (!bytes || |
1667 | GetOverlappedResult (h, get_overlapped (), bytes, false)) | |
1668 | res = 1; | |
1669 | else | |
1670 | { | |
5990b339 CF |
1671 | err = GetLastError (); |
1672 | goto err; | |
ee298432 | 1673 | } |
d9c0e3ec CF |
1674 | break; |
1675 | case WAIT_OBJECT_0 + 1: | |
634a4140 | 1676 | debug_printf ("got a signal"); |
ee298432 | 1677 | CancelIo (h); |
d9c0e3ec | 1678 | set_errno (EINTR); |
ee298432 CF |
1679 | res = 0; |
1680 | break; | |
1681 | default: | |
5990b339 | 1682 | err = GetLastError (); |
634a4140 | 1683 | debug_printf ("WFMO error, %E"); |
5990b339 | 1684 | goto err; |
d9c0e3ec CF |
1685 | break; |
1686 | } | |
1687 | } | |
5990b339 CF |
1688 | goto out; |
1689 | ||
1690 | err: | |
1691 | __seterrno_from_win_error (err); | |
1692 | res = -1; | |
1693 | if (err == ERROR_NO_DATA) | |
1694 | raise (SIGPIPE); | |
1695 | out: | |
d9c0e3ec CF |
1696 | ResetEvent (get_overlapped ()->hEvent); |
1697 | return res; | |
1698 | } | |
1699 | ||
1700 | void | |
1701 | fhandler_base::read_overlapped (void *ptr, size_t& len) | |
1702 | { | |
1703 | #ifdef DEBUGGING | |
1704 | assert (get_overlapped ()); | |
1705 | assert (get_overlapped ()->hEvent); | |
1706 | #endif | |
ee298432 CF |
1707 | while (1) |
1708 | { | |
1709 | bool res = ReadFile (get_handle (), ptr, len, (DWORD *) &len, | |
1710 | get_overlapped ()); | |
1711 | int wres = wait_overlapped (res, false, (DWORD *) &len); | |
1712 | if (wres || !_my_tls.call_signal_handler ()) | |
1713 | break; | |
1714 | } | |
d9c0e3ec CF |
1715 | } |
1716 | ||
1717 | int | |
1718 | fhandler_base::write_overlapped (const void *ptr, size_t len) | |
1719 | { | |
1720 | DWORD bytes_written; | |
1721 | ||
ee298432 CF |
1722 | while (1) |
1723 | { | |
1724 | bool res = WriteFile (get_output_handle (), ptr, len, &bytes_written, | |
1725 | get_overlapped ()); | |
1726 | int wres = wait_overlapped (res, true, &bytes_written); | |
1727 | if (wres < 0) | |
1728 | return -1; | |
1729 | if (wres || !_my_tls.call_signal_handler ()) | |
1730 | break; | |
1731 | } | |
d9c0e3ec CF |
1732 | return bytes_written; |
1733 | } |