xref: /openbsd-src/gnu/usr.bin/perl/win32/win32.c (revision 505ee9ea3b177e2387d907a91ca7da069f3f14d8)
1 /* WIN32.C
2  *
3  * (c) 1995 Microsoft Corporation. All rights reserved.
4  * 		Developed by hip communications inc.
5  * Portions (c) 1993 Intergraph Corporation. All rights reserved.
6  *
7  *    You may distribute under the terms of either the GNU General Public
8  *    License or the Artistic License, as specified in the README file.
9  */
10 #define PERLIO_NOT_STDIO 0
11 #define WIN32_LEAN_AND_MEAN
12 #define WIN32IO_IS_STDIO
13 #include <tchar.h>
14 
15 #ifdef __GNUC__
16 #  define Win32_Winsock
17 #endif
18 
19 #ifndef _WIN32_WINNT
20 #  define _WIN32_WINNT 0x0500     /* needed for CreateHardlink() etc. */
21 #endif
22 
23 #include <windows.h>
24 
25 #ifndef HWND_MESSAGE
26 #  define HWND_MESSAGE ((HWND)-3)
27 #endif
28 
29 #ifndef PROCESSOR_ARCHITECTURE_AMD64
30 #  define PROCESSOR_ARCHITECTURE_AMD64 9
31 #endif
32 
33 #ifndef WC_NO_BEST_FIT_CHARS
34 #  define WC_NO_BEST_FIT_CHARS 0x00000400
35 #endif
36 
37 #include <winnt.h>
38 #include <commctrl.h>
39 #include <tlhelp32.h>
40 #include <io.h>
41 #include <signal.h>
42 
43 /* #include "config.h" */
44 
45 
46 #define PerlIO FILE
47 
48 #include <sys/stat.h>
49 #include "EXTERN.h"
50 #include "perl.h"
51 
52 #define NO_XSLOCKS
53 #define PERL_NO_GET_CONTEXT
54 #include "XSUB.h"
55 
56 #include <fcntl.h>
57 #ifndef __GNUC__
58 /* assert.h conflicts with #define of assert in perl.h */
59 #  include <assert.h>
60 #endif
61 
62 #include <string.h>
63 #include <stdarg.h>
64 #include <float.h>
65 #include <time.h>
66 #include <sys/utime.h>
67 
68 #ifdef __GNUC__
69 /* Mingw32 defaults to globing command line
70  * So we turn it off like this:
71  */
72 int _CRT_glob = 0;
73 #endif
74 
75 #if defined(__MINGW32__) && (__MINGW32_MAJOR_VERSION==1)
76 /* Mingw32-1.1 is missing some prototypes */
77 START_EXTERN_C
78 FILE * _wfopen(LPCWSTR wszFileName, LPCWSTR wszMode);
79 FILE * _wfdopen(int nFd, LPCWSTR wszMode);
80 FILE * _freopen(LPCWSTR wszFileName, LPCWSTR wszMode, FILE * pOldStream);
81 int _flushall();
82 int _fcloseall();
83 END_EXTERN_C
84 #endif
85 
86 #define EXECF_EXEC 1
87 #define EXECF_SPAWN 2
88 #define EXECF_SPAWN_NOWAIT 3
89 
90 #if defined(PERL_IMPLICIT_SYS)
91 #  undef getlogin
92 #  define getlogin g_getlogin
93 #endif
94 
95 /* VS2005 (MSC version 14) provides a mechanism to set an invalid
96  * parameter handler.  This functionality is not available in the
97  * 64-bit compiler from the Platform SDK, which unfortunately also
98  * believes itself to be MSC version 14.
99  *
100  * There is no #define related to _set_invalid_parameter_handler(),
101  * but we can check for one of the constants defined for
102  * _set_abort_behavior(), which was introduced into stdlib.h at
103  * the same time.
104  */
105 
106 #if _MSC_VER >= 1400 && defined(_WRITE_ABORT_MSG)
107 #  define SET_INVALID_PARAMETER_HANDLER
108 #endif
109 
110 #ifdef SET_INVALID_PARAMETER_HANDLER
111 static BOOL	set_silent_invalid_parameter_handler(BOOL newvalue);
112 static void	my_invalid_parameter_handler(const wchar_t* expression,
113 			const wchar_t* function, const wchar_t* file,
114 			unsigned int line, uintptr_t pReserved);
115 #endif
116 
117 #ifndef WIN32_NO_REGISTRY
118 static char*	get_regstr_from(HKEY hkey, const char *valuename, SV **svp);
119 static char*	get_regstr(const char *valuename, SV **svp);
120 #endif
121 
122 static char*	get_emd_part(SV **prev_pathp, STRLEN *const len,
123 			char *trailing, ...);
124 static char*	win32_get_xlib(const char *pl,
125 			WIN32_NO_REGISTRY_M_(const char *xlib)
126 			const char *libname, STRLEN *const len);
127 
128 static BOOL	has_shell_metachars(const char *ptr);
129 static long	tokenize(const char *str, char **dest, char ***destv);
130 static void	get_shell(void);
131 static char*	find_next_space(const char *s);
132 static int	do_spawn2(pTHX_ const char *cmd, int exectype);
133 static int	do_spawn2_handles(pTHX_ const char *cmd, int exectype,
134                         const int *handles);
135 static int	do_spawnvp_handles(int mode, const char *cmdname,
136                         const char * const *argv, const int *handles);
137 static PerlIO * do_popen(const char *mode, const char *command, IV narg,
138 			 SV **args);
139 static long	find_pid(pTHX_ int pid);
140 static void	remove_dead_process(long child);
141 static int	terminate_process(DWORD pid, HANDLE process_handle, int sig);
142 static int	my_killpg(int pid, int sig);
143 static int	my_kill(int pid, int sig);
144 static void	out_of_memory(void);
145 static char*	wstr_to_str(const wchar_t* wstr);
146 static long	filetime_to_clock(PFILETIME ft);
147 static BOOL	filetime_from_time(PFILETIME ft, time_t t);
148 static char*	create_command_line(char *cname, STRLEN clen,
149 				    const char * const *args);
150 static char*	qualified_path(const char *cmd, bool other_exts);
151 static void	ansify_path(void);
152 static LRESULT	win32_process_message(HWND hwnd, UINT msg,
153 			WPARAM wParam, LPARAM lParam);
154 
155 #ifdef USE_ITHREADS
156 static long	find_pseudo_pid(pTHX_ int pid);
157 static void	remove_dead_pseudo_process(long child);
158 static HWND	get_hwnd_delay(pTHX, long child, DWORD tries);
159 #endif
160 
161 #ifdef HAVE_INTERP_INTERN
162 static void	win32_csighandler(int sig);
163 #endif
164 
165 START_EXTERN_C
166 HANDLE	w32_perldll_handle = INVALID_HANDLE_VALUE;
167 char	w32_module_name[MAX_PATH+1];
168 #ifdef WIN32_DYN_IOINFO_SIZE
169 Size_t	w32_ioinfo_size;/* avoid 0 extend op b4 mul, otherwise could be a U8 */
170 #endif
171 END_EXTERN_C
172 
173 static OSVERSIONINFO g_osver = {0, 0, 0, 0, 0, ""};
174 
175 #ifndef WIN32_NO_REGISTRY
176 /* initialized by Perl_win32_init/PERL_SYS_INIT */
177 static HKEY HKCU_Perl_hnd;
178 static HKEY HKLM_Perl_hnd;
179 #endif
180 
181 #ifdef SET_INVALID_PARAMETER_HANDLER
182 static BOOL silent_invalid_parameter_handler = FALSE;
183 
184 static BOOL
185 set_silent_invalid_parameter_handler(BOOL newvalue)
186 {
187     BOOL oldvalue = silent_invalid_parameter_handler;
188 #  ifdef _DEBUG
189     silent_invalid_parameter_handler = newvalue;
190 #  endif
191     return oldvalue;
192 }
193 
194 static void
195 my_invalid_parameter_handler(const wchar_t* expression,
196     const wchar_t* function,
197     const wchar_t* file,
198     unsigned int line,
199     uintptr_t pReserved)
200 {
201 #  ifdef _DEBUG
202     char* ansi_expression;
203     char* ansi_function;
204     char* ansi_file;
205     if (silent_invalid_parameter_handler)
206 	return;
207     ansi_expression = wstr_to_str(expression);
208     ansi_function = wstr_to_str(function);
209     ansi_file = wstr_to_str(file);
210     fprintf(stderr, "Invalid parameter detected in function %s. "
211                     "File: %s, line: %d\n", ansi_function, ansi_file, line);
212     fprintf(stderr, "Expression: %s\n", ansi_expression);
213     free(ansi_expression);
214     free(ansi_function);
215     free(ansi_file);
216 #  endif
217 }
218 #endif
219 
220 EXTERN_C void
221 set_w32_module_name(void)
222 {
223     /* this function may be called at DLL_PROCESS_ATTACH time */
224     char* ptr;
225     HMODULE module = (HMODULE)((w32_perldll_handle == INVALID_HANDLE_VALUE)
226                                ? GetModuleHandle(NULL)
227                                : w32_perldll_handle);
228 
229     WCHAR modulename[MAX_PATH];
230     WCHAR fullname[MAX_PATH];
231     char *ansi;
232 
233     DWORD (__stdcall *pfnGetLongPathNameW)(LPCWSTR, LPWSTR, DWORD) =
234         (DWORD (__stdcall *)(LPCWSTR, LPWSTR, DWORD))
235         GetProcAddress(GetModuleHandle("kernel32.dll"), "GetLongPathNameW");
236 
237     GetModuleFileNameW(module, modulename, sizeof(modulename)/sizeof(WCHAR));
238 
239     /* Make sure we get an absolute pathname in case the module was loaded
240      * explicitly by LoadLibrary() with a relative path. */
241     GetFullPathNameW(modulename, sizeof(fullname)/sizeof(WCHAR), fullname, NULL);
242 
243     /* Make sure we start with the long path name of the module because we
244      * later scan for pathname components to match "5.xx" to locate
245      * compatible sitelib directories, and the short pathname might mangle
246      * this path segment (e.g. by removing the dot on NTFS to something
247      * like "5xx~1.yy") */
248     if (pfnGetLongPathNameW)
249         pfnGetLongPathNameW(fullname, fullname, sizeof(fullname)/sizeof(WCHAR));
250 
251     /* remove \\?\ prefix */
252     if (memcmp(fullname, L"\\\\?\\", 4*sizeof(WCHAR)) == 0)
253         memmove(fullname, fullname+4, (wcslen(fullname+4)+1)*sizeof(WCHAR));
254 
255     ansi = win32_ansipath(fullname);
256     my_strlcpy(w32_module_name, ansi, sizeof(w32_module_name));
257     win32_free(ansi);
258 
259     /* normalize to forward slashes */
260     ptr = w32_module_name;
261     while (*ptr) {
262 	if (*ptr == '\\')
263 	    *ptr = '/';
264 	++ptr;
265     }
266 }
267 
268 #ifndef WIN32_NO_REGISTRY
269 /* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
270 static char*
271 get_regstr_from(HKEY handle, const char *valuename, SV **svp)
272 {
273     /* Retrieve a REG_SZ or REG_EXPAND_SZ from the registry */
274     DWORD type;
275     char *str = NULL;
276     long retval;
277     DWORD datalen;
278 
279     retval = RegQueryValueEx(handle, valuename, 0, &type, NULL, &datalen);
280     if (retval == ERROR_SUCCESS
281 	&& (type == REG_SZ || type == REG_EXPAND_SZ))
282     {
283 	dTHX;
284 	if (!*svp)
285 	    *svp = sv_2mortal(newSVpvs(""));
286 	SvGROW(*svp, datalen);
287 	retval = RegQueryValueEx(handle, valuename, 0, NULL,
288 				 (PBYTE)SvPVX(*svp), &datalen);
289 	if (retval == ERROR_SUCCESS) {
290 	    str = SvPVX(*svp);
291 	    SvCUR_set(*svp,datalen-1);
292 	}
293     }
294     return str;
295 }
296 
297 /* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
298 static char*
299 get_regstr(const char *valuename, SV **svp)
300 {
301     char *str;
302     if (HKCU_Perl_hnd) {
303 	str = get_regstr_from(HKCU_Perl_hnd, valuename, svp);
304 	if (!str)
305 	    goto try_HKLM;
306     }
307     else {
308 	try_HKLM:
309 	if (HKLM_Perl_hnd)
310 	    str = get_regstr_from(HKLM_Perl_hnd, valuename, svp);
311 	else
312 	    str = NULL;
313     }
314     return str;
315 }
316 #endif /* ifndef WIN32_NO_REGISTRY */
317 
318 /* *prev_pathp (if non-NULL) is expected to be POK (valid allocated SvPVX(sv)) */
319 static char *
320 get_emd_part(SV **prev_pathp, STRLEN *const len, char *trailing_path, ...)
321 {
322     char base[10];
323     va_list ap;
324     char mod_name[MAX_PATH+1];
325     char *ptr;
326     char *optr;
327     char *strip;
328     STRLEN baselen;
329 
330     va_start(ap, trailing_path);
331     strip = va_arg(ap, char *);
332 
333     sprintf(base, "%d.%d", (int)PERL_REVISION, (int)PERL_VERSION);
334     baselen = strlen(base);
335 
336     if (!*w32_module_name) {
337 	set_w32_module_name();
338     }
339     strcpy(mod_name, w32_module_name);
340     ptr = strrchr(mod_name, '/');
341     while (ptr && strip) {
342         /* look for directories to skip back */
343 	optr = ptr;
344 	*ptr = '\0';
345 	ptr = strrchr(mod_name, '/');
346 	/* avoid stripping component if there is no slash,
347 	 * or it doesn't match ... */
348 	if (!ptr || stricmp(ptr+1, strip) != 0) {
349 	    /* ... but not if component matches m|5\.$patchlevel.*| */
350 	    if (!ptr || !(*strip == '5' && *(ptr+1) == '5'
351 			  && strnEQ(strip, base, baselen)
352 			  && strnEQ(ptr+1, base, baselen)))
353 	    {
354 		*optr = '/';
355 		ptr = optr;
356 	    }
357 	}
358 	strip = va_arg(ap, char *);
359     }
360     if (!ptr) {
361 	ptr = mod_name;
362 	*ptr++ = '.';
363 	*ptr = '/';
364     }
365     va_end(ap);
366     strcpy(++ptr, trailing_path);
367 
368     /* only add directory if it exists */
369     if (GetFileAttributes(mod_name) != (DWORD) -1) {
370 	/* directory exists */
371 	dTHX;
372 	if (!*prev_pathp)
373 	    *prev_pathp = sv_2mortal(newSVpvs(""));
374 	else if (SvPVX(*prev_pathp))
375 	    sv_catpvs(*prev_pathp, ";");
376 	sv_catpv(*prev_pathp, mod_name);
377 	if(len)
378 	    *len = SvCUR(*prev_pathp);
379 	return SvPVX(*prev_pathp);
380     }
381 
382     return NULL;
383 }
384 
385 EXTERN_C char *
386 win32_get_privlib(WIN32_NO_REGISTRY_M_(const char *pl) STRLEN *const len)
387 {
388     char *stdlib = "lib";
389     SV *sv = NULL;
390 #ifndef WIN32_NO_REGISTRY
391     char buffer[MAX_PATH+1];
392 
393     /* $stdlib = $HKCU{"lib-$]"} || $HKLM{"lib-$]"} || $HKCU{"lib"} || $HKLM{"lib"} || "";  */
394     sprintf(buffer, "%s-%s", stdlib, pl);
395     if (!get_regstr(buffer, &sv))
396 	(void)get_regstr(stdlib, &sv);
397 #endif
398 
399     /* $stdlib .= ";$EMD/../../lib" */
400     return get_emd_part(&sv, len, stdlib, ARCHNAME, "bin", NULL);
401 }
402 
403 static char *
404 win32_get_xlib(const char *pl, WIN32_NO_REGISTRY_M_(const char *xlib)
405 	       const char *libname, STRLEN *const len)
406 {
407 #ifndef WIN32_NO_REGISTRY
408     char regstr[40];
409 #endif
410     char pathstr[MAX_PATH+1];
411     SV *sv1 = NULL;
412     SV *sv2 = NULL;
413 
414 #ifndef WIN32_NO_REGISTRY
415     /* $HKCU{"$xlib-$]"} || $HKLM{"$xlib-$]"} . ---; */
416     sprintf(regstr, "%s-%s", xlib, pl);
417     (void)get_regstr(regstr, &sv1);
418 #endif
419 
420     /* $xlib .=
421      * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/$]/lib";  */
422     sprintf(pathstr, "%s/%s/lib", libname, pl);
423     (void)get_emd_part(&sv1, NULL, pathstr, ARCHNAME, "bin", pl, NULL);
424 
425 #ifndef WIN32_NO_REGISTRY
426     /* $HKCU{$xlib} || $HKLM{$xlib} . ---; */
427     (void)get_regstr(xlib, &sv2);
428 #endif
429 
430     /* $xlib .=
431      * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/lib";  */
432     sprintf(pathstr, "%s/lib", libname);
433     (void)get_emd_part(&sv2, NULL, pathstr, ARCHNAME, "bin", pl, NULL);
434 
435     if (!sv1 && !sv2)
436 	return NULL;
437     if (!sv1) {
438 	sv1 = sv2;
439     } else if (sv2) {
440         dTHX;
441 	sv_catpvs(sv1, ";");
442 	sv_catsv(sv1, sv2);
443     }
444 
445     if (len)
446 	*len = SvCUR(sv1);
447     return SvPVX(sv1);
448 }
449 
450 EXTERN_C char *
451 win32_get_sitelib(const char *pl, STRLEN *const len)
452 {
453     return win32_get_xlib(pl, WIN32_NO_REGISTRY_M_("sitelib") "site", len);
454 }
455 
456 #ifndef PERL_VENDORLIB_NAME
457 #  define PERL_VENDORLIB_NAME	"vendor"
458 #endif
459 
460 EXTERN_C char *
461 win32_get_vendorlib(const char *pl, STRLEN *const len)
462 {
463     return win32_get_xlib(pl, WIN32_NO_REGISTRY_M_("vendorlib") PERL_VENDORLIB_NAME, len);
464 }
465 
466 static BOOL
467 has_shell_metachars(const char *ptr)
468 {
469     int inquote = 0;
470     char quote = '\0';
471 
472     /*
473      * Scan string looking for redirection (< or >) or pipe
474      * characters (|) that are not in a quoted string.
475      * Shell variable interpolation (%VAR%) can also happen inside strings.
476      */
477     while (*ptr) {
478 	switch(*ptr) {
479 	case '%':
480 	    return TRUE;
481 	case '\'':
482 	case '\"':
483 	    if (inquote) {
484 		if (quote == *ptr) {
485 		    inquote = 0;
486 		    quote = '\0';
487 		}
488 	    }
489 	    else {
490 		quote = *ptr;
491 		inquote++;
492 	    }
493 	    break;
494 	case '>':
495 	case '<':
496 	case '|':
497 	    if (!inquote)
498 		return TRUE;
499 	default:
500 	    break;
501 	}
502 	++ptr;
503     }
504     return FALSE;
505 }
506 
507 #if !defined(PERL_IMPLICIT_SYS)
508 /* since the current process environment is being updated in util.c
509  * the library functions will get the correct environment
510  */
511 PerlIO *
512 Perl_my_popen(pTHX_ const char *cmd, const char *mode)
513 {
514     PERL_FLUSHALL_FOR_CHILD;
515     return win32_popen(cmd, mode);
516 }
517 
518 long
519 Perl_my_pclose(pTHX_ PerlIO *fp)
520 {
521     return win32_pclose(fp);
522 }
523 #endif
524 
525 DllExport unsigned long
526 win32_os_id(void)
527 {
528     return (unsigned long)g_osver.dwPlatformId;
529 }
530 
531 DllExport int
532 win32_getpid(void)
533 {
534 #ifdef USE_ITHREADS
535     dTHX;
536     if (w32_pseudo_id)
537 	return -((int)w32_pseudo_id);
538 #endif
539     return _getpid();
540 }
541 
542 /* Tokenize a string.  Words are null-separated, and the list
543  * ends with a doubled null.  Any character (except null and
544  * including backslash) may be escaped by preceding it with a
545  * backslash (the backslash will be stripped).
546  * Returns number of words in result buffer.
547  */
548 static long
549 tokenize(const char *str, char **dest, char ***destv)
550 {
551     char *retstart = NULL;
552     char **retvstart = 0;
553     int items = -1;
554     if (str) {
555 	int slen = strlen(str);
556 	char *ret;
557 	char **retv;
558 	Newx(ret, slen+2, char);
559 	Newx(retv, (slen+3)/2, char*);
560 
561 	retstart = ret;
562 	retvstart = retv;
563 	*retv = ret;
564 	items = 0;
565 	while (*str) {
566 	    *ret = *str++;
567 	    if (*ret == '\\' && *str)
568 		*ret = *str++;
569 	    else if (*ret == ' ') {
570 		while (*str == ' ')
571 		    str++;
572 		if (ret == retstart)
573 		    ret--;
574 		else {
575 		    *ret = '\0';
576 		    ++items;
577 		    if (*str)
578 			*++retv = ret+1;
579 		}
580 	    }
581 	    else if (!*str)
582 		++items;
583 	    ret++;
584 	}
585 	retvstart[items] = NULL;
586 	*ret++ = '\0';
587 	*ret = '\0';
588     }
589     *dest = retstart;
590     *destv = retvstart;
591     return items;
592 }
593 
594 static void
595 get_shell(void)
596 {
597     dTHX;
598     if (!w32_perlshell_tokens) {
599 	/* we don't use COMSPEC here for two reasons:
600 	 *  1. the same reason perl on UNIX doesn't use SHELL--rampant and
601 	 *     uncontrolled unportability of the ensuing scripts.
602 	 *  2. PERL5SHELL could be set to a shell that may not be fit for
603 	 *     interactive use (which is what most programs look in COMSPEC
604 	 *     for).
605 	 */
606 	const char* defaultshell = "cmd.exe /x/d/c";
607 	const char *usershell = PerlEnv_getenv("PERL5SHELL");
608 	w32_perlshell_items = tokenize(usershell ? usershell : defaultshell,
609 				       &w32_perlshell_tokens,
610 				       &w32_perlshell_vec);
611     }
612 }
613 
614 int
615 Perl_do_aspawn(pTHX_ SV *really, SV **mark, SV **sp)
616 {
617     char **argv;
618     char *str;
619     int status;
620     int flag = P_WAIT;
621     int index = 0;
622     int eno;
623 
624     PERL_ARGS_ASSERT_DO_ASPAWN;
625 
626     if (sp <= mark)
627 	return -1;
628 
629     get_shell();
630     Newx(argv, (sp - mark) + w32_perlshell_items + 2, char*);
631 
632     if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
633 	++mark;
634 	flag = SvIVx(*mark);
635     }
636 
637     while (++mark <= sp) {
638 	if (*mark && (str = SvPV_nolen(*mark)))
639 	    argv[index++] = str;
640 	else
641 	    argv[index++] = "";
642     }
643     argv[index++] = 0;
644 
645     status = win32_spawnvp(flag,
646 			   (const char*)(really ? SvPV_nolen(really) : argv[0]),
647 			   (const char* const*)argv);
648 
649     if (status < 0 && (eno = errno, (eno == ENOEXEC || eno == ENOENT))) {
650 	/* possible shell-builtin, invoke with shell */
651 	int sh_items;
652 	sh_items = w32_perlshell_items;
653 	while (--index >= 0)
654 	    argv[index+sh_items] = argv[index];
655 	while (--sh_items >= 0)
656 	    argv[sh_items] = w32_perlshell_vec[sh_items];
657 
658 	status = win32_spawnvp(flag,
659 			       (const char*)(really ? SvPV_nolen(really) : argv[0]),
660 			       (const char* const*)argv);
661     }
662 
663     if (flag == P_NOWAIT) {
664 	PL_statusvalue = -1;	/* >16bits hint for pp_system() */
665     }
666     else {
667 	if (status < 0) {
668 	    if (ckWARN(WARN_EXEC))
669 		Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't spawn \"%s\": %s", argv[0], strerror(errno));
670 	    status = 255 * 256;
671 	}
672 	else
673 	    status *= 256;
674 	PL_statusvalue = status;
675     }
676     Safefree(argv);
677     return (status);
678 }
679 
680 /* returns pointer to the next unquoted space or the end of the string */
681 static char*
682 find_next_space(const char *s)
683 {
684     bool in_quotes = FALSE;
685     while (*s) {
686 	/* ignore doubled backslashes, or backslash+quote */
687 	if (*s == '\\' && (s[1] == '\\' || s[1] == '"')) {
688 	    s += 2;
689 	}
690 	/* keep track of when we're within quotes */
691 	else if (*s == '"') {
692 	    s++;
693 	    in_quotes = !in_quotes;
694 	}
695 	/* break it up only at spaces that aren't in quotes */
696 	else if (!in_quotes && isSPACE(*s))
697 	    return (char*)s;
698 	else
699 	    s++;
700     }
701     return (char*)s;
702 }
703 
704 static int
705 do_spawn2(pTHX_ const char *cmd, int exectype) {
706     return do_spawn2_handles(aTHX_ cmd, exectype, NULL);
707 }
708 
709 static int
710 do_spawn2_handles(pTHX_ const char *cmd, int exectype, const int *handles)
711 {
712     char **a;
713     char *s;
714     char **argv;
715     int status = -1;
716     BOOL needToTry = TRUE;
717     char *cmd2;
718 
719     /* Save an extra exec if possible. See if there are shell
720      * metacharacters in it */
721     if (!has_shell_metachars(cmd)) {
722 	Newx(argv, strlen(cmd) / 2 + 2, char*);
723 	Newx(cmd2, strlen(cmd) + 1, char);
724 	strcpy(cmd2, cmd);
725 	a = argv;
726 	for (s = cmd2; *s;) {
727 	    while (*s && isSPACE(*s))
728 		s++;
729 	    if (*s)
730 		*(a++) = s;
731 	    s = find_next_space(s);
732 	    if (*s)
733 		*s++ = '\0';
734 	}
735 	*a = NULL;
736 	if (argv[0]) {
737 	    switch (exectype) {
738 	    case EXECF_SPAWN:
739 		status = win32_spawnvp(P_WAIT, argv[0],
740 				       (const char* const*)argv);
741 		break;
742 	    case EXECF_SPAWN_NOWAIT:
743 		status = do_spawnvp_handles(P_NOWAIT, argv[0],
744 					    (const char* const*)argv, handles);
745 		break;
746 	    case EXECF_EXEC:
747 		status = win32_execvp(argv[0], (const char* const*)argv);
748 		break;
749 	    }
750 	    if (status != -1 || errno == 0)
751 		needToTry = FALSE;
752 	}
753 	Safefree(argv);
754 	Safefree(cmd2);
755     }
756     if (needToTry) {
757 	char **argv;
758 	int i = -1;
759 	get_shell();
760 	Newx(argv, w32_perlshell_items + 2, char*);
761 	while (++i < w32_perlshell_items)
762 	    argv[i] = w32_perlshell_vec[i];
763 	argv[i++] = (char *)cmd;
764 	argv[i] = NULL;
765 	switch (exectype) {
766 	case EXECF_SPAWN:
767 	    status = win32_spawnvp(P_WAIT, argv[0],
768 				   (const char* const*)argv);
769 	    break;
770 	case EXECF_SPAWN_NOWAIT:
771 	    status = do_spawnvp_handles(P_NOWAIT, argv[0],
772 					(const char* const*)argv, handles);
773 	    break;
774 	case EXECF_EXEC:
775 	    status = win32_execvp(argv[0], (const char* const*)argv);
776 	    break;
777 	}
778 	cmd = argv[0];
779 	Safefree(argv);
780     }
781     if (exectype == EXECF_SPAWN_NOWAIT) {
782 	PL_statusvalue = -1;	/* >16bits hint for pp_system() */
783     }
784     else {
785 	if (status < 0) {
786 	    if (ckWARN(WARN_EXEC))
787 		Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s \"%s\": %s",
788 		     (exectype == EXECF_EXEC ? "exec" : "spawn"),
789 		     cmd, strerror(errno));
790 	    status = 255 * 256;
791 	}
792 	else
793 	    status *= 256;
794 	PL_statusvalue = status;
795     }
796     return (status);
797 }
798 
799 int
800 Perl_do_spawn(pTHX_ char *cmd)
801 {
802     PERL_ARGS_ASSERT_DO_SPAWN;
803 
804     return do_spawn2(aTHX_ cmd, EXECF_SPAWN);
805 }
806 
807 int
808 Perl_do_spawn_nowait(pTHX_ char *cmd)
809 {
810     PERL_ARGS_ASSERT_DO_SPAWN_NOWAIT;
811 
812     return do_spawn2(aTHX_ cmd, EXECF_SPAWN_NOWAIT);
813 }
814 
815 bool
816 Perl_do_exec(pTHX_ const char *cmd)
817 {
818     PERL_ARGS_ASSERT_DO_EXEC;
819 
820     do_spawn2(aTHX_ cmd, EXECF_EXEC);
821     return FALSE;
822 }
823 
824 /* The idea here is to read all the directory names into a string table
825  * (separated by nulls) and when one of the other dir functions is called
826  * return the pointer to the current file name.
827  */
828 DllExport DIR *
829 win32_opendir(const char *filename)
830 {
831     dTHXa(NULL);
832     DIR			*dirp;
833     long		len;
834     long		idx;
835     char		scanname[MAX_PATH+3];
836     WCHAR		wscanname[sizeof(scanname)];
837     WIN32_FIND_DATAW	wFindData;
838     char		buffer[MAX_PATH*2];
839     BOOL		use_default;
840 
841     len = strlen(filename);
842     if (len == 0) {
843 	errno = ENOENT;
844 	return NULL;
845     }
846     if (len > MAX_PATH) {
847 	errno = ENAMETOOLONG;
848 	return NULL;
849     }
850 
851     /* Get us a DIR structure */
852     Newxz(dirp, 1, DIR);
853 
854     /* Create the search pattern */
855     strcpy(scanname, filename);
856 
857     /* bare drive name means look in cwd for drive */
858     if (len == 2 && isALPHA(scanname[0]) && scanname[1] == ':') {
859 	scanname[len++] = '.';
860 	scanname[len++] = '/';
861     }
862     else if (scanname[len-1] != '/' && scanname[len-1] != '\\') {
863 	scanname[len++] = '/';
864     }
865     scanname[len++] = '*';
866     scanname[len] = '\0';
867 
868     /* do the FindFirstFile call */
869     MultiByteToWideChar(CP_ACP, 0, scanname, -1, wscanname, sizeof(wscanname)/sizeof(WCHAR));
870     aTHXa(PERL_GET_THX);
871     dirp->handle = FindFirstFileW(PerlDir_mapW(wscanname), &wFindData);
872 
873     if (dirp->handle == INVALID_HANDLE_VALUE) {
874 	DWORD err = GetLastError();
875 	/* FindFirstFile() fails on empty drives! */
876 	switch (err) {
877 	case ERROR_FILE_NOT_FOUND:
878 	    return dirp;
879 	case ERROR_NO_MORE_FILES:
880 	case ERROR_PATH_NOT_FOUND:
881 	    errno = ENOENT;
882 	    break;
883 	case ERROR_NOT_ENOUGH_MEMORY:
884 	    errno = ENOMEM;
885 	    break;
886 	default:
887 	    errno = EINVAL;
888 	    break;
889 	}
890 	Safefree(dirp);
891 	return NULL;
892     }
893 
894     use_default = FALSE;
895     WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
896                         wFindData.cFileName, -1,
897                         buffer, sizeof(buffer), NULL, &use_default);
898     if (use_default && *wFindData.cAlternateFileName) {
899         WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
900                             wFindData.cAlternateFileName, -1,
901                             buffer, sizeof(buffer), NULL, NULL);
902     }
903 
904     /* now allocate the first part of the string table for
905      * the filenames that we find.
906      */
907     idx = strlen(buffer)+1;
908     if (idx < 256)
909 	dirp->size = 256;
910     else
911 	dirp->size = idx;
912     Newx(dirp->start, dirp->size, char);
913     strcpy(dirp->start, buffer);
914     dirp->nfiles++;
915     dirp->end = dirp->curr = dirp->start;
916     dirp->end += idx;
917     return dirp;
918 }
919 
920 
921 /* Readdir just returns the current string pointer and bumps the
922  * string pointer to the nDllExport entry.
923  */
924 DllExport struct direct *
925 win32_readdir(DIR *dirp)
926 {
927     long         len;
928 
929     if (dirp->curr) {
930 	/* first set up the structure to return */
931 	len = strlen(dirp->curr);
932 	strcpy(dirp->dirstr.d_name, dirp->curr);
933 	dirp->dirstr.d_namlen = len;
934 
935 	/* Fake an inode */
936 	dirp->dirstr.d_ino = dirp->curr - dirp->start;
937 
938 	/* Now set up for the next call to readdir */
939 	dirp->curr += len + 1;
940 	if (dirp->curr >= dirp->end) {
941 	    BOOL res;
942 	    char buffer[MAX_PATH*2];
943 
944             if (dirp->handle == INVALID_HANDLE_VALUE) {
945                 res = 0;
946             }
947 	    /* finding the next file that matches the wildcard
948 	     * (which should be all of them in this directory!).
949 	     */
950 	    else {
951                 WIN32_FIND_DATAW wFindData;
952 		res = FindNextFileW(dirp->handle, &wFindData);
953 		if (res) {
954                     BOOL use_default = FALSE;
955                     WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
956                                         wFindData.cFileName, -1,
957                                         buffer, sizeof(buffer), NULL, &use_default);
958                     if (use_default && *wFindData.cAlternateFileName) {
959                         WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
960                                             wFindData.cAlternateFileName, -1,
961                                             buffer, sizeof(buffer), NULL, NULL);
962                     }
963                 }
964             }
965 	    if (res) {
966 		long endpos = dirp->end - dirp->start;
967 		long newsize = endpos + strlen(buffer) + 1;
968 		/* bump the string table size by enough for the
969 		 * new name and its null terminator */
970 		while (newsize > dirp->size) {
971 		    long curpos = dirp->curr - dirp->start;
972 		    Renew(dirp->start, dirp->size * 2, char);
973 		    dirp->size *= 2;
974 		    dirp->curr = dirp->start + curpos;
975 		}
976 		strcpy(dirp->start + endpos, buffer);
977 		dirp->end = dirp->start + newsize;
978 		dirp->nfiles++;
979 	    }
980 	    else {
981 		dirp->curr = NULL;
982                 if (dirp->handle != INVALID_HANDLE_VALUE) {
983                     FindClose(dirp->handle);
984                     dirp->handle = INVALID_HANDLE_VALUE;
985                 }
986             }
987 	}
988 	return &(dirp->dirstr);
989     }
990     else
991 	return NULL;
992 }
993 
994 /* Telldir returns the current string pointer position */
995 DllExport long
996 win32_telldir(DIR *dirp)
997 {
998     return dirp->curr ? (dirp->curr - dirp->start) : -1;
999 }
1000 
1001 
1002 /* Seekdir moves the string pointer to a previously saved position
1003  * (returned by telldir).
1004  */
1005 DllExport void
1006 win32_seekdir(DIR *dirp, long loc)
1007 {
1008     dirp->curr = loc == -1 ? NULL : dirp->start + loc;
1009 }
1010 
1011 /* Rewinddir resets the string pointer to the start */
1012 DllExport void
1013 win32_rewinddir(DIR *dirp)
1014 {
1015     dirp->curr = dirp->start;
1016 }
1017 
1018 /* free the memory allocated by opendir */
1019 DllExport int
1020 win32_closedir(DIR *dirp)
1021 {
1022     if (dirp->handle != INVALID_HANDLE_VALUE)
1023 	FindClose(dirp->handle);
1024     Safefree(dirp->start);
1025     Safefree(dirp);
1026     return 1;
1027 }
1028 
1029 /* duplicate a open DIR* for interpreter cloning */
1030 DllExport DIR *
1031 win32_dirp_dup(DIR *const dirp, CLONE_PARAMS *const param)
1032 {
1033     dVAR;
1034     PerlInterpreter *const from = param->proto_perl;
1035     PerlInterpreter *const to   = (PerlInterpreter *)PERL_GET_THX;
1036 
1037     long pos;
1038     DIR *dup;
1039 
1040     /* switch back to original interpreter because win32_readdir()
1041      * might Renew(dirp->start).
1042      */
1043     if (from != to) {
1044         PERL_SET_THX(from);
1045     }
1046 
1047     /* mark current position; read all remaining entries into the
1048      * cache, and then restore to current position.
1049      */
1050     pos = win32_telldir(dirp);
1051     while (win32_readdir(dirp)) {
1052         /* read all entries into cache */
1053     }
1054     win32_seekdir(dirp, pos);
1055 
1056     /* switch back to new interpreter to allocate new DIR structure */
1057     if (from != to) {
1058         PERL_SET_THX(to);
1059     }
1060 
1061     Newx(dup, 1, DIR);
1062     memcpy(dup, dirp, sizeof(DIR));
1063 
1064     Newx(dup->start, dirp->size, char);
1065     memcpy(dup->start, dirp->start, dirp->size);
1066 
1067     dup->end = dup->start + (dirp->end - dirp->start);
1068     if (dirp->curr)
1069         dup->curr = dup->start + (dirp->curr - dirp->start);
1070 
1071     return dup;
1072 }
1073 
1074 /*
1075  * various stubs
1076  */
1077 
1078 
1079 /* Ownership
1080  *
1081  * Just pretend that everyone is a superuser. NT will let us know if
1082  * we don\'t really have permission to do something.
1083  */
1084 
1085 #define ROOT_UID    ((uid_t)0)
1086 #define ROOT_GID    ((gid_t)0)
1087 
1088 uid_t
1089 getuid(void)
1090 {
1091     return ROOT_UID;
1092 }
1093 
1094 uid_t
1095 geteuid(void)
1096 {
1097     return ROOT_UID;
1098 }
1099 
1100 gid_t
1101 getgid(void)
1102 {
1103     return ROOT_GID;
1104 }
1105 
1106 gid_t
1107 getegid(void)
1108 {
1109     return ROOT_GID;
1110 }
1111 
1112 int
1113 setuid(uid_t auid)
1114 {
1115     return (auid == ROOT_UID ? 0 : -1);
1116 }
1117 
1118 int
1119 setgid(gid_t agid)
1120 {
1121     return (agid == ROOT_GID ? 0 : -1);
1122 }
1123 
1124 EXTERN_C char *
1125 getlogin(void)
1126 {
1127     dTHX;
1128     char *buf = w32_getlogin_buffer;
1129     DWORD size = sizeof(w32_getlogin_buffer);
1130     if (GetUserName(buf,&size))
1131 	return buf;
1132     return (char*)NULL;
1133 }
1134 
1135 int
1136 chown(const char *path, uid_t owner, gid_t group)
1137 {
1138     /* XXX noop */
1139     return 0;
1140 }
1141 
1142 /*
1143  * XXX this needs strengthening  (for PerlIO)
1144  *   -- BKS, 11-11-200
1145 */
1146 #if !defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 4
1147 int mkstemp(const char *path)
1148 {
1149     dTHX;
1150     char buf[MAX_PATH+1];
1151     int i = 0, fd = -1;
1152 
1153 retry:
1154     if (i++ > 10) { /* give up */
1155 	errno = ENOENT;
1156 	return -1;
1157     }
1158     if (!GetTempFileNameA((LPCSTR)path, "plr", 1, buf)) {
1159 	errno = ENOENT;
1160 	return -1;
1161     }
1162     fd = PerlLIO_open3(buf, O_CREAT|O_RDWR|O_EXCL, 0600);
1163     if (fd == -1)
1164 	goto retry;
1165     return fd;
1166 }
1167 #endif
1168 
1169 static long
1170 find_pid(pTHX_ int pid)
1171 {
1172     long child = w32_num_children;
1173     while (--child >= 0) {
1174 	if ((int)w32_child_pids[child] == pid)
1175 	    return child;
1176     }
1177     return -1;
1178 }
1179 
1180 static void
1181 remove_dead_process(long child)
1182 {
1183     if (child >= 0) {
1184 	dTHX;
1185 	CloseHandle(w32_child_handles[child]);
1186 	Move(&w32_child_handles[child+1], &w32_child_handles[child],
1187 	     (w32_num_children-child-1), HANDLE);
1188 	Move(&w32_child_pids[child+1], &w32_child_pids[child],
1189 	     (w32_num_children-child-1), DWORD);
1190 	w32_num_children--;
1191     }
1192 }
1193 
1194 #ifdef USE_ITHREADS
1195 static long
1196 find_pseudo_pid(pTHX_ int pid)
1197 {
1198     long child = w32_num_pseudo_children;
1199     while (--child >= 0) {
1200 	if ((int)w32_pseudo_child_pids[child] == pid)
1201 	    return child;
1202     }
1203     return -1;
1204 }
1205 
1206 static void
1207 remove_dead_pseudo_process(long child)
1208 {
1209     if (child >= 0) {
1210 	dTHX;
1211 	CloseHandle(w32_pseudo_child_handles[child]);
1212 	Move(&w32_pseudo_child_handles[child+1], &w32_pseudo_child_handles[child],
1213 	     (w32_num_pseudo_children-child-1), HANDLE);
1214 	Move(&w32_pseudo_child_pids[child+1], &w32_pseudo_child_pids[child],
1215 	     (w32_num_pseudo_children-child-1), DWORD);
1216 	Move(&w32_pseudo_child_message_hwnds[child+1], &w32_pseudo_child_message_hwnds[child],
1217 	     (w32_num_pseudo_children-child-1), HWND);
1218 	Move(&w32_pseudo_child_sigterm[child+1], &w32_pseudo_child_sigterm[child],
1219 	     (w32_num_pseudo_children-child-1), char);
1220 	w32_num_pseudo_children--;
1221     }
1222 }
1223 
1224 void
1225 win32_wait_for_children(pTHX)
1226 {
1227     if (w32_pseudo_children && w32_num_pseudo_children) {
1228         long child = 0;
1229         long count = 0;
1230         HANDLE handles[MAXIMUM_WAIT_OBJECTS];
1231 
1232         for (child = 0; child < w32_num_pseudo_children; ++child) {
1233             if (!w32_pseudo_child_sigterm[child])
1234                 handles[count++] = w32_pseudo_child_handles[child];
1235         }
1236         /* XXX should use MsgWaitForMultipleObjects() to continue
1237          * XXX processing messages while we wait.
1238          */
1239         WaitForMultipleObjects(count, handles, TRUE, INFINITE);
1240 
1241         while (w32_num_pseudo_children)
1242             CloseHandle(w32_pseudo_child_handles[--w32_num_pseudo_children]);
1243     }
1244 }
1245 #endif
1246 
1247 static int
1248 terminate_process(DWORD pid, HANDLE process_handle, int sig)
1249 {
1250     switch(sig) {
1251     case 0:
1252         /* "Does process exist?" use of kill */
1253         return 1;
1254     case 2:
1255         if (GenerateConsoleCtrlEvent(CTRL_C_EVENT, pid))
1256             return 1;
1257         break;
1258     case SIGBREAK:
1259     case SIGTERM:
1260         if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pid))
1261             return 1;
1262         break;
1263     default: /* For now be backwards compatible with perl 5.6 */
1264     case 9:
1265         /* Note that we will only be able to kill processes owned by the
1266          * current process owner, even when we are running as an administrator.
1267          * To kill processes of other owners we would need to set the
1268          * 'SeDebugPrivilege' privilege before obtaining the process handle.
1269          */
1270         if (TerminateProcess(process_handle, sig))
1271             return 1;
1272         break;
1273     }
1274     return 0;
1275 }
1276 
1277 /* returns number of processes killed */
1278 static int
1279 my_killpg(int pid, int sig)
1280 {
1281     HANDLE process_handle;
1282     HANDLE snapshot_handle;
1283     int killed = 0;
1284 
1285     process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
1286     if (process_handle == NULL)
1287         return 0;
1288 
1289     killed += terminate_process(pid, process_handle, sig);
1290 
1291     snapshot_handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
1292     if (snapshot_handle != INVALID_HANDLE_VALUE) {
1293         PROCESSENTRY32 entry;
1294 
1295         entry.dwSize = sizeof(entry);
1296         if (Process32First(snapshot_handle, &entry)) {
1297             do {
1298                 if (entry.th32ParentProcessID == (DWORD)pid)
1299                     killed += my_killpg(entry.th32ProcessID, sig);
1300                 entry.dwSize = sizeof(entry);
1301             }
1302             while (Process32Next(snapshot_handle, &entry));
1303         }
1304         CloseHandle(snapshot_handle);
1305     }
1306     CloseHandle(process_handle);
1307     return killed;
1308 }
1309 
1310 /* returns number of processes killed */
1311 static int
1312 my_kill(int pid, int sig)
1313 {
1314     int retval = 0;
1315     HANDLE process_handle;
1316 
1317     if (sig < 0)
1318         return my_killpg(pid, -sig);
1319 
1320     process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
1321     /* OpenProcess() returns NULL on error, *not* INVALID_HANDLE_VALUE */
1322     if (process_handle != NULL) {
1323         retval = terminate_process(pid, process_handle, sig);
1324         CloseHandle(process_handle);
1325     }
1326     return retval;
1327 }
1328 
1329 #ifdef USE_ITHREADS
1330 /* Get a child pseudo-process HWND, with retrying and delaying/yielding.
1331  * The "tries" parameter is the number of retries to make, with a Sleep(1)
1332  * (waiting and yielding the time slot) between each try. Specifying 0 causes
1333  * only Sleep(0) (no waiting and potentially no yielding) to be used, so is not
1334  * recommended
1335  * Returns an hwnd != INVALID_HANDLE_VALUE (so be aware that NULL can be
1336  * returned) or croaks if the child pseudo-process doesn't schedule and deliver
1337  * a HWND in the time period allowed.
1338  */
1339 static HWND
1340 get_hwnd_delay(pTHX, long child, DWORD tries)
1341 {
1342     HWND hwnd = w32_pseudo_child_message_hwnds[child];
1343     if (hwnd != INVALID_HANDLE_VALUE) return hwnd;
1344 
1345     /* Pseudo-process has not yet properly initialized since hwnd isn't set.
1346      * Fast sleep: On some NT kernels/systems, a Sleep(0) won't deschedule a
1347      * thread 100% of the time since threads are attached to a CPU for NUMA and
1348      * caching reasons, and the child thread was attached to a different CPU
1349      * therefore there is no workload on that CPU and Sleep(0) returns control
1350      * without yielding the time slot.
1351      * https://rt.perl.org/rt3/Ticket/Display.html?id=88840
1352      */
1353     Sleep(0);
1354     win32_async_check(aTHX);
1355     hwnd = w32_pseudo_child_message_hwnds[child];
1356     if (hwnd != INVALID_HANDLE_VALUE) return hwnd;
1357 
1358     {
1359 	unsigned int count = 0;
1360 	/* No Sleep(1) if tries==0, just fail instead if we get this far. */
1361 	while (count++ < tries) {
1362 	    Sleep(1);
1363 	    win32_async_check(aTHX);
1364 	    hwnd = w32_pseudo_child_message_hwnds[child];
1365 	    if (hwnd != INVALID_HANDLE_VALUE) return hwnd;
1366 	}
1367     }
1368 
1369     Perl_croak(aTHX_ "panic: child pseudo-process was never scheduled");
1370 }
1371 #endif
1372 
1373 DllExport int
1374 win32_kill(int pid, int sig)
1375 {
1376     dTHX;
1377     long child;
1378 #ifdef USE_ITHREADS
1379     if (pid < 0) {
1380 	/* it is a pseudo-forked child */
1381 	child = find_pseudo_pid(aTHX_ -pid);
1382 	if (child >= 0) {
1383 	    HANDLE hProcess = w32_pseudo_child_handles[child];
1384 	    switch (sig) {
1385 		case 0:
1386 		    /* "Does process exist?" use of kill */
1387 		    return 0;
1388 
1389 		case 9: {
1390 		    /* kill -9 style un-graceful exit */
1391 		    /* Do a wait to make sure child starts and isn't in DLL
1392 		     * Loader Lock */
1393 		    HWND hwnd = get_hwnd_delay(aTHX, child, 5);
1394 		    if (TerminateThread(hProcess, sig)) {
1395 			/* Allow the scheduler to finish cleaning up the other
1396 			 * thread.
1397 			 * Otherwise, if we ExitProcess() before another context
1398 			 * switch happens we will end up with a process exit
1399 			 * code of "sig" instead of our own exit status.
1400 			 * https://rt.cpan.org/Ticket/Display.html?id=66016#txn-908976
1401 			 */
1402 			Sleep(0);
1403 			remove_dead_pseudo_process(child);
1404 			return 0;
1405 		    }
1406 		    break;
1407 		}
1408 
1409 		default: {
1410 		    HWND hwnd = get_hwnd_delay(aTHX, child, 5);
1411 		    /* We fake signals to pseudo-processes using Win32
1412 		     * message queue. */
1413 		    if ((hwnd != NULL && PostMessage(hwnd, WM_USER_KILL, sig, 0)) ||
1414 			PostThreadMessage(-pid, WM_USER_KILL, sig, 0))
1415 		    {
1416 			/* Don't wait for child process to terminate after we send a
1417 			 * SIGTERM because the child may be blocked in a system call
1418 			 * and never receive the signal.
1419 			 */
1420 			if (sig == SIGTERM) {
1421 			    Sleep(0);
1422 			    w32_pseudo_child_sigterm[child] = 1;
1423 			}
1424 			/* It might be us ... */
1425 			PERL_ASYNC_CHECK();
1426 			return 0;
1427 		    }
1428 		    break;
1429 		}
1430 	    } /* switch */
1431 	}
1432     }
1433     else
1434 #endif
1435     {
1436 	child = find_pid(aTHX_ pid);
1437 	if (child >= 0) {
1438             if (my_kill(pid, sig)) {
1439                 DWORD exitcode = 0;
1440                 if (GetExitCodeProcess(w32_child_handles[child], &exitcode) &&
1441                     exitcode != STILL_ACTIVE)
1442                 {
1443                     remove_dead_process(child);
1444                 }
1445                 return 0;
1446             }
1447 	}
1448 	else {
1449             if (my_kill(pid, sig))
1450                 return 0;
1451 	}
1452     }
1453     errno = EINVAL;
1454     return -1;
1455 }
1456 
1457 DllExport int
1458 win32_stat(const char *path, Stat_t *sbuf)
1459 {
1460     char	buffer[MAX_PATH+1];
1461     int		l = strlen(path);
1462     dTHX;
1463     int		res;
1464     int         nlink = 1;
1465     BOOL        expect_dir = FALSE;
1466 
1467     if (l > 1) {
1468 	switch(path[l - 1]) {
1469 	/* FindFirstFile() and stat() are buggy with a trailing
1470 	 * slashes, except for the root directory of a drive */
1471 	case '\\':
1472         case '/':
1473 	    if (l > sizeof(buffer)) {
1474 		errno = ENAMETOOLONG;
1475 		return -1;
1476 	    }
1477             --l;
1478             strncpy(buffer, path, l);
1479             /* remove additional trailing slashes */
1480             while (l > 1 && (buffer[l-1] == '/' || buffer[l-1] == '\\'))
1481                 --l;
1482             /* add back slash if we otherwise end up with just a drive letter */
1483             if (l == 2 && isALPHA(buffer[0]) && buffer[1] == ':')
1484                 buffer[l++] = '\\';
1485             buffer[l] = '\0';
1486             path = buffer;
1487             expect_dir = TRUE;
1488 	    break;
1489 
1490 	/* FindFirstFile() is buggy with "x:", so add a dot :-( */
1491 	case ':':
1492 	    if (l == 2 && isALPHA(path[0])) {
1493 		buffer[0] = path[0];
1494 		buffer[1] = ':';
1495 		buffer[2] = '.';
1496 		buffer[3] = '\0';
1497 		l = 3;
1498 		path = buffer;
1499 	    }
1500 	    break;
1501 	}
1502     }
1503 
1504     path = PerlDir_mapA(path);
1505     l = strlen(path);
1506 
1507     if (!w32_sloppystat) {
1508         /* We must open & close the file once; otherwise file attribute changes  */
1509         /* might not yet have propagated to "other" hard links of the same file. */
1510         /* This also gives us an opportunity to determine the number of links.   */
1511         HANDLE handle = CreateFileA(path, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
1512         if (handle != INVALID_HANDLE_VALUE) {
1513             BY_HANDLE_FILE_INFORMATION bhi;
1514             if (GetFileInformationByHandle(handle, &bhi))
1515                 nlink = bhi.nNumberOfLinks;
1516             CloseHandle(handle);
1517         }
1518 	else {
1519 	    DWORD err = GetLastError();
1520 	    /* very common case, skip CRT stat and its also failing syscalls */
1521 	    if(err == ERROR_FILE_NOT_FOUND) {
1522 		errno = ENOENT;
1523 		return -1;
1524 	    }
1525 	}
1526     }
1527 
1528     /* path will be mapped correctly above */
1529 #if defined(WIN64) || defined(USE_LARGE_FILES)
1530     res = _stati64(path, sbuf);
1531 #else
1532     res = stat(path, sbuf);
1533 #endif
1534     sbuf->st_nlink = nlink;
1535 
1536     if (res < 0) {
1537 	/* CRT is buggy on sharenames, so make sure it really isn't.
1538 	 * XXX using GetFileAttributesEx() will enable us to set
1539 	 * sbuf->st_*time (but note that's not available on the
1540 	 * Windows of 1995) */
1541 	DWORD r = GetFileAttributesA(path);
1542 	if (r != 0xffffffff && (r & FILE_ATTRIBUTE_DIRECTORY)) {
1543 	    /* sbuf may still contain old garbage since stat() failed */
1544 	    Zero(sbuf, 1, Stat_t);
1545 	    sbuf->st_mode = S_IFDIR | S_IREAD;
1546 	    errno = 0;
1547 	    if (!(r & FILE_ATTRIBUTE_READONLY))
1548 		sbuf->st_mode |= S_IWRITE | S_IEXEC;
1549 	    return 0;
1550 	}
1551     }
1552     else {
1553 	if (l == 3 && isALPHA(path[0]) && path[1] == ':'
1554 	    && (path[2] == '\\' || path[2] == '/'))
1555 	{
1556 	    /* The drive can be inaccessible, some _stat()s are buggy */
1557 	    if (!GetVolumeInformationA(path,NULL,0,NULL,NULL,NULL,NULL,0)) {
1558 		errno = ENOENT;
1559 		return -1;
1560 	    }
1561 	}
1562         if (expect_dir && !S_ISDIR(sbuf->st_mode)) {
1563             errno = ENOTDIR;
1564             return -1;
1565         }
1566 	if (S_ISDIR(sbuf->st_mode)) {
1567 	    /* Ensure the "write" bit is switched off in the mode for
1568 	     * directories with the read-only attribute set. Some compilers
1569 	     * switch it on for directories, which is technically correct
1570 	     * (directories are indeed always writable unless denied by DACLs),
1571 	     * but we want stat() and -w to reflect the state of the read-only
1572 	     * attribute for symmetry with chmod(). */
1573 	    DWORD r = GetFileAttributesA(path);
1574 	    if (r != 0xffffffff && (r & FILE_ATTRIBUTE_READONLY)) {
1575 		sbuf->st_mode &= ~S_IWRITE;
1576 	    }
1577 	}
1578     }
1579     return res;
1580 }
1581 
1582 #define isSLASH(c) ((c) == '/' || (c) == '\\')
1583 #define SKIP_SLASHES(s) \
1584     STMT_START {				\
1585 	while (*(s) && isSLASH(*(s)))		\
1586 	    ++(s);				\
1587     } STMT_END
1588 #define COPY_NONSLASHES(d,s) \
1589     STMT_START {				\
1590 	while (*(s) && !isSLASH(*(s)))		\
1591 	    *(d)++ = *(s)++;			\
1592     } STMT_END
1593 
1594 /* Find the longname of a given path.  path is destructively modified.
1595  * It should have space for at least MAX_PATH characters. */
1596 DllExport char *
1597 win32_longpath(char *path)
1598 {
1599     WIN32_FIND_DATA fdata;
1600     HANDLE fhand;
1601     char tmpbuf[MAX_PATH+1];
1602     char *tmpstart = tmpbuf;
1603     char *start = path;
1604     char sep;
1605     if (!path)
1606 	return NULL;
1607 
1608     /* drive prefix */
1609     if (isALPHA(path[0]) && path[1] == ':') {
1610 	start = path + 2;
1611 	*tmpstart++ = path[0];
1612 	*tmpstart++ = ':';
1613     }
1614     /* UNC prefix */
1615     else if (isSLASH(path[0]) && isSLASH(path[1])) {
1616 	start = path + 2;
1617 	*tmpstart++ = path[0];
1618 	*tmpstart++ = path[1];
1619 	SKIP_SLASHES(start);
1620 	COPY_NONSLASHES(tmpstart,start);	/* copy machine name */
1621 	if (*start) {
1622 	    *tmpstart++ = *start++;
1623 	    SKIP_SLASHES(start);
1624 	    COPY_NONSLASHES(tmpstart,start);	/* copy share name */
1625 	}
1626     }
1627     *tmpstart = '\0';
1628     while (*start) {
1629 	/* copy initial slash, if any */
1630 	if (isSLASH(*start)) {
1631 	    *tmpstart++ = *start++;
1632 	    *tmpstart = '\0';
1633 	    SKIP_SLASHES(start);
1634 	}
1635 
1636 	/* FindFirstFile() expands "." and "..", so we need to pass
1637 	 * those through unmolested */
1638 	if (*start == '.'
1639 	    && (!start[1] || isSLASH(start[1])
1640 		|| (start[1] == '.' && (!start[2] || isSLASH(start[2])))))
1641 	{
1642 	    COPY_NONSLASHES(tmpstart,start);	/* copy "." or ".." */
1643 	    *tmpstart = '\0';
1644 	    continue;
1645 	}
1646 
1647 	/* if this is the end, bust outta here */
1648 	if (!*start)
1649 	    break;
1650 
1651 	/* now we're at a non-slash; walk up to next slash */
1652 	while (*start && !isSLASH(*start))
1653 	    ++start;
1654 
1655 	/* stop and find full name of component */
1656 	sep = *start;
1657 	*start = '\0';
1658 	fhand = FindFirstFile(path,&fdata);
1659 	*start = sep;
1660 	if (fhand != INVALID_HANDLE_VALUE) {
1661 	    STRLEN len = strlen(fdata.cFileName);
1662 	    if ((STRLEN)(tmpbuf + sizeof(tmpbuf) - tmpstart) > len) {
1663 		strcpy(tmpstart, fdata.cFileName);
1664 		tmpstart += len;
1665 		FindClose(fhand);
1666 	    }
1667 	    else {
1668 		FindClose(fhand);
1669 		errno = ERANGE;
1670 		return NULL;
1671 	    }
1672 	}
1673 	else {
1674 	    /* failed a step, just return without side effects */
1675 	    /*PerlIO_printf(Perl_debug_log, "Failed to find %s\n", path);*/
1676 	    errno = EINVAL;
1677 	    return NULL;
1678 	}
1679     }
1680     strcpy(path,tmpbuf);
1681     return path;
1682 }
1683 
1684 static void
1685 out_of_memory(void)
1686 {
1687     dVAR;
1688 
1689     if (PL_curinterp)
1690 	croak_no_mem();
1691     exit(1);
1692 }
1693 
1694 void
1695 win32_croak_not_implemented(const char * fname)
1696 {
1697     PERL_ARGS_ASSERT_WIN32_CROAK_NOT_IMPLEMENTED;
1698 
1699     Perl_croak_nocontext("%s not implemented!\n", fname);
1700 }
1701 
1702 /* Converts a wide character (UTF-16) string to the Windows ANSI code page,
1703  * potentially using the system's default replacement character for any
1704  * unrepresentable characters. The caller must free() the returned string. */
1705 static char*
1706 wstr_to_str(const wchar_t* wstr)
1707 {
1708     BOOL used_default = FALSE;
1709     size_t wlen = wcslen(wstr) + 1;
1710     int len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wstr, wlen,
1711                                    NULL, 0, NULL, NULL);
1712     char* str = (char*)malloc(len);
1713     if (!str)
1714         out_of_memory();
1715     WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wstr, wlen,
1716                         str, len, NULL, &used_default);
1717     return str;
1718 }
1719 
1720 /* The win32_ansipath() function takes a Unicode filename and converts it
1721  * into the current Windows codepage. If some characters cannot be mapped,
1722  * then it will convert the short name instead.
1723  *
1724  * The buffer to the ansi pathname must be freed with win32_free() when it
1725  * it no longer needed.
1726  *
1727  * The argument to win32_ansipath() must exist before this function is
1728  * called; otherwise there is no way to determine the short path name.
1729  *
1730  * Ideas for future refinement:
1731  * - Only convert those segments of the path that are not in the current
1732  *   codepage, but leave the other segments in their long form.
1733  * - If the resulting name is longer than MAX_PATH, start converting
1734  *   additional path segments into short names until the full name
1735  *   is shorter than MAX_PATH.  Shorten the filename part last!
1736  */
1737 DllExport char *
1738 win32_ansipath(const WCHAR *widename)
1739 {
1740     char *name;
1741     BOOL use_default = FALSE;
1742     size_t widelen = wcslen(widename)+1;
1743     int len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, widename, widelen,
1744                                   NULL, 0, NULL, NULL);
1745     name = (char*)win32_malloc(len);
1746     if (!name)
1747         out_of_memory();
1748 
1749     WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, widename, widelen,
1750                         name, len, NULL, &use_default);
1751     if (use_default) {
1752         DWORD shortlen = GetShortPathNameW(widename, NULL, 0);
1753         if (shortlen) {
1754             WCHAR *shortname = (WCHAR*)win32_malloc(shortlen*sizeof(WCHAR));
1755             if (!shortname)
1756                 out_of_memory();
1757             shortlen = GetShortPathNameW(widename, shortname, shortlen)+1;
1758 
1759             len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, shortname, shortlen,
1760                                       NULL, 0, NULL, NULL);
1761             name = (char*)win32_realloc(name, len);
1762             if (!name)
1763                 out_of_memory();
1764             WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, shortname, shortlen,
1765                                 name, len, NULL, NULL);
1766             win32_free(shortname);
1767         }
1768     }
1769     return name;
1770 }
1771 
1772 /* the returned string must be freed with win32_freeenvironmentstrings which is
1773  * implemented as a macro
1774  * void win32_freeenvironmentstrings(void* block)
1775  */
1776 DllExport char *
1777 win32_getenvironmentstrings(void)
1778 {
1779     LPWSTR lpWStr, lpWTmp;
1780     LPSTR lpStr, lpTmp;
1781     DWORD env_len, wenvstrings_len = 0, aenvstrings_len = 0;
1782 
1783     /* Get the process environment strings */
1784     lpWTmp = lpWStr = (LPWSTR) GetEnvironmentStringsW();
1785     for (wenvstrings_len = 1; *lpWTmp != '\0'; lpWTmp += env_len + 1) {
1786         env_len = wcslen(lpWTmp);
1787         /* calculate the size of the environment strings */
1788         wenvstrings_len += env_len + 1;
1789     }
1790 
1791     /* Get the number of bytes required to store the ACP encoded string */
1792     aenvstrings_len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
1793                                           lpWStr, wenvstrings_len, NULL, 0, NULL, NULL);
1794     lpTmp = lpStr = (char *)win32_calloc(aenvstrings_len, sizeof(char));
1795     if(!lpTmp)
1796         out_of_memory();
1797 
1798     /* Convert the string from UTF-16 encoding to ACP encoding */
1799     WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, lpWStr, wenvstrings_len, lpStr,
1800                         aenvstrings_len, NULL, NULL);
1801 
1802     FreeEnvironmentStringsW(lpWStr);
1803 
1804     return(lpStr);
1805 }
1806 
1807 DllExport char *
1808 win32_getenv(const char *name)
1809 {
1810     dTHX;
1811     DWORD needlen;
1812     SV *curitem = NULL;
1813     DWORD last_err;
1814 
1815     needlen = GetEnvironmentVariableA(name,NULL,0);
1816     if (needlen != 0) {
1817 	curitem = sv_2mortal(newSVpvs(""));
1818         do {
1819             SvGROW(curitem, needlen+1);
1820             needlen = GetEnvironmentVariableA(name,SvPVX(curitem),
1821                                               needlen);
1822         } while (needlen >= SvLEN(curitem));
1823         SvCUR_set(curitem, needlen);
1824     }
1825     else {
1826 	last_err = GetLastError();
1827 	if (last_err == ERROR_NOT_ENOUGH_MEMORY) {
1828 	    /* It appears the variable is in the env, but the Win32 API
1829 	       doesn't have a canned way of getting it.  So we fall back to
1830 	       grabbing the whole env and pulling this value out if possible */
1831 	    char *envv = GetEnvironmentStrings();
1832     	    char *cur = envv;
1833     	    STRLEN len;
1834     	    while (*cur) {
1835 		char *end = strchr(cur,'=');
1836 		if (end && end != cur) {
1837 		    *end = '\0';
1838 		    if (strEQ(cur,name)) {
1839 			curitem = sv_2mortal(newSVpv(end+1,0));
1840 			*end = '=';
1841 			break;
1842 		    }
1843 	    	    *end = '=';
1844 	    	    cur = end + strlen(end+1)+2;
1845 		}
1846 		else if ((len = strlen(cur)))
1847 	    	    cur += len+1;
1848     	    }
1849     	    FreeEnvironmentStrings(envv);
1850 	}
1851 #ifndef WIN32_NO_REGISTRY
1852 	else {
1853 	    /* last ditch: allow any environment variables that begin with 'PERL'
1854 	       to be obtained from the registry, if found there */
1855 	    if (strBEGINs(name, "PERL"))
1856 		(void)get_regstr(name, &curitem);
1857 	}
1858 #endif
1859     }
1860     if (curitem && SvCUR(curitem))
1861 	return SvPVX(curitem);
1862 
1863     return NULL;
1864 }
1865 
1866 DllExport int
1867 win32_putenv(const char *name)
1868 {
1869     char* curitem;
1870     char* val;
1871     int relval = -1;
1872 
1873     if (name) {
1874         curitem = (char *) win32_malloc(strlen(name)+1);
1875         strcpy(curitem, name);
1876         val = strchr(curitem, '=');
1877         if (val) {
1878             /* The sane way to deal with the environment.
1879              * Has these advantages over putenv() & co.:
1880              *  * enables us to store a truly empty value in the
1881              *    environment (like in UNIX).
1882              *  * we don't have to deal with RTL globals, bugs and leaks
1883              *    (specifically, see http://support.microsoft.com/kb/235601).
1884              *  * Much faster.
1885              * Why you may want to use the RTL environment handling
1886              * (previously enabled by USE_WIN32_RTL_ENV):
1887              *  * environ[] and RTL functions will not reflect changes,
1888              *    which might be an issue if extensions want to access
1889              *    the env. via RTL.  This cuts both ways, since RTL will
1890              *    not see changes made by extensions that call the Win32
1891              *    functions directly, either.
1892              * GSAR 97-06-07
1893              */
1894             *val++ = '\0';
1895             if (SetEnvironmentVariableA(curitem, *val ? val : NULL))
1896                 relval = 0;
1897         }
1898         win32_free(curitem);
1899     }
1900     return relval;
1901 }
1902 
1903 static long
1904 filetime_to_clock(PFILETIME ft)
1905 {
1906     __int64 qw = ft->dwHighDateTime;
1907     qw <<= 32;
1908     qw |= ft->dwLowDateTime;
1909     qw /= 10000;  /* File time ticks at 0.1uS, clock at 1mS */
1910     return (long) qw;
1911 }
1912 
1913 DllExport int
1914 win32_times(struct tms *timebuf)
1915 {
1916     FILETIME user;
1917     FILETIME kernel;
1918     FILETIME dummy;
1919     clock_t process_time_so_far = clock();
1920     if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy,
1921                         &kernel,&user)) {
1922 	timebuf->tms_utime = filetime_to_clock(&user);
1923 	timebuf->tms_stime = filetime_to_clock(&kernel);
1924 	timebuf->tms_cutime = 0;
1925 	timebuf->tms_cstime = 0;
1926     } else {
1927         /* That failed - e.g. Win95 fallback to clock() */
1928 	timebuf->tms_utime = process_time_so_far;
1929 	timebuf->tms_stime = 0;
1930 	timebuf->tms_cutime = 0;
1931 	timebuf->tms_cstime = 0;
1932     }
1933     return process_time_so_far;
1934 }
1935 
1936 /* fix utime() so it works on directories in NT */
1937 static BOOL
1938 filetime_from_time(PFILETIME pFileTime, time_t Time)
1939 {
1940     struct tm *pTM = localtime(&Time);
1941     SYSTEMTIME SystemTime;
1942     FILETIME LocalTime;
1943 
1944     if (pTM == NULL)
1945 	return FALSE;
1946 
1947     SystemTime.wYear   = pTM->tm_year + 1900;
1948     SystemTime.wMonth  = pTM->tm_mon + 1;
1949     SystemTime.wDay    = pTM->tm_mday;
1950     SystemTime.wHour   = pTM->tm_hour;
1951     SystemTime.wMinute = pTM->tm_min;
1952     SystemTime.wSecond = pTM->tm_sec;
1953     SystemTime.wMilliseconds = 0;
1954 
1955     return SystemTimeToFileTime(&SystemTime, &LocalTime) &&
1956            LocalFileTimeToFileTime(&LocalTime, pFileTime);
1957 }
1958 
1959 DllExport int
1960 win32_unlink(const char *filename)
1961 {
1962     dTHX;
1963     int ret;
1964     DWORD attrs;
1965 
1966     filename = PerlDir_mapA(filename);
1967     attrs = GetFileAttributesA(filename);
1968     if (attrs == 0xFFFFFFFF) {
1969         errno = ENOENT;
1970         return -1;
1971     }
1972     if (attrs & FILE_ATTRIBUTE_READONLY) {
1973         (void)SetFileAttributesA(filename, attrs & ~FILE_ATTRIBUTE_READONLY);
1974         ret = unlink(filename);
1975         if (ret == -1)
1976             (void)SetFileAttributesA(filename, attrs);
1977     }
1978     else
1979         ret = unlink(filename);
1980     return ret;
1981 }
1982 
1983 DllExport int
1984 win32_utime(const char *filename, struct utimbuf *times)
1985 {
1986     dTHX;
1987     HANDLE handle;
1988     FILETIME ftCreate;
1989     FILETIME ftAccess;
1990     FILETIME ftWrite;
1991     struct utimbuf TimeBuffer;
1992     int rc;
1993 
1994     filename = PerlDir_mapA(filename);
1995     rc = utime(filename, times);
1996 
1997     /* EACCES: path specifies directory or readonly file */
1998     if (rc == 0 || errno != EACCES)
1999 	return rc;
2000 
2001     if (times == NULL) {
2002 	times = &TimeBuffer;
2003 	time(&times->actime);
2004 	times->modtime = times->actime;
2005     }
2006 
2007     /* This will (and should) still fail on readonly files */
2008     handle = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE,
2009                          FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
2010                          OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
2011     if (handle == INVALID_HANDLE_VALUE)
2012 	return rc;
2013 
2014     if (GetFileTime(handle, &ftCreate, &ftAccess, &ftWrite) &&
2015 	filetime_from_time(&ftAccess, times->actime) &&
2016 	filetime_from_time(&ftWrite, times->modtime) &&
2017 	SetFileTime(handle, &ftCreate, &ftAccess, &ftWrite))
2018     {
2019 	rc = 0;
2020     }
2021 
2022     CloseHandle(handle);
2023     return rc;
2024 }
2025 
2026 typedef union {
2027     unsigned __int64	ft_i64;
2028     FILETIME		ft_val;
2029 } FT_t;
2030 
2031 #ifdef __GNUC__
2032 #define Const64(x) x##LL
2033 #else
2034 #define Const64(x) x##i64
2035 #endif
2036 /* Number of 100 nanosecond units from 1/1/1601 to 1/1/1970 */
2037 #define EPOCH_BIAS  Const64(116444736000000000)
2038 
2039 /* NOTE: This does not compute the timezone info (doing so can be expensive,
2040  * and appears to be unsupported even by glibc) */
2041 DllExport int
2042 win32_gettimeofday(struct timeval *tp, void *not_used)
2043 {
2044     FT_t ft;
2045 
2046     /* this returns time in 100-nanosecond units  (i.e. tens of usecs) */
2047     GetSystemTimeAsFileTime(&ft.ft_val);
2048 
2049     /* seconds since epoch */
2050     tp->tv_sec = (long)((ft.ft_i64 - EPOCH_BIAS) / Const64(10000000));
2051 
2052     /* microseconds remaining */
2053     tp->tv_usec = (long)((ft.ft_i64 / Const64(10)) % Const64(1000000));
2054 
2055     return 0;
2056 }
2057 
2058 DllExport int
2059 win32_uname(struct utsname *name)
2060 {
2061     struct hostent *hep;
2062     STRLEN nodemax = sizeof(name->nodename)-1;
2063 
2064     /* sysname */
2065     switch (g_osver.dwPlatformId) {
2066     case VER_PLATFORM_WIN32_WINDOWS:
2067         strcpy(name->sysname, "Windows");
2068         break;
2069     case VER_PLATFORM_WIN32_NT:
2070         strcpy(name->sysname, "Windows NT");
2071         break;
2072     case VER_PLATFORM_WIN32s:
2073         strcpy(name->sysname, "Win32s");
2074         break;
2075     default:
2076         strcpy(name->sysname, "Win32 Unknown");
2077         break;
2078     }
2079 
2080     /* release */
2081     sprintf(name->release, "%d.%d",
2082             g_osver.dwMajorVersion, g_osver.dwMinorVersion);
2083 
2084     /* version */
2085     sprintf(name->version, "Build %d",
2086             g_osver.dwPlatformId == VER_PLATFORM_WIN32_NT
2087             ? g_osver.dwBuildNumber : (g_osver.dwBuildNumber & 0xffff));
2088     if (g_osver.szCSDVersion[0]) {
2089         char *buf = name->version + strlen(name->version);
2090         sprintf(buf, " (%s)", g_osver.szCSDVersion);
2091     }
2092 
2093     /* nodename */
2094     hep = win32_gethostbyname("localhost");
2095     if (hep) {
2096 	STRLEN len = strlen(hep->h_name);
2097 	if (len <= nodemax) {
2098 	    strcpy(name->nodename, hep->h_name);
2099 	}
2100 	else {
2101 	    strncpy(name->nodename, hep->h_name, nodemax);
2102 	    name->nodename[nodemax] = '\0';
2103 	}
2104     }
2105     else {
2106 	DWORD sz = nodemax;
2107 	if (!GetComputerName(name->nodename, &sz))
2108 	    *name->nodename = '\0';
2109     }
2110 
2111     /* machine (architecture) */
2112     {
2113 	SYSTEM_INFO info;
2114 	DWORD procarch;
2115 	char *arch;
2116 	GetSystemInfo(&info);
2117 
2118 #if (defined(__MINGW32__) && !defined(_ANONYMOUS_UNION) && !defined(__MINGW_EXTENSION))
2119 	procarch = info.u.s.wProcessorArchitecture;
2120 #else
2121 	procarch = info.wProcessorArchitecture;
2122 #endif
2123 	switch (procarch) {
2124 	case PROCESSOR_ARCHITECTURE_INTEL:
2125 	    arch = "x86"; break;
2126 	case PROCESSOR_ARCHITECTURE_IA64:
2127 	    arch = "ia64"; break;
2128 	case PROCESSOR_ARCHITECTURE_AMD64:
2129 	    arch = "amd64"; break;
2130 	case PROCESSOR_ARCHITECTURE_UNKNOWN:
2131 	    arch = "unknown"; break;
2132 	default:
2133 	    sprintf(name->machine, "unknown(0x%x)", procarch);
2134 	    arch = name->machine;
2135 	    break;
2136 	}
2137 	if (name->machine != arch)
2138 	    strcpy(name->machine, arch);
2139     }
2140     return 0;
2141 }
2142 
2143 /* Timing related stuff */
2144 
2145 int
2146 do_raise(pTHX_ int sig)
2147 {
2148     if (sig < SIG_SIZE) {
2149 	Sighandler_t handler = w32_sighandler[sig];
2150 	if (handler == SIG_IGN) {
2151 	    return 0;
2152 	}
2153 	else if (handler != SIG_DFL) {
2154 	    (*handler)(sig);
2155 	    return 0;
2156 	}
2157 	else {
2158 	    /* Choose correct default behaviour */
2159 	    switch (sig) {
2160 #ifdef SIGCLD
2161 		case SIGCLD:
2162 #endif
2163 #ifdef SIGCHLD
2164 		case SIGCHLD:
2165 #endif
2166 		case 0:
2167 		    return 0;
2168 		case SIGTERM:
2169 		default:
2170 		    break;
2171 	    }
2172 	}
2173     }
2174     /* Tell caller to exit thread/process as appropriate */
2175     return 1;
2176 }
2177 
2178 void
2179 sig_terminate(pTHX_ int sig)
2180 {
2181     Perl_warn(aTHX_ "Terminating on signal SIG%s(%d)\n",PL_sig_name[sig], sig);
2182     /* exit() seems to be safe, my_exit() or die() is a problem in ^C
2183        thread
2184      */
2185     exit(sig);
2186 }
2187 
2188 DllExport int
2189 win32_async_check(pTHX)
2190 {
2191     MSG msg;
2192     HWND hwnd = w32_message_hwnd;
2193 
2194     /* Reset w32_poll_count before doing anything else, incase we dispatch
2195      * messages that end up calling back into perl */
2196     w32_poll_count = 0;
2197 
2198     if (hwnd != INVALID_HANDLE_VALUE) {
2199         /* Passing PeekMessage -1 as HWND (2nd arg) only gets PostThreadMessage() messages
2200         * and ignores window messages - should co-exist better with windows apps e.g. Tk
2201         */
2202         if (hwnd == NULL)
2203             hwnd = (HWND)-1;
2204 
2205         while (PeekMessage(&msg, hwnd, WM_TIMER,    WM_TIMER,    PM_REMOVE|PM_NOYIELD) ||
2206                PeekMessage(&msg, hwnd, WM_USER_MIN, WM_USER_MAX, PM_REMOVE|PM_NOYIELD))
2207         {
2208             /* re-post a WM_QUIT message (we'll mark it as read later) */
2209             if(msg.message == WM_QUIT) {
2210                 PostQuitMessage((int)msg.wParam);
2211                 break;
2212             }
2213 
2214             if(!CallMsgFilter(&msg, MSGF_USER))
2215             {
2216                 TranslateMessage(&msg);
2217                 DispatchMessage(&msg);
2218             }
2219         }
2220     }
2221 
2222     /* Call PeekMessage() to mark all pending messages in the queue as "old".
2223      * This is necessary when we are being called by win32_msgwait() to
2224      * make sure MsgWaitForMultipleObjects() stops reporting the same waiting
2225      * message over and over.  An example how this can happen is when
2226      * Perl is calling win32_waitpid() inside a GUI application and the GUI
2227      * is generating messages before the process terminated.
2228      */
2229     PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE|PM_NOYIELD);
2230 
2231     /* Above or other stuff may have set a signal flag */
2232     if (PL_sig_pending)
2233         despatch_signals();
2234 
2235     return 1;
2236 }
2237 
2238 /* This function will not return until the timeout has elapsed, or until
2239  * one of the handles is ready. */
2240 DllExport DWORD
2241 win32_msgwait(pTHX_ DWORD count, LPHANDLE handles, DWORD timeout, LPDWORD resultp)
2242 {
2243     int retry = 0;
2244     /* We may need several goes at this - so compute when we stop */
2245     FT_t ticks = {0};
2246     unsigned __int64 endtime = timeout;
2247     if (timeout != INFINITE) {
2248 	GetSystemTimeAsFileTime(&ticks.ft_val);
2249 	ticks.ft_i64 /= 10000;
2250 	endtime += ticks.ft_i64;
2251     }
2252     /* This was a race condition. Do not let a non INFINITE timeout to
2253      * MsgWaitForMultipleObjects roll under 0 creating a near
2254      * infinity/~(UINT32)0 timeout which will appear as a deadlock to the
2255      * user who did a CORE perl function with a non infinity timeout,
2256      * sleep for example.  This is 64 to 32 truncation minefield.
2257      *
2258      * This scenario can only be created if the timespan from the return of
2259      * MsgWaitForMultipleObjects to GetSystemTimeAsFileTime exceeds 1 ms. To
2260      * generate the scenario, manual breakpoints in a C debugger are required,
2261      * or a context switch occurred in win32_async_check in PeekMessage, or random
2262      * messages are delivered to the *thread* message queue of the Perl thread
2263      * from another process (msctf.dll doing IPC among its instances, VS debugger
2264      * causes msctf.dll to be loaded into Perl by kernel), see [perl #33096].
2265      */
2266     while (ticks.ft_i64 <= endtime || retry) {
2267 	/* if timeout's type is lengthened, remember to split 64b timeout
2268 	 * into multiple non-infinity runs of MWFMO */
2269 	DWORD result = MsgWaitForMultipleObjects(count, handles, FALSE,
2270 						(DWORD)(endtime - ticks.ft_i64),
2271 						QS_POSTMESSAGE|QS_TIMER|QS_SENDMESSAGE);
2272         retry = 0;
2273 	if (resultp)
2274 	   *resultp = result;
2275 	if (result == WAIT_TIMEOUT) {
2276 	    /* Ran out of time - explicit return of zero to avoid -ve if we
2277 	       have scheduling issues
2278              */
2279 	    return 0;
2280 	}
2281 	if (timeout != INFINITE) {
2282 	    GetSystemTimeAsFileTime(&ticks.ft_val);
2283 	    ticks.ft_i64 /= 10000;
2284 	}
2285 	if (result == WAIT_OBJECT_0 + count) {
2286 	    /* Message has arrived - check it */
2287 	    (void)win32_async_check(aTHX);
2288             retry = 1;
2289 	}
2290 	else {
2291 	   /* Not timeout or message - one of handles is ready */
2292 	   break;
2293 	}
2294     }
2295     /* If we are past the end say zero */
2296     if (!ticks.ft_i64 || ticks.ft_i64 > endtime)
2297 	return 0;
2298     /* compute time left to wait */
2299     ticks.ft_i64 = endtime - ticks.ft_i64;
2300     /* if more ms than DWORD, then return max DWORD */
2301     return ticks.ft_i64 <= UINT_MAX ? (DWORD)ticks.ft_i64 : UINT_MAX;
2302 }
2303 
2304 int
2305 win32_internal_wait(pTHX_ int *status, DWORD timeout)
2306 {
2307     /* XXX this wait emulation only knows about processes
2308      * spawned via win32_spawnvp(P_NOWAIT, ...).
2309      */
2310     int i, retval;
2311     DWORD exitcode, waitcode;
2312 
2313 #ifdef USE_ITHREADS
2314     if (w32_num_pseudo_children) {
2315 	win32_msgwait(aTHX_ w32_num_pseudo_children, w32_pseudo_child_handles,
2316 		      timeout, &waitcode);
2317         /* Time out here if there are no other children to wait for. */
2318 	if (waitcode == WAIT_TIMEOUT) {
2319 	    if (!w32_num_children) {
2320 		return 0;
2321 	    }
2322 	}
2323 	else if (waitcode != WAIT_FAILED) {
2324 	    if (waitcode >= WAIT_ABANDONED_0
2325 		&& waitcode < WAIT_ABANDONED_0 + w32_num_pseudo_children)
2326 		i = waitcode - WAIT_ABANDONED_0;
2327 	    else
2328 		i = waitcode - WAIT_OBJECT_0;
2329 	    if (GetExitCodeThread(w32_pseudo_child_handles[i], &exitcode)) {
2330 		*status = (int)((exitcode & 0xff) << 8);
2331 		retval = (int)w32_pseudo_child_pids[i];
2332 		remove_dead_pseudo_process(i);
2333 		return -retval;
2334 	    }
2335 	}
2336     }
2337 #endif
2338 
2339     if (!w32_num_children) {
2340 	errno = ECHILD;
2341 	return -1;
2342     }
2343 
2344     /* if a child exists, wait for it to die */
2345     win32_msgwait(aTHX_ w32_num_children, w32_child_handles, timeout, &waitcode);
2346     if (waitcode == WAIT_TIMEOUT) {
2347 	return 0;
2348     }
2349     if (waitcode != WAIT_FAILED) {
2350 	if (waitcode >= WAIT_ABANDONED_0
2351 	    && waitcode < WAIT_ABANDONED_0 + w32_num_children)
2352 	    i = waitcode - WAIT_ABANDONED_0;
2353 	else
2354 	    i = waitcode - WAIT_OBJECT_0;
2355 	if (GetExitCodeProcess(w32_child_handles[i], &exitcode) ) {
2356 	    *status = (int)((exitcode & 0xff) << 8);
2357 	    retval = (int)w32_child_pids[i];
2358 	    remove_dead_process(i);
2359 	    return retval;
2360 	}
2361     }
2362 
2363     errno = GetLastError();
2364     return -1;
2365 }
2366 
2367 DllExport int
2368 win32_waitpid(int pid, int *status, int flags)
2369 {
2370     dTHX;
2371     DWORD timeout = (flags & WNOHANG) ? 0 : INFINITE;
2372     int retval = -1;
2373     long child;
2374     if (pid == -1)				/* XXX threadid == 1 ? */
2375 	return win32_internal_wait(aTHX_ status, timeout);
2376 #ifdef USE_ITHREADS
2377     else if (pid < 0) {
2378 	child = find_pseudo_pid(aTHX_ -pid);
2379 	if (child >= 0) {
2380 	    HANDLE hThread = w32_pseudo_child_handles[child];
2381 	    DWORD waitcode;
2382 	    win32_msgwait(aTHX_ 1, &hThread, timeout, &waitcode);
2383 	    if (waitcode == WAIT_TIMEOUT) {
2384 		return 0;
2385 	    }
2386 	    else if (waitcode == WAIT_OBJECT_0) {
2387 		if (GetExitCodeThread(hThread, &waitcode)) {
2388 		    *status = (int)((waitcode & 0xff) << 8);
2389 		    retval = (int)w32_pseudo_child_pids[child];
2390 		    remove_dead_pseudo_process(child);
2391 		    return -retval;
2392 		}
2393 	    }
2394 	    else
2395 		errno = ECHILD;
2396 	}
2397     }
2398 #endif
2399     else {
2400 	HANDLE hProcess;
2401 	DWORD waitcode;
2402 	child = find_pid(aTHX_ pid);
2403 	if (child >= 0) {
2404 	    hProcess = w32_child_handles[child];
2405 	    win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
2406 	    if (waitcode == WAIT_TIMEOUT) {
2407 		return 0;
2408 	    }
2409 	    else if (waitcode == WAIT_OBJECT_0) {
2410 		if (GetExitCodeProcess(hProcess, &waitcode)) {
2411 		    *status = (int)((waitcode & 0xff) << 8);
2412 		    retval = (int)w32_child_pids[child];
2413 		    remove_dead_process(child);
2414 		    return retval;
2415 		}
2416 	    }
2417 	    else
2418 		errno = ECHILD;
2419 	}
2420 	else {
2421 	    hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
2422 	    if (hProcess) {
2423 		win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
2424 		if (waitcode == WAIT_TIMEOUT) {
2425                     CloseHandle(hProcess);
2426 		    return 0;
2427 		}
2428 		else if (waitcode == WAIT_OBJECT_0) {
2429 		    if (GetExitCodeProcess(hProcess, &waitcode)) {
2430 			*status = (int)((waitcode & 0xff) << 8);
2431 			CloseHandle(hProcess);
2432 			return pid;
2433 		    }
2434 		}
2435 		CloseHandle(hProcess);
2436 	    }
2437 	    else
2438 		errno = ECHILD;
2439 	}
2440     }
2441     return retval >= 0 ? pid : retval;
2442 }
2443 
2444 DllExport int
2445 win32_wait(int *status)
2446 {
2447     dTHX;
2448     return win32_internal_wait(aTHX_ status, INFINITE);
2449 }
2450 
2451 DllExport unsigned int
2452 win32_sleep(unsigned int t)
2453 {
2454     dTHX;
2455     /* Win32 times are in ms so *1000 in and /1000 out */
2456     if (t > UINT_MAX / 1000) {
2457 	Perl_ck_warner(aTHX_ packWARN(WARN_OVERFLOW),
2458 			"sleep(%lu) too large", t);
2459     }
2460     return win32_msgwait(aTHX_ 0, NULL, t * 1000, NULL) / 1000;
2461 }
2462 
2463 DllExport int
2464 win32_pause(void)
2465 {
2466     dTHX;
2467     win32_msgwait(aTHX_ 0, NULL, INFINITE, NULL);
2468     return -1;
2469 }
2470 
2471 DllExport unsigned int
2472 win32_alarm(unsigned int sec)
2473 {
2474     /*
2475      * the 'obvious' implentation is SetTimer() with a callback
2476      * which does whatever receiving SIGALRM would do
2477      * we cannot use SIGALRM even via raise() as it is not
2478      * one of the supported codes in <signal.h>
2479      */
2480     dTHX;
2481 
2482     if (w32_message_hwnd == INVALID_HANDLE_VALUE)
2483         w32_message_hwnd = win32_create_message_window();
2484 
2485     if (sec) {
2486         if (w32_message_hwnd == NULL)
2487             w32_timerid = SetTimer(NULL, w32_timerid, sec*1000, NULL);
2488         else {
2489   	    w32_timerid = 1;
2490             SetTimer(w32_message_hwnd, w32_timerid, sec*1000, NULL);
2491         }
2492     }
2493     else {
2494     	if (w32_timerid) {
2495             KillTimer(w32_message_hwnd, w32_timerid);
2496   	    w32_timerid = 0;
2497     	}
2498     }
2499     return 0;
2500 }
2501 
2502 extern char *	des_fcrypt(const char *txt, const char *salt, char *cbuf);
2503 
2504 DllExport char *
2505 win32_crypt(const char *txt, const char *salt)
2506 {
2507     dTHX;
2508     return des_fcrypt(txt, salt, w32_crypt_buffer);
2509 }
2510 
2511 /* simulate flock by locking a range on the file */
2512 
2513 #define LK_LEN		0xffff0000
2514 
2515 DllExport int
2516 win32_flock(int fd, int oper)
2517 {
2518     OVERLAPPED o;
2519     int i = -1;
2520     HANDLE fh;
2521 
2522     fh = (HANDLE)_get_osfhandle(fd);
2523     if (fh == (HANDLE)-1)  /* _get_osfhandle() already sets errno to EBADF */
2524         return -1;
2525 
2526     memset(&o, 0, sizeof(o));
2527 
2528     switch(oper) {
2529     case LOCK_SH:		/* shared lock */
2530 	if (LockFileEx(fh, 0, 0, LK_LEN, 0, &o))
2531             i = 0;
2532 	break;
2533     case LOCK_EX:		/* exclusive lock */
2534 	if (LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o))
2535             i = 0;
2536 	break;
2537     case LOCK_SH|LOCK_NB:	/* non-blocking shared lock */
2538 	if (LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o))
2539             i = 0;
2540 	break;
2541     case LOCK_EX|LOCK_NB:	/* non-blocking exclusive lock */
2542 	if (LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
2543 		       0, LK_LEN, 0, &o))
2544             i = 0;
2545 	break;
2546     case LOCK_UN:		/* unlock lock */
2547 	if (UnlockFileEx(fh, 0, LK_LEN, 0, &o))
2548             i = 0;
2549 	break;
2550     default:			/* unknown */
2551 	errno = EINVAL;
2552 	return -1;
2553     }
2554     if (i == -1) {
2555         if (GetLastError() == ERROR_LOCK_VIOLATION)
2556             errno = EWOULDBLOCK;
2557         else
2558             errno = EINVAL;
2559     }
2560     return i;
2561 }
2562 
2563 #undef LK_LEN
2564 
2565 extern int convert_wsa_error_to_errno(int wsaerr); /* in win32sck.c */
2566 
2567 /* Get the errno value corresponding to the given err. This function is not
2568  * intended to handle conversion of general GetLastError() codes. It only exists
2569  * to translate Windows sockets error codes from WSAGetLastError(). Such codes
2570  * used to be assigned to errno/$! in earlier versions of perl; this function is
2571  * used to catch any old Perl code which is still trying to assign such values
2572  * to $! and convert them to errno values instead.
2573  */
2574 int
2575 win32_get_errno(int err)
2576 {
2577     return convert_wsa_error_to_errno(err);
2578 }
2579 
2580 /*
2581  *  redirected io subsystem for all XS modules
2582  *
2583  */
2584 
2585 DllExport int *
2586 win32_errno(void)
2587 {
2588     return (&errno);
2589 }
2590 
2591 DllExport char ***
2592 win32_environ(void)
2593 {
2594     return (&(_environ));
2595 }
2596 
2597 /* the rest are the remapped stdio routines */
2598 DllExport FILE *
2599 win32_stderr(void)
2600 {
2601     return (stderr);
2602 }
2603 
2604 DllExport FILE *
2605 win32_stdin(void)
2606 {
2607     return (stdin);
2608 }
2609 
2610 DllExport FILE *
2611 win32_stdout(void)
2612 {
2613     return (stdout);
2614 }
2615 
2616 DllExport int
2617 win32_ferror(FILE *fp)
2618 {
2619     return (ferror(fp));
2620 }
2621 
2622 
2623 DllExport int
2624 win32_feof(FILE *fp)
2625 {
2626     return (feof(fp));
2627 }
2628 
2629 #ifdef ERRNO_HAS_POSIX_SUPPLEMENT
2630 extern int convert_errno_to_wsa_error(int err); /* in win32sck.c */
2631 #endif
2632 
2633 /*
2634  * Since the errors returned by the socket error function
2635  * WSAGetLastError() are not known by the library routine strerror
2636  * we have to roll our own to cover the case of socket errors
2637  * that could not be converted to regular errno values by
2638  * get_last_socket_error() in win32/win32sck.c.
2639  */
2640 
2641 DllExport char *
2642 win32_strerror(int e)
2643 {
2644 #if !defined __MINGW32__      /* compiler intolerance */
2645     extern int sys_nerr;
2646 #endif
2647 
2648     if (e < 0 || e > sys_nerr) {
2649         dTHXa(NULL);
2650 	if (e < 0)
2651 	    e = GetLastError();
2652 #ifdef ERRNO_HAS_POSIX_SUPPLEMENT
2653 	/* VC10+ and some MinGW/gcc-4.8+ define a "POSIX supplement" of errno
2654 	 * values ranging from EADDRINUSE (100) to EWOULDBLOCK (140), but
2655 	 * sys_nerr is still 43 and strerror() returns "Unknown error" for them.
2656 	 * We must therefore still roll our own messages for these codes, and
2657 	 * additionally map them to corresponding Windows (sockets) error codes
2658 	 * first to avoid getting the wrong system message.
2659 	 */
2660 	else if (e >= EADDRINUSE && e <= EWOULDBLOCK) {
2661 	    e = convert_errno_to_wsa_error(e);
2662 	}
2663 #endif
2664 
2665 	aTHXa(PERL_GET_THX);
2666 	if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
2667                          |FORMAT_MESSAGE_IGNORE_INSERTS, NULL, e, 0,
2668 			  w32_strerror_buffer, sizeof(w32_strerror_buffer),
2669                           NULL) == 0)
2670         {
2671 	    strcpy(w32_strerror_buffer, "Unknown Error");
2672         }
2673 	return w32_strerror_buffer;
2674     }
2675 #undef strerror
2676     return strerror(e);
2677 #define strerror win32_strerror
2678 }
2679 
2680 DllExport void
2681 win32_str_os_error(void *sv, DWORD dwErr)
2682 {
2683     DWORD dwLen;
2684     char *sMsg;
2685     dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
2686 			  |FORMAT_MESSAGE_IGNORE_INSERTS
2687 			  |FORMAT_MESSAGE_FROM_SYSTEM, NULL,
2688 			   dwErr, 0, (char *)&sMsg, 1, NULL);
2689     /* strip trailing whitespace and period */
2690     if (0 < dwLen) {
2691 	do {
2692 	    --dwLen;	/* dwLen doesn't include trailing null */
2693 	} while (0 < dwLen && isSPACE(sMsg[dwLen]));
2694 	if ('.' != sMsg[dwLen])
2695 	    dwLen++;
2696 	sMsg[dwLen] = '\0';
2697     }
2698     if (0 == dwLen) {
2699 	sMsg = (char*)LocalAlloc(0, 64/**sizeof(TCHAR)*/);
2700 	if (sMsg)
2701 	    dwLen = sprintf(sMsg,
2702 			    "Unknown error #0x%lX (lookup 0x%lX)",
2703 			    dwErr, GetLastError());
2704     }
2705     if (sMsg) {
2706 	dTHX;
2707 	sv_setpvn((SV*)sv, sMsg, dwLen);
2708 	LocalFree(sMsg);
2709     }
2710 }
2711 
2712 DllExport int
2713 win32_fprintf(FILE *fp, const char *format, ...)
2714 {
2715     va_list marker;
2716     va_start(marker, format);     /* Initialize variable arguments. */
2717 
2718     return (vfprintf(fp, format, marker));
2719 }
2720 
2721 DllExport int
2722 win32_printf(const char *format, ...)
2723 {
2724     va_list marker;
2725     va_start(marker, format);     /* Initialize variable arguments. */
2726 
2727     return (vprintf(format, marker));
2728 }
2729 
2730 DllExport int
2731 win32_vfprintf(FILE *fp, const char *format, va_list args)
2732 {
2733     return (vfprintf(fp, format, args));
2734 }
2735 
2736 DllExport int
2737 win32_vprintf(const char *format, va_list args)
2738 {
2739     return (vprintf(format, args));
2740 }
2741 
2742 DllExport size_t
2743 win32_fread(void *buf, size_t size, size_t count, FILE *fp)
2744 {
2745     return fread(buf, size, count, fp);
2746 }
2747 
2748 DllExport size_t
2749 win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
2750 {
2751     return fwrite(buf, size, count, fp);
2752 }
2753 
2754 #define MODE_SIZE 10
2755 
2756 DllExport FILE *
2757 win32_fopen(const char *filename, const char *mode)
2758 {
2759     dTHXa(NULL);
2760     FILE *f;
2761 
2762     if (!*filename)
2763 	return NULL;
2764 
2765     if (stricmp(filename, "/dev/null")==0)
2766 	filename = "NUL";
2767 
2768     aTHXa(PERL_GET_THX);
2769     f = fopen(PerlDir_mapA(filename), mode);
2770     /* avoid buffering headaches for child processes */
2771     if (f && *mode == 'a')
2772 	win32_fseek(f, 0, SEEK_END);
2773     return f;
2774 }
2775 
2776 DllExport FILE *
2777 win32_fdopen(int handle, const char *mode)
2778 {
2779     FILE *f;
2780     f = fdopen(handle, (char *) mode);
2781     /* avoid buffering headaches for child processes */
2782     if (f && *mode == 'a')
2783 	win32_fseek(f, 0, SEEK_END);
2784     return f;
2785 }
2786 
2787 DllExport FILE *
2788 win32_freopen(const char *path, const char *mode, FILE *stream)
2789 {
2790     dTHXa(NULL);
2791     if (stricmp(path, "/dev/null")==0)
2792 	path = "NUL";
2793 
2794     aTHXa(PERL_GET_THX);
2795     return freopen(PerlDir_mapA(path), mode, stream);
2796 }
2797 
2798 DllExport int
2799 win32_fclose(FILE *pf)
2800 {
2801 #ifdef WIN32_NO_SOCKETS
2802     return fclose(pf);
2803 #else
2804     return my_fclose(pf);	/* defined in win32sck.c */
2805 #endif
2806 }
2807 
2808 DllExport int
2809 win32_fputs(const char *s,FILE *pf)
2810 {
2811     return fputs(s, pf);
2812 }
2813 
2814 DllExport int
2815 win32_fputc(int c,FILE *pf)
2816 {
2817     return fputc(c,pf);
2818 }
2819 
2820 DllExport int
2821 win32_ungetc(int c,FILE *pf)
2822 {
2823     return ungetc(c,pf);
2824 }
2825 
2826 DllExport int
2827 win32_getc(FILE *pf)
2828 {
2829     return getc(pf);
2830 }
2831 
2832 DllExport int
2833 win32_fileno(FILE *pf)
2834 {
2835     return fileno(pf);
2836 }
2837 
2838 DllExport void
2839 win32_clearerr(FILE *pf)
2840 {
2841     clearerr(pf);
2842     return;
2843 }
2844 
2845 DllExport int
2846 win32_fflush(FILE *pf)
2847 {
2848     return fflush(pf);
2849 }
2850 
2851 DllExport Off_t
2852 win32_ftell(FILE *pf)
2853 {
2854 #if defined(WIN64) || defined(USE_LARGE_FILES)
2855     fpos_t pos;
2856     if (fgetpos(pf, &pos))
2857 	return -1;
2858     return (Off_t)pos;
2859 #else
2860     return ftell(pf);
2861 #endif
2862 }
2863 
2864 DllExport int
2865 win32_fseek(FILE *pf, Off_t offset,int origin)
2866 {
2867 #if defined(WIN64) || defined(USE_LARGE_FILES)
2868     fpos_t pos;
2869     switch (origin) {
2870     case SEEK_CUR:
2871 	if (fgetpos(pf, &pos))
2872 	    return -1;
2873 	offset += pos;
2874 	break;
2875     case SEEK_END:
2876 	fseek(pf, 0, SEEK_END);
2877 	pos = _telli64(fileno(pf));
2878 	offset += pos;
2879 	break;
2880     case SEEK_SET:
2881 	break;
2882     default:
2883 	errno = EINVAL;
2884 	return -1;
2885     }
2886     return fsetpos(pf, &offset);
2887 #else
2888     return fseek(pf, (long)offset, origin);
2889 #endif
2890 }
2891 
2892 DllExport int
2893 win32_fgetpos(FILE *pf,fpos_t *p)
2894 {
2895     return fgetpos(pf, p);
2896 }
2897 
2898 DllExport int
2899 win32_fsetpos(FILE *pf,const fpos_t *p)
2900 {
2901     return fsetpos(pf, p);
2902 }
2903 
2904 DllExport void
2905 win32_rewind(FILE *pf)
2906 {
2907     rewind(pf);
2908     return;
2909 }
2910 
2911 DllExport int
2912 win32_tmpfd(void)
2913 {
2914     char prefix[MAX_PATH+1];
2915     char filename[MAX_PATH+1];
2916     DWORD len = GetTempPath(MAX_PATH, prefix);
2917     if (len && len < MAX_PATH) {
2918 	if (GetTempFileName(prefix, "plx", 0, filename)) {
2919 	    HANDLE fh = CreateFile(filename,
2920 				   DELETE | GENERIC_READ | GENERIC_WRITE,
2921 				   0,
2922 				   NULL,
2923 				   CREATE_ALWAYS,
2924 				   FILE_ATTRIBUTE_NORMAL
2925 				   | FILE_FLAG_DELETE_ON_CLOSE,
2926 				   NULL);
2927 	    if (fh != INVALID_HANDLE_VALUE) {
2928 		int fd = win32_open_osfhandle((intptr_t)fh, 0);
2929 		if (fd >= 0) {
2930 		    PERL_DEB(dTHX;)
2931 		    DEBUG_p(PerlIO_printf(Perl_debug_log,
2932 					  "Created tmpfile=%s\n",filename));
2933 		    return fd;
2934 		}
2935 	    }
2936 	}
2937     }
2938     return -1;
2939 }
2940 
2941 DllExport FILE*
2942 win32_tmpfile(void)
2943 {
2944     int fd = win32_tmpfd();
2945     if (fd >= 0)
2946 	return win32_fdopen(fd, "w+b");
2947     return NULL;
2948 }
2949 
2950 DllExport void
2951 win32_abort(void)
2952 {
2953     abort();
2954     return;
2955 }
2956 
2957 DllExport int
2958 win32_fstat(int fd, Stat_t *sbufptr)
2959 {
2960 #if defined(WIN64) || defined(USE_LARGE_FILES)
2961     return _fstati64(fd, sbufptr);
2962 #else
2963     return fstat(fd, sbufptr);
2964 #endif
2965 }
2966 
2967 DllExport int
2968 win32_pipe(int *pfd, unsigned int size, int mode)
2969 {
2970     return _pipe(pfd, size, mode);
2971 }
2972 
2973 DllExport PerlIO*
2974 win32_popenlist(const char *mode, IV narg, SV **args)
2975 {
2976     get_shell();
2977 
2978     return do_popen(mode, NULL, narg, args);
2979 }
2980 
2981 STATIC PerlIO*
2982 do_popen(const char *mode, const char *command, IV narg, SV **args) {
2983     int p[2];
2984     int handles[3];
2985     int parent, child;
2986     int stdfd;
2987     int ourmode;
2988     int childpid;
2989     DWORD nhandle;
2990     int lock_held = 0;
2991     const char **args_pvs = NULL;
2992 
2993     /* establish which ends read and write */
2994     if (strchr(mode,'w')) {
2995         stdfd = 0;		/* stdin */
2996         parent = 1;
2997         child = 0;
2998 	nhandle = STD_INPUT_HANDLE;
2999     }
3000     else if (strchr(mode,'r')) {
3001         stdfd = 1;		/* stdout */
3002         parent = 0;
3003         child = 1;
3004 	nhandle = STD_OUTPUT_HANDLE;
3005     }
3006     else
3007         return NULL;
3008 
3009     /* set the correct mode */
3010     if (strchr(mode,'b'))
3011         ourmode = O_BINARY;
3012     else if (strchr(mode,'t'))
3013         ourmode = O_TEXT;
3014     else
3015         ourmode = _fmode & (O_TEXT | O_BINARY);
3016 
3017     /* the child doesn't inherit handles */
3018     ourmode |= O_NOINHERIT;
3019 
3020     if (win32_pipe(p, 512, ourmode) == -1)
3021         return NULL;
3022 
3023     /* Previously this code redirected stdin/out temporarily so the
3024        child process inherited those handles, this caused race
3025        conditions when another thread was writing/reading those
3026        handles.
3027 
3028        To avoid that we just feed the handles to CreateProcess() so
3029        the handles are redirected only in the child.
3030      */
3031     handles[child] = p[child];
3032     handles[parent] = -1;
3033     handles[2] = -1;
3034 
3035     /* CreateProcess() requires inheritable handles */
3036     if (!SetHandleInformation((HANDLE)_get_osfhandle(p[child]), HANDLE_FLAG_INHERIT,
3037 			      HANDLE_FLAG_INHERIT)) {
3038         goto cleanup;
3039     }
3040 
3041     /* start the child */
3042     {
3043 	dTHX;
3044 
3045 	if (command) {
3046 	    if ((childpid = do_spawn2_handles(aTHX_ command, EXECF_SPAWN_NOWAIT, handles)) == -1)
3047 	        goto cleanup;
3048 
3049 	}
3050 	else {
3051 	    int i;
3052 	    const char *exe_name;
3053 
3054 	    Newx(args_pvs, narg + 1 + w32_perlshell_items, const char *);
3055 	    SAVEFREEPV(args_pvs);
3056 	    for (i = 0; i < narg; ++i)
3057 	        args_pvs[i] = SvPV_nolen(args[i]);
3058 	    args_pvs[i] = NULL;
3059 	    exe_name = qualified_path(args_pvs[0], TRUE);
3060 	    if (!exe_name)
3061 	        /* let CreateProcess() try to find it instead */
3062 	        exe_name = args_pvs[0];
3063 
3064 	    if ((childpid = do_spawnvp_handles(P_NOWAIT, exe_name, args_pvs, handles)) == -1) {
3065 	        goto cleanup;
3066 	    }
3067 	}
3068 
3069 	win32_close(p[child]);
3070 
3071 	sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid);
3072 
3073 	/* set process id so that it can be returned by perl's open() */
3074 	PL_forkprocess = childpid;
3075     }
3076 
3077     /* we have an fd, return a file stream */
3078     return (PerlIO_fdopen(p[parent], (char *)mode));
3079 
3080 cleanup:
3081     /* we don't need to check for errors here */
3082     win32_close(p[0]);
3083     win32_close(p[1]);
3084 
3085     return (NULL);
3086 }
3087 
3088 /*
3089  * a popen() clone that respects PERL5SHELL
3090  *
3091  * changed to return PerlIO* rather than FILE * by BKS, 11-11-2000
3092  */
3093 
3094 DllExport PerlIO*
3095 win32_popen(const char *command, const char *mode)
3096 {
3097 #ifdef USE_RTL_POPEN
3098     return _popen(command, mode);
3099 #else
3100     return do_popen(mode, command, 0, NULL);
3101 #endif /* USE_RTL_POPEN */
3102 }
3103 
3104 /*
3105  * pclose() clone
3106  */
3107 
3108 DllExport int
3109 win32_pclose(PerlIO *pf)
3110 {
3111 #ifdef USE_RTL_POPEN
3112     return _pclose(pf);
3113 #else
3114     dTHX;
3115     int childpid, status;
3116     SV *sv;
3117 
3118     sv = *av_fetch(w32_fdpid, PerlIO_fileno(pf), TRUE);
3119 
3120     if (SvIOK(sv))
3121 	childpid = SvIVX(sv);
3122     else
3123 	childpid = 0;
3124 
3125     if (!childpid) {
3126 	errno = EBADF;
3127         return -1;
3128     }
3129 
3130 #ifdef USE_PERLIO
3131     PerlIO_close(pf);
3132 #else
3133     fclose(pf);
3134 #endif
3135     SvIVX(sv) = 0;
3136 
3137     if (win32_waitpid(childpid, &status, 0) == -1)
3138         return -1;
3139 
3140     return status;
3141 
3142 #endif /* USE_RTL_POPEN */
3143 }
3144 
3145 DllExport int
3146 win32_link(const char *oldname, const char *newname)
3147 {
3148     dTHXa(NULL);
3149     WCHAR wOldName[MAX_PATH+1];
3150     WCHAR wNewName[MAX_PATH+1];
3151 
3152     if (MultiByteToWideChar(CP_ACP, 0, oldname, -1, wOldName, MAX_PATH+1) &&
3153         MultiByteToWideChar(CP_ACP, 0, newname, -1, wNewName, MAX_PATH+1) &&
3154 	((aTHXa(PERL_GET_THX)), wcscpy(wOldName, PerlDir_mapW(wOldName)),
3155         CreateHardLinkW(PerlDir_mapW(wNewName), wOldName, NULL)))
3156     {
3157 	return 0;
3158     }
3159     /* This isn't perfect, eg. Win32 returns ERROR_ACCESS_DENIED for
3160        both permissions errors and if the source is a directory, while
3161        POSIX wants EACCES and EPERM respectively.
3162 
3163        Determined by experimentation on Windows 7 x64 SP1, since MS
3164        don't document what error codes are returned.
3165     */
3166     switch (GetLastError()) {
3167     case ERROR_BAD_NET_NAME:
3168     case ERROR_BAD_NETPATH:
3169     case ERROR_BAD_PATHNAME:
3170     case ERROR_FILE_NOT_FOUND:
3171     case ERROR_FILENAME_EXCED_RANGE:
3172     case ERROR_INVALID_DRIVE:
3173     case ERROR_PATH_NOT_FOUND:
3174       errno = ENOENT;
3175       break;
3176     case ERROR_ALREADY_EXISTS:
3177       errno = EEXIST;
3178       break;
3179     case ERROR_ACCESS_DENIED:
3180       errno = EACCES;
3181       break;
3182     case ERROR_NOT_SAME_DEVICE:
3183       errno = EXDEV;
3184       break;
3185     case ERROR_DISK_FULL:
3186       errno = ENOSPC;
3187       break;
3188     case ERROR_NOT_ENOUGH_QUOTA:
3189       errno = EDQUOT;
3190       break;
3191     default:
3192       /* ERROR_INVALID_FUNCTION - eg. on a FAT volume */
3193       errno = EINVAL;
3194       break;
3195     }
3196     return -1;
3197 }
3198 
3199 DllExport int
3200 win32_rename(const char *oname, const char *newname)
3201 {
3202     char szOldName[MAX_PATH+1];
3203     BOOL bResult;
3204     DWORD dwFlags = MOVEFILE_COPY_ALLOWED;
3205     dTHX;
3206 
3207     if (stricmp(newname, oname))
3208         dwFlags |= MOVEFILE_REPLACE_EXISTING;
3209     strcpy(szOldName, PerlDir_mapA(oname));
3210 
3211     bResult = MoveFileExA(szOldName,PerlDir_mapA(newname), dwFlags);
3212     if (!bResult) {
3213         DWORD err = GetLastError();
3214         switch (err) {
3215         case ERROR_BAD_NET_NAME:
3216         case ERROR_BAD_NETPATH:
3217         case ERROR_BAD_PATHNAME:
3218         case ERROR_FILE_NOT_FOUND:
3219         case ERROR_FILENAME_EXCED_RANGE:
3220         case ERROR_INVALID_DRIVE:
3221         case ERROR_NO_MORE_FILES:
3222         case ERROR_PATH_NOT_FOUND:
3223             errno = ENOENT;
3224             break;
3225         case ERROR_DISK_FULL:
3226             errno = ENOSPC;
3227             break;
3228         case ERROR_NOT_ENOUGH_QUOTA:
3229             errno = EDQUOT;
3230             break;
3231         default:
3232             errno = EACCES;
3233             break;
3234         }
3235         return -1;
3236     }
3237     return 0;
3238 }
3239 
3240 DllExport int
3241 win32_setmode(int fd, int mode)
3242 {
3243     return setmode(fd, mode);
3244 }
3245 
3246 DllExport int
3247 win32_chsize(int fd, Off_t size)
3248 {
3249 #if defined(WIN64) || defined(USE_LARGE_FILES)
3250     int retval = 0;
3251     Off_t cur, end, extend;
3252 
3253     cur = win32_tell(fd);
3254     if (cur < 0)
3255 	return -1;
3256     end = win32_lseek(fd, 0, SEEK_END);
3257     if (end < 0)
3258 	return -1;
3259     extend = size - end;
3260     if (extend == 0) {
3261 	/* do nothing */
3262     }
3263     else if (extend > 0) {
3264 	/* must grow the file, padding with nulls */
3265 	char b[4096];
3266 	int oldmode = win32_setmode(fd, O_BINARY);
3267 	size_t count;
3268 	memset(b, '\0', sizeof(b));
3269 	do {
3270 	    count = extend >= sizeof(b) ? sizeof(b) : (size_t)extend;
3271 	    count = win32_write(fd, b, count);
3272 	    if ((int)count < 0) {
3273 		retval = -1;
3274 		break;
3275 	    }
3276 	} while ((extend -= count) > 0);
3277 	win32_setmode(fd, oldmode);
3278     }
3279     else {
3280 	/* shrink the file */
3281 	win32_lseek(fd, size, SEEK_SET);
3282 	if (!SetEndOfFile((HANDLE)_get_osfhandle(fd))) {
3283 	    errno = EACCES;
3284 	    retval = -1;
3285 	}
3286     }
3287     win32_lseek(fd, cur, SEEK_SET);
3288     return retval;
3289 #else
3290     return chsize(fd, (long)size);
3291 #endif
3292 }
3293 
3294 DllExport Off_t
3295 win32_lseek(int fd, Off_t offset, int origin)
3296 {
3297 #if defined(WIN64) || defined(USE_LARGE_FILES)
3298     return _lseeki64(fd, offset, origin);
3299 #else
3300     return lseek(fd, (long)offset, origin);
3301 #endif
3302 }
3303 
3304 DllExport Off_t
3305 win32_tell(int fd)
3306 {
3307 #if defined(WIN64) || defined(USE_LARGE_FILES)
3308     return _telli64(fd);
3309 #else
3310     return tell(fd);
3311 #endif
3312 }
3313 
3314 DllExport int
3315 win32_open(const char *path, int flag, ...)
3316 {
3317     dTHXa(NULL);
3318     va_list ap;
3319     int pmode;
3320 
3321     va_start(ap, flag);
3322     pmode = va_arg(ap, int);
3323     va_end(ap);
3324 
3325     if (stricmp(path, "/dev/null")==0)
3326 	path = "NUL";
3327 
3328     aTHXa(PERL_GET_THX);
3329     return open(PerlDir_mapA(path), flag, pmode);
3330 }
3331 
3332 /* close() that understands socket */
3333 extern int my_close(int);	/* in win32sck.c */
3334 
3335 DllExport int
3336 win32_close(int fd)
3337 {
3338 #ifdef WIN32_NO_SOCKETS
3339     return close(fd);
3340 #else
3341     return my_close(fd);
3342 #endif
3343 }
3344 
3345 DllExport int
3346 win32_eof(int fd)
3347 {
3348     return eof(fd);
3349 }
3350 
3351 DllExport int
3352 win32_isatty(int fd)
3353 {
3354     /* The Microsoft isatty() function returns true for *all*
3355      * character mode devices, including "nul".  Our implementation
3356      * should only return true if the handle has a console buffer.
3357      */
3358     DWORD mode;
3359     HANDLE fh = (HANDLE)_get_osfhandle(fd);
3360     if (fh == (HANDLE)-1) {
3361         /* errno is already set to EBADF */
3362         return 0;
3363     }
3364 
3365     if (GetConsoleMode(fh, &mode))
3366         return 1;
3367 
3368     errno = ENOTTY;
3369     return 0;
3370 }
3371 
3372 DllExport int
3373 win32_dup(int fd)
3374 {
3375     return dup(fd);
3376 }
3377 
3378 DllExport int
3379 win32_dup2(int fd1,int fd2)
3380 {
3381     return dup2(fd1,fd2);
3382 }
3383 
3384 DllExport int
3385 win32_read(int fd, void *buf, unsigned int cnt)
3386 {
3387     return read(fd, buf, cnt);
3388 }
3389 
3390 DllExport int
3391 win32_write(int fd, const void *buf, unsigned int cnt)
3392 {
3393     return write(fd, buf, cnt);
3394 }
3395 
3396 DllExport int
3397 win32_mkdir(const char *dir, int mode)
3398 {
3399     dTHX;
3400     return mkdir(PerlDir_mapA(dir)); /* just ignore mode */
3401 }
3402 
3403 DllExport int
3404 win32_rmdir(const char *dir)
3405 {
3406     dTHX;
3407     return rmdir(PerlDir_mapA(dir));
3408 }
3409 
3410 DllExport int
3411 win32_chdir(const char *dir)
3412 {
3413     if (!dir || !*dir) {
3414 	errno = ENOENT;
3415 	return -1;
3416     }
3417     return chdir(dir);
3418 }
3419 
3420 DllExport  int
3421 win32_access(const char *path, int mode)
3422 {
3423     dTHX;
3424     return access(PerlDir_mapA(path), mode);
3425 }
3426 
3427 DllExport  int
3428 win32_chmod(const char *path, int mode)
3429 {
3430     dTHX;
3431     return chmod(PerlDir_mapA(path), mode);
3432 }
3433 
3434 
3435 static char *
3436 create_command_line(char *cname, STRLEN clen, const char * const *args)
3437 {
3438     PERL_DEB(dTHX;)
3439     int index, argc;
3440     char *cmd, *ptr;
3441     const char *arg;
3442     STRLEN len = 0;
3443     bool bat_file = FALSE;
3444     bool cmd_shell = FALSE;
3445     bool dumb_shell = FALSE;
3446     bool extra_quotes = FALSE;
3447     bool quote_next = FALSE;
3448 
3449     if (!cname)
3450 	cname = (char*)args[0];
3451 
3452     /* The NT cmd.exe shell has the following peculiarity that needs to be
3453      * worked around.  It strips a leading and trailing dquote when any
3454      * of the following is true:
3455      *    1. the /S switch was used
3456      *    2. there are more than two dquotes
3457      *    3. there is a special character from this set: &<>()@^|
3458      *    4. no whitespace characters within the two dquotes
3459      *    5. string between two dquotes isn't an executable file
3460      * To work around this, we always add a leading and trailing dquote
3461      * to the string, if the first argument is either "cmd.exe" or "cmd",
3462      * and there were at least two or more arguments passed to cmd.exe
3463      * (not including switches).
3464      * XXX the above rules (from "cmd /?") don't seem to be applied
3465      * always, making for the convolutions below :-(
3466      */
3467     if (cname) {
3468 	if (!clen)
3469 	    clen = strlen(cname);
3470 
3471 	if (clen > 4
3472 	    && (stricmp(&cname[clen-4], ".bat") == 0
3473 		|| (stricmp(&cname[clen-4], ".cmd") == 0)))
3474 	{
3475 	    bat_file = TRUE;
3476             len += 3;
3477 	}
3478 	else {
3479 	    char *exe = strrchr(cname, '/');
3480 	    char *exe2 = strrchr(cname, '\\');
3481 	    if (exe2 > exe)
3482 		exe = exe2;
3483 	    if (exe)
3484 		++exe;
3485 	    else
3486 		exe = cname;
3487 	    if (stricmp(exe, "cmd.exe") == 0 || stricmp(exe, "cmd") == 0) {
3488 		cmd_shell = TRUE;
3489 		len += 3;
3490 	    }
3491 	    else if (stricmp(exe, "command.com") == 0
3492 		     || stricmp(exe, "command") == 0)
3493 	    {
3494 		dumb_shell = TRUE;
3495 	    }
3496 	}
3497     }
3498 
3499     DEBUG_p(PerlIO_printf(Perl_debug_log, "Args "));
3500     for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3501 	STRLEN curlen = strlen(arg);
3502 	if (!(arg[0] == '"' && arg[curlen-1] == '"'))
3503 	    len += 2;	/* assume quoting needed (worst case) */
3504 	len += curlen + 1;
3505 	DEBUG_p(PerlIO_printf(Perl_debug_log, "[%s]",arg));
3506     }
3507     DEBUG_p(PerlIO_printf(Perl_debug_log, "\n"));
3508 
3509     argc = index;
3510     Newx(cmd, len, char);
3511     ptr = cmd;
3512 
3513     if (bat_file) {
3514 	*ptr++ = '"';
3515 	extra_quotes = TRUE;
3516     }
3517 
3518     for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3519 	bool do_quote = 0;
3520 	STRLEN curlen = strlen(arg);
3521 
3522 	/* we want to protect empty arguments and ones with spaces with
3523 	 * dquotes, but only if they aren't already there */
3524 	if (!dumb_shell) {
3525 	    if (!curlen) {
3526 		do_quote = 1;
3527 	    }
3528 	    else if (quote_next) {
3529 		/* see if it really is multiple arguments pretending to
3530 		 * be one and force a set of quotes around it */
3531 		if (*find_next_space(arg))
3532 		    do_quote = 1;
3533 	    }
3534 	    else if (!(arg[0] == '"' && curlen > 1 && arg[curlen-1] == '"')) {
3535 		STRLEN i = 0;
3536 		while (i < curlen) {
3537 		    if (isSPACE(arg[i])) {
3538 			do_quote = 1;
3539 		    }
3540 		    else if (arg[i] == '"') {
3541 			do_quote = 0;
3542 			break;
3543 		    }
3544 		    i++;
3545 		}
3546 	    }
3547 	}
3548 
3549 	if (do_quote)
3550 	    *ptr++ = '"';
3551 
3552 	strcpy(ptr, arg);
3553 	ptr += curlen;
3554 
3555 	if (do_quote)
3556 	    *ptr++ = '"';
3557 
3558 	if (args[index+1])
3559 	    *ptr++ = ' ';
3560 
3561     	if (!extra_quotes
3562 	    && cmd_shell
3563 	    && curlen >= 2
3564 	    && *arg  == '/'     /* see if arg is "/c", "/x/c", "/x/d/c" etc. */
3565 	    && stricmp(arg+curlen-2, "/c") == 0)
3566 	{
3567 	    /* is there a next argument? */
3568 	    if (args[index+1]) {
3569 		/* are there two or more next arguments? */
3570 		if (args[index+2]) {
3571 		    *ptr++ = '"';
3572 		    extra_quotes = TRUE;
3573 		}
3574 		else {
3575 		    /* single argument, force quoting if it has spaces */
3576 		    quote_next = TRUE;
3577 		}
3578 	    }
3579 	}
3580     }
3581 
3582     if (extra_quotes)
3583 	*ptr++ = '"';
3584 
3585     *ptr = '\0';
3586 
3587     return cmd;
3588 }
3589 
3590 static const char *exe_extensions[] =
3591   {
3592     ".exe", /* this must be first */
3593     ".cmd",
3594     ".bat"
3595   };
3596 
3597 static char *
3598 qualified_path(const char *cmd, bool other_exts)
3599 {
3600     char *pathstr;
3601     char *fullcmd, *curfullcmd;
3602     STRLEN cmdlen = 0;
3603     int has_slash = 0;
3604 
3605     if (!cmd)
3606 	return NULL;
3607     fullcmd = (char*)cmd;
3608     while (*fullcmd) {
3609 	if (*fullcmd == '/' || *fullcmd == '\\')
3610 	    has_slash++;
3611 	fullcmd++;
3612 	cmdlen++;
3613     }
3614 
3615     /* look in PATH */
3616     {
3617 	dTHX;
3618 	pathstr = PerlEnv_getenv("PATH");
3619     }
3620     /* worst case: PATH is a single directory; we need additional space
3621      * to append "/", ".exe" and trailing "\0" */
3622     Newx(fullcmd, (pathstr ? strlen(pathstr) : 0) + cmdlen + 6, char);
3623     curfullcmd = fullcmd;
3624 
3625     while (1) {
3626 	DWORD res;
3627 
3628 	/* start by appending the name to the current prefix */
3629 	strcpy(curfullcmd, cmd);
3630 	curfullcmd += cmdlen;
3631 
3632 	/* if it doesn't end with '.', or has no extension, try adding
3633 	 * a trailing .exe first */
3634 	if (cmd[cmdlen-1] != '.'
3635 	    && (cmdlen < 4 || cmd[cmdlen-4] != '.'))
3636 	{
3637 	    int i;
3638 	    /* first extension is .exe */
3639 	    int ext_limit = other_exts ? C_ARRAY_LENGTH(exe_extensions) : 1;
3640 	    for (i = 0; i < ext_limit; ++i) {
3641 	        strcpy(curfullcmd, exe_extensions[i]);
3642 	        res = GetFileAttributes(fullcmd);
3643 	        if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3644 		    return fullcmd;
3645 	    }
3646 
3647 	    *curfullcmd = '\0';
3648 	}
3649 
3650 	/* that failed, try the bare name */
3651 	res = GetFileAttributes(fullcmd);
3652 	if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3653 	    return fullcmd;
3654 
3655 	/* quit if no other path exists, or if cmd already has path */
3656 	if (!pathstr || !*pathstr || has_slash)
3657 	    break;
3658 
3659 	/* skip leading semis */
3660 	while (*pathstr == ';')
3661 	    pathstr++;
3662 
3663 	/* build a new prefix from scratch */
3664 	curfullcmd = fullcmd;
3665 	while (*pathstr && *pathstr != ';') {
3666 	    if (*pathstr == '"') {	/* foo;"baz;etc";bar */
3667 		pathstr++;		/* skip initial '"' */
3668 		while (*pathstr && *pathstr != '"') {
3669                     *curfullcmd++ = *pathstr++;
3670 		}
3671 		if (*pathstr)
3672 		    pathstr++;		/* skip trailing '"' */
3673 	    }
3674 	    else {
3675                 *curfullcmd++ = *pathstr++;
3676 	    }
3677 	}
3678 	if (*pathstr)
3679 	    pathstr++;			/* skip trailing semi */
3680 	if (curfullcmd > fullcmd	/* append a dir separator */
3681 	    && curfullcmd[-1] != '/' && curfullcmd[-1] != '\\')
3682 	{
3683 	    *curfullcmd++ = '\\';
3684 	}
3685     }
3686 
3687     Safefree(fullcmd);
3688     return NULL;
3689 }
3690 
3691 /* The following are just place holders.
3692  * Some hosts may provide and environment that the OS is
3693  * not tracking, therefore, these host must provide that
3694  * environment and the current directory to CreateProcess
3695  */
3696 
3697 DllExport void*
3698 win32_get_childenv(void)
3699 {
3700     return NULL;
3701 }
3702 
3703 DllExport void
3704 win32_free_childenv(void* d)
3705 {
3706 }
3707 
3708 DllExport void
3709 win32_clearenv(void)
3710 {
3711     char *envv = GetEnvironmentStrings();
3712     char *cur = envv;
3713     STRLEN len;
3714     while (*cur) {
3715 	char *end = strchr(cur,'=');
3716 	if (end && end != cur) {
3717 	    *end = '\0';
3718 	    SetEnvironmentVariable(cur, NULL);
3719 	    *end = '=';
3720 	    cur = end + strlen(end+1)+2;
3721 	}
3722 	else if ((len = strlen(cur)))
3723 	    cur += len+1;
3724     }
3725     FreeEnvironmentStrings(envv);
3726 }
3727 
3728 DllExport char*
3729 win32_get_childdir(void)
3730 {
3731     char* ptr;
3732     char szfilename[MAX_PATH+1];
3733 
3734     GetCurrentDirectoryA(MAX_PATH+1, szfilename);
3735     Newx(ptr, strlen(szfilename)+1, char);
3736     strcpy(ptr, szfilename);
3737     return ptr;
3738 }
3739 
3740 DllExport void
3741 win32_free_childdir(char* d)
3742 {
3743     Safefree(d);
3744 }
3745 
3746 
3747 /* XXX this needs to be made more compatible with the spawnvp()
3748  * provided by the various RTLs.  In particular, searching for
3749  * *.{com,bat,cmd} files (as done by the RTLs) is unimplemented.
3750  * This doesn't significantly affect perl itself, because we
3751  * always invoke things using PERL5SHELL if a direct attempt to
3752  * spawn the executable fails.
3753  *
3754  * XXX splitting and rejoining the commandline between do_aspawn()
3755  * and win32_spawnvp() could also be avoided.
3756  */
3757 
3758 DllExport int
3759 win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
3760 {
3761 #ifdef USE_RTL_SPAWNVP
3762     return _spawnvp(mode, cmdname, (char * const *)argv);
3763 #else
3764     return do_spawnvp_handles(mode, cmdname, argv, NULL);
3765 #endif
3766 }
3767 
3768 static int
3769 do_spawnvp_handles(int mode, const char *cmdname, const char *const *argv,
3770                 const int *handles) {
3771     dTHXa(NULL);
3772     int ret;
3773     void* env;
3774     char* dir;
3775     child_IO_table tbl;
3776     STARTUPINFO StartupInfo;
3777     PROCESS_INFORMATION ProcessInformation;
3778     DWORD create = 0;
3779     char *cmd;
3780     char *fullcmd = NULL;
3781     char *cname = (char *)cmdname;
3782     STRLEN clen = 0;
3783 
3784     if (cname) {
3785 	clen = strlen(cname);
3786 	/* if command name contains dquotes, must remove them */
3787 	if (strchr(cname, '"')) {
3788 	    cmd = cname;
3789 	    Newx(cname,clen+1,char);
3790 	    clen = 0;
3791 	    while (*cmd) {
3792 		if (*cmd != '"') {
3793 		    cname[clen] = *cmd;
3794 		    ++clen;
3795 		}
3796 		++cmd;
3797 	    }
3798 	    cname[clen] = '\0';
3799 	}
3800     }
3801 
3802     cmd = create_command_line(cname, clen, argv);
3803 
3804     aTHXa(PERL_GET_THX);
3805     env = PerlEnv_get_childenv();
3806     dir = PerlEnv_get_childdir();
3807 
3808     switch(mode) {
3809     case P_NOWAIT:	/* asynch + remember result */
3810 	if (w32_num_children >= MAXIMUM_WAIT_OBJECTS) {
3811 	    errno = EAGAIN;
3812 	    ret = -1;
3813 	    goto RETVAL;
3814 	}
3815 	/* Create a new process group so we can use GenerateConsoleCtrlEvent()
3816 	 * in win32_kill()
3817 	 */
3818         create |= CREATE_NEW_PROCESS_GROUP;
3819 	/* FALL THROUGH */
3820 
3821     case P_WAIT:	/* synchronous execution */
3822 	break;
3823     default:		/* invalid mode */
3824 	errno = EINVAL;
3825 	ret = -1;
3826 	goto RETVAL;
3827     }
3828 
3829     memset(&StartupInfo,0,sizeof(StartupInfo));
3830     StartupInfo.cb = sizeof(StartupInfo);
3831     memset(&tbl,0,sizeof(tbl));
3832     PerlEnv_get_child_IO(&tbl);
3833     StartupInfo.dwFlags		= tbl.dwFlags;
3834     StartupInfo.dwX		= tbl.dwX;
3835     StartupInfo.dwY		= tbl.dwY;
3836     StartupInfo.dwXSize		= tbl.dwXSize;
3837     StartupInfo.dwYSize		= tbl.dwYSize;
3838     StartupInfo.dwXCountChars	= tbl.dwXCountChars;
3839     StartupInfo.dwYCountChars	= tbl.dwYCountChars;
3840     StartupInfo.dwFillAttribute	= tbl.dwFillAttribute;
3841     StartupInfo.wShowWindow	= tbl.wShowWindow;
3842     StartupInfo.hStdInput	= handles && handles[0] != -1 ?
3843             (HANDLE)_get_osfhandle(handles[0]) : tbl.childStdIn;
3844     StartupInfo.hStdOutput	= handles && handles[1] != -1 ?
3845             (HANDLE)_get_osfhandle(handles[1]) : tbl.childStdOut;
3846     StartupInfo.hStdError	= handles && handles[2] != -1 ?
3847 	    (HANDLE)_get_osfhandle(handles[2]) : tbl.childStdErr;
3848     if (StartupInfo.hStdInput == INVALID_HANDLE_VALUE &&
3849 	StartupInfo.hStdOutput == INVALID_HANDLE_VALUE &&
3850 	StartupInfo.hStdError == INVALID_HANDLE_VALUE)
3851     {
3852 	create |= CREATE_NEW_CONSOLE;
3853     }
3854     else {
3855 	StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
3856     }
3857     if (w32_use_showwindow) {
3858         StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
3859         StartupInfo.wShowWindow = w32_showwindow;
3860     }
3861 
3862     DEBUG_p(PerlIO_printf(Perl_debug_log, "Spawning [%s] with [%s]\n",
3863 			  cname,cmd));
3864 RETRY:
3865     if (!CreateProcess(cname,		/* search PATH to find executable */
3866 		       cmd,		/* executable, and its arguments */
3867 		       NULL,		/* process attributes */
3868 		       NULL,		/* thread attributes */
3869 		       TRUE,		/* inherit handles */
3870 		       create,		/* creation flags */
3871 		       (LPVOID)env,	/* inherit environment */
3872 		       dir,		/* inherit cwd */
3873 		       &StartupInfo,
3874 		       &ProcessInformation))
3875     {
3876 	/* initial NULL argument to CreateProcess() does a PATH
3877 	 * search, but it always first looks in the directory
3878 	 * where the current process was started, which behavior
3879 	 * is undesirable for backward compatibility.  So we
3880 	 * jump through our own hoops by picking out the path
3881 	 * we really want it to use. */
3882 	if (!fullcmd) {
3883 	    fullcmd = qualified_path(cname, FALSE);
3884 	    if (fullcmd) {
3885 		if (cname != cmdname)
3886 		    Safefree(cname);
3887 		cname = fullcmd;
3888 		DEBUG_p(PerlIO_printf(Perl_debug_log,
3889 				      "Retrying [%s] with same args\n",
3890 				      cname));
3891 		goto RETRY;
3892 	    }
3893 	}
3894 	errno = ENOENT;
3895 	ret = -1;
3896 	goto RETVAL;
3897     }
3898 
3899     if (mode == P_NOWAIT) {
3900 	/* asynchronous spawn -- store handle, return PID */
3901 	ret = (int)ProcessInformation.dwProcessId;
3902 
3903 	w32_child_handles[w32_num_children] = ProcessInformation.hProcess;
3904 	w32_child_pids[w32_num_children] = (DWORD)ret;
3905 	++w32_num_children;
3906     }
3907     else  {
3908 	DWORD status;
3909 	win32_msgwait(aTHX_ 1, &ProcessInformation.hProcess, INFINITE, NULL);
3910 	/* FIXME: if msgwait returned due to message perhaps forward the
3911 	   "signal" to the process
3912          */
3913 	GetExitCodeProcess(ProcessInformation.hProcess, &status);
3914 	ret = (int)status;
3915 	CloseHandle(ProcessInformation.hProcess);
3916     }
3917 
3918     CloseHandle(ProcessInformation.hThread);
3919 
3920 RETVAL:
3921     PerlEnv_free_childenv(env);
3922     PerlEnv_free_childdir(dir);
3923     Safefree(cmd);
3924     if (cname != cmdname)
3925 	Safefree(cname);
3926     return ret;
3927 }
3928 
3929 DllExport int
3930 win32_execv(const char *cmdname, const char *const *argv)
3931 {
3932 #ifdef USE_ITHREADS
3933     dTHX;
3934     /* if this is a pseudo-forked child, we just want to spawn
3935      * the new program, and return */
3936     if (w32_pseudo_id)
3937 	return _spawnv(P_WAIT, cmdname, argv);
3938 #endif
3939     return _execv(cmdname, argv);
3940 }
3941 
3942 DllExport int
3943 win32_execvp(const char *cmdname, const char *const *argv)
3944 {
3945 #ifdef USE_ITHREADS
3946     dTHX;
3947     /* if this is a pseudo-forked child, we just want to spawn
3948      * the new program, and return */
3949     if (w32_pseudo_id) {
3950 	int status = win32_spawnvp(P_WAIT, cmdname, (const char *const *)argv);
3951 	if (status != -1) {
3952 	    my_exit(status);
3953 	    return 0;
3954 	}
3955 	else
3956 	    return status;
3957     }
3958 #endif
3959     return _execvp(cmdname, argv);
3960 }
3961 
3962 DllExport void
3963 win32_perror(const char *str)
3964 {
3965     perror(str);
3966 }
3967 
3968 DllExport void
3969 win32_setbuf(FILE *pf, char *buf)
3970 {
3971     setbuf(pf, buf);
3972 }
3973 
3974 DllExport int
3975 win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
3976 {
3977     return setvbuf(pf, buf, type, size);
3978 }
3979 
3980 DllExport int
3981 win32_flushall(void)
3982 {
3983     return flushall();
3984 }
3985 
3986 DllExport int
3987 win32_fcloseall(void)
3988 {
3989     return fcloseall();
3990 }
3991 
3992 DllExport char*
3993 win32_fgets(char *s, int n, FILE *pf)
3994 {
3995     return fgets(s, n, pf);
3996 }
3997 
3998 DllExport char*
3999 win32_gets(char *s)
4000 {
4001     return gets(s);
4002 }
4003 
4004 DllExport int
4005 win32_fgetc(FILE *pf)
4006 {
4007     return fgetc(pf);
4008 }
4009 
4010 DllExport int
4011 win32_putc(int c, FILE *pf)
4012 {
4013     return putc(c,pf);
4014 }
4015 
4016 DllExport int
4017 win32_puts(const char *s)
4018 {
4019     return puts(s);
4020 }
4021 
4022 DllExport int
4023 win32_getchar(void)
4024 {
4025     return getchar();
4026 }
4027 
4028 DllExport int
4029 win32_putchar(int c)
4030 {
4031     return putchar(c);
4032 }
4033 
4034 #ifdef MYMALLOC
4035 
4036 #ifndef USE_PERL_SBRK
4037 
4038 static char *committed = NULL;		/* XXX threadead */
4039 static char *base      = NULL;		/* XXX threadead */
4040 static char *reserved  = NULL;		/* XXX threadead */
4041 static char *brk       = NULL;		/* XXX threadead */
4042 static DWORD pagesize  = 0;		/* XXX threadead */
4043 
4044 void *
4045 sbrk(ptrdiff_t need)
4046 {
4047  void *result;
4048  if (!pagesize)
4049   {SYSTEM_INFO info;
4050    GetSystemInfo(&info);
4051    /* Pretend page size is larger so we don't perpetually
4052     * call the OS to commit just one page ...
4053     */
4054    pagesize = info.dwPageSize << 3;
4055   }
4056  if (brk+need >= reserved)
4057   {
4058    DWORD size = brk+need-reserved;
4059    char *addr;
4060    char *prev_committed = NULL;
4061    if (committed && reserved && committed < reserved)
4062     {
4063      /* Commit last of previous chunk cannot span allocations */
4064      addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
4065      if (addr)
4066       {
4067       /* Remember where we committed from in case we want to decommit later */
4068       prev_committed = committed;
4069       committed = reserved;
4070       }
4071     }
4072    /* Reserve some (more) space
4073     * Contiguous blocks give us greater efficiency, so reserve big blocks -
4074     * this is only address space not memory...
4075     * Note this is a little sneaky, 1st call passes NULL as reserved
4076     * so lets system choose where we start, subsequent calls pass
4077     * the old end address so ask for a contiguous block
4078     */
4079 sbrk_reserve:
4080    if (size < 64*1024*1024)
4081     size = 64*1024*1024;
4082    size = ((size + pagesize - 1) / pagesize) * pagesize;
4083    addr  = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
4084    if (addr)
4085     {
4086      reserved = addr+size;
4087      if (!base)
4088       base = addr;
4089      if (!committed)
4090       committed = base;
4091      if (!brk)
4092       brk = committed;
4093     }
4094    else if (reserved)
4095     {
4096       /* The existing block could not be extended far enough, so decommit
4097        * anything that was just committed above and start anew */
4098       if (prev_committed)
4099        {
4100        if (!VirtualFree(prev_committed,reserved-prev_committed,MEM_DECOMMIT))
4101         return (void *) -1;
4102        }
4103       reserved = base = committed = brk = NULL;
4104       size = need;
4105       goto sbrk_reserve;
4106     }
4107    else
4108     {
4109      return (void *) -1;
4110     }
4111   }
4112  result = brk;
4113  brk += need;
4114  if (brk > committed)
4115   {
4116    DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
4117    char *addr;
4118    if (committed+size > reserved)
4119     size = reserved-committed;
4120    addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
4121    if (addr)
4122     committed += size;
4123    else
4124     return (void *) -1;
4125   }
4126  return result;
4127 }
4128 
4129 #endif
4130 #endif
4131 
4132 DllExport void*
4133 win32_malloc(size_t size)
4134 {
4135     return malloc(size);
4136 }
4137 
4138 DllExport void*
4139 win32_calloc(size_t numitems, size_t size)
4140 {
4141     return calloc(numitems,size);
4142 }
4143 
4144 DllExport void*
4145 win32_realloc(void *block, size_t size)
4146 {
4147     return realloc(block,size);
4148 }
4149 
4150 DllExport void
4151 win32_free(void *block)
4152 {
4153     free(block);
4154 }
4155 
4156 
4157 DllExport int
4158 win32_open_osfhandle(intptr_t handle, int flags)
4159 {
4160     return _open_osfhandle(handle, flags);
4161 }
4162 
4163 DllExport intptr_t
4164 win32_get_osfhandle(int fd)
4165 {
4166     return (intptr_t)_get_osfhandle(fd);
4167 }
4168 
4169 DllExport FILE *
4170 win32_fdupopen(FILE *pf)
4171 {
4172     FILE* pfdup;
4173     fpos_t pos;
4174     char mode[3];
4175     int fileno = win32_dup(win32_fileno(pf));
4176 
4177     /* open the file in the same mode */
4178     if (PERLIO_FILE_flag(pf) & PERLIO_FILE_flag_RD) {
4179 	mode[0] = 'r';
4180 	mode[1] = 0;
4181     }
4182     else if (PERLIO_FILE_flag(pf) & PERLIO_FILE_flag_WR) {
4183 	mode[0] = 'a';
4184 	mode[1] = 0;
4185     }
4186     else if (PERLIO_FILE_flag(pf) & PERLIO_FILE_flag_RW) {
4187 	mode[0] = 'r';
4188 	mode[1] = '+';
4189 	mode[2] = 0;
4190     }
4191 
4192     /* it appears that the binmode is attached to the
4193      * file descriptor so binmode files will be handled
4194      * correctly
4195      */
4196     pfdup = win32_fdopen(fileno, mode);
4197 
4198     /* move the file pointer to the same position */
4199     if (!fgetpos(pf, &pos)) {
4200 	fsetpos(pfdup, &pos);
4201     }
4202     return pfdup;
4203 }
4204 
4205 DllExport void*
4206 win32_dynaload(const char* filename)
4207 {
4208     dTHXa(NULL);
4209     char buf[MAX_PATH+1];
4210     const char *first;
4211 
4212     /* LoadLibrary() doesn't recognize forward slashes correctly,
4213      * so turn 'em back. */
4214     first = strchr(filename, '/');
4215     if (first) {
4216 	STRLEN len = strlen(filename);
4217 	if (len <= MAX_PATH) {
4218 	    strcpy(buf, filename);
4219 	    filename = &buf[first - filename];
4220 	    while (*filename) {
4221 		if (*filename == '/')
4222 		    *(char*)filename = '\\';
4223 		++filename;
4224 	    }
4225 	    filename = buf;
4226 	}
4227     }
4228     aTHXa(PERL_GET_THX);
4229     return LoadLibraryExA(PerlDir_mapA(filename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
4230 }
4231 
4232 XS(w32_SetChildShowWindow)
4233 {
4234     dXSARGS;
4235     BOOL use_showwindow = w32_use_showwindow;
4236     /* use "unsigned short" because Perl has redefined "WORD" */
4237     unsigned short showwindow = w32_showwindow;
4238 
4239     if (items > 1)
4240 	croak_xs_usage(cv, "[showwindow]");
4241 
4242     if (items == 0 || !SvOK(ST(0)))
4243         w32_use_showwindow = FALSE;
4244     else {
4245         w32_use_showwindow = TRUE;
4246         w32_showwindow = (unsigned short)SvIV(ST(0));
4247     }
4248 
4249     EXTEND(SP, 1);
4250     if (use_showwindow)
4251         ST(0) = sv_2mortal(newSViv(showwindow));
4252     else
4253         ST(0) = &PL_sv_undef;
4254     XSRETURN(1);
4255 }
4256 
4257 
4258 #ifdef PERL_IS_MINIPERL
4259 /* shelling out is much slower, full perl uses Win32.pm */
4260 XS(w32_GetCwd)
4261 {
4262     dXSARGS;
4263     /* Make the host for current directory */
4264     char* ptr = PerlEnv_get_childdir();
4265     /*
4266      * If ptr != Nullch
4267      *   then it worked, set PV valid,
4268      *   else return 'undef'
4269      */
4270     if (ptr) {
4271 	SV *sv = sv_newmortal();
4272 	sv_setpv(sv, ptr);
4273 	PerlEnv_free_childdir(ptr);
4274 
4275 #ifndef INCOMPLETE_TAINTS
4276 	SvTAINTED_on(sv);
4277 #endif
4278 
4279 	ST(0) = sv;
4280 	XSRETURN(1);
4281     }
4282     XSRETURN_UNDEF;
4283 }
4284 #endif
4285 
4286 void
4287 Perl_init_os_extras(void)
4288 {
4289     dTHXa(NULL);
4290     char *file = __FILE__;
4291 
4292     /* Initialize Win32CORE if it has been statically linked. */
4293 #ifndef PERL_IS_MINIPERL
4294     void (*pfn_init)(pTHX);
4295     HMODULE module = (HMODULE)((w32_perldll_handle == INVALID_HANDLE_VALUE)
4296                                ? GetModuleHandle(NULL)
4297                                : w32_perldll_handle);
4298     pfn_init = (void (*)(pTHX))GetProcAddress(module, "init_Win32CORE");
4299     aTHXa(PERL_GET_THX);
4300     if (pfn_init)
4301         pfn_init(aTHX);
4302 #else
4303     aTHXa(PERL_GET_THX);
4304 #endif
4305 
4306     newXS("Win32::SetChildShowWindow", w32_SetChildShowWindow, file);
4307 #ifdef PERL_IS_MINIPERL
4308     newXS("Win32::GetCwd", w32_GetCwd, file);
4309 #endif
4310 }
4311 
4312 void *
4313 win32_signal_context(void)
4314 {
4315     dTHX;
4316 #ifdef MULTIPLICITY
4317     if (!my_perl) {
4318 	my_perl = PL_curinterp;
4319 	PERL_SET_THX(my_perl);
4320     }
4321     return my_perl;
4322 #else
4323     return PL_curinterp;
4324 #endif
4325 }
4326 
4327 
4328 BOOL WINAPI
4329 win32_ctrlhandler(DWORD dwCtrlType)
4330 {
4331 #ifdef MULTIPLICITY
4332     dTHXa(PERL_GET_SIG_CONTEXT);
4333 
4334     if (!my_perl)
4335 	return FALSE;
4336 #endif
4337 
4338     switch(dwCtrlType) {
4339     case CTRL_CLOSE_EVENT:
4340      /*  A signal that the system sends to all processes attached to a console when
4341          the user closes the console (either by choosing the Close command from the
4342          console window's System menu, or by choosing the End Task command from the
4343          Task List
4344       */
4345 	if (do_raise(aTHX_ 1))	      /* SIGHUP */
4346 	    sig_terminate(aTHX_ 1);
4347 	return TRUE;
4348 
4349     case CTRL_C_EVENT:
4350 	/*  A CTRL+c signal was received */
4351 	if (do_raise(aTHX_ SIGINT))
4352 	    sig_terminate(aTHX_ SIGINT);
4353 	return TRUE;
4354 
4355     case CTRL_BREAK_EVENT:
4356 	/*  A CTRL+BREAK signal was received */
4357 	if (do_raise(aTHX_ SIGBREAK))
4358 	    sig_terminate(aTHX_ SIGBREAK);
4359 	return TRUE;
4360 
4361     case CTRL_LOGOFF_EVENT:
4362       /*  A signal that the system sends to all console processes when a user is logging
4363           off. This signal does not indicate which user is logging off, so no
4364           assumptions can be made.
4365        */
4366 	break;
4367     case CTRL_SHUTDOWN_EVENT:
4368       /*  A signal that the system sends to all console processes when the system is
4369           shutting down.
4370        */
4371 	if (do_raise(aTHX_ SIGTERM))
4372 	    sig_terminate(aTHX_ SIGTERM);
4373 	return TRUE;
4374     default:
4375 	break;
4376     }
4377     return FALSE;
4378 }
4379 
4380 
4381 #ifdef SET_INVALID_PARAMETER_HANDLER
4382 #  include <crtdbg.h>
4383 #endif
4384 
4385 static void
4386 ansify_path(void)
4387 {
4388     size_t len;
4389     char *ansi_path;
4390     WCHAR *wide_path;
4391     WCHAR *wide_dir;
4392 
4393     /* fetch Unicode version of PATH */
4394     len = 2000;
4395     wide_path = (WCHAR*)win32_malloc(len*sizeof(WCHAR));
4396     while (wide_path) {
4397         size_t newlen = GetEnvironmentVariableW(L"PATH", wide_path, len);
4398         if (newlen == 0) {
4399             win32_free(wide_path);
4400             return;
4401         }
4402         if (newlen < len)
4403             break;
4404         len = newlen;
4405         wide_path = (WCHAR*)win32_realloc(wide_path, len*sizeof(WCHAR));
4406     }
4407     if (!wide_path)
4408         return;
4409 
4410     /* convert to ANSI pathnames */
4411     wide_dir = wide_path;
4412     ansi_path = NULL;
4413     while (wide_dir) {
4414         WCHAR *sep = wcschr(wide_dir, ';');
4415         char *ansi_dir;
4416         size_t ansi_len;
4417         size_t wide_len;
4418 
4419         if (sep)
4420             *sep++ = '\0';
4421 
4422         /* remove quotes around pathname */
4423         if (*wide_dir == '"')
4424             ++wide_dir;
4425         wide_len = wcslen(wide_dir);
4426         if (wide_len && wide_dir[wide_len-1] == '"')
4427             wide_dir[wide_len-1] = '\0';
4428 
4429         /* append ansi_dir to ansi_path */
4430         ansi_dir = win32_ansipath(wide_dir);
4431         ansi_len = strlen(ansi_dir);
4432         if (ansi_path) {
4433             size_t newlen = len + 1 + ansi_len;
4434             ansi_path = (char*)win32_realloc(ansi_path, newlen+1);
4435             if (!ansi_path)
4436                 break;
4437             ansi_path[len] = ';';
4438             memcpy(ansi_path+len+1, ansi_dir, ansi_len+1);
4439             len = newlen;
4440         }
4441         else {
4442             len = ansi_len;
4443             ansi_path = (char*)win32_malloc(5+len+1);
4444             if (!ansi_path)
4445                 break;
4446             memcpy(ansi_path, "PATH=", 5);
4447             memcpy(ansi_path+5, ansi_dir, len+1);
4448             len += 5;
4449         }
4450         win32_free(ansi_dir);
4451         wide_dir = sep;
4452     }
4453 
4454     if (ansi_path) {
4455         /* Update C RTL environ array.  This will only have full effect if
4456          * perl_parse() is later called with `environ` as the `env` argument.
4457          * Otherwise S_init_postdump_symbols() will overwrite PATH again.
4458          *
4459          * We do have to ansify() the PATH before Perl has been fully
4460          * initialized because S_find_script() uses the PATH when perl
4461          * is being invoked with the -S option.  This happens before %ENV
4462          * is initialized in S_init_postdump_symbols().
4463          *
4464          * XXX Is this a bug? Should S_find_script() use the environment
4465          * XXX passed in the `env` arg to parse_perl()?
4466          */
4467         putenv(ansi_path);
4468         /* Keep system environment in sync because S_init_postdump_symbols()
4469          * will not call mg_set() if it initializes %ENV from `environ`.
4470          */
4471         SetEnvironmentVariableA("PATH", ansi_path+5);
4472         win32_free(ansi_path);
4473     }
4474     win32_free(wide_path);
4475 }
4476 
4477 void
4478 Perl_win32_init(int *argcp, char ***argvp)
4479 {
4480 #ifdef SET_INVALID_PARAMETER_HANDLER
4481     _invalid_parameter_handler oldHandler, newHandler;
4482     newHandler = my_invalid_parameter_handler;
4483     oldHandler = _set_invalid_parameter_handler(newHandler);
4484     _CrtSetReportMode(_CRT_ASSERT, 0);
4485 #endif
4486     /* Disable floating point errors, Perl will trap the ones we
4487      * care about.  VC++ RTL defaults to switching these off
4488      * already, but some RTLs don't.  Since we don't
4489      * want to be at the vendor's whim on the default, we set
4490      * it explicitly here.
4491      */
4492 #if !defined(__GNUC__)
4493     _control87(MCW_EM, MCW_EM);
4494 #endif
4495     MALLOC_INIT;
4496 
4497     /* When the manifest resource requests Common-Controls v6 then
4498      * user32.dll no longer registers all the Windows classes used for
4499      * standard controls but leaves some of them to be registered by
4500      * comctl32.dll.  InitCommonControls() doesn't do anything but calling
4501      * it makes sure comctl32.dll gets loaded into the process and registers
4502      * the standard control classes.  Without this even normal Windows APIs
4503      * like MessageBox() can fail under some versions of Windows XP.
4504      */
4505     InitCommonControls();
4506 
4507     g_osver.dwOSVersionInfoSize = sizeof(g_osver);
4508     GetVersionEx(&g_osver);
4509 
4510 #ifdef WIN32_DYN_IOINFO_SIZE
4511     {
4512 	Size_t ioinfo_size = _msize((void*)__pioinfo[0]);;
4513 	if((SSize_t)ioinfo_size <= 0) { /* -1 is err */
4514 	    fprintf(stderr, "panic: invalid size for ioinfo\n"); /* no interp */
4515 	    exit(1);
4516 	}
4517 	ioinfo_size /= IOINFO_ARRAY_ELTS;
4518 	w32_ioinfo_size = ioinfo_size;
4519     }
4520 #endif
4521 
4522     ansify_path();
4523 
4524 #ifndef WIN32_NO_REGISTRY
4525     {
4526 	LONG retval;
4527 	retval = RegOpenKeyExW(HKEY_CURRENT_USER, L"SOFTWARE\\Perl", 0, KEY_READ, &HKCU_Perl_hnd);
4528 	if (retval != ERROR_SUCCESS) {
4529 	    HKCU_Perl_hnd = NULL;
4530 	}
4531 	retval = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Perl", 0, KEY_READ, &HKLM_Perl_hnd);
4532 	if (retval != ERROR_SUCCESS) {
4533 	    HKLM_Perl_hnd = NULL;
4534 	}
4535     }
4536 #endif
4537 }
4538 
4539 void
4540 Perl_win32_term(void)
4541 {
4542     HINTS_REFCNT_TERM;
4543     OP_REFCNT_TERM;
4544     PERLIO_TERM;
4545     MALLOC_TERM;
4546     LOCALE_TERM;
4547 #ifndef WIN32_NO_REGISTRY
4548     /* handles might be NULL, RegCloseKey then returns ERROR_INVALID_HANDLE
4549        but no point of checking and we can't die() at this point */
4550     RegCloseKey(HKLM_Perl_hnd);
4551     RegCloseKey(HKCU_Perl_hnd);
4552     /* the handles are in an undefined state until the next PERL_SYS_INIT3 */
4553 #endif
4554 }
4555 
4556 void
4557 win32_get_child_IO(child_IO_table* ptbl)
4558 {
4559     ptbl->childStdIn	= GetStdHandle(STD_INPUT_HANDLE);
4560     ptbl->childStdOut	= GetStdHandle(STD_OUTPUT_HANDLE);
4561     ptbl->childStdErr	= GetStdHandle(STD_ERROR_HANDLE);
4562 }
4563 
4564 Sighandler_t
4565 win32_signal(int sig, Sighandler_t subcode)
4566 {
4567     dTHXa(NULL);
4568     if (sig < SIG_SIZE) {
4569 	int save_errno = errno;
4570 	Sighandler_t result;
4571 #ifdef SET_INVALID_PARAMETER_HANDLER
4572 	/* Silence our invalid parameter handler since we expect to make some
4573 	 * calls with invalid signal numbers giving a SIG_ERR result. */
4574 	BOOL oldvalue = set_silent_invalid_parameter_handler(TRUE);
4575 #endif
4576 	result = signal(sig, subcode);
4577 #ifdef SET_INVALID_PARAMETER_HANDLER
4578 	set_silent_invalid_parameter_handler(oldvalue);
4579 #endif
4580 	aTHXa(PERL_GET_THX);
4581 	if (result == SIG_ERR) {
4582 	    result = w32_sighandler[sig];
4583 	    errno = save_errno;
4584 	}
4585 	w32_sighandler[sig] = subcode;
4586 	return result;
4587     }
4588     else {
4589 	errno = EINVAL;
4590 	return SIG_ERR;
4591     }
4592 }
4593 
4594 /* The PerlMessageWindowClass's WindowProc */
4595 LRESULT CALLBACK
4596 win32_message_window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
4597 {
4598     return win32_process_message(hwnd, msg, wParam, lParam) ?
4599         0 : DefWindowProc(hwnd, msg, wParam, lParam);
4600 }
4601 
4602 /* The real message handler. Can be called with
4603  * hwnd == NULL to process our thread messages. Returns TRUE for any messages
4604  * that it processes */
4605 static LRESULT
4606 win32_process_message(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
4607 {
4608     /* BEWARE. The context retrieved using dTHX; is the context of the
4609      * 'parent' thread during the CreateWindow() phase - i.e. for all messages
4610      * up to and including WM_CREATE.  If it ever happens that you need the
4611      * 'child' context before this, then it needs to be passed into
4612      * win32_create_message_window(), and passed to the WM_NCCREATE handler
4613      * from the lparam of CreateWindow().  It could then be stored/retrieved
4614      * using [GS]etWindowLongPtr(... GWLP_USERDATA ...), possibly eliminating
4615      * the dTHX calls here. */
4616     /* XXX For now it is assumed that the overhead of the dTHX; for what
4617      * are relativley infrequent code-paths, is better than the added
4618      * complexity of getting the correct context passed into
4619      * win32_create_message_window() */
4620     dTHX;
4621 
4622     switch(msg) {
4623 
4624 #ifdef USE_ITHREADS
4625         case WM_USER_MESSAGE: {
4626             long child = find_pseudo_pid(aTHX_ (int)wParam);
4627             if (child >= 0) {
4628                 w32_pseudo_child_message_hwnds[child] = (HWND)lParam;
4629                 return 1;
4630             }
4631             break;
4632         }
4633 #endif
4634 
4635         case WM_USER_KILL: {
4636             /* We use WM_USER_KILL to fake kill() with other signals */
4637             int sig = (int)wParam;
4638             if (do_raise(aTHX_ sig))
4639                 sig_terminate(aTHX_ sig);
4640 
4641             return 1;
4642         }
4643 
4644         case WM_TIMER: {
4645             /* alarm() is a one-shot but SetTimer() repeats so kill it */
4646             if (w32_timerid && w32_timerid==(UINT)wParam) {
4647                 KillTimer(w32_message_hwnd, w32_timerid);
4648                 w32_timerid=0;
4649 
4650                 /* Now fake a call to signal handler */
4651                 if (do_raise(aTHX_ 14))
4652                     sig_terminate(aTHX_ 14);
4653 
4654                 return 1;
4655             }
4656             break;
4657         }
4658 
4659         default:
4660             break;
4661 
4662     } /* switch */
4663 
4664     /* Above or other stuff may have set a signal flag, and we may not have
4665      * been called from win32_async_check() (e.g. some other GUI's message
4666      * loop.  BUT DON'T dispatch signals here: If someone has set a SIGALRM
4667      * handler that die's, and the message loop that calls here is wrapped
4668      * in an eval, then you may well end up with orphaned windows - signals
4669      * are dispatched by win32_async_check() */
4670 
4671     return 0;
4672 }
4673 
4674 void
4675 win32_create_message_window_class(void)
4676 {
4677     /* create the window class for "message only" windows */
4678     WNDCLASS wc;
4679 
4680     Zero(&wc, 1, wc);
4681     wc.lpfnWndProc = win32_message_window_proc;
4682     wc.hInstance = (HINSTANCE)GetModuleHandle(NULL);
4683     wc.lpszClassName = "PerlMessageWindowClass";
4684 
4685     /* second and subsequent calls will fail, but class
4686      * will already be registered */
4687     RegisterClass(&wc);
4688 }
4689 
4690 HWND
4691 win32_create_message_window(void)
4692 {
4693     win32_create_message_window_class();
4694     return CreateWindow("PerlMessageWindowClass", "PerlMessageWindow",
4695                         0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
4696 }
4697 
4698 #ifdef HAVE_INTERP_INTERN
4699 
4700 static void
4701 win32_csighandler(int sig)
4702 {
4703 #if 0
4704     dTHXa(PERL_GET_SIG_CONTEXT);
4705     Perl_warn(aTHX_ "Got signal %d",sig);
4706 #endif
4707     /* Does nothing */
4708 }
4709 
4710 #if defined(__MINGW32__) && defined(__cplusplus)
4711 #define CAST_HWND__(x) (HWND__*)(x)
4712 #else
4713 #define CAST_HWND__(x) x
4714 #endif
4715 
4716 void
4717 Perl_sys_intern_init(pTHX)
4718 {
4719     dVAR;
4720     int i;
4721 
4722     w32_perlshell_tokens	= NULL;
4723     w32_perlshell_vec		= (char**)NULL;
4724     w32_perlshell_items		= 0;
4725     w32_fdpid			= newAV();
4726     Newx(w32_children, 1, child_tab);
4727     w32_num_children		= 0;
4728 #  ifdef USE_ITHREADS
4729     w32_pseudo_id		= 0;
4730     Newx(w32_pseudo_children, 1, pseudo_child_tab);
4731     w32_num_pseudo_children	= 0;
4732 #  endif
4733     w32_timerid                 = 0;
4734     w32_message_hwnd            = CAST_HWND__(INVALID_HANDLE_VALUE);
4735     w32_poll_count              = 0;
4736 #ifdef PERL_IS_MINIPERL
4737     w32_sloppystat              = TRUE;
4738 #else
4739     w32_sloppystat              = FALSE;
4740 #endif
4741     for (i=0; i < SIG_SIZE; i++) {
4742     	w32_sighandler[i] = SIG_DFL;
4743     }
4744 #  ifdef MULTIPLICITY
4745     if (my_perl == PL_curinterp) {
4746 #  else
4747     {
4748 #  endif
4749 	/* Force C runtime signal stuff to set its console handler */
4750 	signal(SIGINT,win32_csighandler);
4751 	signal(SIGBREAK,win32_csighandler);
4752 
4753         /* We spawn asynchronous processes with the CREATE_NEW_PROCESS_GROUP
4754          * flag.  This has the side-effect of disabling Ctrl-C events in all
4755          * processes in this group.
4756          * We re-enable Ctrl-C handling by calling SetConsoleCtrlHandler()
4757          * with a NULL handler.
4758          */
4759         SetConsoleCtrlHandler(NULL,FALSE);
4760 
4761 	/* Push our handler on top */
4762 	SetConsoleCtrlHandler(win32_ctrlhandler,TRUE);
4763     }
4764 }
4765 
4766 void
4767 Perl_sys_intern_clear(pTHX)
4768 {
4769     dVAR;
4770 
4771     Safefree(w32_perlshell_tokens);
4772     Safefree(w32_perlshell_vec);
4773     /* NOTE: w32_fdpid is freed by sv_clean_all() */
4774     Safefree(w32_children);
4775     if (w32_timerid) {
4776     	KillTimer(w32_message_hwnd, w32_timerid);
4777     	w32_timerid = 0;
4778     }
4779     if (w32_message_hwnd != NULL && w32_message_hwnd != INVALID_HANDLE_VALUE)
4780         DestroyWindow(w32_message_hwnd);
4781 #  ifdef MULTIPLICITY
4782     if (my_perl == PL_curinterp) {
4783 #  else
4784     {
4785 #  endif
4786 	SetConsoleCtrlHandler(win32_ctrlhandler,FALSE);
4787     }
4788 #  ifdef USE_ITHREADS
4789     Safefree(w32_pseudo_children);
4790 #  endif
4791 }
4792 
4793 #  ifdef USE_ITHREADS
4794 
4795 void
4796 Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
4797 {
4798     PERL_ARGS_ASSERT_SYS_INTERN_DUP;
4799 
4800     dst->perlshell_tokens	= NULL;
4801     dst->perlshell_vec		= (char**)NULL;
4802     dst->perlshell_items	= 0;
4803     dst->fdpid			= newAV();
4804     Newxz(dst->children, 1, child_tab);
4805     dst->pseudo_id		= 0;
4806     Newxz(dst->pseudo_children, 1, pseudo_child_tab);
4807     dst->timerid                = 0;
4808     dst->message_hwnd		= CAST_HWND__(INVALID_HANDLE_VALUE);
4809     dst->poll_count             = 0;
4810     dst->sloppystat             = src->sloppystat;
4811     Copy(src->sigtable,dst->sigtable,SIG_SIZE,Sighandler_t);
4812 }
4813 #  endif /* USE_ITHREADS */
4814 #endif /* HAVE_INTERP_INTERN */
4815