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