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