3 * (c) 1995 Microsoft Corporation. All rights reserved.
4 * Developed by hip communications inc.
5 * Portions (c) 1993 Intergraph Corporation. All rights reserved.
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.
10 #define PERLIO_NOT_STDIO 0
11 #define WIN32_LEAN_AND_MEAN
12 #define WIN32IO_IS_STDIO
13 /* for CreateSymbolicLinkA() etc */
14 #define _WIN32_WINNT 0x0601
18 # define Win32_Winsock
24 # define HWND_MESSAGE ((HWND)-3)
27 #ifndef PROCESSOR_ARCHITECTURE_AMD64
28 # define PROCESSOR_ARCHITECTURE_AMD64 9
31 #ifndef WC_NO_BEST_FIT_CHARS
32 # define WC_NO_BEST_FIT_CHARS 0x00000400
42 /* #include "config.h" */
52 #define PERL_NO_GET_CONTEXT
57 /* assert.h conflicts with #define of assert in perl.h */
65 #include <sys/utime.h>
69 /* Mingw32 defaults to globing command line
70 * So we turn it off like this:
75 #if defined(__MINGW32__) && (__MINGW32_MAJOR_VERSION==1)
76 /* Mingw32-1.1 is missing some prototypes */
78 FILE * _wfopen(LPCWSTR wszFileName, LPCWSTR wszMode);
79 FILE * _wfdopen(int nFd, LPCWSTR wszMode);
80 FILE * _freopen(LPCWSTR wszFileName, LPCWSTR wszMode, FILE * pOldStream);
88 #define EXECF_SPAWN_NOWAIT 3
90 #if defined(PERL_IMPLICIT_SYS)
92 # define getlogin g_getlogin
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.
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
106 #if _MSC_VER >= 1400 && defined(_WRITE_ABORT_MSG)
107 # define SET_INVALID_PARAMETER_HANDLER
110 #ifdef SET_INVALID_PARAMETER_HANDLER
111 static BOOL set_silent_invalid_parameter_handler(BOOL newvalue);
112 static void my_invalid_parameter_handler(const wchar_t* expression,
113 const wchar_t* function, const wchar_t* file,
114 unsigned int line, uintptr_t pReserved);
117 #ifndef WIN32_NO_REGISTRY
118 static char* get_regstr_from(HKEY hkey, const char *valuename, SV **svp);
119 static char* get_regstr(const char *valuename, SV **svp);
122 static char* get_emd_part(SV **prev_pathp, STRLEN *const len,
123 char *trailing, ...);
124 static char* win32_get_xlib(const char *pl,
125 WIN32_NO_REGISTRY_M_(const char *xlib)
126 const char *libname, STRLEN *const len);
128 static BOOL has_shell_metachars(const char *ptr);
129 static long tokenize(const char *str, char **dest, char ***destv);
130 static void get_shell(void);
131 static char* find_next_space(const char *s);
132 static int do_spawn2(pTHX_ const char *cmd, int exectype);
133 static int do_spawn2_handles(pTHX_ const char *cmd, int exectype,
135 static int do_spawnvp_handles(int mode, const char *cmdname,
136 const char * const *argv, const int *handles);
137 static PerlIO * do_popen(const char *mode, const char *command, IV narg,
139 static long find_pid(pTHX_ int pid);
140 static void remove_dead_process(long child);
141 static int terminate_process(DWORD pid, HANDLE process_handle, int sig);
142 static int my_killpg(int pid, int sig);
143 static int my_kill(int pid, int sig);
144 static void out_of_memory(void);
145 static char* wstr_to_str(const wchar_t* wstr);
146 static long filetime_to_clock(PFILETIME ft);
147 static BOOL filetime_from_time(PFILETIME ft, time_t t);
148 static char* create_command_line(char *cname, STRLEN clen,
149 const char * const *args);
150 static char* qualified_path(const char *cmd, bool other_exts);
151 static void ansify_path(void);
152 static LRESULT win32_process_message(HWND hwnd, UINT msg,
153 WPARAM wParam, LPARAM lParam);
156 static long find_pseudo_pid(pTHX_ int pid);
157 static void remove_dead_pseudo_process(long child);
158 static HWND get_hwnd_delay(pTHX, long child, DWORD tries);
161 #ifdef HAVE_INTERP_INTERN
162 static void win32_csighandler(int sig);
165 static void translate_to_errno(void);
168 HANDLE w32_perldll_handle = INVALID_HANDLE_VALUE;
169 char w32_module_name[MAX_PATH+1];
170 #ifdef WIN32_DYN_IOINFO_SIZE
171 Size_t w32_ioinfo_size;/* avoid 0 extend op b4 mul, otherwise could be a U8 */
175 static OSVERSIONINFO g_osver = {0, 0, 0, 0, 0, ""};
177 #ifndef WIN32_NO_REGISTRY
178 /* initialized by Perl_win32_init/PERL_SYS_INIT */
179 static HKEY HKCU_Perl_hnd;
180 static HKEY HKLM_Perl_hnd;
183 /* the time_t epoch start time as a filetime expressed as a large integer */
184 static ULARGE_INTEGER time_t_epoch_base_filetime;
186 static const SYSTEMTIME time_t_epoch_base_systemtime = {
194 0 /* wMilliseconds */
197 #define FILETIME_CHUNKS_PER_SECOND (10000000UL)
199 #ifdef SET_INVALID_PARAMETER_HANDLER
200 static BOOL silent_invalid_parameter_handler = FALSE;
203 set_silent_invalid_parameter_handler(BOOL newvalue)
205 BOOL oldvalue = silent_invalid_parameter_handler;
207 silent_invalid_parameter_handler = newvalue;
213 my_invalid_parameter_handler(const wchar_t* expression,
214 const wchar_t* function,
220 char* ansi_expression;
223 if (silent_invalid_parameter_handler)
225 ansi_expression = wstr_to_str(expression);
226 ansi_function = wstr_to_str(function);
227 ansi_file = wstr_to_str(file);
228 fprintf(stderr, "Invalid parameter detected in function %s. "
229 "File: %s, line: %d\n", ansi_function, ansi_file, line);
230 fprintf(stderr, "Expression: %s\n", ansi_expression);
231 free(ansi_expression);
239 set_w32_module_name(void)
241 /* this function may be called at DLL_PROCESS_ATTACH time */
243 HMODULE module = (HMODULE)((w32_perldll_handle == INVALID_HANDLE_VALUE)
244 ? GetModuleHandle(NULL)
245 : w32_perldll_handle);
247 WCHAR modulename[MAX_PATH];
248 WCHAR fullname[MAX_PATH];
251 DWORD (__stdcall *pfnGetLongPathNameW)(LPCWSTR, LPWSTR, DWORD) =
252 (DWORD (__stdcall *)(LPCWSTR, LPWSTR, DWORD))
253 GetProcAddress(GetModuleHandle("kernel32.dll"), "GetLongPathNameW");
255 GetModuleFileNameW(module, modulename, sizeof(modulename)/sizeof(WCHAR));
257 /* Make sure we get an absolute pathname in case the module was loaded
258 * explicitly by LoadLibrary() with a relative path. */
259 GetFullPathNameW(modulename, sizeof(fullname)/sizeof(WCHAR), fullname, NULL);
261 /* Make sure we start with the long path name of the module because we
262 * later scan for pathname components to match "5.xx" to locate
263 * compatible sitelib directories, and the short pathname might mangle
264 * this path segment (e.g. by removing the dot on NTFS to something
265 * like "5xx~1.yy") */
266 if (pfnGetLongPathNameW)
267 pfnGetLongPathNameW(fullname, fullname, sizeof(fullname)/sizeof(WCHAR));
269 /* remove \\?\ prefix */
270 if (memcmp(fullname, L"\\\\?\\", 4*sizeof(WCHAR)) == 0)
271 memmove(fullname, fullname+4, (wcslen(fullname+4)+1)*sizeof(WCHAR));
273 ansi = win32_ansipath(fullname);
274 my_strlcpy(w32_module_name, ansi, sizeof(w32_module_name));
277 /* normalize to forward slashes */
278 ptr = w32_module_name;
286 #ifndef WIN32_NO_REGISTRY
287 /* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
289 get_regstr_from(HKEY handle, const char *valuename, SV **svp)
291 /* Retrieve a REG_SZ or REG_EXPAND_SZ from the registry */
297 retval = RegQueryValueEx(handle, valuename, 0, &type, NULL, &datalen);
298 if (retval == ERROR_SUCCESS
299 && (type == REG_SZ || type == REG_EXPAND_SZ))
303 *svp = sv_2mortal(newSVpvs(""));
304 SvGROW(*svp, datalen);
305 retval = RegQueryValueEx(handle, valuename, 0, NULL,
306 (PBYTE)SvPVX(*svp), &datalen);
307 if (retval == ERROR_SUCCESS) {
309 SvCUR_set(*svp,datalen-1);
315 /* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
317 get_regstr(const char *valuename, SV **svp)
321 str = get_regstr_from(HKCU_Perl_hnd, valuename, svp);
328 str = get_regstr_from(HKLM_Perl_hnd, valuename, svp);
334 #endif /* ifndef WIN32_NO_REGISTRY */
336 /* *prev_pathp (if non-NULL) is expected to be POK (valid allocated SvPVX(sv)) */
338 get_emd_part(SV **prev_pathp, STRLEN *const len, char *trailing_path, ...)
342 char mod_name[MAX_PATH+1];
348 va_start(ap, trailing_path);
349 strip = va_arg(ap, char *);
351 sprintf(base, "%d.%d", (int)PERL_REVISION, (int)PERL_VERSION);
352 baselen = strlen(base);
354 if (!*w32_module_name) {
355 set_w32_module_name();
357 strcpy(mod_name, w32_module_name);
358 ptr = strrchr(mod_name, '/');
359 while (ptr && strip) {
360 /* look for directories to skip back */
363 ptr = strrchr(mod_name, '/');
364 /* avoid stripping component if there is no slash,
365 * or it doesn't match ... */
366 if (!ptr || stricmp(ptr+1, strip) != 0) {
367 /* ... but not if component matches m|5\.$patchlevel.*| */
368 if (!ptr || !(*strip == '5' && *(ptr+1) == '5'
369 && strnEQ(strip, base, baselen)
370 && strnEQ(ptr+1, base, baselen)))
376 strip = va_arg(ap, char *);
384 strcpy(++ptr, trailing_path);
386 /* only add directory if it exists */
387 if (GetFileAttributes(mod_name) != (DWORD) -1) {
388 /* directory exists */
391 *prev_pathp = sv_2mortal(newSVpvs(""));
392 else if (SvPVX(*prev_pathp))
393 sv_catpvs(*prev_pathp, ";");
394 sv_catpv(*prev_pathp, mod_name);
396 *len = SvCUR(*prev_pathp);
397 return SvPVX(*prev_pathp);
404 win32_get_privlib(WIN32_NO_REGISTRY_M_(const char *pl) STRLEN *const len)
406 char *stdlib = "lib";
408 #ifndef WIN32_NO_REGISTRY
409 char buffer[MAX_PATH+1];
411 /* $stdlib = $HKCU{"lib-$]"} || $HKLM{"lib-$]"} || $HKCU{"lib"} || $HKLM{"lib"} || ""; */
412 sprintf(buffer, "%s-%s", stdlib, pl);
413 if (!get_regstr(buffer, &sv))
414 (void)get_regstr(stdlib, &sv);
417 /* $stdlib .= ";$EMD/../../lib" */
418 return get_emd_part(&sv, len, stdlib, ARCHNAME, "bin", NULL);
422 win32_get_xlib(const char *pl, WIN32_NO_REGISTRY_M_(const char *xlib)
423 const char *libname, STRLEN *const len)
425 #ifndef WIN32_NO_REGISTRY
428 char pathstr[MAX_PATH+1];
432 #ifndef WIN32_NO_REGISTRY
433 /* $HKCU{"$xlib-$]"} || $HKLM{"$xlib-$]"} . ---; */
434 sprintf(regstr, "%s-%s", xlib, pl);
435 (void)get_regstr(regstr, &sv1);
439 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/$]/lib"; */
440 sprintf(pathstr, "%s/%s/lib", libname, pl);
441 (void)get_emd_part(&sv1, NULL, pathstr, ARCHNAME, "bin", pl, NULL);
443 #ifndef WIN32_NO_REGISTRY
444 /* $HKCU{$xlib} || $HKLM{$xlib} . ---; */
445 (void)get_regstr(xlib, &sv2);
449 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/lib"; */
450 sprintf(pathstr, "%s/lib", libname);
451 (void)get_emd_part(&sv2, NULL, pathstr, ARCHNAME, "bin", pl, NULL);
469 win32_get_sitelib(const char *pl, STRLEN *const len)
471 return win32_get_xlib(pl, WIN32_NO_REGISTRY_M_("sitelib") "site", len);
474 #ifndef PERL_VENDORLIB_NAME
475 # define PERL_VENDORLIB_NAME "vendor"
479 win32_get_vendorlib(const char *pl, STRLEN *const len)
481 return win32_get_xlib(pl, WIN32_NO_REGISTRY_M_("vendorlib") PERL_VENDORLIB_NAME, len);
485 has_shell_metachars(const char *ptr)
491 * Scan string looking for redirection (< or >) or pipe
492 * characters (|) that are not in a quoted string.
493 * Shell variable interpolation (%VAR%) can also happen inside strings.
525 #if !defined(PERL_IMPLICIT_SYS)
526 /* since the current process environment is being updated in util.c
527 * the library functions will get the correct environment
530 Perl_my_popen(pTHX_ const char *cmd, const char *mode)
532 PERL_FLUSHALL_FOR_CHILD;
533 return win32_popen(cmd, mode);
537 Perl_my_pclose(pTHX_ PerlIO *fp)
539 return win32_pclose(fp);
543 DllExport unsigned long
546 return (unsigned long)g_osver.dwPlatformId;
555 return -((int)w32_pseudo_id);
560 /* Tokenize a string. Words are null-separated, and the list
561 * ends with a doubled null. Any character (except null and
562 * including backslash) may be escaped by preceding it with a
563 * backslash (the backslash will be stripped).
564 * Returns number of words in result buffer.
567 tokenize(const char *str, char **dest, char ***destv)
569 char *retstart = NULL;
570 char **retvstart = 0;
573 int slen = strlen(str);
576 Newx(ret, slen+2, char);
577 Newx(retv, (slen+3)/2, char*);
585 if (*ret == '\\' && *str)
587 else if (*ret == ' ') {
603 retvstart[items] = NULL;
616 if (!w32_perlshell_tokens) {
617 /* we don't use COMSPEC here for two reasons:
618 * 1. the same reason perl on UNIX doesn't use SHELL--rampant and
619 * uncontrolled unportability of the ensuing scripts.
620 * 2. PERL5SHELL could be set to a shell that may not be fit for
621 * interactive use (which is what most programs look in COMSPEC
624 const char* defaultshell = "cmd.exe /x/d/c";
625 const char *usershell = PerlEnv_getenv("PERL5SHELL");
626 w32_perlshell_items = tokenize(usershell ? usershell : defaultshell,
627 &w32_perlshell_tokens,
633 Perl_do_aspawn(pTHX_ SV *really, SV **mark, SV **sp)
642 PERL_ARGS_ASSERT_DO_ASPAWN;
648 Newx(argv, (sp - mark) + w32_perlshell_items + 2, char*);
650 if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
655 while (++mark <= sp) {
656 if (*mark && (str = SvPV_nolen(*mark)))
663 status = win32_spawnvp(flag,
664 (const char*)(really ? SvPV_nolen(really) : argv[0]),
665 (const char* const*)argv);
667 if (status < 0 && (eno = errno, (eno == ENOEXEC || eno == ENOENT))) {
668 /* possible shell-builtin, invoke with shell */
670 sh_items = w32_perlshell_items;
672 argv[index+sh_items] = argv[index];
673 while (--sh_items >= 0)
674 argv[sh_items] = w32_perlshell_vec[sh_items];
676 status = win32_spawnvp(flag,
677 (const char*)(really ? SvPV_nolen(really) : argv[0]),
678 (const char* const*)argv);
681 if (flag == P_NOWAIT) {
682 PL_statusvalue = -1; /* >16bits hint for pp_system() */
686 if (ckWARN(WARN_EXEC))
687 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't spawn \"%s\": %s", argv[0], strerror(errno));
692 PL_statusvalue = status;
698 /* returns pointer to the next unquoted space or the end of the string */
700 find_next_space(const char *s)
702 bool in_quotes = FALSE;
704 /* ignore doubled backslashes, or backslash+quote */
705 if (*s == '\\' && (s[1] == '\\' || s[1] == '"')) {
708 /* keep track of when we're within quotes */
709 else if (*s == '"') {
711 in_quotes = !in_quotes;
713 /* break it up only at spaces that aren't in quotes */
714 else if (!in_quotes && isSPACE(*s))
723 do_spawn2(pTHX_ const char *cmd, int exectype) {
724 return do_spawn2_handles(aTHX_ cmd, exectype, NULL);
728 do_spawn2_handles(pTHX_ const char *cmd, int exectype, const int *handles)
734 BOOL needToTry = TRUE;
737 /* Save an extra exec if possible. See if there are shell
738 * metacharacters in it */
739 if (!has_shell_metachars(cmd)) {
740 Newx(argv, strlen(cmd) / 2 + 2, char*);
741 Newx(cmd2, strlen(cmd) + 1, char);
744 for (s = cmd2; *s;) {
745 while (*s && isSPACE(*s))
749 s = find_next_space(s);
757 status = win32_spawnvp(P_WAIT, argv[0],
758 (const char* const*)argv);
760 case EXECF_SPAWN_NOWAIT:
761 status = do_spawnvp_handles(P_NOWAIT, argv[0],
762 (const char* const*)argv, handles);
765 status = win32_execvp(argv[0], (const char* const*)argv);
768 if (status != -1 || errno == 0)
778 Newx(argv, w32_perlshell_items + 2, char*);
779 while (++i < w32_perlshell_items)
780 argv[i] = w32_perlshell_vec[i];
781 argv[i++] = (char *)cmd;
785 status = win32_spawnvp(P_WAIT, argv[0],
786 (const char* const*)argv);
788 case EXECF_SPAWN_NOWAIT:
789 status = do_spawnvp_handles(P_NOWAIT, argv[0],
790 (const char* const*)argv, handles);
793 status = win32_execvp(argv[0], (const char* const*)argv);
799 if (exectype == EXECF_SPAWN_NOWAIT) {
800 PL_statusvalue = -1; /* >16bits hint for pp_system() */
804 if (ckWARN(WARN_EXEC))
805 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s \"%s\": %s",
806 (exectype == EXECF_EXEC ? "exec" : "spawn"),
807 cmd, strerror(errno));
812 PL_statusvalue = status;
818 Perl_do_spawn(pTHX_ char *cmd)
820 PERL_ARGS_ASSERT_DO_SPAWN;
822 return do_spawn2(aTHX_ cmd, EXECF_SPAWN);
826 Perl_do_spawn_nowait(pTHX_ char *cmd)
828 PERL_ARGS_ASSERT_DO_SPAWN_NOWAIT;
830 return do_spawn2(aTHX_ cmd, EXECF_SPAWN_NOWAIT);
834 Perl_do_exec(pTHX_ const char *cmd)
836 PERL_ARGS_ASSERT_DO_EXEC;
838 do_spawn2(aTHX_ cmd, EXECF_EXEC);
842 /* The idea here is to read all the directory names into a string table
843 * (separated by nulls) and when one of the other dir functions is called
844 * return the pointer to the current file name.
847 win32_opendir(const char *filename)
853 char scanname[MAX_PATH+3];
854 WCHAR wscanname[sizeof(scanname)];
855 WIN32_FIND_DATAW wFindData;
856 char buffer[MAX_PATH*2];
859 len = strlen(filename);
864 if (len > MAX_PATH) {
865 errno = ENAMETOOLONG;
869 /* Get us a DIR structure */
872 /* Create the search pattern */
873 strcpy(scanname, filename);
875 /* bare drive name means look in cwd for drive */
876 if (len == 2 && isALPHA(scanname[0]) && scanname[1] == ':') {
877 scanname[len++] = '.';
878 scanname[len++] = '/';
880 else if (scanname[len-1] != '/' && scanname[len-1] != '\\') {
881 scanname[len++] = '/';
883 scanname[len++] = '*';
884 scanname[len] = '\0';
886 /* do the FindFirstFile call */
887 MultiByteToWideChar(CP_ACP, 0, scanname, -1, wscanname, sizeof(wscanname)/sizeof(WCHAR));
889 dirp->handle = FindFirstFileW(PerlDir_mapW(wscanname), &wFindData);
891 if (dirp->handle == INVALID_HANDLE_VALUE) {
892 DWORD err = GetLastError();
893 /* FindFirstFile() fails on empty drives! */
895 case ERROR_FILE_NOT_FOUND:
897 case ERROR_NO_MORE_FILES:
898 case ERROR_PATH_NOT_FOUND:
901 case ERROR_NOT_ENOUGH_MEMORY:
913 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
914 wFindData.cFileName, -1,
915 buffer, sizeof(buffer), NULL, &use_default);
916 if (use_default && *wFindData.cAlternateFileName) {
917 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
918 wFindData.cAlternateFileName, -1,
919 buffer, sizeof(buffer), NULL, NULL);
922 /* now allocate the first part of the string table for
923 * the filenames that we find.
925 idx = strlen(buffer)+1;
930 Newx(dirp->start, dirp->size, char);
931 strcpy(dirp->start, buffer);
933 dirp->end = dirp->curr = dirp->start;
939 /* Readdir just returns the current string pointer and bumps the
940 * string pointer to the nDllExport entry.
942 DllExport struct direct *
943 win32_readdir(DIR *dirp)
948 /* first set up the structure to return */
949 len = strlen(dirp->curr);
950 strcpy(dirp->dirstr.d_name, dirp->curr);
951 dirp->dirstr.d_namlen = len;
954 dirp->dirstr.d_ino = dirp->curr - dirp->start;
956 /* Now set up for the next call to readdir */
957 dirp->curr += len + 1;
958 if (dirp->curr >= dirp->end) {
960 char buffer[MAX_PATH*2];
962 if (dirp->handle == INVALID_HANDLE_VALUE) {
965 /* finding the next file that matches the wildcard
966 * (which should be all of them in this directory!).
969 WIN32_FIND_DATAW wFindData;
970 res = FindNextFileW(dirp->handle, &wFindData);
972 BOOL use_default = FALSE;
973 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
974 wFindData.cFileName, -1,
975 buffer, sizeof(buffer), NULL, &use_default);
976 if (use_default && *wFindData.cAlternateFileName) {
977 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
978 wFindData.cAlternateFileName, -1,
979 buffer, sizeof(buffer), NULL, NULL);
984 long endpos = dirp->end - dirp->start;
985 long newsize = endpos + strlen(buffer) + 1;
986 /* bump the string table size by enough for the
987 * new name and its null terminator */
988 while (newsize > dirp->size) {
989 long curpos = dirp->curr - dirp->start;
990 Renew(dirp->start, dirp->size * 2, char);
992 dirp->curr = dirp->start + curpos;
994 strcpy(dirp->start + endpos, buffer);
995 dirp->end = dirp->start + newsize;
1000 if (dirp->handle != INVALID_HANDLE_VALUE) {
1001 FindClose(dirp->handle);
1002 dirp->handle = INVALID_HANDLE_VALUE;
1006 return &(dirp->dirstr);
1012 /* Telldir returns the current string pointer position */
1014 win32_telldir(DIR *dirp)
1016 return dirp->curr ? (dirp->curr - dirp->start) : -1;
1020 /* Seekdir moves the string pointer to a previously saved position
1021 * (returned by telldir).
1024 win32_seekdir(DIR *dirp, long loc)
1026 dirp->curr = loc == -1 ? NULL : dirp->start + loc;
1029 /* Rewinddir resets the string pointer to the start */
1031 win32_rewinddir(DIR *dirp)
1033 dirp->curr = dirp->start;
1036 /* free the memory allocated by opendir */
1038 win32_closedir(DIR *dirp)
1040 if (dirp->handle != INVALID_HANDLE_VALUE)
1041 FindClose(dirp->handle);
1042 Safefree(dirp->start);
1047 /* duplicate a open DIR* for interpreter cloning */
1049 win32_dirp_dup(DIR *const dirp, CLONE_PARAMS *const param)
1051 PerlInterpreter *const from = param->proto_perl;
1052 PerlInterpreter *const to = (PerlInterpreter *)PERL_GET_THX;
1057 /* switch back to original interpreter because win32_readdir()
1058 * might Renew(dirp->start).
1064 /* mark current position; read all remaining entries into the
1065 * cache, and then restore to current position.
1067 pos = win32_telldir(dirp);
1068 while (win32_readdir(dirp)) {
1069 /* read all entries into cache */
1071 win32_seekdir(dirp, pos);
1073 /* switch back to new interpreter to allocate new DIR structure */
1079 memcpy(dup, dirp, sizeof(DIR));
1081 Newx(dup->start, dirp->size, char);
1082 memcpy(dup->start, dirp->start, dirp->size);
1084 dup->end = dup->start + (dirp->end - dirp->start);
1086 dup->curr = dup->start + (dirp->curr - dirp->start);
1098 * Just pretend that everyone is a superuser. NT will let us know if
1099 * we don\'t really have permission to do something.
1102 #define ROOT_UID ((uid_t)0)
1103 #define ROOT_GID ((gid_t)0)
1132 return (auid == ROOT_UID ? 0 : -1);
1138 return (agid == ROOT_GID ? 0 : -1);
1145 char *buf = w32_getlogin_buffer;
1146 DWORD size = sizeof(w32_getlogin_buffer);
1147 if (GetUserName(buf,&size))
1153 chown(const char *path, uid_t owner, gid_t group)
1160 * XXX this needs strengthening (for PerlIO)
1163 #if !defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 4
1164 int mkstemp(const char *path)
1167 char buf[MAX_PATH+1];
1171 if (i++ > 10) { /* give up */
1175 if (!GetTempFileNameA((LPCSTR)path, "plr", 1, buf)) {
1179 fd = PerlLIO_open3(buf, O_CREAT|O_RDWR|O_EXCL, 0600);
1187 find_pid(pTHX_ int pid)
1189 long child = w32_num_children;
1190 while (--child >= 0) {
1191 if ((int)w32_child_pids[child] == pid)
1198 remove_dead_process(long child)
1202 CloseHandle(w32_child_handles[child]);
1203 Move(&w32_child_handles[child+1], &w32_child_handles[child],
1204 (w32_num_children-child-1), HANDLE);
1205 Move(&w32_child_pids[child+1], &w32_child_pids[child],
1206 (w32_num_children-child-1), DWORD);
1213 find_pseudo_pid(pTHX_ int pid)
1215 long child = w32_num_pseudo_children;
1216 while (--child >= 0) {
1217 if ((int)w32_pseudo_child_pids[child] == pid)
1224 remove_dead_pseudo_process(long child)
1228 CloseHandle(w32_pseudo_child_handles[child]);
1229 Move(&w32_pseudo_child_handles[child+1], &w32_pseudo_child_handles[child],
1230 (w32_num_pseudo_children-child-1), HANDLE);
1231 Move(&w32_pseudo_child_pids[child+1], &w32_pseudo_child_pids[child],
1232 (w32_num_pseudo_children-child-1), DWORD);
1233 Move(&w32_pseudo_child_message_hwnds[child+1], &w32_pseudo_child_message_hwnds[child],
1234 (w32_num_pseudo_children-child-1), HWND);
1235 Move(&w32_pseudo_child_sigterm[child+1], &w32_pseudo_child_sigterm[child],
1236 (w32_num_pseudo_children-child-1), char);
1237 w32_num_pseudo_children--;
1242 win32_wait_for_children(pTHX)
1244 if (w32_pseudo_children && w32_num_pseudo_children) {
1247 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
1249 for (child = 0; child < w32_num_pseudo_children; ++child) {
1250 if (!w32_pseudo_child_sigterm[child])
1251 handles[count++] = w32_pseudo_child_handles[child];
1253 /* XXX should use MsgWaitForMultipleObjects() to continue
1254 * XXX processing messages while we wait.
1256 WaitForMultipleObjects(count, handles, TRUE, INFINITE);
1258 while (w32_num_pseudo_children)
1259 CloseHandle(w32_pseudo_child_handles[--w32_num_pseudo_children]);
1265 terminate_process(DWORD pid, HANDLE process_handle, int sig)
1269 /* "Does process exist?" use of kill */
1272 if (GenerateConsoleCtrlEvent(CTRL_C_EVENT, pid))
1277 if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pid))
1280 default: /* For now be backwards compatible with perl 5.6 */
1282 /* Note that we will only be able to kill processes owned by the
1283 * current process owner, even when we are running as an administrator.
1284 * To kill processes of other owners we would need to set the
1285 * 'SeDebugPrivilege' privilege before obtaining the process handle.
1287 if (TerminateProcess(process_handle, sig))
1294 /* returns number of processes killed */
1296 my_killpg(int pid, int sig)
1298 HANDLE process_handle;
1299 HANDLE snapshot_handle;
1302 process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
1303 if (process_handle == NULL)
1306 killed += terminate_process(pid, process_handle, sig);
1308 snapshot_handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
1309 if (snapshot_handle != INVALID_HANDLE_VALUE) {
1310 PROCESSENTRY32 entry;
1312 entry.dwSize = sizeof(entry);
1313 if (Process32First(snapshot_handle, &entry)) {
1315 if (entry.th32ParentProcessID == (DWORD)pid)
1316 killed += my_killpg(entry.th32ProcessID, sig);
1317 entry.dwSize = sizeof(entry);
1319 while (Process32Next(snapshot_handle, &entry));
1321 CloseHandle(snapshot_handle);
1323 CloseHandle(process_handle);
1327 /* returns number of processes killed */
1329 my_kill(int pid, int sig)
1332 HANDLE process_handle;
1335 return my_killpg(pid, -sig);
1337 process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
1338 /* OpenProcess() returns NULL on error, *not* INVALID_HANDLE_VALUE */
1339 if (process_handle != NULL) {
1340 retval = terminate_process(pid, process_handle, sig);
1341 CloseHandle(process_handle);
1347 /* Get a child pseudo-process HWND, with retrying and delaying/yielding.
1348 * The "tries" parameter is the number of retries to make, with a Sleep(1)
1349 * (waiting and yielding the time slot) between each try. Specifying 0 causes
1350 * only Sleep(0) (no waiting and potentially no yielding) to be used, so is not
1352 * Returns an hwnd != INVALID_HANDLE_VALUE (so be aware that NULL can be
1353 * returned) or croaks if the child pseudo-process doesn't schedule and deliver
1354 * a HWND in the time period allowed.
1357 get_hwnd_delay(pTHX, long child, DWORD tries)
1359 HWND hwnd = w32_pseudo_child_message_hwnds[child];
1360 if (hwnd != INVALID_HANDLE_VALUE) return hwnd;
1362 /* Pseudo-process has not yet properly initialized since hwnd isn't set.
1363 * Fast sleep: On some NT kernels/systems, a Sleep(0) won't deschedule a
1364 * thread 100% of the time since threads are attached to a CPU for NUMA and
1365 * caching reasons, and the child thread was attached to a different CPU
1366 * therefore there is no workload on that CPU and Sleep(0) returns control
1367 * without yielding the time slot.
1368 * https://github.com/Perl/perl5/issues/11267
1371 win32_async_check(aTHX);
1372 hwnd = w32_pseudo_child_message_hwnds[child];
1373 if (hwnd != INVALID_HANDLE_VALUE) return hwnd;
1376 unsigned int count = 0;
1377 /* No Sleep(1) if tries==0, just fail instead if we get this far. */
1378 while (count++ < tries) {
1380 win32_async_check(aTHX);
1381 hwnd = w32_pseudo_child_message_hwnds[child];
1382 if (hwnd != INVALID_HANDLE_VALUE) return hwnd;
1386 Perl_croak(aTHX_ "panic: child pseudo-process was never scheduled");
1391 win32_kill(int pid, int sig)
1397 /* it is a pseudo-forked child */
1398 child = find_pseudo_pid(aTHX_ -pid);
1400 HANDLE hProcess = w32_pseudo_child_handles[child];
1403 /* "Does process exist?" use of kill */
1407 /* kill -9 style un-graceful exit */
1408 /* Do a wait to make sure child starts and isn't in DLL
1410 HWND hwnd = get_hwnd_delay(aTHX, child, 5);
1411 if (TerminateThread(hProcess, sig)) {
1412 /* Allow the scheduler to finish cleaning up the other
1414 * Otherwise, if we ExitProcess() before another context
1415 * switch happens we will end up with a process exit
1416 * code of "sig" instead of our own exit status.
1417 * https://rt.cpan.org/Ticket/Display.html?id=66016#txn-908976
1420 remove_dead_pseudo_process(child);
1427 HWND hwnd = get_hwnd_delay(aTHX, child, 5);
1428 /* We fake signals to pseudo-processes using Win32
1430 if ((hwnd != NULL && PostMessage(hwnd, WM_USER_KILL, sig, 0)) ||
1431 PostThreadMessage(-pid, WM_USER_KILL, sig, 0))
1433 /* Don't wait for child process to terminate after we send a
1434 * SIGTERM because the child may be blocked in a system call
1435 * and never receive the signal.
1437 if (sig == SIGTERM) {
1439 w32_pseudo_child_sigterm[child] = 1;
1441 /* It might be us ... */
1453 child = find_pid(aTHX_ pid);
1455 if (my_kill(pid, sig)) {
1457 if (GetExitCodeProcess(w32_child_handles[child], &exitcode) &&
1458 exitcode != STILL_ACTIVE)
1460 remove_dead_process(child);
1466 if (my_kill(pid, sig))
1476 translate_ft_to_time_t(FILETIME ft) {
1477 SYSTEMTIME st, local_st;
1480 if (!FileTimeToSystemTime(&ft, &st) ||
1481 !SystemTimeToTzSpecificLocalTime(NULL, &st, &local_st)) {
1485 Zero(&pt, 1, struct tm);
1486 pt.tm_year = local_st.wYear - 1900;
1487 pt.tm_mon = local_st.wMonth - 1;
1488 pt.tm_mday = local_st.wDay;
1489 pt.tm_hour = local_st.wHour;
1490 pt.tm_min = local_st.wMinute;
1491 pt.tm_sec = local_st.wSecond;
1497 typedef DWORD (__stdcall *pGetFinalPathNameByHandleA_t)(HANDLE, LPSTR, DWORD, DWORD);
1500 win32_stat_low(HANDLE handle, const char *path, STRLEN len, Stat_t *sbuf) {
1501 DWORD type = GetFileType(handle);
1502 BY_HANDLE_FILE_INFORMATION bhi;
1504 Zero(sbuf, 1, Stat_t);
1506 type &= ~FILE_TYPE_REMOTE;
1509 case FILE_TYPE_DISK:
1510 if (GetFileInformationByHandle(handle, &bhi)) {
1511 sbuf->st_dev = bhi.dwVolumeSerialNumber;
1512 sbuf->st_ino = bhi.nFileIndexHigh;
1513 sbuf->st_ino <<= 32;
1514 sbuf->st_ino |= bhi.nFileIndexLow;
1515 sbuf->st_nlink = bhi.nNumberOfLinks;
1518 /* ucrt sets this to the drive letter for
1519 stat(), lets not reproduce that mistake */
1521 sbuf->st_size = bhi.nFileSizeHigh;
1522 sbuf->st_size <<= 32;
1523 sbuf->st_size |= bhi.nFileSizeLow;
1525 sbuf->st_atime = translate_ft_to_time_t(bhi.ftLastAccessTime);
1526 sbuf->st_mtime = translate_ft_to_time_t(bhi.ftLastWriteTime);
1527 sbuf->st_ctime = translate_ft_to_time_t(bhi.ftCreationTime);
1529 if (bhi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1530 sbuf->st_mode = _S_IFDIR | _S_IREAD | _S_IEXEC;
1531 /* duplicate the logic from the end of the old win32_stat() */
1532 if (!(bhi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
1533 sbuf->st_mode |= S_IWRITE;
1537 char path_buf[MAX_PATH+1];
1538 sbuf->st_mode = _S_IFREG;
1541 pGetFinalPathNameByHandleA_t pGetFinalPathNameByHandleA =
1542 (pGetFinalPathNameByHandleA_t)GetProcAddress(GetModuleHandle("kernel32.dll"), "GetFinalPathNameByHandleA");
1543 if (pGetFinalPathNameByHandleA) {
1544 len = pGetFinalPathNameByHandleA(handle, path_buf, sizeof(path_buf), 0);
1550 /* < to ensure there's space for the \0 */
1551 if (len && len < sizeof(path_buf)) {
1556 if (path && len > 4 &&
1557 (_stricmp(path + len - 4, ".exe") == 0 ||
1558 _stricmp(path + len - 4, ".bat") == 0 ||
1559 _stricmp(path + len - 4, ".cmd") == 0 ||
1560 _stricmp(path + len - 4, ".com") == 0)) {
1561 sbuf->st_mode |= _S_IEXEC;
1563 if (!(bhi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
1564 sbuf->st_mode |= _S_IWRITE;
1566 sbuf->st_mode |= _S_IREAD;
1570 translate_to_errno();
1575 case FILE_TYPE_CHAR:
1576 case FILE_TYPE_PIPE:
1577 sbuf->st_mode = (type == FILE_TYPE_CHAR) ? _S_IFCHR : _S_IFIFO;
1578 if (handle == GetStdHandle(STD_INPUT_HANDLE) ||
1579 handle == GetStdHandle(STD_OUTPUT_HANDLE) ||
1580 handle == GetStdHandle(STD_ERROR_HANDLE)) {
1581 sbuf->st_mode |= _S_IWRITE | _S_IREAD;
1589 /* owner == user == group */
1590 sbuf->st_mode |= (sbuf->st_mode & 0700) >> 3;
1591 sbuf->st_mode |= (sbuf->st_mode & 0700) >> 6;
1597 win32_stat(const char *path, Stat_t *sbuf)
1599 size_t l = strlen(path);
1601 BOOL expect_dir = FALSE;
1605 path = PerlDir_mapA(path);
1609 CreateFileA(path, FILE_READ_ATTRIBUTES,
1610 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
1611 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1612 if (handle != INVALID_HANDLE_VALUE) {
1613 result = win32_stat_low(handle, path, l, sbuf);
1614 CloseHandle(handle);
1617 translate_to_errno();
1625 translate_to_errno(void)
1627 /* This isn't perfect, eg. Win32 returns ERROR_ACCESS_DENIED for
1628 both permissions errors and if the source is a directory, while
1629 POSIX wants EACCES and EPERM respectively.
1631 switch (GetLastError()) {
1632 case ERROR_BAD_NET_NAME:
1633 case ERROR_BAD_NETPATH:
1634 case ERROR_BAD_PATHNAME:
1635 case ERROR_FILE_NOT_FOUND:
1636 case ERROR_FILENAME_EXCED_RANGE:
1637 case ERROR_INVALID_DRIVE:
1638 case ERROR_PATH_NOT_FOUND:
1641 case ERROR_ALREADY_EXISTS:
1644 case ERROR_ACCESS_DENIED:
1647 case ERROR_PRIVILEGE_NOT_HELD:
1650 case ERROR_NOT_SAME_DEVICE:
1653 case ERROR_DISK_FULL:
1656 case ERROR_NOT_ENOUGH_QUOTA:
1660 /* ERROR_INVALID_FUNCTION - eg. symlink on a FAT volume */
1668 https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_reparse_data_buffer
1670 Renamed to avoid conflicts, apparently some SDKs define this
1673 Hoisted the symlink and mount point data into a new type to allow us
1674 to make a pointer to it, and to avoid C++ scoping issues.
1679 USHORT SubstituteNameOffset;
1680 USHORT SubstituteNameLength;
1681 USHORT PrintNameOffset;
1682 USHORT PrintNameLength;
1684 WCHAR PathBuffer[MAX_PATH*3];
1685 } MY_SYMLINK_REPARSE_BUFFER, *PMY_SYMLINK_REPARSE_BUFFER;
1688 USHORT SubstituteNameOffset;
1689 USHORT SubstituteNameLength;
1690 USHORT PrintNameOffset;
1691 USHORT PrintNameLength;
1692 WCHAR PathBuffer[MAX_PATH*3];
1693 } MY_MOUNT_POINT_REPARSE_BUFFER;
1697 USHORT ReparseDataLength;
1700 MY_SYMLINK_REPARSE_BUFFER SymbolicLinkReparseBuffer;
1701 MY_MOUNT_POINT_REPARSE_BUFFER MountPointReparseBuffer;
1703 UCHAR DataBuffer[1];
1704 } GenericReparseBuffer;
1706 } MY_REPARSE_DATA_BUFFER, *PMY_REPARSE_DATA_BUFFER;
1708 #ifndef IO_REPARSE_TAG_SYMLINK
1709 # define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
1713 is_symlink(HANDLE h) {
1714 MY_REPARSE_DATA_BUFFER linkdata;
1715 const MY_SYMLINK_REPARSE_BUFFER * const sd =
1716 &linkdata.Data.SymbolicLinkReparseBuffer;
1717 DWORD linkdata_returned;
1719 if (!DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, &linkdata, sizeof(linkdata), &linkdata_returned, NULL)) {
1723 if (linkdata_returned < offsetof(MY_REPARSE_DATA_BUFFER, Data.SymbolicLinkReparseBuffer.PathBuffer)
1724 || (linkdata.ReparseTag != IO_REPARSE_TAG_SYMLINK
1725 && linkdata.ReparseTag != IO_REPARSE_TAG_MOUNT_POINT)) {
1726 /* some other type of reparse point */
1734 is_symlink_name(const char *name) {
1735 HANDLE f = CreateFileA(name, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1736 FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, 0);
1739 if (f == INVALID_HANDLE_VALUE) {
1742 result = is_symlink(f);
1749 win32_readlink(const char *pathname, char *buf, size_t bufsiz) {
1750 MY_REPARSE_DATA_BUFFER linkdata;
1752 DWORD fileattr = GetFileAttributes(pathname);
1753 DWORD linkdata_returned;
1757 if (fileattr == INVALID_FILE_ATTRIBUTES) {
1758 translate_to_errno();
1762 if (!(fileattr & FILE_ATTRIBUTE_REPARSE_POINT)) {
1763 /* not a symbolic link */
1769 CreateFileA(pathname, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1770 FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, 0);
1771 if (hlink == INVALID_HANDLE_VALUE) {
1772 translate_to_errno();
1776 if (!DeviceIoControl(hlink, FSCTL_GET_REPARSE_POINT, NULL, 0, &linkdata, sizeof(linkdata), &linkdata_returned, NULL)) {
1777 translate_to_errno();
1783 switch (linkdata.ReparseTag) {
1784 case IO_REPARSE_TAG_SYMLINK:
1786 const MY_SYMLINK_REPARSE_BUFFER * const sd =
1787 &linkdata.Data.SymbolicLinkReparseBuffer;
1788 if (linkdata_returned < offsetof(MY_REPARSE_DATA_BUFFER, Data.SymbolicLinkReparseBuffer.PathBuffer)) {
1793 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
1794 sd->PathBuffer + sd->SubstituteNameOffset/2,
1795 sd->SubstituteNameLength/2,
1796 buf, (int)bufsiz, NULL, &used_default);
1799 case IO_REPARSE_TAG_MOUNT_POINT:
1801 const MY_MOUNT_POINT_REPARSE_BUFFER * const rd =
1802 &linkdata.Data.MountPointReparseBuffer;
1803 if (linkdata_returned < offsetof(MY_REPARSE_DATA_BUFFER, Data.MountPointReparseBuffer.PathBuffer)) {
1808 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
1809 rd->PathBuffer + rd->SubstituteNameOffset/2,
1810 rd->SubstituteNameLength/2,
1811 buf, (int)bufsiz, NULL, &used_default);
1820 if (bytes_out == 0 || used_default) {
1821 /* failed conversion from unicode to ANSI or otherwise failed */
1825 if ((size_t)bytes_out > bufsiz) {
1834 win32_lstat(const char *path, Stat_t *sbuf)
1838 DWORD attr = GetFileAttributes(path); /* doesn't follow symlinks */
1840 if (attr == INVALID_FILE_ATTRIBUTES) {
1841 translate_to_errno();
1845 if (!(attr & FILE_ATTRIBUTE_REPARSE_POINT)) {
1846 return win32_stat(path, sbuf);
1849 f = CreateFileA(path, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1850 FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, 0);
1851 if (f == INVALID_HANDLE_VALUE) {
1852 translate_to_errno();
1856 if (!is_symlink(f)) {
1858 return win32_stat(path, sbuf);
1861 result = win32_stat_low(f, NULL, 0, sbuf);
1865 sbuf->st_mode = (sbuf->st_mode & ~_S_IFMT) | _S_IFLNK;
1871 #define isSLASH(c) ((c) == '/' || (c) == '\\')
1872 #define SKIP_SLASHES(s) \
1874 while (*(s) && isSLASH(*(s))) \
1877 #define COPY_NONSLASHES(d,s) \
1879 while (*(s) && !isSLASH(*(s))) \
1883 /* Find the longname of a given path. path is destructively modified.
1884 * It should have space for at least MAX_PATH characters. */
1886 win32_longpath(char *path)
1888 WIN32_FIND_DATA fdata;
1890 char tmpbuf[MAX_PATH+1];
1891 char *tmpstart = tmpbuf;
1898 if (isALPHA(path[0]) && path[1] == ':') {
1900 *tmpstart++ = path[0];
1904 else if (isSLASH(path[0]) && isSLASH(path[1])) {
1906 *tmpstart++ = path[0];
1907 *tmpstart++ = path[1];
1908 SKIP_SLASHES(start);
1909 COPY_NONSLASHES(tmpstart,start); /* copy machine name */
1911 *tmpstart++ = *start++;
1912 SKIP_SLASHES(start);
1913 COPY_NONSLASHES(tmpstart,start); /* copy share name */
1918 /* copy initial slash, if any */
1919 if (isSLASH(*start)) {
1920 *tmpstart++ = *start++;
1922 SKIP_SLASHES(start);
1925 /* FindFirstFile() expands "." and "..", so we need to pass
1926 * those through unmolested */
1928 && (!start[1] || isSLASH(start[1])
1929 || (start[1] == '.' && (!start[2] || isSLASH(start[2])))))
1931 COPY_NONSLASHES(tmpstart,start); /* copy "." or ".." */
1936 /* if this is the end, bust outta here */
1940 /* now we're at a non-slash; walk up to next slash */
1941 while (*start && !isSLASH(*start))
1944 /* stop and find full name of component */
1947 fhand = FindFirstFile(path,&fdata);
1949 if (fhand != INVALID_HANDLE_VALUE) {
1950 STRLEN len = strlen(fdata.cFileName);
1951 if ((STRLEN)(tmpbuf + sizeof(tmpbuf) - tmpstart) > len) {
1952 strcpy(tmpstart, fdata.cFileName);
1963 /* failed a step, just return without side effects */
1968 strcpy(path,tmpbuf);
1982 win32_croak_not_implemented(const char * fname)
1984 PERL_ARGS_ASSERT_WIN32_CROAK_NOT_IMPLEMENTED;
1986 Perl_croak_nocontext("%s not implemented!\n", fname);
1989 /* Converts a wide character (UTF-16) string to the Windows ANSI code page,
1990 * potentially using the system's default replacement character for any
1991 * unrepresentable characters. The caller must free() the returned string. */
1993 wstr_to_str(const wchar_t* wstr)
1995 BOOL used_default = FALSE;
1996 size_t wlen = wcslen(wstr) + 1;
1997 int len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wstr, wlen,
1998 NULL, 0, NULL, NULL);
1999 char* str = (char*)malloc(len);
2002 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wstr, wlen,
2003 str, len, NULL, &used_default);
2007 /* The win32_ansipath() function takes a Unicode filename and converts it
2008 * into the current Windows codepage. If some characters cannot be mapped,
2009 * then it will convert the short name instead.
2011 * The buffer to the ansi pathname must be freed with win32_free() when it
2012 * is no longer needed.
2014 * The argument to win32_ansipath() must exist before this function is
2015 * called; otherwise there is no way to determine the short path name.
2017 * Ideas for future refinement:
2018 * - Only convert those segments of the path that are not in the current
2019 * codepage, but leave the other segments in their long form.
2020 * - If the resulting name is longer than MAX_PATH, start converting
2021 * additional path segments into short names until the full name
2022 * is shorter than MAX_PATH. Shorten the filename part last!
2025 win32_ansipath(const WCHAR *widename)
2028 BOOL use_default = FALSE;
2029 size_t widelen = wcslen(widename)+1;
2030 int len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, widename, widelen,
2031 NULL, 0, NULL, NULL);
2032 name = (char*)win32_malloc(len);
2036 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, widename, widelen,
2037 name, len, NULL, &use_default);
2039 DWORD shortlen = GetShortPathNameW(widename, NULL, 0);
2041 WCHAR *shortname = (WCHAR*)win32_malloc(shortlen*sizeof(WCHAR));
2044 shortlen = GetShortPathNameW(widename, shortname, shortlen)+1;
2046 len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, shortname, shortlen,
2047 NULL, 0, NULL, NULL);
2048 name = (char*)win32_realloc(name, len);
2051 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, shortname, shortlen,
2052 name, len, NULL, NULL);
2053 win32_free(shortname);
2059 /* the returned string must be freed with win32_freeenvironmentstrings which is
2060 * implemented as a macro
2061 * void win32_freeenvironmentstrings(void* block)
2064 win32_getenvironmentstrings(void)
2066 LPWSTR lpWStr, lpWTmp;
2068 DWORD env_len, wenvstrings_len = 0, aenvstrings_len = 0;
2070 /* Get the process environment strings */
2071 lpWTmp = lpWStr = (LPWSTR) GetEnvironmentStringsW();
2072 for (wenvstrings_len = 1; *lpWTmp != '\0'; lpWTmp += env_len + 1) {
2073 env_len = wcslen(lpWTmp);
2074 /* calculate the size of the environment strings */
2075 wenvstrings_len += env_len + 1;
2078 /* Get the number of bytes required to store the ACP encoded string */
2079 aenvstrings_len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
2080 lpWStr, wenvstrings_len, NULL, 0, NULL, NULL);
2081 lpTmp = lpStr = (char *)win32_calloc(aenvstrings_len, sizeof(char));
2085 /* Convert the string from UTF-16 encoding to ACP encoding */
2086 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, lpWStr, wenvstrings_len, lpStr,
2087 aenvstrings_len, NULL, NULL);
2089 FreeEnvironmentStringsW(lpWStr);
2095 win32_getenv(const char *name)
2102 needlen = GetEnvironmentVariableA(name,NULL,0);
2104 curitem = sv_2mortal(newSVpvs(""));
2106 SvGROW(curitem, needlen+1);
2107 needlen = GetEnvironmentVariableA(name,SvPVX(curitem),
2109 } while (needlen >= SvLEN(curitem));
2110 SvCUR_set(curitem, needlen);
2113 last_err = GetLastError();
2114 if (last_err == ERROR_NOT_ENOUGH_MEMORY) {
2115 /* It appears the variable is in the env, but the Win32 API
2116 doesn't have a canned way of getting it. So we fall back to
2117 grabbing the whole env and pulling this value out if possible */
2118 char *envv = GetEnvironmentStrings();
2122 char *end = strchr(cur,'=');
2123 if (end && end != cur) {
2125 if (strEQ(cur,name)) {
2126 curitem = sv_2mortal(newSVpv(end+1,0));
2131 cur = end + strlen(end+1)+2;
2133 else if ((len = strlen(cur)))
2136 FreeEnvironmentStrings(envv);
2138 #ifndef WIN32_NO_REGISTRY
2140 /* last ditch: allow any environment variables that begin with 'PERL'
2141 to be obtained from the registry, if found there */
2142 if (strBEGINs(name, "PERL"))
2143 (void)get_regstr(name, &curitem);
2147 if (curitem && SvCUR(curitem))
2148 return SvPVX(curitem);
2154 win32_putenv(const char *name)
2161 curitem = (char *) win32_malloc(strlen(name)+1);
2162 strcpy(curitem, name);
2163 val = strchr(curitem, '=');
2165 /* The sane way to deal with the environment.
2166 * Has these advantages over putenv() & co.:
2167 * * enables us to store a truly empty value in the
2168 * environment (like in UNIX).
2169 * * we don't have to deal with RTL globals, bugs and leaks
2170 * (specifically, see http://support.microsoft.com/kb/235601).
2172 * Why you may want to use the RTL environment handling
2173 * (previously enabled by USE_WIN32_RTL_ENV):
2174 * * environ[] and RTL functions will not reflect changes,
2175 * which might be an issue if extensions want to access
2176 * the env. via RTL. This cuts both ways, since RTL will
2177 * not see changes made by extensions that call the Win32
2178 * functions directly, either.
2182 if (SetEnvironmentVariableA(curitem, *val ? val : NULL))
2185 win32_free(curitem);
2191 filetime_to_clock(PFILETIME ft)
2193 __int64 qw = ft->dwHighDateTime;
2195 qw |= ft->dwLowDateTime;
2196 qw /= 10000; /* File time ticks at 0.1uS, clock at 1mS */
2201 win32_times(struct tms *timebuf)
2206 clock_t process_time_so_far = clock();
2207 if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy,
2209 timebuf->tms_utime = filetime_to_clock(&user);
2210 timebuf->tms_stime = filetime_to_clock(&kernel);
2211 timebuf->tms_cutime = 0;
2212 timebuf->tms_cstime = 0;
2214 /* That failed - e.g. Win95 fallback to clock() */
2215 timebuf->tms_utime = process_time_so_far;
2216 timebuf->tms_stime = 0;
2217 timebuf->tms_cutime = 0;
2218 timebuf->tms_cstime = 0;
2220 return process_time_so_far;
2224 filetime_from_time(PFILETIME pFileTime, time_t Time)
2231 pFileTime->dwLowDateTime = 0;
2232 pFileTime->dwHighDateTime = 0;
2233 fprintf(stderr, "fail bad gmtime\n");
2237 st.wYear = pt->tm_year + 1900;
2238 st.wMonth = pt->tm_mon + 1;
2239 st.wDay = pt->tm_mday;
2240 st.wHour = pt->tm_hour;
2241 st.wMinute = pt->tm_min;
2242 st.wSecond = pt->tm_sec;
2243 st.wMilliseconds = 0;
2245 if (!SystemTimeToFileTime(&st, pFileTime)) {
2246 pFileTime->dwLowDateTime = 0;
2247 pFileTime->dwHighDateTime = 0;
2255 win32_unlink(const char *filename)
2261 filename = PerlDir_mapA(filename);
2262 attrs = GetFileAttributesA(filename);
2263 if (attrs == 0xFFFFFFFF) {
2267 if (attrs & FILE_ATTRIBUTE_READONLY) {
2268 (void)SetFileAttributesA(filename, attrs & ~FILE_ATTRIBUTE_READONLY);
2269 ret = unlink(filename);
2271 (void)SetFileAttributesA(filename, attrs);
2273 else if ((attrs & (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY))
2274 == (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY)
2275 && is_symlink_name(filename)) {
2276 ret = rmdir(filename);
2279 ret = unlink(filename);
2285 win32_utime(const char *filename, struct utimbuf *times)
2291 struct utimbuf TimeBuffer;
2294 filename = PerlDir_mapA(filename);
2295 /* This will (and should) still fail on readonly files */
2296 handle = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE,
2297 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2298 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
2299 if (handle == INVALID_HANDLE_VALUE) {
2300 translate_to_errno();
2304 if (times == NULL) {
2305 times = &TimeBuffer;
2306 time(×->actime);
2307 times->modtime = times->actime;
2310 if (filetime_from_time(&ftAccess, times->actime) &&
2311 filetime_from_time(&ftWrite, times->modtime)) {
2312 if (SetFileTime(handle, NULL, &ftAccess, &ftWrite)) {
2316 translate_to_errno();
2320 errno = EINVAL; /* bad time? */
2323 CloseHandle(handle);
2328 unsigned __int64 ft_i64;
2333 #define Const64(x) x##LL
2335 #define Const64(x) x##i64
2337 /* Number of 100 nanosecond units from 1/1/1601 to 1/1/1970 */
2338 #define EPOCH_BIAS Const64(116444736000000000)
2340 /* NOTE: This does not compute the timezone info (doing so can be expensive,
2341 * and appears to be unsupported even by glibc) */
2343 win32_gettimeofday(struct timeval *tp, void *not_used)
2347 /* this returns time in 100-nanosecond units (i.e. tens of usecs) */
2348 GetSystemTimeAsFileTime(&ft.ft_val);
2350 /* seconds since epoch */
2351 tp->tv_sec = (long)((ft.ft_i64 - EPOCH_BIAS) / Const64(10000000));
2353 /* microseconds remaining */
2354 tp->tv_usec = (long)((ft.ft_i64 / Const64(10)) % Const64(1000000));
2360 win32_uname(struct utsname *name)
2362 struct hostent *hep;
2363 STRLEN nodemax = sizeof(name->nodename)-1;
2366 switch (g_osver.dwPlatformId) {
2367 case VER_PLATFORM_WIN32_WINDOWS:
2368 strcpy(name->sysname, "Windows");
2370 case VER_PLATFORM_WIN32_NT:
2371 strcpy(name->sysname, "Windows NT");
2373 case VER_PLATFORM_WIN32s:
2374 strcpy(name->sysname, "Win32s");
2377 strcpy(name->sysname, "Win32 Unknown");
2382 sprintf(name->release, "%d.%d",
2383 g_osver.dwMajorVersion, g_osver.dwMinorVersion);
2386 sprintf(name->version, "Build %d",
2387 g_osver.dwPlatformId == VER_PLATFORM_WIN32_NT
2388 ? g_osver.dwBuildNumber : (g_osver.dwBuildNumber & 0xffff));
2389 if (g_osver.szCSDVersion[0]) {
2390 char *buf = name->version + strlen(name->version);
2391 sprintf(buf, " (%s)", g_osver.szCSDVersion);
2395 hep = win32_gethostbyname("localhost");
2397 STRLEN len = strlen(hep->h_name);
2398 if (len <= nodemax) {
2399 strcpy(name->nodename, hep->h_name);
2402 strncpy(name->nodename, hep->h_name, nodemax);
2403 name->nodename[nodemax] = '\0';
2408 if (!GetComputerName(name->nodename, &sz))
2409 *name->nodename = '\0';
2412 /* machine (architecture) */
2417 GetSystemInfo(&info);
2419 #if (defined(__MINGW32__) && !defined(_ANONYMOUS_UNION) && !defined(__MINGW_EXTENSION))
2420 procarch = info.u.s.wProcessorArchitecture;
2422 procarch = info.wProcessorArchitecture;
2425 case PROCESSOR_ARCHITECTURE_INTEL:
2426 arch = "x86"; break;
2427 case PROCESSOR_ARCHITECTURE_IA64:
2428 arch = "ia64"; break;
2429 case PROCESSOR_ARCHITECTURE_AMD64:
2430 arch = "amd64"; break;
2431 case PROCESSOR_ARCHITECTURE_UNKNOWN:
2432 arch = "unknown"; break;
2434 sprintf(name->machine, "unknown(0x%x)", procarch);
2435 arch = name->machine;
2438 if (name->machine != arch)
2439 strcpy(name->machine, arch);
2444 /* Timing related stuff */
2447 do_raise(pTHX_ int sig)
2449 if (sig < SIG_SIZE) {
2450 Sighandler_t handler = w32_sighandler[sig];
2451 if (handler == SIG_IGN) {
2454 else if (handler != SIG_DFL) {
2459 /* Choose correct default behaviour */
2475 /* Tell caller to exit thread/process as appropriate */
2480 sig_terminate(pTHX_ int sig)
2482 Perl_warn(aTHX_ "Terminating on signal SIG%s(%d)\n",PL_sig_name[sig], sig);
2483 /* exit() seems to be safe, my_exit() or die() is a problem in ^C
2490 win32_async_check(pTHX)
2493 HWND hwnd = w32_message_hwnd;
2495 /* Reset w32_poll_count before doing anything else, incase we dispatch
2496 * messages that end up calling back into perl */
2499 if (hwnd != INVALID_HANDLE_VALUE) {
2500 /* Passing PeekMessage -1 as HWND (2nd arg) only gets PostThreadMessage() messages
2501 * and ignores window messages - should co-exist better with windows apps e.g. Tk
2506 while (PeekMessage(&msg, hwnd, WM_TIMER, WM_TIMER, PM_REMOVE|PM_NOYIELD) ||
2507 PeekMessage(&msg, hwnd, WM_USER_MIN, WM_USER_MAX, PM_REMOVE|PM_NOYIELD))
2509 /* re-post a WM_QUIT message (we'll mark it as read later) */
2510 if(msg.message == WM_QUIT) {
2511 PostQuitMessage((int)msg.wParam);
2515 if(!CallMsgFilter(&msg, MSGF_USER))
2517 TranslateMessage(&msg);
2518 DispatchMessage(&msg);
2523 /* Call PeekMessage() to mark all pending messages in the queue as "old".
2524 * This is necessary when we are being called by win32_msgwait() to
2525 * make sure MsgWaitForMultipleObjects() stops reporting the same waiting
2526 * message over and over. An example how this can happen is when
2527 * Perl is calling win32_waitpid() inside a GUI application and the GUI
2528 * is generating messages before the process terminated.
2530 PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE|PM_NOYIELD);
2532 /* Above or other stuff may have set a signal flag */
2539 /* This function will not return until the timeout has elapsed, or until
2540 * one of the handles is ready. */
2542 win32_msgwait(pTHX_ DWORD count, LPHANDLE handles, DWORD timeout, LPDWORD resultp)
2544 /* We may need several goes at this - so compute when we stop */
2546 unsigned __int64 endtime = timeout;
2547 if (timeout != INFINITE) {
2548 GetSystemTimeAsFileTime(&ticks.ft_val);
2549 ticks.ft_i64 /= 10000;
2550 endtime += ticks.ft_i64;
2552 /* This was a race condition. Do not let a non INFINITE timeout to
2553 * MsgWaitForMultipleObjects roll under 0 creating a near
2554 * infinity/~(UINT32)0 timeout which will appear as a deadlock to the
2555 * user who did a CORE perl function with a non infinity timeout,
2556 * sleep for example. This is 64 to 32 truncation minefield.
2558 * This scenario can only be created if the timespan from the return of
2559 * MsgWaitForMultipleObjects to GetSystemTimeAsFileTime exceeds 1 ms. To
2560 * generate the scenario, manual breakpoints in a C debugger are required,
2561 * or a context switch occurred in win32_async_check in PeekMessage, or random
2562 * messages are delivered to the *thread* message queue of the Perl thread
2563 * from another process (msctf.dll doing IPC among its instances, VS debugger
2564 * causes msctf.dll to be loaded into Perl by kernel), see [perl #33096].
2566 while (ticks.ft_i64 <= endtime) {
2567 /* if timeout's type is lengthened, remember to split 64b timeout
2568 * into multiple non-infinity runs of MWFMO */
2569 DWORD result = MsgWaitForMultipleObjects(count, handles, FALSE,
2570 (DWORD)(endtime - ticks.ft_i64),
2571 QS_POSTMESSAGE|QS_TIMER|QS_SENDMESSAGE);
2574 if (result == WAIT_TIMEOUT) {
2575 /* Ran out of time - explicit return of zero to avoid -ve if we
2576 have scheduling issues
2580 if (timeout != INFINITE) {
2581 GetSystemTimeAsFileTime(&ticks.ft_val);
2582 ticks.ft_i64 /= 10000;
2584 if (result == WAIT_OBJECT_0 + count) {
2585 /* Message has arrived - check it */
2586 (void)win32_async_check(aTHX);
2589 if (ticks.ft_i64 > endtime)
2590 endtime = ticks.ft_i64;
2595 /* Not timeout or message - one of handles is ready */
2599 /* If we are past the end say zero */
2600 if (!ticks.ft_i64 || ticks.ft_i64 > endtime)
2602 /* compute time left to wait */
2603 ticks.ft_i64 = endtime - ticks.ft_i64;
2604 /* if more ms than DWORD, then return max DWORD */
2605 return ticks.ft_i64 <= UINT_MAX ? (DWORD)ticks.ft_i64 : UINT_MAX;
2609 win32_internal_wait(pTHX_ int *status, DWORD timeout)
2611 /* XXX this wait emulation only knows about processes
2612 * spawned via win32_spawnvp(P_NOWAIT, ...).
2615 DWORD exitcode, waitcode;
2618 if (w32_num_pseudo_children) {
2619 win32_msgwait(aTHX_ w32_num_pseudo_children, w32_pseudo_child_handles,
2620 timeout, &waitcode);
2621 /* Time out here if there are no other children to wait for. */
2622 if (waitcode == WAIT_TIMEOUT) {
2623 if (!w32_num_children) {
2627 else if (waitcode != WAIT_FAILED) {
2628 if (waitcode >= WAIT_ABANDONED_0
2629 && waitcode < WAIT_ABANDONED_0 + w32_num_pseudo_children)
2630 i = waitcode - WAIT_ABANDONED_0;
2632 i = waitcode - WAIT_OBJECT_0;
2633 if (GetExitCodeThread(w32_pseudo_child_handles[i], &exitcode)) {
2634 *status = (int)((exitcode & 0xff) << 8);
2635 retval = (int)w32_pseudo_child_pids[i];
2636 remove_dead_pseudo_process(i);
2643 if (!w32_num_children) {
2648 /* if a child exists, wait for it to die */
2649 win32_msgwait(aTHX_ w32_num_children, w32_child_handles, timeout, &waitcode);
2650 if (waitcode == WAIT_TIMEOUT) {
2653 if (waitcode != WAIT_FAILED) {
2654 if (waitcode >= WAIT_ABANDONED_0
2655 && waitcode < WAIT_ABANDONED_0 + w32_num_children)
2656 i = waitcode - WAIT_ABANDONED_0;
2658 i = waitcode - WAIT_OBJECT_0;
2659 if (GetExitCodeProcess(w32_child_handles[i], &exitcode) ) {
2660 *status = (int)((exitcode & 0xff) << 8);
2661 retval = (int)w32_child_pids[i];
2662 remove_dead_process(i);
2667 errno = GetLastError();
2672 win32_waitpid(int pid, int *status, int flags)
2675 DWORD timeout = (flags & WNOHANG) ? 0 : INFINITE;
2678 if (pid == -1) /* XXX threadid == 1 ? */
2679 return win32_internal_wait(aTHX_ status, timeout);
2682 child = find_pseudo_pid(aTHX_ -pid);
2684 HANDLE hThread = w32_pseudo_child_handles[child];
2686 win32_msgwait(aTHX_ 1, &hThread, timeout, &waitcode);
2687 if (waitcode == WAIT_TIMEOUT) {
2690 else if (waitcode == WAIT_OBJECT_0) {
2691 if (GetExitCodeThread(hThread, &waitcode)) {
2692 *status = (int)((waitcode & 0xff) << 8);
2693 retval = (int)w32_pseudo_child_pids[child];
2694 remove_dead_pseudo_process(child);
2706 child = find_pid(aTHX_ pid);
2708 hProcess = w32_child_handles[child];
2709 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
2710 if (waitcode == WAIT_TIMEOUT) {
2713 else if (waitcode == WAIT_OBJECT_0) {
2714 if (GetExitCodeProcess(hProcess, &waitcode)) {
2715 *status = (int)((waitcode & 0xff) << 8);
2716 retval = (int)w32_child_pids[child];
2717 remove_dead_process(child);
2725 hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
2727 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
2728 if (waitcode == WAIT_TIMEOUT) {
2729 CloseHandle(hProcess);
2732 else if (waitcode == WAIT_OBJECT_0) {
2733 if (GetExitCodeProcess(hProcess, &waitcode)) {
2734 *status = (int)((waitcode & 0xff) << 8);
2735 CloseHandle(hProcess);
2739 CloseHandle(hProcess);
2745 return retval >= 0 ? pid : retval;
2749 win32_wait(int *status)
2752 return win32_internal_wait(aTHX_ status, INFINITE);
2755 DllExport unsigned int
2756 win32_sleep(unsigned int t)
2759 /* Win32 times are in ms so *1000 in and /1000 out */
2760 if (t > UINT_MAX / 1000) {
2761 Perl_ck_warner(aTHX_ packWARN(WARN_OVERFLOW),
2762 "sleep(%lu) too large", t);
2764 return win32_msgwait(aTHX_ 0, NULL, t * 1000, NULL) / 1000;
2771 win32_msgwait(aTHX_ 0, NULL, INFINITE, NULL);
2775 DllExport unsigned int
2776 win32_alarm(unsigned int sec)
2779 * the 'obvious' implentation is SetTimer() with a callback
2780 * which does whatever receiving SIGALRM would do
2781 * we cannot use SIGALRM even via raise() as it is not
2782 * one of the supported codes in <signal.h>
2786 if (w32_message_hwnd == INVALID_HANDLE_VALUE)
2787 w32_message_hwnd = win32_create_message_window();
2790 if (w32_message_hwnd == NULL)
2791 w32_timerid = SetTimer(NULL, w32_timerid, sec*1000, NULL);
2794 SetTimer(w32_message_hwnd, w32_timerid, sec*1000, NULL);
2799 KillTimer(w32_message_hwnd, w32_timerid);
2806 extern char * des_fcrypt(const char *txt, const char *salt, char *cbuf);
2809 win32_crypt(const char *txt, const char *salt)
2812 return des_fcrypt(txt, salt, w32_crypt_buffer);
2815 /* simulate flock by locking a range on the file */
2817 #define LK_LEN 0xffff0000
2820 win32_flock(int fd, int oper)
2826 fh = (HANDLE)_get_osfhandle(fd);
2827 if (fh == (HANDLE)-1) /* _get_osfhandle() already sets errno to EBADF */
2830 memset(&o, 0, sizeof(o));
2833 case LOCK_SH: /* shared lock */
2834 if (LockFileEx(fh, 0, 0, LK_LEN, 0, &o))
2837 case LOCK_EX: /* exclusive lock */
2838 if (LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o))
2841 case LOCK_SH|LOCK_NB: /* non-blocking shared lock */
2842 if (LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o))
2845 case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */
2846 if (LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
2850 case LOCK_UN: /* unlock lock */
2851 if (UnlockFileEx(fh, 0, LK_LEN, 0, &o))
2854 default: /* unknown */
2859 if (GetLastError() == ERROR_LOCK_VIOLATION)
2860 errno = EWOULDBLOCK;
2869 extern int convert_wsa_error_to_errno(int wsaerr); /* in win32sck.c */
2871 /* Get the errno value corresponding to the given err. This function is not
2872 * intended to handle conversion of general GetLastError() codes. It only exists
2873 * to translate Windows sockets error codes from WSAGetLastError(). Such codes
2874 * used to be assigned to errno/$! in earlier versions of perl; this function is
2875 * used to catch any old Perl code which is still trying to assign such values
2876 * to $! and convert them to errno values instead.
2879 win32_get_errno(int err)
2881 return convert_wsa_error_to_errno(err);
2885 * redirected io subsystem for all XS modules
2898 return (&(_environ));
2901 /* the rest are the remapped stdio routines */
2921 win32_ferror(FILE *fp)
2923 return (ferror(fp));
2928 win32_feof(FILE *fp)
2933 #ifdef ERRNO_HAS_POSIX_SUPPLEMENT
2934 extern int convert_errno_to_wsa_error(int err); /* in win32sck.c */
2938 * Since the errors returned by the socket error function
2939 * WSAGetLastError() are not known by the library routine strerror
2940 * we have to roll our own to cover the case of socket errors
2941 * that could not be converted to regular errno values by
2942 * get_last_socket_error() in win32/win32sck.c.
2946 win32_strerror(int e)
2948 #if !defined __MINGW32__ /* compiler intolerance */
2949 extern int sys_nerr;
2952 if (e < 0 || e > sys_nerr) {
2956 #ifdef ERRNO_HAS_POSIX_SUPPLEMENT
2957 /* VC10+ and some MinGW/gcc-4.8+ define a "POSIX supplement" of errno
2958 * values ranging from EADDRINUSE (100) to EWOULDBLOCK (140), but
2959 * sys_nerr is still 43 and strerror() returns "Unknown error" for them.
2960 * We must therefore still roll our own messages for these codes, and
2961 * additionally map them to corresponding Windows (sockets) error codes
2962 * first to avoid getting the wrong system message.
2964 else if (inRANGE(e, EADDRINUSE, EWOULDBLOCK)) {
2965 e = convert_errno_to_wsa_error(e);
2969 aTHXa(PERL_GET_THX);
2970 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
2971 |FORMAT_MESSAGE_IGNORE_INSERTS, NULL, e, 0,
2972 w32_strerror_buffer, sizeof(w32_strerror_buffer),
2975 strcpy(w32_strerror_buffer, "Unknown Error");
2977 return w32_strerror_buffer;
2981 #define strerror win32_strerror
2985 win32_str_os_error(void *sv, DWORD dwErr)
2989 dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
2990 |FORMAT_MESSAGE_IGNORE_INSERTS
2991 |FORMAT_MESSAGE_FROM_SYSTEM, NULL,
2992 dwErr, 0, (char *)&sMsg, 1, NULL);
2993 /* strip trailing whitespace and period */
2996 --dwLen; /* dwLen doesn't include trailing null */
2997 } while (0 < dwLen && isSPACE(sMsg[dwLen]));
2998 if ('.' != sMsg[dwLen])
3003 sMsg = (char*)LocalAlloc(0, 64/**sizeof(TCHAR)*/);
3005 dwLen = sprintf(sMsg,
3006 "Unknown error #0x%lX (lookup 0x%lX)",
3007 dwErr, GetLastError());
3011 sv_setpvn((SV*)sv, sMsg, dwLen);
3017 win32_fprintf(FILE *fp, const char *format, ...)
3020 va_start(marker, format); /* Initialize variable arguments. */
3022 return (vfprintf(fp, format, marker));
3026 win32_printf(const char *format, ...)
3029 va_start(marker, format); /* Initialize variable arguments. */
3031 return (vprintf(format, marker));
3035 win32_vfprintf(FILE *fp, const char *format, va_list args)
3037 return (vfprintf(fp, format, args));
3041 win32_vprintf(const char *format, va_list args)
3043 return (vprintf(format, args));
3047 win32_fread(void *buf, size_t size, size_t count, FILE *fp)
3049 return fread(buf, size, count, fp);
3053 win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
3055 return fwrite(buf, size, count, fp);
3058 #define MODE_SIZE 10
3061 win32_fopen(const char *filename, const char *mode)
3069 if (stricmp(filename, "/dev/null")==0)
3072 aTHXa(PERL_GET_THX);
3073 f = fopen(PerlDir_mapA(filename), mode);
3074 /* avoid buffering headaches for child processes */
3075 if (f && *mode == 'a')
3076 win32_fseek(f, 0, SEEK_END);
3081 win32_fdopen(int handle, const char *mode)
3084 f = fdopen(handle, (char *) mode);
3085 /* avoid buffering headaches for child processes */
3086 if (f && *mode == 'a')
3087 win32_fseek(f, 0, SEEK_END);
3092 win32_freopen(const char *path, const char *mode, FILE *stream)
3095 if (stricmp(path, "/dev/null")==0)
3098 aTHXa(PERL_GET_THX);
3099 return freopen(PerlDir_mapA(path), mode, stream);
3103 win32_fclose(FILE *pf)
3105 #ifdef WIN32_NO_SOCKETS
3108 return my_fclose(pf); /* defined in win32sck.c */
3113 win32_fputs(const char *s,FILE *pf)
3115 return fputs(s, pf);
3119 win32_fputc(int c,FILE *pf)
3125 win32_ungetc(int c,FILE *pf)
3127 return ungetc(c,pf);
3131 win32_getc(FILE *pf)
3137 win32_fileno(FILE *pf)
3143 win32_clearerr(FILE *pf)
3150 win32_fflush(FILE *pf)
3156 win32_ftell(FILE *pf)
3159 if (fgetpos(pf, &pos))
3165 win32_fseek(FILE *pf, Off_t offset,int origin)
3170 if (fgetpos(pf, &pos))
3175 fseek(pf, 0, SEEK_END);
3176 pos = _telli64(fileno(pf));
3185 return fsetpos(pf, &offset);
3189 win32_fgetpos(FILE *pf,fpos_t *p)
3191 return fgetpos(pf, p);
3195 win32_fsetpos(FILE *pf,const fpos_t *p)
3197 return fsetpos(pf, p);
3201 win32_rewind(FILE *pf)
3210 return win32_tmpfd_mode(0);
3214 win32_tmpfd_mode(int mode)
3216 char prefix[MAX_PATH+1];
3217 char filename[MAX_PATH+1];
3218 DWORD len = GetTempPath(MAX_PATH, prefix);
3219 mode &= ~( O_ACCMODE | O_CREAT | O_EXCL );
3221 if (len && len < MAX_PATH) {
3222 if (GetTempFileName(prefix, "plx", 0, filename)) {
3223 HANDLE fh = CreateFile(filename,
3224 DELETE | GENERIC_READ | GENERIC_WRITE,
3228 FILE_ATTRIBUTE_NORMAL
3229 | FILE_FLAG_DELETE_ON_CLOSE,
3231 if (fh != INVALID_HANDLE_VALUE) {
3232 int fd = win32_open_osfhandle((intptr_t)fh, mode);
3235 DEBUG_p(PerlIO_printf(Perl_debug_log,
3236 "Created tmpfile=%s\n",filename));
3248 int fd = win32_tmpfd();
3250 return win32_fdopen(fd, "w+b");
3262 win32_fstat(int fd, Stat_t *sbufptr)
3264 HANDLE handle = (HANDLE)win32_get_osfhandle(fd);
3266 return win32_stat_low(handle, NULL, 0, sbufptr);
3270 win32_pipe(int *pfd, unsigned int size, int mode)
3272 return _pipe(pfd, size, mode);
3276 win32_popenlist(const char *mode, IV narg, SV **args)
3280 return do_popen(mode, NULL, narg, args);
3284 do_popen(const char *mode, const char *command, IV narg, SV **args) {
3293 const char **args_pvs = NULL;
3295 /* establish which ends read and write */
3296 if (strchr(mode,'w')) {
3297 stdfd = 0; /* stdin */
3300 nhandle = STD_INPUT_HANDLE;
3302 else if (strchr(mode,'r')) {
3303 stdfd = 1; /* stdout */
3306 nhandle = STD_OUTPUT_HANDLE;
3311 /* set the correct mode */
3312 if (strchr(mode,'b'))
3314 else if (strchr(mode,'t'))
3317 ourmode = _fmode & (O_TEXT | O_BINARY);
3319 /* the child doesn't inherit handles */
3320 ourmode |= O_NOINHERIT;
3322 if (win32_pipe(p, 512, ourmode) == -1)
3325 /* Previously this code redirected stdin/out temporarily so the
3326 child process inherited those handles, this caused race
3327 conditions when another thread was writing/reading those
3330 To avoid that we just feed the handles to CreateProcess() so
3331 the handles are redirected only in the child.
3333 handles[child] = p[child];
3334 handles[parent] = -1;
3337 /* CreateProcess() requires inheritable handles */
3338 if (!SetHandleInformation((HANDLE)_get_osfhandle(p[child]), HANDLE_FLAG_INHERIT,
3339 HANDLE_FLAG_INHERIT)) {
3343 /* start the child */
3348 if ((childpid = do_spawn2_handles(aTHX_ command, EXECF_SPAWN_NOWAIT, handles)) == -1)
3354 const char *exe_name;
3356 Newx(args_pvs, narg + 1 + w32_perlshell_items, const char *);
3357 SAVEFREEPV(args_pvs);
3358 for (i = 0; i < narg; ++i)
3359 args_pvs[i] = SvPV_nolen(args[i]);
3361 exe_name = qualified_path(args_pvs[0], TRUE);
3363 /* let CreateProcess() try to find it instead */
3364 exe_name = args_pvs[0];
3366 if ((childpid = do_spawnvp_handles(P_NOWAIT, exe_name, args_pvs, handles)) == -1) {
3371 win32_close(p[child]);
3373 sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid);
3375 /* set process id so that it can be returned by perl's open() */
3376 PL_forkprocess = childpid;
3379 /* we have an fd, return a file stream */
3380 return (PerlIO_fdopen(p[parent], (char *)mode));
3383 /* we don't need to check for errors here */
3391 * a popen() clone that respects PERL5SHELL
3393 * changed to return PerlIO* rather than FILE * by BKS, 11-11-2000
3397 win32_popen(const char *command, const char *mode)
3399 #ifdef USE_RTL_POPEN
3400 return _popen(command, mode);
3402 return do_popen(mode, command, 0, NULL);
3403 #endif /* USE_RTL_POPEN */
3411 win32_pclose(PerlIO *pf)
3413 #ifdef USE_RTL_POPEN
3417 int childpid, status;
3420 sv = *av_fetch(w32_fdpid, PerlIO_fileno(pf), TRUE);
3423 childpid = SvIVX(sv);
3439 if (win32_waitpid(childpid, &status, 0) == -1)
3444 #endif /* USE_RTL_POPEN */
3448 win32_link(const char *oldname, const char *newname)
3451 WCHAR wOldName[MAX_PATH+1];
3452 WCHAR wNewName[MAX_PATH+1];
3454 if (MultiByteToWideChar(CP_ACP, 0, oldname, -1, wOldName, MAX_PATH+1) &&
3455 MultiByteToWideChar(CP_ACP, 0, newname, -1, wNewName, MAX_PATH+1) &&
3456 ((aTHXa(PERL_GET_THX)), wcscpy(wOldName, PerlDir_mapW(wOldName)),
3457 CreateHardLinkW(PerlDir_mapW(wNewName), wOldName, NULL)))
3461 translate_to_errno();
3465 typedef BOOLEAN (__stdcall *pCreateSymbolicLinkA_t)(LPCSTR, LPCSTR, DWORD);
3467 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
3468 # define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
3471 #ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
3472 # define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 0x2
3476 win32_symlink(const char *oldfile, const char *newfile)
3479 size_t oldfile_len = strlen(oldfile);
3480 pCreateSymbolicLinkA_t pCreateSymbolicLinkA =
3481 (pCreateSymbolicLinkA_t)GetProcAddress(GetModuleHandle("kernel32.dll"), "CreateSymbolicLinkA");
3482 DWORD create_flags = 0;
3484 /* this flag can be used only on Windows 10 1703 or newer */
3485 if (g_osver.dwMajorVersion > 10 ||
3486 (g_osver.dwMajorVersion == 10 &&
3487 (g_osver.dwMinorVersion > 0 || g_osver.dwBuildNumber > 15063)))
3489 create_flags |= SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
3492 if (!pCreateSymbolicLinkA) {
3497 /* oldfile might be relative and we don't want to change that,
3500 newfile = PerlDir_mapA(newfile);
3502 /* are we linking to a directory?
3503 CreateSymlinkA() needs to know if the target is a directory,
3504 If it looks like a directory name:
3507 - ends in /. or /.. (with either slash)
3508 - is a simple drive letter
3509 assume it's a directory.
3511 Otherwise if the oldfile is relative we need to make a relative path
3512 based on the newfile to check if the target is a directory.
3514 if ((oldfile_len >= 1 && isSLASH(oldfile[oldfile_len-1])) ||
3515 strEQ(oldfile, "..") ||
3516 strEQ(oldfile, ".") ||
3517 (isSLASH(oldfile[oldfile_len-2]) && oldfile[oldfile_len-1] == '.') ||
3518 strEQ(oldfile+oldfile_len-3, "\\..") ||
3519 strEQ(oldfile+oldfile_len-3, "/..") ||
3520 (oldfile_len == 2 && oldfile[1] == ':')) {
3521 create_flags |= SYMBOLIC_LINK_FLAG_DIRECTORY;
3525 const char *dest_path = oldfile;
3526 char szTargetName[MAX_PATH+1];
3528 if (oldfile_len >= 3 && oldfile[1] == ':' && oldfile[2] != '\\' && oldfile[2] != '/') {
3529 /* relative to current directory on a drive */
3530 /* dest_path = oldfile; already done */
3532 else if (oldfile[0] != '\\' && oldfile[0] != '/') {
3533 size_t newfile_len = strlen(newfile);
3534 char *last_slash = strrchr(newfile, '/');
3535 char *last_bslash = strrchr(newfile, '\\');
3536 char *end_dir = last_slash && last_bslash
3537 ? ( last_slash > last_bslash ? last_slash : last_bslash)
3538 : last_slash ? last_slash : last_bslash ? last_bslash : NULL;
3541 if ((end_dir - newfile + 1) + oldfile_len > MAX_PATH) {
3547 memcpy(szTargetName, newfile, end_dir - newfile + 1);
3548 strcpy(szTargetName + (end_dir - newfile + 1), oldfile);
3549 dest_path = szTargetName;
3552 /* newpath is just a filename */
3553 /* dest_path = oldfile; */
3557 dest_attr = GetFileAttributes(dest_path);
3558 if (dest_attr != (DWORD)-1 && (dest_attr & FILE_ATTRIBUTE_DIRECTORY)) {
3559 create_flags |= SYMBOLIC_LINK_FLAG_DIRECTORY;
3563 if (!pCreateSymbolicLinkA(newfile, oldfile, create_flags)) {
3564 translate_to_errno();
3572 win32_rename(const char *oname, const char *newname)
3574 char szOldName[MAX_PATH+1];
3576 DWORD dwFlags = MOVEFILE_COPY_ALLOWED;
3579 if (stricmp(newname, oname))
3580 dwFlags |= MOVEFILE_REPLACE_EXISTING;
3581 strcpy(szOldName, PerlDir_mapA(oname));
3583 bResult = MoveFileExA(szOldName,PerlDir_mapA(newname), dwFlags);
3585 DWORD err = GetLastError();
3587 case ERROR_BAD_NET_NAME:
3588 case ERROR_BAD_NETPATH:
3589 case ERROR_BAD_PATHNAME:
3590 case ERROR_FILE_NOT_FOUND:
3591 case ERROR_FILENAME_EXCED_RANGE:
3592 case ERROR_INVALID_DRIVE:
3593 case ERROR_NO_MORE_FILES:
3594 case ERROR_PATH_NOT_FOUND:
3597 case ERROR_DISK_FULL:
3600 case ERROR_NOT_ENOUGH_QUOTA:
3613 win32_setmode(int fd, int mode)
3615 return setmode(fd, mode);
3619 win32_chsize(int fd, Off_t size)
3622 Off_t cur, end, extend;
3624 cur = win32_tell(fd);
3627 end = win32_lseek(fd, 0, SEEK_END);
3630 extend = size - end;
3634 else if (extend > 0) {
3635 /* must grow the file, padding with nulls */
3637 int oldmode = win32_setmode(fd, O_BINARY);
3639 memset(b, '\0', sizeof(b));
3641 count = extend >= sizeof(b) ? sizeof(b) : (size_t)extend;
3642 count = win32_write(fd, b, count);
3643 if ((int)count < 0) {
3647 } while ((extend -= count) > 0);
3648 win32_setmode(fd, oldmode);
3651 /* shrink the file */
3652 win32_lseek(fd, size, SEEK_SET);
3653 if (!SetEndOfFile((HANDLE)_get_osfhandle(fd))) {
3658 win32_lseek(fd, cur, SEEK_SET);
3663 win32_lseek(int fd, Off_t offset, int origin)
3665 return _lseeki64(fd, offset, origin);
3671 return _telli64(fd);
3675 win32_open(const char *path, int flag, ...)
3682 pmode = va_arg(ap, int);
3685 if (stricmp(path, "/dev/null")==0)
3688 aTHXa(PERL_GET_THX);
3689 return open(PerlDir_mapA(path), flag, pmode);
3692 /* close() that understands socket */
3693 extern int my_close(int); /* in win32sck.c */
3698 #ifdef WIN32_NO_SOCKETS
3701 return my_close(fd);
3712 win32_isatty(int fd)
3714 /* The Microsoft isatty() function returns true for *all*
3715 * character mode devices, including "nul". Our implementation
3716 * should only return true if the handle has a console buffer.
3719 HANDLE fh = (HANDLE)_get_osfhandle(fd);
3720 if (fh == (HANDLE)-1) {
3721 /* errno is already set to EBADF */
3725 if (GetConsoleMode(fh, &mode))
3739 win32_dup2(int fd1,int fd2)
3741 return dup2(fd1,fd2);
3745 win32_read(int fd, void *buf, unsigned int cnt)
3747 return read(fd, buf, cnt);
3751 win32_write(int fd, const void *buf, unsigned int cnt)
3753 return write(fd, buf, cnt);
3757 win32_mkdir(const char *dir, int mode)
3760 return mkdir(PerlDir_mapA(dir)); /* just ignore mode */
3764 win32_rmdir(const char *dir)
3767 return rmdir(PerlDir_mapA(dir));
3771 win32_chdir(const char *dir)
3773 if (!dir || !*dir) {
3781 win32_access(const char *path, int mode)
3784 return access(PerlDir_mapA(path), mode);
3788 win32_chmod(const char *path, int mode)
3791 return chmod(PerlDir_mapA(path), mode);
3796 create_command_line(char *cname, STRLEN clen, const char * const *args)
3803 bool bat_file = FALSE;
3804 bool cmd_shell = FALSE;
3805 bool dumb_shell = FALSE;
3806 bool extra_quotes = FALSE;
3807 bool quote_next = FALSE;
3810 cname = (char*)args[0];
3812 /* The NT cmd.exe shell has the following peculiarity that needs to be
3813 * worked around. It strips a leading and trailing dquote when any
3814 * of the following is true:
3815 * 1. the /S switch was used
3816 * 2. there are more than two dquotes
3817 * 3. there is a special character from this set: &<>()@^|
3818 * 4. no whitespace characters within the two dquotes
3819 * 5. string between two dquotes isn't an executable file
3820 * To work around this, we always add a leading and trailing dquote
3821 * to the string, if the first argument is either "cmd.exe" or "cmd",
3822 * and there were at least two or more arguments passed to cmd.exe
3823 * (not including switches).
3824 * XXX the above rules (from "cmd /?") don't seem to be applied
3825 * always, making for the convolutions below :-(
3829 clen = strlen(cname);
3832 && (stricmp(&cname[clen-4], ".bat") == 0
3833 || (stricmp(&cname[clen-4], ".cmd") == 0)))
3839 char *exe = strrchr(cname, '/');
3840 char *exe2 = strrchr(cname, '\\');
3847 if (stricmp(exe, "cmd.exe") == 0 || stricmp(exe, "cmd") == 0) {
3851 else if (stricmp(exe, "command.com") == 0
3852 || stricmp(exe, "command") == 0)
3859 DEBUG_p(PerlIO_printf(Perl_debug_log, "Args "));
3860 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3861 STRLEN curlen = strlen(arg);
3862 if (!(arg[0] == '"' && arg[curlen-1] == '"'))
3863 len += 2; /* assume quoting needed (worst case) */
3865 DEBUG_p(PerlIO_printf(Perl_debug_log, "[%s]",arg));
3867 DEBUG_p(PerlIO_printf(Perl_debug_log, "\n"));
3870 Newx(cmd, len, char);
3875 extra_quotes = TRUE;
3878 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3880 STRLEN curlen = strlen(arg);
3882 /* we want to protect empty arguments and ones with spaces with
3883 * dquotes, but only if they aren't already there */
3888 else if (quote_next) {
3889 /* see if it really is multiple arguments pretending to
3890 * be one and force a set of quotes around it */
3891 if (*find_next_space(arg))
3894 else if (!(arg[0] == '"' && curlen > 1 && arg[curlen-1] == '"')) {
3896 while (i < curlen) {
3897 if (isSPACE(arg[i])) {
3900 else if (arg[i] == '"') {
3924 && *arg == '/' /* see if arg is "/c", "/x/c", "/x/d/c" etc. */
3925 && stricmp(arg+curlen-2, "/c") == 0)
3927 /* is there a next argument? */
3928 if (args[index+1]) {
3929 /* are there two or more next arguments? */
3930 if (args[index+2]) {
3932 extra_quotes = TRUE;
3935 /* single argument, force quoting if it has spaces */
3950 static const char *exe_extensions[] =
3952 ".exe", /* this must be first */
3958 qualified_path(const char *cmd, bool other_exts)
3961 char *fullcmd, *curfullcmd;
3967 fullcmd = (char*)cmd;
3969 if (*fullcmd == '/' || *fullcmd == '\\')
3978 pathstr = PerlEnv_getenv("PATH");
3980 /* worst case: PATH is a single directory; we need additional space
3981 * to append "/", ".exe" and trailing "\0" */
3982 Newx(fullcmd, (pathstr ? strlen(pathstr) : 0) + cmdlen + 6, char);
3983 curfullcmd = fullcmd;
3988 /* start by appending the name to the current prefix */
3989 strcpy(curfullcmd, cmd);
3990 curfullcmd += cmdlen;
3992 /* if it doesn't end with '.', or has no extension, try adding
3993 * a trailing .exe first */
3994 if (cmd[cmdlen-1] != '.'
3995 && (cmdlen < 4 || cmd[cmdlen-4] != '.'))
3998 /* first extension is .exe */
3999 int ext_limit = other_exts ? C_ARRAY_LENGTH(exe_extensions) : 1;
4000 for (i = 0; i < ext_limit; ++i) {
4001 strcpy(curfullcmd, exe_extensions[i]);
4002 res = GetFileAttributes(fullcmd);
4003 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
4010 /* that failed, try the bare name */
4011 res = GetFileAttributes(fullcmd);
4012 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
4015 /* quit if no other path exists, or if cmd already has path */
4016 if (!pathstr || !*pathstr || has_slash)
4019 /* skip leading semis */
4020 while (*pathstr == ';')
4023 /* build a new prefix from scratch */
4024 curfullcmd = fullcmd;
4025 while (*pathstr && *pathstr != ';') {
4026 if (*pathstr == '"') { /* foo;"baz;etc";bar */
4027 pathstr++; /* skip initial '"' */
4028 while (*pathstr && *pathstr != '"') {
4029 *curfullcmd++ = *pathstr++;
4032 pathstr++; /* skip trailing '"' */
4035 *curfullcmd++ = *pathstr++;
4039 pathstr++; /* skip trailing semi */
4040 if (curfullcmd > fullcmd /* append a dir separator */
4041 && curfullcmd[-1] != '/' && curfullcmd[-1] != '\\')
4043 *curfullcmd++ = '\\';
4051 /* The following are just place holders.
4052 * Some hosts may provide and environment that the OS is
4053 * not tracking, therefore, these host must provide that
4054 * environment and the current directory to CreateProcess
4058 win32_get_childenv(void)
4064 win32_free_childenv(void* d)
4069 win32_clearenv(void)
4071 char *envv = GetEnvironmentStrings();
4075 char *end = strchr(cur,'=');
4076 if (end && end != cur) {
4078 SetEnvironmentVariable(cur, NULL);
4080 cur = end + strlen(end+1)+2;
4082 else if ((len = strlen(cur)))
4085 FreeEnvironmentStrings(envv);
4089 win32_get_childdir(void)
4092 char szfilename[MAX_PATH+1];
4094 GetCurrentDirectoryA(MAX_PATH+1, szfilename);
4095 Newx(ptr, strlen(szfilename)+1, char);
4096 strcpy(ptr, szfilename);
4101 win32_free_childdir(char* d)
4107 /* XXX this needs to be made more compatible with the spawnvp()
4108 * provided by the various RTLs. In particular, searching for
4109 * *.{com,bat,cmd} files (as done by the RTLs) is unimplemented.
4110 * This doesn't significantly affect perl itself, because we
4111 * always invoke things using PERL5SHELL if a direct attempt to
4112 * spawn the executable fails.
4114 * XXX splitting and rejoining the commandline between do_aspawn()
4115 * and win32_spawnvp() could also be avoided.
4119 win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
4121 #ifdef USE_RTL_SPAWNVP
4122 return _spawnvp(mode, cmdname, (char * const *)argv);
4124 return do_spawnvp_handles(mode, cmdname, argv, NULL);
4129 do_spawnvp_handles(int mode, const char *cmdname, const char *const *argv,
4130 const int *handles) {
4136 STARTUPINFO StartupInfo;
4137 PROCESS_INFORMATION ProcessInformation;
4140 char *fullcmd = NULL;
4141 char *cname = (char *)cmdname;
4145 clen = strlen(cname);
4146 /* if command name contains dquotes, must remove them */
4147 if (strchr(cname, '"')) {
4149 Newx(cname,clen+1,char);
4162 cmd = create_command_line(cname, clen, argv);
4164 aTHXa(PERL_GET_THX);
4165 env = PerlEnv_get_childenv();
4166 dir = PerlEnv_get_childdir();
4169 case P_NOWAIT: /* asynch + remember result */
4170 if (w32_num_children >= MAXIMUM_WAIT_OBJECTS) {
4175 /* Create a new process group so we can use GenerateConsoleCtrlEvent()
4178 create |= CREATE_NEW_PROCESS_GROUP;
4181 case P_WAIT: /* synchronous execution */
4183 default: /* invalid mode */
4189 memset(&StartupInfo,0,sizeof(StartupInfo));
4190 StartupInfo.cb = sizeof(StartupInfo);
4191 memset(&tbl,0,sizeof(tbl));
4192 PerlEnv_get_child_IO(&tbl);
4193 StartupInfo.dwFlags = tbl.dwFlags;
4194 StartupInfo.dwX = tbl.dwX;
4195 StartupInfo.dwY = tbl.dwY;
4196 StartupInfo.dwXSize = tbl.dwXSize;
4197 StartupInfo.dwYSize = tbl.dwYSize;
4198 StartupInfo.dwXCountChars = tbl.dwXCountChars;
4199 StartupInfo.dwYCountChars = tbl.dwYCountChars;
4200 StartupInfo.dwFillAttribute = tbl.dwFillAttribute;
4201 StartupInfo.wShowWindow = tbl.wShowWindow;
4202 StartupInfo.hStdInput = handles && handles[0] != -1 ?
4203 (HANDLE)_get_osfhandle(handles[0]) : tbl.childStdIn;
4204 StartupInfo.hStdOutput = handles && handles[1] != -1 ?
4205 (HANDLE)_get_osfhandle(handles[1]) : tbl.childStdOut;
4206 StartupInfo.hStdError = handles && handles[2] != -1 ?
4207 (HANDLE)_get_osfhandle(handles[2]) : tbl.childStdErr;
4208 if (StartupInfo.hStdInput == INVALID_HANDLE_VALUE &&
4209 StartupInfo.hStdOutput == INVALID_HANDLE_VALUE &&
4210 StartupInfo.hStdError == INVALID_HANDLE_VALUE)
4212 create |= CREATE_NEW_CONSOLE;
4215 StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
4217 if (w32_use_showwindow) {
4218 StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
4219 StartupInfo.wShowWindow = w32_showwindow;
4222 DEBUG_p(PerlIO_printf(Perl_debug_log, "Spawning [%s] with [%s]\n",
4225 if (!CreateProcess(cname, /* search PATH to find executable */
4226 cmd, /* executable, and its arguments */
4227 NULL, /* process attributes */
4228 NULL, /* thread attributes */
4229 TRUE, /* inherit handles */
4230 create, /* creation flags */
4231 (LPVOID)env, /* inherit environment */
4232 dir, /* inherit cwd */
4234 &ProcessInformation))
4236 /* initial NULL argument to CreateProcess() does a PATH
4237 * search, but it always first looks in the directory
4238 * where the current process was started, which behavior
4239 * is undesirable for backward compatibility. So we
4240 * jump through our own hoops by picking out the path
4241 * we really want it to use. */
4243 fullcmd = qualified_path(cname, FALSE);
4245 if (cname != cmdname)
4248 DEBUG_p(PerlIO_printf(Perl_debug_log,
4249 "Retrying [%s] with same args\n",
4259 if (mode == P_NOWAIT) {
4260 /* asynchronous spawn -- store handle, return PID */
4261 ret = (int)ProcessInformation.dwProcessId;
4263 w32_child_handles[w32_num_children] = ProcessInformation.hProcess;
4264 w32_child_pids[w32_num_children] = (DWORD)ret;
4269 win32_msgwait(aTHX_ 1, &ProcessInformation.hProcess, INFINITE, NULL);
4270 /* FIXME: if msgwait returned due to message perhaps forward the
4271 "signal" to the process
4273 GetExitCodeProcess(ProcessInformation.hProcess, &status);
4275 CloseHandle(ProcessInformation.hProcess);
4278 CloseHandle(ProcessInformation.hThread);
4281 PerlEnv_free_childenv(env);
4282 PerlEnv_free_childdir(dir);
4284 if (cname != cmdname)
4290 win32_execv(const char *cmdname, const char *const *argv)
4294 /* if this is a pseudo-forked child, we just want to spawn
4295 * the new program, and return */
4297 return _spawnv(P_WAIT, cmdname, argv);
4299 return _execv(cmdname, argv);
4303 win32_execvp(const char *cmdname, const char *const *argv)
4307 /* if this is a pseudo-forked child, we just want to spawn
4308 * the new program, and return */
4309 if (w32_pseudo_id) {
4310 int status = win32_spawnvp(P_WAIT, cmdname, (const char *const *)argv);
4319 return _execvp(cmdname, argv);
4323 win32_perror(const char *str)
4329 win32_setbuf(FILE *pf, char *buf)
4335 win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
4337 return setvbuf(pf, buf, type, size);
4341 win32_flushall(void)
4347 win32_fcloseall(void)
4353 win32_fgets(char *s, int n, FILE *pf)
4355 return fgets(s, n, pf);
4365 win32_fgetc(FILE *pf)
4371 win32_putc(int c, FILE *pf)
4377 win32_puts(const char *s)
4389 win32_putchar(int c)
4396 #ifndef USE_PERL_SBRK
4398 static char *committed = NULL; /* XXX threadead */
4399 static char *base = NULL; /* XXX threadead */
4400 static char *reserved = NULL; /* XXX threadead */
4401 static char *brk = NULL; /* XXX threadead */
4402 static DWORD pagesize = 0; /* XXX threadead */
4405 sbrk(ptrdiff_t need)
4410 GetSystemInfo(&info);
4411 /* Pretend page size is larger so we don't perpetually
4412 * call the OS to commit just one page ...
4414 pagesize = info.dwPageSize << 3;
4416 if (brk+need >= reserved)
4418 DWORD size = brk+need-reserved;
4420 char *prev_committed = NULL;
4421 if (committed && reserved && committed < reserved)
4423 /* Commit last of previous chunk cannot span allocations */
4424 addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
4427 /* Remember where we committed from in case we want to decommit later */
4428 prev_committed = committed;
4429 committed = reserved;
4432 /* Reserve some (more) space
4433 * Contiguous blocks give us greater efficiency, so reserve big blocks -
4434 * this is only address space not memory...
4435 * Note this is a little sneaky, 1st call passes NULL as reserved
4436 * so lets system choose where we start, subsequent calls pass
4437 * the old end address so ask for a contiguous block
4440 if (size < 64*1024*1024)
4441 size = 64*1024*1024;
4442 size = ((size + pagesize - 1) / pagesize) * pagesize;
4443 addr = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
4446 reserved = addr+size;
4456 /* The existing block could not be extended far enough, so decommit
4457 * anything that was just committed above and start anew */
4460 if (!VirtualFree(prev_committed,reserved-prev_committed,MEM_DECOMMIT))
4463 reserved = base = committed = brk = NULL;
4474 if (brk > committed)
4476 DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
4478 if (committed+size > reserved)
4479 size = reserved-committed;
4480 addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
4493 win32_malloc(size_t size)
4495 return malloc(size);
4499 win32_calloc(size_t numitems, size_t size)
4501 return calloc(numitems,size);
4505 win32_realloc(void *block, size_t size)
4507 return realloc(block,size);
4511 win32_free(void *block)
4518 win32_open_osfhandle(intptr_t handle, int flags)
4520 return _open_osfhandle(handle, flags);
4524 win32_get_osfhandle(int fd)
4526 return (intptr_t)_get_osfhandle(fd);
4530 win32_fdupopen(FILE *pf)
4535 int fileno = win32_dup(win32_fileno(pf));
4537 /* open the file in the same mode */
4538 if (PERLIO_FILE_flag(pf) & PERLIO_FILE_flag_RD) {
4542 else if (PERLIO_FILE_flag(pf) & PERLIO_FILE_flag_WR) {
4546 else if (PERLIO_FILE_flag(pf) & PERLIO_FILE_flag_RW) {
4552 /* it appears that the binmode is attached to the
4553 * file descriptor so binmode files will be handled
4556 pfdup = win32_fdopen(fileno, mode);
4558 /* move the file pointer to the same position */
4559 if (!fgetpos(pf, &pos)) {
4560 fsetpos(pfdup, &pos);
4566 win32_dynaload(const char* filename)
4569 char buf[MAX_PATH+1];
4572 /* LoadLibrary() doesn't recognize forward slashes correctly,
4573 * so turn 'em back. */
4574 first = strchr(filename, '/');
4576 STRLEN len = strlen(filename);
4577 if (len <= MAX_PATH) {
4578 strcpy(buf, filename);
4579 filename = &buf[first - filename];
4581 if (*filename == '/')
4582 *(char*)filename = '\\';
4588 aTHXa(PERL_GET_THX);
4589 return LoadLibraryExA(PerlDir_mapA(filename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
4592 XS(w32_SetChildShowWindow)
4595 BOOL use_showwindow = w32_use_showwindow;
4596 /* use "unsigned short" because Perl has redefined "WORD" */
4597 unsigned short showwindow = w32_showwindow;
4600 croak_xs_usage(cv, "[showwindow]");
4602 if (items == 0 || !SvOK(ST(0)))
4603 w32_use_showwindow = FALSE;
4605 w32_use_showwindow = TRUE;
4606 w32_showwindow = (unsigned short)SvIV(ST(0));
4611 ST(0) = sv_2mortal(newSViv(showwindow));
4613 ST(0) = &PL_sv_undef;
4618 #ifdef PERL_IS_MINIPERL
4619 /* shelling out is much slower, full perl uses Win32.pm */
4623 /* Make the host for current directory */
4624 char* ptr = PerlEnv_get_childdir();
4627 * then it worked, set PV valid,
4628 * else return 'undef'
4631 SV *sv = sv_newmortal();
4633 PerlEnv_free_childdir(ptr);
4635 #ifndef INCOMPLETE_TAINTS
4647 Perl_init_os_extras(void)
4650 char *file = __FILE__;
4652 /* Initialize Win32CORE if it has been statically linked. */
4653 #ifndef PERL_IS_MINIPERL
4654 void (*pfn_init)(pTHX);
4655 HMODULE module = (HMODULE)((w32_perldll_handle == INVALID_HANDLE_VALUE)
4656 ? GetModuleHandle(NULL)
4657 : w32_perldll_handle);
4658 pfn_init = (void (*)(pTHX))GetProcAddress(module, "init_Win32CORE");
4659 aTHXa(PERL_GET_THX);
4663 aTHXa(PERL_GET_THX);
4666 newXS("Win32::SetChildShowWindow", w32_SetChildShowWindow, file);
4667 #ifdef PERL_IS_MINIPERL
4668 newXS("Win32::GetCwd", w32_GetCwd, file);
4673 win32_signal_context(void)
4678 my_perl = PL_curinterp;
4679 PERL_SET_THX(my_perl);
4683 return PL_curinterp;
4689 win32_ctrlhandler(DWORD dwCtrlType)
4692 dTHXa(PERL_GET_SIG_CONTEXT);
4698 switch(dwCtrlType) {
4699 case CTRL_CLOSE_EVENT:
4700 /* A signal that the system sends to all processes attached to a console when
4701 the user closes the console (either by choosing the Close command from the
4702 console window's System menu, or by choosing the End Task command from the
4705 if (do_raise(aTHX_ 1)) /* SIGHUP */
4706 sig_terminate(aTHX_ 1);
4710 /* A CTRL+c signal was received */
4711 if (do_raise(aTHX_ SIGINT))
4712 sig_terminate(aTHX_ SIGINT);
4715 case CTRL_BREAK_EVENT:
4716 /* A CTRL+BREAK signal was received */
4717 if (do_raise(aTHX_ SIGBREAK))
4718 sig_terminate(aTHX_ SIGBREAK);
4721 case CTRL_LOGOFF_EVENT:
4722 /* A signal that the system sends to all console processes when a user is logging
4723 off. This signal does not indicate which user is logging off, so no
4724 assumptions can be made.
4727 case CTRL_SHUTDOWN_EVENT:
4728 /* A signal that the system sends to all console processes when the system is
4731 if (do_raise(aTHX_ SIGTERM))
4732 sig_terminate(aTHX_ SIGTERM);
4741 #ifdef SET_INVALID_PARAMETER_HANDLER
4742 # include <crtdbg.h>
4753 /* fetch Unicode version of PATH */
4755 wide_path = (WCHAR*)win32_malloc(len*sizeof(WCHAR));
4757 size_t newlen = GetEnvironmentVariableW(L"PATH", wide_path, len);
4759 win32_free(wide_path);
4765 wide_path = (WCHAR*)win32_realloc(wide_path, len*sizeof(WCHAR));
4770 /* convert to ANSI pathnames */
4771 wide_dir = wide_path;
4774 WCHAR *sep = wcschr(wide_dir, ';');
4782 /* remove quotes around pathname */
4783 if (*wide_dir == '"')
4785 wide_len = wcslen(wide_dir);
4786 if (wide_len && wide_dir[wide_len-1] == '"')
4787 wide_dir[wide_len-1] = '\0';
4789 /* append ansi_dir to ansi_path */
4790 ansi_dir = win32_ansipath(wide_dir);
4791 ansi_len = strlen(ansi_dir);
4793 size_t newlen = len + 1 + ansi_len;
4794 ansi_path = (char*)win32_realloc(ansi_path, newlen+1);
4797 ansi_path[len] = ';';
4798 memcpy(ansi_path+len+1, ansi_dir, ansi_len+1);
4803 ansi_path = (char*)win32_malloc(5+len+1);
4806 memcpy(ansi_path, "PATH=", 5);
4807 memcpy(ansi_path+5, ansi_dir, len+1);
4810 win32_free(ansi_dir);
4815 /* Update C RTL environ array. This will only have full effect if
4816 * perl_parse() is later called with `environ` as the `env` argument.
4817 * Otherwise S_init_postdump_symbols() will overwrite PATH again.
4819 * We do have to ansify() the PATH before Perl has been fully
4820 * initialized because S_find_script() uses the PATH when perl
4821 * is being invoked with the -S option. This happens before %ENV
4822 * is initialized in S_init_postdump_symbols().
4824 * XXX Is this a bug? Should S_find_script() use the environment
4825 * XXX passed in the `env` arg to parse_perl()?
4828 /* Keep system environment in sync because S_init_postdump_symbols()
4829 * will not call mg_set() if it initializes %ENV from `environ`.
4831 SetEnvironmentVariableA("PATH", ansi_path+5);
4832 win32_free(ansi_path);
4834 win32_free(wide_path);
4838 Perl_win32_init(int *argcp, char ***argvp)
4840 #ifdef SET_INVALID_PARAMETER_HANDLER
4841 _invalid_parameter_handler oldHandler, newHandler;
4842 newHandler = my_invalid_parameter_handler;
4843 oldHandler = _set_invalid_parameter_handler(newHandler);
4844 _CrtSetReportMode(_CRT_ASSERT, 0);
4846 /* Disable floating point errors, Perl will trap the ones we
4847 * care about. VC++ RTL defaults to switching these off
4848 * already, but some RTLs don't. Since we don't
4849 * want to be at the vendor's whim on the default, we set
4850 * it explicitly here.
4852 #if !defined(__GNUC__)
4853 _control87(MCW_EM, MCW_EM);
4857 /* When the manifest resource requests Common-Controls v6 then
4858 * user32.dll no longer registers all the Windows classes used for
4859 * standard controls but leaves some of them to be registered by
4860 * comctl32.dll. InitCommonControls() doesn't do anything but calling
4861 * it makes sure comctl32.dll gets loaded into the process and registers
4862 * the standard control classes. Without this even normal Windows APIs
4863 * like MessageBox() can fail under some versions of Windows XP.
4865 InitCommonControls();
4867 g_osver.dwOSVersionInfoSize = sizeof(g_osver);
4868 GetVersionEx(&g_osver);
4870 #ifdef WIN32_DYN_IOINFO_SIZE
4872 Size_t ioinfo_size = _msize((void*)__pioinfo[0]);;
4873 if((SSize_t)ioinfo_size <= 0) { /* -1 is err */
4874 fprintf(stderr, "panic: invalid size for ioinfo\n"); /* no interp */
4877 ioinfo_size /= IOINFO_ARRAY_ELTS;
4878 w32_ioinfo_size = ioinfo_size;
4884 #ifndef WIN32_NO_REGISTRY
4887 retval = RegOpenKeyExW(HKEY_CURRENT_USER, L"SOFTWARE\\Perl", 0, KEY_READ, &HKCU_Perl_hnd);
4888 if (retval != ERROR_SUCCESS) {
4889 HKCU_Perl_hnd = NULL;
4891 retval = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Perl", 0, KEY_READ, &HKLM_Perl_hnd);
4892 if (retval != ERROR_SUCCESS) {
4893 HKLM_Perl_hnd = NULL;
4900 if (!SystemTimeToFileTime(&time_t_epoch_base_systemtime,
4902 fprintf(stderr, "panic: cannot convert base system time to filetime\n"); /* no interp */
4905 time_t_epoch_base_filetime.LowPart = ft.dwLowDateTime;
4906 time_t_epoch_base_filetime.HighPart = ft.dwHighDateTime;
4911 Perl_win32_term(void)
4919 #ifndef WIN32_NO_REGISTRY
4920 /* handles might be NULL, RegCloseKey then returns ERROR_INVALID_HANDLE
4921 but no point of checking and we can't die() at this point */
4922 RegCloseKey(HKLM_Perl_hnd);
4923 RegCloseKey(HKCU_Perl_hnd);
4924 /* the handles are in an undefined state until the next PERL_SYS_INIT3 */
4929 win32_get_child_IO(child_IO_table* ptbl)
4931 ptbl->childStdIn = GetStdHandle(STD_INPUT_HANDLE);
4932 ptbl->childStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
4933 ptbl->childStdErr = GetStdHandle(STD_ERROR_HANDLE);
4937 win32_signal(int sig, Sighandler_t subcode)
4940 if (sig < SIG_SIZE) {
4941 int save_errno = errno;
4942 Sighandler_t result;
4943 #ifdef SET_INVALID_PARAMETER_HANDLER
4944 /* Silence our invalid parameter handler since we expect to make some
4945 * calls with invalid signal numbers giving a SIG_ERR result. */
4946 BOOL oldvalue = set_silent_invalid_parameter_handler(TRUE);
4948 result = signal(sig, subcode);
4949 #ifdef SET_INVALID_PARAMETER_HANDLER
4950 set_silent_invalid_parameter_handler(oldvalue);
4952 aTHXa(PERL_GET_THX);
4953 if (result == SIG_ERR) {
4954 result = w32_sighandler[sig];
4957 w32_sighandler[sig] = subcode;
4966 /* The PerlMessageWindowClass's WindowProc */
4968 win32_message_window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
4970 return win32_process_message(hwnd, msg, wParam, lParam) ?
4971 0 : DefWindowProc(hwnd, msg, wParam, lParam);
4974 /* The real message handler. Can be called with
4975 * hwnd == NULL to process our thread messages. Returns TRUE for any messages
4976 * that it processes */
4978 win32_process_message(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
4980 /* BEWARE. The context retrieved using dTHX; is the context of the
4981 * 'parent' thread during the CreateWindow() phase - i.e. for all messages
4982 * up to and including WM_CREATE. If it ever happens that you need the
4983 * 'child' context before this, then it needs to be passed into
4984 * win32_create_message_window(), and passed to the WM_NCCREATE handler
4985 * from the lparam of CreateWindow(). It could then be stored/retrieved
4986 * using [GS]etWindowLongPtr(... GWLP_USERDATA ...), possibly eliminating
4987 * the dTHX calls here. */
4988 /* XXX For now it is assumed that the overhead of the dTHX; for what
4989 * are relativley infrequent code-paths, is better than the added
4990 * complexity of getting the correct context passed into
4991 * win32_create_message_window() */
4997 case WM_USER_MESSAGE: {
4998 long child = find_pseudo_pid(aTHX_ (int)wParam);
5000 w32_pseudo_child_message_hwnds[child] = (HWND)lParam;
5007 case WM_USER_KILL: {
5008 /* We use WM_USER_KILL to fake kill() with other signals */
5009 int sig = (int)wParam;
5010 if (do_raise(aTHX_ sig))
5011 sig_terminate(aTHX_ sig);
5017 /* alarm() is a one-shot but SetTimer() repeats so kill it */
5018 if (w32_timerid && w32_timerid==(UINT)wParam) {
5019 KillTimer(w32_message_hwnd, w32_timerid);
5022 /* Now fake a call to signal handler */
5023 if (do_raise(aTHX_ 14))
5024 sig_terminate(aTHX_ 14);
5036 /* Above or other stuff may have set a signal flag, and we may not have
5037 * been called from win32_async_check() (e.g. some other GUI's message
5038 * loop. BUT DON'T dispatch signals here: If someone has set a SIGALRM
5039 * handler that die's, and the message loop that calls here is wrapped
5040 * in an eval, then you may well end up with orphaned windows - signals
5041 * are dispatched by win32_async_check() */
5047 win32_create_message_window_class(void)
5049 /* create the window class for "message only" windows */
5053 wc.lpfnWndProc = win32_message_window_proc;
5054 wc.hInstance = (HINSTANCE)GetModuleHandle(NULL);
5055 wc.lpszClassName = "PerlMessageWindowClass";
5057 /* second and subsequent calls will fail, but class
5058 * will already be registered */
5063 win32_create_message_window(void)
5065 win32_create_message_window_class();
5066 return CreateWindow("PerlMessageWindowClass", "PerlMessageWindow",
5067 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
5070 #ifdef HAVE_INTERP_INTERN
5073 win32_csighandler(int sig)
5076 dTHXa(PERL_GET_SIG_CONTEXT);
5077 Perl_warn(aTHX_ "Got signal %d",sig);
5082 #if defined(__MINGW32__) && defined(__cplusplus)
5083 #define CAST_HWND__(x) (HWND__*)(x)
5085 #define CAST_HWND__(x) x
5089 Perl_sys_intern_init(pTHX)
5093 w32_perlshell_tokens = NULL;
5094 w32_perlshell_vec = (char**)NULL;
5095 w32_perlshell_items = 0;
5096 w32_fdpid = newAV();
5097 Newx(w32_children, 1, child_tab);
5098 w32_num_children = 0;
5099 # ifdef USE_ITHREADS
5101 Newx(w32_pseudo_children, 1, pseudo_child_tab);
5102 w32_num_pseudo_children = 0;
5105 w32_message_hwnd = CAST_HWND__(INVALID_HANDLE_VALUE);
5107 for (i=0; i < SIG_SIZE; i++) {
5108 w32_sighandler[i] = SIG_DFL;
5110 # ifdef MULTIPLICITY
5111 if (my_perl == PL_curinterp) {
5115 /* Force C runtime signal stuff to set its console handler */
5116 signal(SIGINT,win32_csighandler);
5117 signal(SIGBREAK,win32_csighandler);
5119 /* We spawn asynchronous processes with the CREATE_NEW_PROCESS_GROUP
5120 * flag. This has the side-effect of disabling Ctrl-C events in all
5121 * processes in this group.
5122 * We re-enable Ctrl-C handling by calling SetConsoleCtrlHandler()
5123 * with a NULL handler.
5125 SetConsoleCtrlHandler(NULL,FALSE);
5127 /* Push our handler on top */
5128 SetConsoleCtrlHandler(win32_ctrlhandler,TRUE);
5133 Perl_sys_intern_clear(pTHX)
5136 Safefree(w32_perlshell_tokens);
5137 Safefree(w32_perlshell_vec);
5138 /* NOTE: w32_fdpid is freed by sv_clean_all() */
5139 Safefree(w32_children);
5141 KillTimer(w32_message_hwnd, w32_timerid);
5144 if (w32_message_hwnd != NULL && w32_message_hwnd != INVALID_HANDLE_VALUE)
5145 DestroyWindow(w32_message_hwnd);
5146 # ifdef MULTIPLICITY
5147 if (my_perl == PL_curinterp) {
5151 SetConsoleCtrlHandler(win32_ctrlhandler,FALSE);
5153 # ifdef USE_ITHREADS
5154 Safefree(w32_pseudo_children);
5158 # ifdef USE_ITHREADS
5161 Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
5163 PERL_ARGS_ASSERT_SYS_INTERN_DUP;
5165 dst->perlshell_tokens = NULL;
5166 dst->perlshell_vec = (char**)NULL;
5167 dst->perlshell_items = 0;
5168 dst->fdpid = newAV();
5169 Newxz(dst->children, 1, child_tab);
5171 Newxz(dst->pseudo_children, 1, pseudo_child_tab);
5173 dst->message_hwnd = CAST_HWND__(INVALID_HANDLE_VALUE);
5174 dst->poll_count = 0;
5175 Copy(src->sigtable,dst->sigtable,SIG_SIZE,Sighandler_t);
5177 # endif /* USE_ITHREADS */
5178 #endif /* HAVE_INTERP_INTERN */