]>
Commit | Line | Data |
---|---|---|
9015e0fb | 1 | /* dtable.cc: file descriptor support. |
1fd5e000 | 2 | |
bc837d22 CF |
3 | Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, |
4 | 2007, 2008, 2009, 2010, 2011, 2012 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 | ||
12 | #define __INSIDE_CYGWIN_NET__ | |
13 | ||
4c8d72de | 14 | #include "winsup.h" |
1fd5e000 CF |
15 | #include <stdlib.h> |
16 | #include <stdio.h> | |
1fd5e000 | 17 | #include <unistd.h> |
1ffe3e67 | 18 | #include <wchar.h> |
1fd5e000 | 19 | |
a1299ba5 | 20 | #define USE_SYS_TYPES_FD_SET |
d0b178fe | 21 | #include <winsock.h> |
e2ebe117 | 22 | #include "pinfo.h" |
9e2baf8d | 23 | #include "cygerrno.h" |
95a8465b | 24 | #include "perprocess.h" |
bccd5e0d | 25 | #include "path.h" |
7ac61736 | 26 | #include "fhandler.h" |
b4fa8164 | 27 | #include "select.h" |
bccd5e0d | 28 | #include "dtable.h" |
0381fec6 | 29 | #include "cygheap.h" |
ab5d348d | 30 | #include "tls_pbuf.h" |
2402700d | 31 | #include "ntdll.h" |
f09acf77 | 32 | #include "shared_info.h" |
1fd5e000 | 33 | |
57c89867 | 34 | static const NO_COPY DWORD std_consts[] = {STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, |
083abe54 | 35 | STD_ERROR_HANDLE}; |
164a681c | 36 | |
88f0dc31 | 37 | static bool handle_to_fn (HANDLE, char *); |
1ffe3e67 CF |
38 | |
39 | #define WCLEN(x) ((sizeof (x) / sizeof (WCHAR)) - 1) | |
c8a66289 CF |
40 | static const char unknown_file[] = "some disk file"; |
41 | static const WCHAR DEV_NULL[] = L"\\Device\\Null"; | |
019fc8d8 | 42 | static const WCHAR DEV_SOCKET[] = L"\\Device\\Afd"; |
1ffe3e67 | 43 | |
c8a66289 CF |
44 | static const WCHAR DEVICE_PREFIX[] = L"\\device\\"; |
45 | static const size_t DEVICE_PREFIX_LEN WCLEN (DEVICE_PREFIX); | |
1ffe3e67 CF |
46 | |
47 | static const WCHAR DEV_NAMED_PIPE[] = L"\\Device\\NamedPipe\\"; | |
48 | static const size_t DEV_NAMED_PIPE_LEN = WCLEN (DEV_NAMED_PIPE); | |
dd76747b | 49 | |
1ffe3e67 CF |
50 | static const WCHAR DEV_REMOTE[] = L"\\Device\\LanmanRedirector\\"; |
51 | static const size_t DEV_REMOTE_LEN = WCLEN (DEV_REMOTE); | |
52 | ||
53 | static const WCHAR DEV_REMOTE1[] = L"\\Device\\WinDfs\\Root\\"; | |
54 | static const size_t DEV_REMOTE1_LEN = WCLEN (DEV_REMOTE1); | |
634a4140 | 55 | |
1fd5e000 CF |
56 | /* Set aside space for the table of fds */ |
57 | void | |
2d1d1eb1 | 58 | dtable_init () |
1fd5e000 | 59 | { |
0381fec6 | 60 | if (!cygheap->fdtab.size) |
c729f227 | 61 | cygheap->fdtab.extend (NOFILE_INCR); |
1fd5e000 CF |
62 | } |
63 | ||
64 | void __stdcall | |
65 | set_std_handle (int fd) | |
66 | { | |
30fa1549 | 67 | fhandler_base *fh = cygheap->fdtab[fd]; |
1fd5e000 | 68 | if (fd == 0) |
30fa1549 | 69 | SetStdHandle (std_consts[fd], fh ? fh->get_handle () : NULL); |
164a681c | 70 | else if (fd <= 2) |
30fa1549 | 71 | SetStdHandle (std_consts[fd], fh ? fh->get_output_handle () : NULL); |
1fd5e000 CF |
72 | } |
73 | ||
74 | int | |
9015e0fb | 75 | dtable::extend (int howmuch) |
1fd5e000 CF |
76 | { |
77 | int new_size = size + howmuch; | |
78 | fhandler_base **newfds; | |
79 | ||
80 | if (howmuch <= 0) | |
81 | return 0; | |
82 | ||
29bca9bb | 83 | if (new_size > OPEN_MAX_MAX) |
4d782b42 CF |
84 | { |
85 | set_errno (EMFILE); | |
86 | return 0; | |
87 | } | |
88 | ||
c729f227 | 89 | /* Try to allocate more space for fd table. We can't call realloc () |
1fd5e000 CF |
90 | here to preserve old table if memory allocation fails */ |
91 | ||
b0e82b74 | 92 | if (!(newfds = (fhandler_base **) ccalloc (HEAP_ARGV, new_size, sizeof newfds[0]))) |
1fd5e000 CF |
93 | { |
94 | debug_printf ("calloc failed"); | |
4d782b42 | 95 | set_errno (ENOMEM); |
1fd5e000 CF |
96 | return 0; |
97 | } | |
98 | if (fds) | |
99 | { | |
4d782b42 | 100 | memcpy (newfds, fds, size * sizeof (fds[0])); |
3301015b | 101 | cfree (fds); |
1fd5e000 CF |
102 | } |
103 | ||
104 | size = new_size; | |
105 | fds = newfds; | |
41f42725 | 106 | debug_printf ("size %d, fds %p", size, fds); |
1fd5e000 CF |
107 | return 1; |
108 | } | |
109 | ||
083abe54 CF |
110 | void |
111 | dtable::get_debugger_info () | |
112 | { | |
3c4f2024 CF |
113 | extern bool jit_debug; |
114 | if (!jit_debug && being_debugged ()) | |
083abe54 | 115 | { |
23771fa1 | 116 | char std[3][sizeof ("/dev/ptyNNNN")]; |
083abe54 CF |
117 | std[0][0] = std[1][0] = std [2][0] = '\0'; |
118 | char buf[sizeof ("cYgstd %x") + 32]; | |
119 | sprintf (buf, "cYgstd %x %x %x", (unsigned) &std, sizeof (std[0]), 3); | |
120 | OutputDebugString (buf); | |
121 | for (int i = 0; i < 3; i++) | |
122 | if (std[i][0]) | |
123 | { | |
083abe54 | 124 | HANDLE h = GetStdHandle (std_consts[i]); |
7ac61736 | 125 | fhandler_base *fh = build_fh_name (std[i]); |
083abe54 CF |
126 | if (!fh) |
127 | continue; | |
7ac61736 | 128 | fds[i] = fh; |
061095b5 CV |
129 | if (!fh->open ((i ? (i == 2 ? O_RDWR : O_WRONLY) : O_RDONLY) |
130 | | O_BINARY, 0777)) | |
083abe54 CF |
131 | release (i); |
132 | else | |
8f19b4b6 CV |
133 | { |
134 | CloseHandle (h); | |
135 | /* Copy to Windows' idea of a standard handle, otherwise | |
136 | we have invalid standard handles when calling Windows | |
137 | functions (small_printf and strace might suffer, too). */ | |
138 | SetStdHandle (std_consts[i], i ? fh->get_output_handle () | |
139 | : fh->get_handle ()); | |
140 | } | |
083abe54 CF |
141 | } |
142 | } | |
143 | } | |
144 | ||
1fd5e000 | 145 | /* Initialize the file descriptor/handle mapping table. |
10dedaaa CF |
146 | This function should only be called when a cygwin function is invoked |
147 | by a non-cygwin function, i.e., it should only happen very rarely. */ | |
1fd5e000 CF |
148 | |
149 | void | |
083abe54 | 150 | dtable::stdio_init () |
1fd5e000 | 151 | { |
8cb359d9 | 152 | if (myself->cygstarted || ISSTATE (myself, PID_CYGPARENT)) |
3eb92a58 | 153 | { |
44d2fc0a | 154 | tty_min *t = cygwin_shared->tty.get_cttyp (); |
a345dc55 | 155 | if (t && t->is_console) |
f09acf77 | 156 | init_console_handler (true); |
3eb92a58 CF |
157 | return; |
158 | } | |
1fd5e000 | 159 | |
083abe54 CF |
160 | HANDLE in = GetStdHandle (STD_INPUT_HANDLE); |
161 | HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); | |
162 | HANDLE err = GetStdHandle (STD_ERROR_HANDLE); | |
1fd5e000 | 163 | |
54030e21 | 164 | init_std_file_from_handle (0, in); |
083abe54 CF |
165 | |
166 | /* STD_ERROR_HANDLE has been observed to be the same as | |
167 | STD_OUTPUT_HANDLE. We need separate handles (e.g. using pipes | |
168 | to pass data from child to parent). */ | |
edf5a5bd CV |
169 | /* CV 2008-10-17: Under debugger control, std fd's have been potentially |
170 | initialized in dtable::get_debugger_info (). In this case | |
171 | init_std_file_from_handle is a no-op, so, even if out == err we don't | |
172 | want to duplicate the handle since it will be unused. */ | |
8f19b4b6 | 173 | if (out == err && (!being_debugged () || not_open (2))) |
083abe54 CF |
174 | { |
175 | /* Since this code is not invoked for forked tasks, we don't have | |
176 | to worry about the close-on-exec flag here. */ | |
7bdbf062 CV |
177 | if (!DuplicateHandle (GetCurrentProcess (), out, |
178 | GetCurrentProcess (), &err, | |
179 | 0, TRUE, DUPLICATE_SAME_ACCESS)) | |
1fd5e000 | 180 | { |
083abe54 CF |
181 | /* If that fails, do this as a fall back. */ |
182 | err = out; | |
7bdbf062 | 183 | system_printf ("couldn't make stderr distinct from stdout, %E"); |
1fd5e000 | 184 | } |
1fd5e000 | 185 | } |
083abe54 | 186 | |
54030e21 CF |
187 | init_std_file_from_handle (1, out); |
188 | init_std_file_from_handle (2, err); | |
1fd5e000 CF |
189 | } |
190 | ||
8e10c431 CF |
191 | const int dtable::initial_archetype_size; |
192 | ||
193 | fhandler_base * | |
194 | dtable::find_archetype (device& dev) | |
195 | { | |
196 | for (unsigned i = 0; i < farchetype; i++) | |
44d2fc0a | 197 | if (archetypes[i]->get_device () == (DWORD) dev) |
8e10c431 CF |
198 | return archetypes[i]; |
199 | return NULL; | |
200 | } | |
201 | ||
202 | fhandler_base ** | |
203 | dtable::add_archetype () | |
204 | { | |
205 | if (farchetype++ >= narchetypes) | |
634a4140 | 206 | archetypes = (fhandler_base **) crealloc_abort (archetypes, (narchetypes += initial_archetype_size) * sizeof archetypes[0]); |
8e10c431 CF |
207 | return archetypes + farchetype - 1; |
208 | } | |
209 | ||
210 | void | |
211 | dtable::delete_archetype (fhandler_base *fh) | |
212 | { | |
8ed5c9b6 | 213 | for (unsigned i = 0; i < farchetype; i++) |
8e10c431 CF |
214 | if (fh == archetypes[i]) |
215 | { | |
6ae28c22 CF |
216 | debug_printf ("deleting element %d for %s(%d/%d)", i, fh->get_name (), |
217 | fh->dev ().get_major (), fh->dev ().get_minor ()); | |
8e10c431 CF |
218 | if (i < --farchetype) |
219 | archetypes[i] = archetypes[farchetype]; | |
220 | break; | |
221 | } | |
222 | ||
223 | delete fh; | |
224 | } | |
225 | ||
1fd5e000 | 226 | int |
9015e0fb | 227 | dtable::find_unused_handle (int start) |
1fd5e000 | 228 | { |
1fd5e000 CF |
229 | do |
230 | { | |
e773b7cf | 231 | for (size_t i = start; i < size; i++) |
91892f50 CF |
232 | /* See if open -- no need for overhead of not_open */ |
233 | if (fds[i] == NULL) | |
1fd5e000 CF |
234 | return i; |
235 | } | |
236 | while (extend (NOFILE_INCR)); | |
237 | return -1; | |
238 | } | |
239 | ||
0646a508 | 240 | void |
9015e0fb | 241 | dtable::release (int fd) |
1fd5e000 | 242 | { |
0646a508 CF |
243 | if (fds[fd]->need_fixup_before ()) |
244 | dec_need_fixup_before (); | |
3143cb7c | 245 | fds[fd]->dec_refcnt (); |
0646a508 | 246 | fds[fd] = NULL; |
30fa1549 CF |
247 | if (fd <= 2) |
248 | set_std_handle (fd); | |
1fd5e000 CF |
249 | } |
250 | ||
45586380 | 251 | extern "C" int |
ebd645e7 CF |
252 | cygwin_attach_handle_to_fd (char *name, int fd, HANDLE handle, mode_t bin, |
253 | DWORD myaccess) | |
254 | { | |
255 | if (fd == -1) | |
256 | fd = cygheap->fdtab.find_unused_handle (); | |
7ac61736 | 257 | fhandler_base *fh = build_fh_name (name); |
e5b7e4d1 CF |
258 | if (!fh) |
259 | return -1; | |
7ac61736 | 260 | cygheap->fdtab[fd] = fh; |
3143cb7c | 261 | cygheap->fdtab[fd]->inc_refcnt (); |
7ac61736 | 262 | fh->init (handle, myaccess, bin ?: fh->pc_binmode ()); |
ebd645e7 CF |
263 | return fd; |
264 | } | |
265 | ||
1fd5e000 | 266 | void |
54030e21 | 267 | dtable::init_std_file_from_handle (int fd, HANDLE handle) |
1fd5e000 | 268 | { |
5e7c84e5 | 269 | tmp_pathbuf tp; |
ebd645e7 | 270 | CONSOLE_SCREEN_BUFFER_INFO buf; |
ebd645e7 | 271 | DCB dcb; |
abb58a6d | 272 | unsigned bin = O_BINARY; |
44d2fc0a | 273 | device dev = {}; |
ebd645e7 CF |
274 | |
275 | first_fd_for_open = 0; | |
1ac6d1a1 | 276 | |
083abe54 CF |
277 | if (!not_open (fd)) |
278 | return; | |
279 | ||
cef69559 | 280 | SetLastError (0); |
1ffe3e67 | 281 | DWORD access = 0; |
cef69559 | 282 | DWORD ft = GetFileType (handle); |
5e7c84e5 | 283 | char *name = tp.c_get (); |
1ffe3e67 | 284 | name[0] = '\0'; |
88f0dc31 CF |
285 | if (ft == FILE_TYPE_UNKNOWN && GetLastError () == ERROR_INVALID_HANDLE) |
286 | /* can't figure out what this is */; | |
287 | else if (ft == FILE_TYPE_PIPE) | |
1fd5e000 | 288 | { |
019fc8d8 CV |
289 | int rcv = 0, len = sizeof (int); |
290 | ||
88f0dc31 | 291 | if (handle_to_fn (handle, name)) |
02a33ea7 | 292 | dev.parse (name); |
019fc8d8 | 293 | else if (strcmp (name, ":sock:") == 0 |
02dbd9ae CV |
294 | /* NtQueryObject returns an error when called on an LSP socket |
295 | handle. While fdsock now tries to fetch the underlying | |
296 | base socket, this only works on Vista and later. */ | |
019fc8d8 CV |
297 | || (strcmp (name, unknown_file) == 0 |
298 | && !::getsockopt ((SOCKET) handle, SOL_SOCKET, SO_RCVBUF, | |
299 | (char *) &rcv, &len))) | |
300 | { | |
301 | /* socket */ | |
302 | dev = *tcp_dev; | |
303 | name[0] = '\0'; | |
304 | } | |
1ffe3e67 CF |
305 | else if (fd == 0) |
306 | dev = *piper_dev; | |
4ab6034f | 307 | else |
1ffe3e67 | 308 | dev = *pipew_dev; |
4ab6034f | 309 | } |
92ddb742 | 310 | else if (GetConsoleScreenBufferInfo (handle, &buf) |
b86f999a | 311 | || GetNumberOfConsoleInputEvents (handle, (DWORD *) &buf)) |
1ffe3e67 | 312 | { |
92ddb742 | 313 | /* Console I/O */ |
c75b5b2d | 314 | if (myself->ctty > 0) |
44d2fc0a | 315 | dev.parse (myself->ctty); |
1ffe3e67 | 316 | else |
6ae28c22 CF |
317 | { |
318 | dev.parse (FH_CONSOLE); | |
319 | CloseHandle (handle); | |
320 | handle = INVALID_HANDLE_VALUE; | |
321 | } | |
1ffe3e67 | 322 | } |
1ffe3e67 | 323 | else if (GetCommState (handle, &dcb)) |
92ddb742 CF |
324 | /* FIXME: Not right - assumes ttyS0 */ |
325 | dev.parse (DEV_SERIAL_MAJOR, 0); | |
1ffe3e67 CF |
326 | else |
327 | /* Try to figure it out from context - probably a disk file */ | |
328 | handle_to_fn (handle, name); | |
cef69559 | 329 | |
1ffe3e67 | 330 | if (!name[0] && !dev) |
cef69559 CF |
331 | fds[fd] = NULL; |
332 | else | |
4ab6034f | 333 | { |
7ac61736 CF |
334 | fhandler_base *fh; |
335 | ||
336 | if (dev) | |
1ffe3e67 | 337 | fh = build_fh_dev (dev); |
7ac61736 CF |
338 | else |
339 | fh = build_fh_name (name); | |
340 | ||
e5b7e4d1 CF |
341 | if (!fh) |
342 | return; | |
343 | ||
1ffe3e67 | 344 | if (name[0]) |
abb58a6d | 345 | { |
634a4140 CF |
346 | bin = fh->pc_binmode (); |
347 | if (!bin) | |
348 | { | |
349 | bin = fh->get_default_fmode (O_RDWR); | |
350 | if (!bin && dev) | |
351 | bin = O_BINARY; | |
352 | } | |
abb58a6d | 353 | } |
9655ff26 | 354 | |
02a33ea7 CV |
355 | IO_STATUS_BLOCK io; |
356 | FILE_ACCESS_INFORMATION fai; | |
6ae28c22 | 357 | int openflags = O_BINARY; |
02a33ea7 CV |
358 | |
359 | /* Console windows are not kernel objects, so the access mask returned | |
179bee57 CV |
360 | by NtQueryInformationFile is meaningless. CMD always hands down |
361 | stdin handles as R/O handles, but our tty slave sides are R/W. */ | |
06f46dc3 | 362 | if (fh->is_tty ()) |
6ae28c22 CF |
363 | { |
364 | openflags |= O_RDWR; | |
365 | access |= GENERIC_READ | GENERIC_WRITE; | |
366 | } | |
367 | else if (!iscons_dev (dev) | |
368 | && NT_SUCCESS (NtQueryInformationFile (handle, &io, &fai, | |
369 | sizeof fai, | |
370 | FileAccessInformation))) | |
02a33ea7 | 371 | { |
02a33ea7 | 372 | if (fai.AccessFlags & FILE_WRITE_DATA) |
6ae28c22 CF |
373 | { |
374 | openflags |= O_WRONLY; | |
375 | access |= GENERIC_WRITE; | |
376 | } | |
377 | if (fai.AccessFlags & FILE_READ_DATA) | |
378 | { | |
379 | openflags |= openflags & O_WRONLY ? O_RDWR : O_RDONLY; | |
380 | access |= GENERIC_READ; | |
381 | } | |
02a33ea7 | 382 | } |
4248960e | 383 | else if (fd == 0) |
6ae28c22 CF |
384 | { |
385 | openflags |= O_RDONLY; | |
386 | access |= GENERIC_READ; | |
387 | } | |
70300fdb | 388 | else |
6ae28c22 CF |
389 | { |
390 | openflags |= O_WRONLY; | |
391 | access |= GENERIC_WRITE; /* Should be rdwr for stderr but not sure that's | |
392 | possible for some versions of handles */ | |
393 | } | |
394 | if (!fh->init (handle, access, bin)) | |
3c4f2024 | 395 | api_fatal ("couldn't initialize fd %d for %s", fd, fh->get_name ()); |
1ae0a7c5 | 396 | |
6ae28c22 CF |
397 | fh->open_setup (openflags); |
398 | fh->usecount = 0; | |
1ae0a7c5 | 399 | cygheap->fdtab[fd] = fh; |
3143cb7c | 400 | cygheap->fdtab[fd]->inc_refcnt (); |
1ae0a7c5 | 401 | set_std_handle (fd); |
cef69559 | 402 | paranoid_printf ("fd %d, handle %p", fd, handle); |
1fd5e000 | 403 | } |
1fd5e000 CF |
404 | } |
405 | ||
3d938be6 CV |
406 | #define cnew(name, ...) \ |
407 | ({ \ | |
408 | void* ptr = (void*) ccalloc (HEAP_FHANDLER, 1, sizeof (name)); \ | |
c38da4ee | 409 | ptr ? new (ptr) name (__VA_ARGS__) : NULL; \ |
3d938be6 | 410 | }) |
1ffe3e67 | 411 | |
23771fa1 CF |
412 | #define cnew_no_ctor(name, ...) \ |
413 | ({ \ | |
414 | void* ptr = (void*) ccalloc (HEAP_FHANDLER, 1, sizeof (name)); \ | |
415 | ptr ? new (ptr) name (ptr) : NULL; \ | |
416 | }) | |
417 | ||
4ee93264 CV |
418 | fhandler_base * |
419 | build_fh_name (const char *name, unsigned opt, suffix_info *si) | |
1fd5e000 | 420 | { |
4ee93264 | 421 | path_conv pc (name, opt | PC_NULLEMPTY | PC_POSIX, si); |
4ab6034f CF |
422 | if (pc.error) |
423 | { | |
3d938be6 CV |
424 | fhandler_base *fh = cnew (fhandler_nodevice); |
425 | if (fh) | |
6a7bea70 CF |
426 | fh->set_error (pc.error); |
427 | set_errno (fh ? pc.error : EMFILE); | |
e00700cd | 428 | return fh; |
1fd5e000 CF |
429 | } |
430 | ||
7ac61736 | 431 | return build_fh_pc (pc); |
1fd5e000 CF |
432 | } |
433 | ||
434 | fhandler_base * | |
7ac61736 | 435 | build_fh_dev (const device& dev, const char *unix_name) |
ff938546 | 436 | { |
7ac61736 | 437 | path_conv pc (dev); |
7ac61736 | 438 | if (unix_name) |
a9e9da89 | 439 | pc.set_normalized_path (unix_name); |
7ac61736 | 440 | else |
a9e9da89 | 441 | pc.set_normalized_path (dev.name); |
7ac61736 | 442 | return build_fh_pc (pc); |
ff938546 CF |
443 | } |
444 | ||
6a7bea70 | 445 | #define fh_unset ((fhandler_base *) 1) |
6ae28c22 CF |
446 | static device last_tty_dev; |
447 | #define fh_last_tty_dev ((fhandler_termios *) cygheap->fdtab.find_archetype (last_tty_dev)) | |
23771fa1 | 448 | |
92ddb742 | 449 | static fhandler_base * |
23771fa1 | 450 | fh_alloc (path_conv& pc) |
1fd5e000 | 451 | { |
6a7bea70 | 452 | fhandler_base *fh = fh_unset; |
23771fa1 | 453 | fhandler_base *fhraw = NULL; |
1fd5e000 | 454 | |
23771fa1 | 455 | switch (pc.dev.get_major ()) |
7b02cb30 | 456 | { |
38d732a1 | 457 | case DEV_PTYS_MAJOR: |
23771fa1 CF |
458 | fh = cnew (fhandler_pty_slave, pc.dev.get_minor ()); |
459 | break; | |
38d732a1 | 460 | case DEV_PTYM_MAJOR: |
23771fa1 | 461 | fh = cnew (fhandler_pty_master, pc.dev.get_minor ()); |
7b02cb30 | 462 | break; |
7b02cb30 CF |
463 | case DEV_FLOPPY_MAJOR: |
464 | case DEV_CDROM_MAJOR: | |
465 | case DEV_SD_MAJOR: | |
cc9dbc90 | 466 | case DEV_SD1_MAJOR: |
9e3f289f CV |
467 | case DEV_SD2_MAJOR: |
468 | case DEV_SD3_MAJOR: | |
469 | case DEV_SD4_MAJOR: | |
470 | case DEV_SD5_MAJOR: | |
471 | case DEV_SD6_MAJOR: | |
472 | case DEV_SD7_MAJOR: | |
3d938be6 | 473 | fh = cnew (fhandler_dev_floppy); |
7b02cb30 CF |
474 | break; |
475 | case DEV_TAPE_MAJOR: | |
3d938be6 | 476 | fh = cnew (fhandler_dev_tape); |
7b02cb30 CF |
477 | break; |
478 | case DEV_SERIAL_MAJOR: | |
3d938be6 | 479 | fh = cnew (fhandler_serial); |
7b02cb30 | 480 | break; |
44d2fc0a | 481 | case DEV_CONS_MAJOR: |
23771fa1 | 482 | fh = cnew (fhandler_console, pc.dev); |
44d2fc0a | 483 | break; |
7b02cb30 | 484 | default: |
6c95669d | 485 | switch ((DWORD) pc.dev) |
7b02cb30 CF |
486 | { |
487 | case FH_CONSOLE: | |
488 | case FH_CONIN: | |
489 | case FH_CONOUT: | |
23771fa1 | 490 | fh = cnew (fhandler_console, pc.dev); |
7b02cb30 | 491 | break; |
23771fa1 CF |
492 | case FH_PTMX: |
493 | if (pc.isopen ()) | |
494 | fh = cnew (fhandler_pty_master, -1); | |
495 | else | |
1b23b30b | 496 | fhraw = cnew_no_ctor (fhandler_pty_master, -1); |
7b02cb30 CF |
497 | break; |
498 | case FH_WINDOWS: | |
3d938be6 | 499 | fh = cnew (fhandler_windows); |
7b02cb30 CF |
500 | break; |
501 | case FH_FIFO: | |
3d938be6 | 502 | fh = cnew (fhandler_fifo); |
7b02cb30 CF |
503 | break; |
504 | case FH_PIPE: | |
505 | case FH_PIPER: | |
506 | case FH_PIPEW: | |
3d938be6 | 507 | fh = cnew (fhandler_pipe); |
7b02cb30 CF |
508 | break; |
509 | case FH_TCP: | |
510 | case FH_UDP: | |
511 | case FH_ICMP: | |
512 | case FH_UNIX: | |
513 | case FH_STREAM: | |
514 | case FH_DGRAM: | |
3d938be6 | 515 | fh = cnew (fhandler_socket); |
7b02cb30 CF |
516 | break; |
517 | case FH_FS: | |
3d938be6 | 518 | fh = cnew (fhandler_disk_file); |
7b02cb30 CF |
519 | break; |
520 | case FH_NULL: | |
3d938be6 | 521 | fh = cnew (fhandler_dev_null); |
7b02cb30 CF |
522 | break; |
523 | case FH_ZERO: | |
524 | case FH_FULL: | |
3d938be6 | 525 | fh = cnew (fhandler_dev_zero); |
7b02cb30 CF |
526 | break; |
527 | case FH_RANDOM: | |
528 | case FH_URANDOM: | |
3d938be6 | 529 | fh = cnew (fhandler_dev_random); |
7b02cb30 CF |
530 | break; |
531 | case FH_MEM: | |
73447abb | 532 | case FH_KMEM: |
7b02cb30 | 533 | case FH_PORT: |
3d938be6 | 534 | fh = cnew (fhandler_dev_mem); |
7b02cb30 CF |
535 | break; |
536 | case FH_CLIPBOARD: | |
3d938be6 | 537 | fh = cnew (fhandler_dev_clipboard); |
7b02cb30 CF |
538 | break; |
539 | case FH_OSS_DSP: | |
3d938be6 | 540 | fh = cnew (fhandler_dev_dsp); |
7b02cb30 CF |
541 | break; |
542 | case FH_PROC: | |
3d938be6 | 543 | fh = cnew (fhandler_proc); |
7b02cb30 CF |
544 | break; |
545 | case FH_REGISTRY: | |
3d938be6 | 546 | fh = cnew (fhandler_registry); |
7b02cb30 CF |
547 | break; |
548 | case FH_PROCESS: | |
38f50ae4 | 549 | case FH_PROCESSFD: |
3d938be6 | 550 | fh = cnew (fhandler_process); |
7b02cb30 | 551 | break; |
96d7dee2 | 552 | case FH_PROCNET: |
3d938be6 | 553 | fh = cnew (fhandler_procnet); |
96d7dee2 | 554 | break; |
43f65cdd | 555 | case FH_PROCSYS: |
3d938be6 | 556 | fh = cnew (fhandler_procsys); |
43f65cdd | 557 | break; |
d68288f6 | 558 | case FH_PROCSYSVIPC: |
3d938be6 | 559 | fh = cnew (fhandler_procsysvipc); |
d68288f6 | 560 | break; |
7b02cb30 | 561 | case FH_NETDRIVE: |
3d938be6 | 562 | fh = cnew (fhandler_netdrive); |
7b02cb30 | 563 | break; |
1f312200 CV |
564 | case FH_DEV: |
565 | fh = cnew (fhandler_dev); | |
566 | break; | |
f7c8c454 CV |
567 | case FH_CYGDRIVE: |
568 | fh = cnew (fhandler_cygdrive); | |
569 | break; | |
7b02cb30 | 570 | case FH_TTY: |
23771fa1 | 571 | if (!pc.isopen ()) |
38d732a1 | 572 | { |
1b23b30b | 573 | fhraw = cnew_no_ctor (fhandler_console, -1); |
6ae28c22 CF |
574 | debug_printf ("not called from open for /dev/tty"); |
575 | } | |
576 | else if (myself->ctty <= 0 && last_tty_dev | |
577 | && !myself->set_ctty (fh_last_tty_dev, 0)) | |
578 | debug_printf ("no /dev/tty assigned"); | |
579 | else if (myself->ctty > 0) | |
580 | { | |
581 | debug_printf ("determining /dev/tty assignment for ctty %p", myself->ctty); | |
38d732a1 CF |
582 | if (iscons_dev (myself->ctty)) |
583 | fh = cnew (fhandler_console, pc.dev); | |
584 | else | |
585 | fh = cnew (fhandler_pty_slave, myself->ctty); | |
6ae28c22 CF |
586 | if (fh->dev () != FH_NADA) |
587 | fh->set_name ("/dev/tty"); | |
38d732a1 | 588 | } |
23771fa1 | 589 | break; |
7b02cb30 | 590 | case FH_KMSG: |
3d938be6 | 591 | fh = cnew (fhandler_mailslot); |
7b02cb30 | 592 | break; |
0e1ba888 | 593 | } |
7b02cb30 | 594 | } |
7ac61736 | 595 | |
23771fa1 CF |
596 | /* If `fhraw' is set that means that this fhandler is just a dummy |
597 | set up for stat(). Mock it up for use by stat without actually | |
598 | trying to do any real initialization. */ | |
599 | if (fhraw) | |
600 | { | |
601 | fh = fhraw; | |
602 | fh->set_name (pc); | |
603 | if (fh->use_archetype ()) | |
604 | fh->archetype = fh; | |
605 | } | |
2e82c935 | 606 | if (fh == fh_unset) |
3d938be6 | 607 | fh = cnew (fhandler_nodevice); |
23771fa1 CF |
608 | else if (fh->dev () == FH_ERROR) |
609 | { | |
8b4bd082 | 610 | if (!pc.isopen () && pc.dev.isfs ()) |
080f275b | 611 | fh->dev () = pc.dev; /* Special case: This file actually exists on |
8b4bd082 CF |
612 | disk and we're not trying to open it so just |
613 | return the info from pc. */ | |
080f275b CF |
614 | else |
615 | { | |
616 | delete fh; | |
617 | fh = NULL; | |
618 | } | |
23771fa1 | 619 | } |
92ddb742 CF |
620 | return fh; |
621 | } | |
622 | ||
623 | fhandler_base * | |
6ae28c22 | 624 | build_fh_pc (path_conv& pc) |
92ddb742 | 625 | { |
23771fa1 | 626 | fhandler_base *fh = fh_alloc (pc); |
2e82c935 | 627 | |
1c1b04b8 | 628 | if (!fh) |
9e1fd6bc | 629 | { |
23771fa1 | 630 | set_errno (ENXIO); |
9e1fd6bc CV |
631 | goto out; |
632 | } | |
7ac61736 | 633 | |
92ddb742 | 634 | if (!fh->use_archetype ()) |
6ae28c22 | 635 | fh->set_name (pc); |
92ddb742 | 636 | else if ((fh->archetype = cygheap->fdtab.find_archetype (fh->dev ()))) |
6ae28c22 CF |
637 | { |
638 | debug_printf ("found an archetype for %s(%d/%d) io_handle %p", fh->get_name (), fh->dev ().get_major (), fh->dev ().get_minor (), | |
639 | fh->archetype->get_io_handle ()); | |
640 | if (!fh->get_name ()) | |
641 | fh->set_name (fh->archetype->dev ().name); | |
642 | } | |
643 | else if (cygwin_finished_initializing && !pc.isopen ()) | |
644 | fh->set_name (pc); | |
92ddb742 CF |
645 | else |
646 | { | |
6ae28c22 CF |
647 | if (!fh->get_name ()) |
648 | fh->set_name (fh->dev ().name); | |
23771fa1 CF |
649 | fh->archetype = fh->clone (); |
650 | debug_printf ("created an archetype (%p) for %s(%d/%d)", fh->archetype, fh->get_name (), fh->dev ().get_major (), fh->dev ().get_minor ()); | |
92ddb742 CF |
651 | fh->archetype->archetype = NULL; |
652 | *cygheap->fdtab.add_archetype () = fh->archetype; | |
653 | } | |
654 | ||
6ae28c22 CF |
655 | |
656 | /* Keep track of the last tty-like thing opened. We could potentially want | |
657 | to open it if /dev/tty is referenced. */ | |
23771fa1 | 658 | if (myself->ctty > 0 || !fh->is_tty () || !pc.isctty_capable ()) |
6ae28c22 CF |
659 | last_tty_dev = FH_NADA; |
660 | else | |
661 | last_tty_dev = fh->dev (); | |
23771fa1 | 662 | |
c3a9063f | 663 | out: |
6ae28c22 | 664 | debug_printf ("fh %p, dev %p", fh, fh ? (DWORD) fh->dev () : 0); |
7ac61736 | 665 | return fh; |
1fd5e000 CF |
666 | } |
667 | ||
668 | fhandler_base * | |
e70fdfb9 | 669 | dtable::dup_worker (fhandler_base *oldfh, int flags) |
1fd5e000 | 670 | { |
1c1b04b8 CV |
671 | /* Don't call set_name in build_fh_pc. It will be called in |
672 | fhandler_base::operator= below. Calling it twice will result | |
673 | in double allocation. */ | |
23771fa1 | 674 | fhandler_base *newfh = oldfh->clone (); |
6a7bea70 CF |
675 | if (!newfh) |
676 | debug_printf ("build_fh_pc failed"); | |
677 | else | |
1fd5e000 | 678 | { |
92ddb742 CF |
679 | if (!oldfh->archetype) |
680 | newfh->set_io_handle (NULL); | |
23771fa1 | 681 | |
5a0d1edb | 682 | newfh->pc.reset_conv_handle (); |
23771fa1 | 683 | if (oldfh->dup (newfh, flags)) |
6a7bea70 | 684 | { |
1c1b04b8 CV |
685 | delete newfh; |
686 | newfh = NULL; | |
6a7bea70 CF |
687 | debug_printf ("oldfh->dup failed"); |
688 | } | |
689 | else | |
690 | { | |
8fa8b3a3 CF |
691 | /* Don't increment refcnt here since we don't know if this is a |
692 | allocated fd. So we leave this chore to the caller. */ | |
693 | ||
92ddb742 CF |
694 | newfh->usecount = 0; |
695 | newfh->archetype_usecount (1); | |
8fa8b3a3 | 696 | |
e70fdfb9 | 697 | /* The O_CLOEXEC flag enforces close-on-exec behaviour. */ |
92ddb742 | 698 | newfh->set_close_on_exec (!!(flags & O_CLOEXEC)); |
4eb5175d CF |
699 | debug_printf ("duped '%s' old %p, new %p", oldfh->get_name (), |
700 | oldfh->get_io_handle (), newfh->get_io_handle ()); | |
6a7bea70 | 701 | } |
1fd5e000 | 702 | } |
1fd5e000 CF |
703 | return newfh; |
704 | } | |
705 | ||
706 | int | |
e70fdfb9 | 707 | dtable::dup3 (int oldfd, int newfd, int flags) |
1fd5e000 CF |
708 | { |
709 | int res = -1; | |
710 | fhandler_base *newfh = NULL; // = NULL to avoid an incorrect warning | |
711 | ||
712 | MALLOC_CHECK; | |
e70fdfb9 | 713 | debug_printf ("dup3 (%d, %d, %p)", oldfd, newfd, flags); |
2d1d1eb1 | 714 | lock (); |
3143cb7c | 715 | bool do_unlock = true; |
b9c61a8d CF |
716 | bool unlock_on_return; |
717 | if (!(flags & O_EXCL)) | |
718 | unlock_on_return = true; /* Relinquish lock on return */ | |
719 | else | |
720 | { | |
721 | flags &= ~O_EXCL; | |
722 | unlock_on_return = false; /* Return with lock set on success */ | |
723 | } | |
1fd5e000 CF |
724 | |
725 | if (not_open (oldfd)) | |
726 | { | |
5a449743 | 727 | syscall_printf ("fd %d not open", oldfd); |
1fd5e000 CF |
728 | set_errno (EBADF); |
729 | goto done; | |
730 | } | |
f6187d46 | 731 | if (newfd >= OPEN_MAX_MAX || newfd < 0) |
4c78be52 CF |
732 | { |
733 | syscall_printf ("new fd out of bounds: %d", newfd); | |
734 | set_errno (EBADF); | |
735 | goto done; | |
736 | } | |
e70fdfb9 | 737 | if ((flags & ~O_CLOEXEC) != 0) |
1fd5e000 | 738 | { |
e70fdfb9 CV |
739 | syscall_printf ("invalid flags value %x", flags); |
740 | set_errno (EINVAL); | |
741 | return -1; | |
1fd5e000 CF |
742 | } |
743 | ||
23771fa1 CF |
744 | /* This is a temporary kludge until all utilities can catch up with |
745 | a change in behavior that implements linux functionality: opening | |
746 | a tty should not automatically cause it to become the controlling | |
747 | tty for the process. */ | |
748 | if (newfd > 2) | |
749 | flags |= O_NOCTTY; | |
750 | ||
e70fdfb9 | 751 | if ((newfh = dup_worker (fds[oldfd], flags)) == NULL) |
1fd5e000 CF |
752 | { |
753 | res = -1; | |
754 | goto done; | |
755 | } | |
756 | ||
a9934559 CF |
757 | debug_printf ("newfh->io_handle %p, oldfh->io_handle %p, new win32_name %p, old win32_name %p", |
758 | newfh->get_io_handle (), fds[oldfd]->get_io_handle (), newfh->get_win32_name (), fds[oldfd]->get_win32_name ()); | |
b0e82b74 | 759 | |
4c78be52 | 760 | if (!not_open (newfd)) |
5ec14fe4 | 761 | close (newfd); |
8fa8b3a3 CF |
762 | else if ((size_t) newfd > size |
763 | && find_unused_handle (newfd) < 0) | |
764 | /* couldn't extend fdtab */ | |
5a449743 | 765 | { |
4c78be52 CF |
766 | newfh->close (); |
767 | res = -1; | |
5a449743 CF |
768 | goto done; |
769 | } | |
b0e82b74 | 770 | |
1fd5e000 | 771 | fds[newfd] = newfh; |
dd4f0b23 | 772 | |
1fd5e000 CF |
773 | if ((res = newfd) <= 2) |
774 | set_std_handle (res); | |
b9c61a8d | 775 | do_unlock = unlock_on_return; |
1fd5e000 | 776 | |
1fd5e000 | 777 | done: |
4c78be52 | 778 | MALLOC_CHECK; |
3143cb7c CF |
779 | if (do_unlock) |
780 | unlock (); | |
b9aa8149 | 781 | syscall_printf ("%R = dup3(%d, %d, %p)", res, oldfd, newfd, flags); |
1fd5e000 CF |
782 | |
783 | return res; | |
784 | } | |
785 | ||
b4fa8164 CF |
786 | bool |
787 | dtable::select_read (int fd, select_stuff *ss) | |
1fd5e000 | 788 | { |
b0e82b74 | 789 | if (not_open (fd)) |
1fd5e000 CF |
790 | { |
791 | set_errno (EBADF); | |
b4fa8164 | 792 | return false; |
1fd5e000 | 793 | } |
b0e82b74 | 794 | fhandler_base *fh = fds[fd]; |
b4fa8164 | 795 | select_record *s = fh->select_read (ss); |
1fd5e000 | 796 | s->fd = fd; |
c7ef20e7 CF |
797 | if (!s->fh) |
798 | s->fh = fh; | |
169c465a | 799 | s->thread_errno = 0; |
1fd5e000 | 800 | debug_printf ("%s fd %d", fh->get_name (), fd); |
b4fa8164 | 801 | return true; |
1fd5e000 CF |
802 | } |
803 | ||
b4fa8164 CF |
804 | bool |
805 | dtable::select_write (int fd, select_stuff *ss) | |
1fd5e000 | 806 | { |
b0e82b74 | 807 | if (not_open (fd)) |
1fd5e000 CF |
808 | { |
809 | set_errno (EBADF); | |
810 | return NULL; | |
811 | } | |
b0e82b74 | 812 | fhandler_base *fh = fds[fd]; |
b4fa8164 | 813 | select_record *s = fh->select_write (ss); |
1fd5e000 CF |
814 | s->fd = fd; |
815 | s->fh = fh; | |
169c465a | 816 | s->thread_errno = 0; |
106e3acf | 817 | debug_printf ("%s fd %d", fh->get_name (), fd); |
b4fa8164 | 818 | return true; |
1fd5e000 CF |
819 | } |
820 | ||
b4fa8164 CF |
821 | bool |
822 | dtable::select_except (int fd, select_stuff *ss) | |
1fd5e000 | 823 | { |
b0e82b74 | 824 | if (not_open (fd)) |
1fd5e000 CF |
825 | { |
826 | set_errno (EBADF); | |
827 | return NULL; | |
828 | } | |
b0e82b74 | 829 | fhandler_base *fh = fds[fd]; |
b4fa8164 | 830 | select_record *s = fh->select_except (ss); |
1fd5e000 CF |
831 | s->fd = fd; |
832 | s->fh = fh; | |
169c465a | 833 | s->thread_errno = 0; |
1fd5e000 | 834 | debug_printf ("%s fd %d", fh->get_name (), fd); |
b4fa8164 | 835 | return true; |
1fd5e000 CF |
836 | } |
837 | ||
c16548b2 CF |
838 | void |
839 | dtable::move_fd (int from, int to) | |
840 | { | |
841 | // close (to); /* It is assumed that this is close-on-exec */ | |
842 | fds[to] = fds[from]; | |
843 | fds[from] = NULL; | |
844 | } | |
845 | ||
fef1edbc CF |
846 | void |
847 | dtable::set_file_pointers_for_exec () | |
848 | { | |
cce64750 CV |
849 | /* This is not POSIX-compliant so the function is only called for |
850 | non-Cygwin processes. */ | |
ad4e943f | 851 | LONG off_high = 0; |
2d1d1eb1 | 852 | lock (); |
fef1edbc CF |
853 | fhandler_base *fh; |
854 | for (size_t i = 0; i < size; i++) | |
855 | if ((fh = fds[i]) != NULL && fh->get_flags () & O_APPEND) | |
ad4e943f | 856 | SetFilePointer (fh->get_handle (), 0, &off_high, FILE_END); |
2d1d1eb1 | 857 | unlock (); |
fef1edbc CF |
858 | } |
859 | ||
881beea8 CF |
860 | void |
861 | dtable::fixup_close (size_t i, fhandler_base *fh) | |
862 | { | |
863 | if (fh->archetype) | |
864 | { | |
865 | debug_printf ("closing fd %d since it is an archetype", i); | |
866 | fh->close_with_arch (); | |
867 | } | |
868 | release (i); | |
869 | } | |
870 | ||
b0e82b74 | 871 | void |
52806019 | 872 | dtable::fixup_after_exec () |
1fd5e000 | 873 | { |
b0e82b74 | 874 | first_fd_for_open = 0; |
2e78b61d | 875 | fhandler_base *fh; |
b0e82b74 | 876 | for (size_t i = 0; i < size; i++) |
2e78b61d | 877 | if ((fh = fds[i]) != NULL) |
4f7ac76a | 878 | { |
2e78b61d | 879 | fh->clear_readahead (); |
59297e04 | 880 | fh->fixup_after_exec (); |
881beea8 CF |
881 | /* Close the handle if it's close-on-exec or if an error was detected |
882 | (typically with opening a console in a gui app) by fixup_after_exec. | |
883 | */ | |
55dcba98 | 884 | if (fh->close_on_exec () || (!fh->nohandle () && !fh->get_io_handle ())) |
881beea8 | 885 | fixup_close (i, fh); |
421ba492 CF |
886 | else if (fh->get_popen_pid ()) |
887 | close (i); | |
59297e04 CF |
888 | else if (i == 0) |
889 | SetStdHandle (std_consts[i], fh->get_io_handle ()); | |
890 | else if (i <= 2) | |
891 | SetStdHandle (std_consts[i], fh->get_output_handle ()); | |
4f7ac76a | 892 | } |
1fd5e000 CF |
893 | } |
894 | ||
895 | void | |
9015e0fb | 896 | dtable::fixup_after_fork (HANDLE parent) |
1fd5e000 | 897 | { |
b0e82b74 | 898 | fhandler_base *fh; |
1fd5e000 | 899 | for (size_t i = 0; i < size; i++) |
b0e82b74 | 900 | if ((fh = fds[i]) != NULL) |
1fd5e000 | 901 | { |
56551a9b | 902 | if (fh->close_on_exec () || fh->need_fork_fixup ()) |
1fd5e000 | 903 | { |
c729f227 | 904 | debug_printf ("fd %d (%s)", i, fh->get_name ()); |
1fd5e000 | 905 | fh->fixup_after_fork (parent); |
55dcba98 | 906 | if (!fh->nohandle () && !fh->get_io_handle ()) |
881beea8 CF |
907 | { |
908 | /* This should actually never happen but it's here to make sure | |
909 | we don't crash due to access of an unopened file handle. */ | |
910 | fixup_close (i, fh); | |
911 | continue; | |
912 | } | |
1fd5e000 | 913 | } |
f3acbe3e CF |
914 | if (i == 0) |
915 | SetStdHandle (std_consts[i], fh->get_io_handle ()); | |
916 | else if (i <= 2) | |
917 | SetStdHandle (std_consts[i], fh->get_output_handle ()); | |
1fd5e000 | 918 | } |
1fd5e000 CF |
919 | } |
920 | ||
88f0dc31 CF |
921 | static void |
922 | decode_tty (char *buf, WCHAR *w32) | |
1ffe3e67 CF |
923 | { |
924 | int ttyn = wcstol (w32, NULL, 10); | |
92601445 | 925 | __ptsname (buf, ttyn); |
1ffe3e67 CF |
926 | } |
927 | ||
88f0dc31 CF |
928 | /* Try to derive posix filename from given handle. Return true if |
929 | the handle is associated with a cygwin tty. */ | |
930 | static bool | |
2402700d CF |
931 | handle_to_fn (HANDLE h, char *posix_fn) |
932 | { | |
ab5d348d | 933 | tmp_pathbuf tp; |
1ffe3e67 | 934 | ULONG len = 0; |
1ffe3e67 | 935 | WCHAR *maxmatchdos = NULL; |
5e7c84e5 | 936 | PWCHAR device = tp.w_get (); |
1ffe3e67 | 937 | int maxmatchlen = 0; |
019fc8d8 CV |
938 | OBJECT_NAME_INFORMATION *ntfn = (OBJECT_NAME_INFORMATION *) tp.w_get (); |
939 | ||
940 | NTSTATUS status = NtQueryObject (h, ObjectNameInformation, ntfn, 65536, &len); | |
941 | if (!NT_SUCCESS (status)) | |
942 | debug_printf ("NtQueryObject failed, %p", status); | |
943 | // NT seems to do this on an unopened file | |
944 | else if (!ntfn->Name.Buffer) | |
945 | debug_printf ("nt->Name.Buffer == NULL"); | |
7b9e380f | 946 | else |
1ffe3e67 | 947 | { |
019fc8d8 CV |
948 | WCHAR *w32 = ntfn->Name.Buffer; |
949 | size_t w32len = ntfn->Name.Length / sizeof (WCHAR); | |
950 | w32[w32len] = L'\0'; | |
2bb6b3e5 | 951 | |
019fc8d8 CV |
952 | if (wcscasecmp (w32, DEV_NULL) == 0) |
953 | { | |
954 | strcpy (posix_fn, "/dev/null"); | |
955 | return false; | |
956 | } | |
2bb6b3e5 | 957 | |
019fc8d8 CV |
958 | if (wcscasecmp (w32, DEV_SOCKET) == 0) |
959 | { | |
960 | strcpy (posix_fn, ":sock:"); | |
961 | return false; | |
962 | } | |
2402700d | 963 | |
019fc8d8 CV |
964 | if (wcsncasecmp (w32, DEV_NAMED_PIPE, DEV_NAMED_PIPE_LEN) == 0) |
965 | { | |
966 | w32 += DEV_NAMED_PIPE_LEN; | |
967 | if (wcsncmp (w32, L"cygwin-", WCLEN (L"cygwin-")) != 0) | |
968 | return false; | |
969 | w32 += WCLEN (L"cygwin-"); | |
526b0fbc | 970 | /* Check for installation key and trailing dash. */ |
8895d962 CV |
971 | w32len = cygheap->installation_key.Length / sizeof (WCHAR); |
972 | if (w32len | |
973 | && wcsncmp (w32, cygheap->installation_key.Buffer, w32len) != 0) | |
526b0fbc CV |
974 | return false; |
975 | w32 += w32len; | |
976 | if (*w32 != L'-') | |
977 | return false; | |
978 | ++w32; | |
2ae8e0e4 | 979 | bool istty = wcsncmp (w32, L"pty", WCLEN (L"pty")) == 0; |
019fc8d8 | 980 | if (istty) |
2ae8e0e4 | 981 | decode_tty (posix_fn, w32 + WCLEN (L"pty")); |
019fc8d8 CV |
982 | else if (wcsncmp (w32, L"pipe", WCLEN (L"pipe")) == 0) |
983 | strcpy (posix_fn, "/dev/pipe"); | |
984 | return istty; | |
985 | } | |
5bf785a0 | 986 | |
019fc8d8 CV |
987 | WCHAR fnbuf[64 * 1024]; |
988 | if (wcsncasecmp (w32, DEVICE_PREFIX, DEVICE_PREFIX_LEN) != 0 | |
989 | || !QueryDosDeviceW (NULL, fnbuf, sizeof (fnbuf))) | |
990 | { | |
991 | sys_wcstombs (posix_fn, NT_MAX_PATH, w32, w32len); | |
992 | return false; | |
993 | } | |
2402700d | 994 | |
019fc8d8 CV |
995 | for (WCHAR *s = fnbuf; *s; s = wcschr (s, '\0') + 1) |
996 | { | |
5e7c84e5 | 997 | if (!QueryDosDeviceW (s, device, NT_MAX_PATH)) |
019fc8d8 CV |
998 | continue; |
999 | if (wcschr (s, ':') == NULL) | |
1000 | continue; | |
1001 | WCHAR *q = wcsrchr (device, ';'); | |
1002 | if (q) | |
7b9e380f | 1003 | { |
019fc8d8 CV |
1004 | WCHAR *r = wcschr (q, '\\'); |
1005 | if (r) | |
1006 | wcscpy (q, r + 1); | |
7b9e380f | 1007 | } |
019fc8d8 CV |
1008 | int devlen = wcslen (device); |
1009 | if (device[devlen - 1] == L'\\') | |
1010 | device[--devlen] = L'\0'; | |
1011 | if (devlen < maxmatchlen) | |
1012 | continue; | |
1013 | if (wcsncmp (device, w32, devlen) != 0|| | |
1014 | (w32[devlen] != L'\0' && w32[devlen] != L'\\')) | |
1015 | continue; | |
1016 | maxmatchlen = devlen; | |
1017 | maxmatchdos = s; | |
1018 | debug_printf ("current match '%W' = '%W'\n", s, device); | |
1019 | } | |
1ffe3e67 | 1020 | |
019fc8d8 CV |
1021 | if (maxmatchlen) |
1022 | { | |
1023 | WCHAR *p = wcschr (w32 + DEVICE_PREFIX_LEN, L'\\'); | |
1024 | size_t n = wcslen (maxmatchdos); | |
1025 | WCHAR ch; | |
1026 | if (!p) | |
1027 | ch = L'\0'; | |
1028 | else | |
7b9e380f | 1029 | { |
019fc8d8 CV |
1030 | if (maxmatchdos[n - 1] == L'\\') |
1031 | n--; | |
1032 | w32 += maxmatchlen - n; | |
1033 | ch = L'\\'; | |
7b9e380f | 1034 | } |
019fc8d8 CV |
1035 | memcpy (w32, maxmatchdos, n * sizeof (WCHAR)); |
1036 | w32[n] = ch; | |
1037 | } | |
1038 | else if (wcsncmp (w32, DEV_REMOTE, DEV_REMOTE_LEN) == 0) | |
1039 | { | |
1040 | w32 += DEV_REMOTE_LEN - 2; | |
1041 | *w32 = L'\\'; | |
1042 | debug_printf ("remote drive"); | |
1043 | } | |
1044 | else if (wcsncmp (w32, DEV_REMOTE1, DEV_REMOTE1_LEN) == 0) | |
1045 | { | |
1046 | w32 += DEV_REMOTE1_LEN - 2; | |
1047 | *w32 = L'\\'; | |
1048 | debug_printf ("remote drive"); | |
1049 | } | |
1ffe3e67 | 1050 | |
019fc8d8 CV |
1051 | cygwin_conv_path (CCP_WIN_W_TO_POSIX | CCP_ABSOLUTE, w32, posix_fn, |
1052 | NT_MAX_PATH); | |
37be5a67 | 1053 | |
019fc8d8 CV |
1054 | debug_printf ("derived path '%W', posix '%s'", w32, posix_fn); |
1055 | return false; | |
634a4140 | 1056 | } |
2402700d | 1057 | |
1ffe3e67 | 1058 | strcpy (posix_fn, unknown_file); |
88f0dc31 | 1059 | return false; |
2402700d | 1060 | } |
b14f53a8 CV |
1061 | |
1062 | void | |
1063 | dtable::fixup_before_fork (DWORD target_proc_id) | |
1064 | { | |
1065 | lock (); | |
1066 | fhandler_base *fh; | |
1067 | for (size_t i = 0; i < size; i++) | |
1068 | if ((fh = fds[i]) != NULL) | |
1069 | { | |
b86f999a CF |
1070 | debug_printf ("fd %d (%s)", i, fh->get_name ()); |
1071 | fh->fixup_before_fork_exec (target_proc_id); | |
b14f53a8 CV |
1072 | } |
1073 | unlock (); | |
b86f999a CF |
1074 | } |
1075 | ||
b14f53a8 CV |
1076 | void |
1077 | dtable::fixup_before_exec (DWORD target_proc_id) | |
1078 | { | |
1079 | lock (); | |
1080 | fhandler_base *fh; | |
1081 | for (size_t i = 0; i < size; i++) | |
1082 | if ((fh = fds[i]) != NULL && !fh->close_on_exec ()) | |
1083 | { | |
b86f999a CF |
1084 | debug_printf ("fd %d (%s)", i, fh->get_name ()); |
1085 | fh->fixup_before_fork_exec (target_proc_id); | |
b14f53a8 CV |
1086 | } |
1087 | unlock (); | |
b86f999a | 1088 | } |