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