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
16 # define Win32_Winsock
20 # define _WIN32_WINNT 0x0500 /* needed for CreateHardlink() etc. */
26 # define HWND_MESSAGE ((HWND)-3)
29 #ifndef PROCESSOR_ARCHITECTURE_AMD64
30 # define PROCESSOR_ARCHITECTURE_AMD64 9
33 #ifndef WC_NO_BEST_FIT_CHARS
34 # define WC_NO_BEST_FIT_CHARS 0x00000400
43 /* #include "config.h" */
45 #if !defined(PERLIO_IS_STDIO) && !defined(USE_SFIO)
54 #define PERL_NO_GET_CONTEXT
59 /* assert.h conflicts with #define of assert in perl.h */
67 #include <sys/utime.h>
70 /* Mingw32 defaults to globing command line
71 * So we turn it off like this:
76 #if defined(__MINGW32__) && (__MINGW32_MAJOR_VERSION==1)
77 /* Mingw32-1.1 is missing some prototypes */
79 FILE * _wfopen(LPCWSTR wszFileName, LPCWSTR wszMode);
80 FILE * _wfdopen(int nFd, LPCWSTR wszMode);
81 FILE * _freopen(LPCWSTR wszFileName, LPCWSTR wszMode, FILE * pOldStream);
89 #define EXECF_SPAWN_NOWAIT 3
91 #if defined(PERL_IMPLICIT_SYS)
92 # undef win32_get_privlib
93 # define win32_get_privlib g_win32_get_privlib
94 # undef win32_get_sitelib
95 # define win32_get_sitelib g_win32_get_sitelib
96 # undef win32_get_vendorlib
97 # define win32_get_vendorlib g_win32_get_vendorlib
99 # define getlogin g_getlogin
102 /* VS2005 (MSC version 14) provides a mechanism to set an invalid
103 * parameter handler. This functionality is not available in the
104 * 64-bit compiler from the Platform SDK, which unfortunately also
105 * believes itself to be MSC version 14.
107 * There is no #define related to _set_invalid_parameter_handler(),
108 * but we can check for one of the constants defined for
109 * _set_abort_behavior(), which was introduced into stdlib.h at
113 #if _MSC_VER >= 1400 && defined(_WRITE_ABORT_MSG)
114 # define SET_INVALID_PARAMETER_HANDLER
117 #ifdef SET_INVALID_PARAMETER_HANDLER
118 static BOOL set_silent_invalid_parameter_handler(BOOL newvalue);
119 static void my_invalid_parameter_handler(const wchar_t* expression,
120 const wchar_t* function, const wchar_t* file,
121 unsigned int line, uintptr_t pReserved);
124 static char* get_regstr_from(HKEY hkey, const char *valuename, SV **svp);
125 static char* get_regstr(const char *valuename, SV **svp);
126 static char* get_emd_part(SV **prev_pathp, STRLEN *const len,
127 char *trailing, ...);
128 static char* win32_get_xlib(const char *pl, const char *xlib,
129 const char *libname, STRLEN *const len);
130 static BOOL has_shell_metachars(const char *ptr);
131 static long tokenize(const char *str, char **dest, char ***destv);
132 static void get_shell(void);
133 static char* find_next_space(const char *s);
134 static int do_spawn2(pTHX_ const char *cmd, int exectype);
135 static long find_pid(pTHX_ int pid);
136 static void remove_dead_process(long child);
137 static int terminate_process(DWORD pid, HANDLE process_handle, int sig);
138 static int my_kill(int pid, int sig);
139 static void out_of_memory(void);
140 static char* wstr_to_str(const wchar_t* wstr);
141 static long filetime_to_clock(PFILETIME ft);
142 static BOOL filetime_from_time(PFILETIME ft, time_t t);
143 static char* create_command_line(char *cname, STRLEN clen,
144 const char * const *args);
145 static char* qualified_path(const char *cmd);
146 static void ansify_path(void);
147 static LRESULT win32_process_message(HWND hwnd, UINT msg,
148 WPARAM wParam, LPARAM lParam);
151 static long find_pseudo_pid(pTHX_ int pid);
152 static void remove_dead_pseudo_process(long child);
153 static HWND get_hwnd_delay(pTHX, long child, DWORD tries);
156 #ifdef HAVE_INTERP_INTERN
157 static void win32_csighandler(int sig);
161 HANDLE w32_perldll_handle = INVALID_HANDLE_VALUE;
162 char w32_module_name[MAX_PATH+1];
165 static OSVERSIONINFO g_osver = {0, 0, 0, 0, 0, ""};
167 #ifdef SET_INVALID_PARAMETER_HANDLER
168 static BOOL silent_invalid_parameter_handler = FALSE;
171 set_silent_invalid_parameter_handler(BOOL newvalue)
173 BOOL oldvalue = silent_invalid_parameter_handler;
175 silent_invalid_parameter_handler = newvalue;
181 my_invalid_parameter_handler(const wchar_t* expression,
182 const wchar_t* function,
188 char* ansi_expression;
191 if (silent_invalid_parameter_handler)
193 ansi_expression = wstr_to_str(expression);
194 ansi_function = wstr_to_str(function);
195 ansi_file = wstr_to_str(file);
196 fprintf(stderr, "Invalid parameter detected in function %s. "
197 "File: %s, line: %d\n", ansi_function, ansi_file, line);
198 fprintf(stderr, "Expression: %s\n", ansi_expression);
199 free(ansi_expression);
207 set_w32_module_name(void)
209 /* this function may be called at DLL_PROCESS_ATTACH time */
211 HMODULE module = (HMODULE)((w32_perldll_handle == INVALID_HANDLE_VALUE)
212 ? GetModuleHandle(NULL)
213 : w32_perldll_handle);
215 OSVERSIONINFO osver; /* g_osver may not yet be initialized */
216 osver.dwOSVersionInfoSize = sizeof(osver);
217 GetVersionEx(&osver);
219 if (osver.dwMajorVersion > 4) {
220 WCHAR modulename[MAX_PATH];
221 WCHAR fullname[MAX_PATH];
224 DWORD (__stdcall *pfnGetLongPathNameW)(LPCWSTR, LPWSTR, DWORD) =
225 (DWORD (__stdcall *)(LPCWSTR, LPWSTR, DWORD))
226 GetProcAddress(GetModuleHandle("kernel32.dll"), "GetLongPathNameW");
228 GetModuleFileNameW(module, modulename, sizeof(modulename)/sizeof(WCHAR));
230 /* Make sure we get an absolute pathname in case the module was loaded
231 * explicitly by LoadLibrary() with a relative path. */
232 GetFullPathNameW(modulename, sizeof(fullname)/sizeof(WCHAR), fullname, NULL);
234 /* Make sure we start with the long path name of the module because we
235 * later scan for pathname components to match "5.xx" to locate
236 * compatible sitelib directories, and the short pathname might mangle
237 * this path segment (e.g. by removing the dot on NTFS to something
238 * like "5xx~1.yy") */
239 if (pfnGetLongPathNameW)
240 pfnGetLongPathNameW(fullname, fullname, sizeof(fullname)/sizeof(WCHAR));
242 /* remove \\?\ prefix */
243 if (memcmp(fullname, L"\\\\?\\", 4*sizeof(WCHAR)) == 0)
244 memmove(fullname, fullname+4, (wcslen(fullname+4)+1)*sizeof(WCHAR));
246 ansi = win32_ansipath(fullname);
247 my_strlcpy(w32_module_name, ansi, sizeof(w32_module_name));
251 GetModuleFileName(module, w32_module_name, sizeof(w32_module_name));
253 /* remove \\?\ prefix */
254 if (memcmp(w32_module_name, "\\\\?\\", 4) == 0)
255 memmove(w32_module_name, w32_module_name+4, strlen(w32_module_name+4)+1);
257 /* try to get full path to binary (which may be mangled when perl is
258 * run from a 16-bit app) */
259 /*PerlIO_printf(Perl_debug_log, "Before %s\n", w32_module_name);*/
260 win32_longpath(w32_module_name);
261 /*PerlIO_printf(Perl_debug_log, "After %s\n", w32_module_name);*/
264 /* normalize to forward slashes */
265 ptr = w32_module_name;
273 /* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
275 get_regstr_from(HKEY hkey, const char *valuename, SV **svp)
277 /* Retrieve a REG_SZ or REG_EXPAND_SZ from the registry */
280 const char *subkey = "Software\\Perl";
284 retval = RegOpenKeyEx(hkey, subkey, 0, KEY_READ, &handle);
285 if (retval == ERROR_SUCCESS) {
287 retval = RegQueryValueEx(handle, valuename, 0, &type, NULL, &datalen);
288 if (retval == ERROR_SUCCESS
289 && (type == REG_SZ || type == REG_EXPAND_SZ))
293 *svp = sv_2mortal(newSVpvn("",0));
294 SvGROW(*svp, datalen);
295 retval = RegQueryValueEx(handle, valuename, 0, NULL,
296 (PBYTE)SvPVX(*svp), &datalen);
297 if (retval == ERROR_SUCCESS) {
299 SvCUR_set(*svp,datalen-1);
307 /* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
309 get_regstr(const char *valuename, SV **svp)
311 char *str = get_regstr_from(HKEY_CURRENT_USER, valuename, svp);
313 str = get_regstr_from(HKEY_LOCAL_MACHINE, valuename, svp);
317 /* *prev_pathp (if non-NULL) is expected to be POK (valid allocated SvPVX(sv)) */
319 get_emd_part(SV **prev_pathp, STRLEN *const len, char *trailing_path, ...)
323 char mod_name[MAX_PATH+1];
329 va_start(ap, trailing_path);
330 strip = va_arg(ap, char *);
332 sprintf(base, "%d.%d", (int)PERL_REVISION, (int)PERL_VERSION);
333 baselen = strlen(base);
335 if (!*w32_module_name) {
336 set_w32_module_name();
338 strcpy(mod_name, w32_module_name);
339 ptr = strrchr(mod_name, '/');
340 while (ptr && strip) {
341 /* look for directories to skip back */
344 ptr = strrchr(mod_name, '/');
345 /* avoid stripping component if there is no slash,
346 * or it doesn't match ... */
347 if (!ptr || stricmp(ptr+1, strip) != 0) {
348 /* ... but not if component matches m|5\.$patchlevel.*| */
349 if (!ptr || !(*strip == '5' && *(ptr+1) == '5'
350 && strncmp(strip, base, baselen) == 0
351 && strncmp(ptr+1, base, baselen) == 0))
357 strip = va_arg(ap, char *);
365 strcpy(++ptr, trailing_path);
367 /* only add directory if it exists */
368 if (GetFileAttributes(mod_name) != (DWORD) -1) {
369 /* directory exists */
372 *prev_pathp = sv_2mortal(newSVpvn("",0));
373 else if (SvPVX(*prev_pathp))
374 sv_catpvn(*prev_pathp, ";", 1);
375 sv_catpv(*prev_pathp, mod_name);
377 *len = SvCUR(*prev_pathp);
378 return SvPVX(*prev_pathp);
385 win32_get_privlib(const char *pl, STRLEN *const len)
387 char *stdlib = "lib";
388 char buffer[MAX_PATH+1];
391 /* $stdlib = $HKCU{"lib-$]"} || $HKLM{"lib-$]"} || $HKCU{"lib"} || $HKLM{"lib"} || ""; */
392 sprintf(buffer, "%s-%s", stdlib, pl);
393 if (!get_regstr(buffer, &sv))
394 (void)get_regstr(stdlib, &sv);
396 /* $stdlib .= ";$EMD/../../lib" */
397 return get_emd_part(&sv, len, stdlib, ARCHNAME, "bin", NULL);
401 win32_get_xlib(const char *pl, const char *xlib, const char *libname,
405 char pathstr[MAX_PATH+1];
409 /* $HKCU{"$xlib-$]"} || $HKLM{"$xlib-$]"} . ---; */
410 sprintf(regstr, "%s-%s", xlib, pl);
411 (void)get_regstr(regstr, &sv1);
414 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/$]/lib"; */
415 sprintf(pathstr, "%s/%s/lib", libname, pl);
416 (void)get_emd_part(&sv1, NULL, pathstr, ARCHNAME, "bin", pl, NULL);
418 /* $HKCU{$xlib} || $HKLM{$xlib} . ---; */
419 (void)get_regstr(xlib, &sv2);
422 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/lib"; */
423 sprintf(pathstr, "%s/lib", libname);
424 (void)get_emd_part(&sv2, NULL, pathstr, ARCHNAME, "bin", pl, NULL);
432 sv_catpvn(sv1, ";", 1);
442 win32_get_sitelib(const char *pl, STRLEN *const len)
444 return win32_get_xlib(pl, "sitelib", "site", len);
447 #ifndef PERL_VENDORLIB_NAME
448 # define PERL_VENDORLIB_NAME "vendor"
452 win32_get_vendorlib(const char *pl, STRLEN *const len)
454 return win32_get_xlib(pl, "vendorlib", PERL_VENDORLIB_NAME, len);
458 has_shell_metachars(const char *ptr)
464 * Scan string looking for redirection (< or >) or pipe
465 * characters (|) that are not in a quoted string.
466 * Shell variable interpolation (%VAR%) can also happen inside strings.
498 #if !defined(PERL_IMPLICIT_SYS)
499 /* since the current process environment is being updated in util.c
500 * the library functions will get the correct environment
503 Perl_my_popen(pTHX_ const char *cmd, const char *mode)
505 PERL_FLUSHALL_FOR_CHILD;
506 return win32_popen(cmd, mode);
510 Perl_my_pclose(pTHX_ PerlIO *fp)
512 return win32_pclose(fp);
516 DllExport unsigned long
519 return (unsigned long)g_osver.dwPlatformId;
528 return -((int)w32_pseudo_id);
533 /* Tokenize a string. Words are null-separated, and the list
534 * ends with a doubled null. Any character (except null and
535 * including backslash) may be escaped by preceding it with a
536 * backslash (the backslash will be stripped).
537 * Returns number of words in result buffer.
540 tokenize(const char *str, char **dest, char ***destv)
542 char *retstart = NULL;
543 char **retvstart = 0;
546 int slen = strlen(str);
549 Newx(ret, slen+2, char);
550 Newx(retv, (slen+3)/2, char*);
558 if (*ret == '\\' && *str)
560 else if (*ret == ' ') {
576 retvstart[items] = NULL;
589 if (!w32_perlshell_tokens) {
590 /* we don't use COMSPEC here for two reasons:
591 * 1. the same reason perl on UNIX doesn't use SHELL--rampant and
592 * uncontrolled unportability of the ensuing scripts.
593 * 2. PERL5SHELL could be set to a shell that may not be fit for
594 * interactive use (which is what most programs look in COMSPEC
597 const char* defaultshell = "cmd.exe /x/d/c";
598 const char *usershell = PerlEnv_getenv("PERL5SHELL");
599 w32_perlshell_items = tokenize(usershell ? usershell : defaultshell,
600 &w32_perlshell_tokens,
606 Perl_do_aspawn(pTHX_ SV *really, SV **mark, SV **sp)
614 PERL_ARGS_ASSERT_DO_ASPAWN;
620 Newx(argv, (sp - mark) + w32_perlshell_items + 2, char*);
622 if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
627 while (++mark <= sp) {
628 if (*mark && (str = SvPV_nolen(*mark)))
635 status = win32_spawnvp(flag,
636 (const char*)(really ? SvPV_nolen(really) : argv[0]),
637 (const char* const*)argv);
639 if (status < 0 && (errno == ENOEXEC || errno == ENOENT)) {
640 /* possible shell-builtin, invoke with shell */
642 sh_items = w32_perlshell_items;
644 argv[index+sh_items] = argv[index];
645 while (--sh_items >= 0)
646 argv[sh_items] = w32_perlshell_vec[sh_items];
648 status = win32_spawnvp(flag,
649 (const char*)(really ? SvPV_nolen(really) : argv[0]),
650 (const char* const*)argv);
653 if (flag == P_NOWAIT) {
654 PL_statusvalue = -1; /* >16bits hint for pp_system() */
658 if (ckWARN(WARN_EXEC))
659 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't spawn \"%s\": %s", argv[0], strerror(errno));
664 PL_statusvalue = status;
670 /* returns pointer to the next unquoted space or the end of the string */
672 find_next_space(const char *s)
674 bool in_quotes = FALSE;
676 /* ignore doubled backslashes, or backslash+quote */
677 if (*s == '\\' && (s[1] == '\\' || s[1] == '"')) {
680 /* keep track of when we're within quotes */
681 else if (*s == '"') {
683 in_quotes = !in_quotes;
685 /* break it up only at spaces that aren't in quotes */
686 else if (!in_quotes && isSPACE(*s))
695 do_spawn2(pTHX_ const char *cmd, int exectype)
701 BOOL needToTry = TRUE;
704 /* Save an extra exec if possible. See if there are shell
705 * metacharacters in it */
706 if (!has_shell_metachars(cmd)) {
707 Newx(argv, strlen(cmd) / 2 + 2, char*);
708 Newx(cmd2, strlen(cmd) + 1, char);
711 for (s = cmd2; *s;) {
712 while (*s && isSPACE(*s))
716 s = find_next_space(s);
724 status = win32_spawnvp(P_WAIT, argv[0],
725 (const char* const*)argv);
727 case EXECF_SPAWN_NOWAIT:
728 status = win32_spawnvp(P_NOWAIT, argv[0],
729 (const char* const*)argv);
732 status = win32_execvp(argv[0], (const char* const*)argv);
735 if (status != -1 || errno == 0)
745 Newx(argv, w32_perlshell_items + 2, char*);
746 while (++i < w32_perlshell_items)
747 argv[i] = w32_perlshell_vec[i];
748 argv[i++] = (char *)cmd;
752 status = win32_spawnvp(P_WAIT, argv[0],
753 (const char* const*)argv);
755 case EXECF_SPAWN_NOWAIT:
756 status = win32_spawnvp(P_NOWAIT, argv[0],
757 (const char* const*)argv);
760 status = win32_execvp(argv[0], (const char* const*)argv);
766 if (exectype == EXECF_SPAWN_NOWAIT) {
767 PL_statusvalue = -1; /* >16bits hint for pp_system() */
771 if (ckWARN(WARN_EXEC))
772 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s \"%s\": %s",
773 (exectype == EXECF_EXEC ? "exec" : "spawn"),
774 cmd, strerror(errno));
779 PL_statusvalue = status;
785 Perl_do_spawn(pTHX_ char *cmd)
787 PERL_ARGS_ASSERT_DO_SPAWN;
789 return do_spawn2(aTHX_ cmd, EXECF_SPAWN);
793 Perl_do_spawn_nowait(pTHX_ char *cmd)
795 PERL_ARGS_ASSERT_DO_SPAWN_NOWAIT;
797 return do_spawn2(aTHX_ cmd, EXECF_SPAWN_NOWAIT);
801 Perl_do_exec(pTHX_ const char *cmd)
803 PERL_ARGS_ASSERT_DO_EXEC;
805 do_spawn2(aTHX_ cmd, EXECF_EXEC);
809 /* The idea here is to read all the directory names into a string table
810 * (separated by nulls) and when one of the other dir functions is called
811 * return the pointer to the current file name.
814 win32_opendir(const char *filename)
820 char scanname[MAX_PATH+3];
821 WCHAR wscanname[sizeof(scanname)];
822 WIN32_FIND_DATAW wFindData;
823 char buffer[MAX_PATH*2];
826 len = strlen(filename);
831 if (len > MAX_PATH) {
832 errno = ENAMETOOLONG;
836 /* Get us a DIR structure */
839 /* Create the search pattern */
840 strcpy(scanname, filename);
842 /* bare drive name means look in cwd for drive */
843 if (len == 2 && isALPHA(scanname[0]) && scanname[1] == ':') {
844 scanname[len++] = '.';
845 scanname[len++] = '/';
847 else if (scanname[len-1] != '/' && scanname[len-1] != '\\') {
848 scanname[len++] = '/';
850 scanname[len++] = '*';
851 scanname[len] = '\0';
853 /* do the FindFirstFile call */
854 MultiByteToWideChar(CP_ACP, 0, scanname, -1, wscanname, sizeof(wscanname)/sizeof(WCHAR));
856 dirp->handle = FindFirstFileW(PerlDir_mapW(wscanname), &wFindData);
858 if (dirp->handle == INVALID_HANDLE_VALUE) {
859 DWORD err = GetLastError();
860 /* FindFirstFile() fails on empty drives! */
862 case ERROR_FILE_NOT_FOUND:
864 case ERROR_NO_MORE_FILES:
865 case ERROR_PATH_NOT_FOUND:
868 case ERROR_NOT_ENOUGH_MEMORY:
880 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
881 wFindData.cFileName, -1,
882 buffer, sizeof(buffer), NULL, &use_default);
883 if (use_default && *wFindData.cAlternateFileName) {
884 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
885 wFindData.cAlternateFileName, -1,
886 buffer, sizeof(buffer), NULL, NULL);
889 /* now allocate the first part of the string table for
890 * the filenames that we find.
892 idx = strlen(buffer)+1;
897 Newx(dirp->start, dirp->size, char);
898 strcpy(dirp->start, buffer);
900 dirp->end = dirp->curr = dirp->start;
906 /* Readdir just returns the current string pointer and bumps the
907 * string pointer to the nDllExport entry.
909 DllExport struct direct *
910 win32_readdir(DIR *dirp)
915 /* first set up the structure to return */
916 len = strlen(dirp->curr);
917 strcpy(dirp->dirstr.d_name, dirp->curr);
918 dirp->dirstr.d_namlen = len;
921 dirp->dirstr.d_ino = dirp->curr - dirp->start;
923 /* Now set up for the next call to readdir */
924 dirp->curr += len + 1;
925 if (dirp->curr >= dirp->end) {
927 char buffer[MAX_PATH*2];
929 if (dirp->handle == INVALID_HANDLE_VALUE) {
932 /* finding the next file that matches the wildcard
933 * (which should be all of them in this directory!).
936 WIN32_FIND_DATAW wFindData;
937 res = FindNextFileW(dirp->handle, &wFindData);
939 BOOL use_default = FALSE;
940 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
941 wFindData.cFileName, -1,
942 buffer, sizeof(buffer), NULL, &use_default);
943 if (use_default && *wFindData.cAlternateFileName) {
944 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
945 wFindData.cAlternateFileName, -1,
946 buffer, sizeof(buffer), NULL, NULL);
951 long endpos = dirp->end - dirp->start;
952 long newsize = endpos + strlen(buffer) + 1;
953 /* bump the string table size by enough for the
954 * new name and its null terminator */
955 while (newsize > dirp->size) {
956 long curpos = dirp->curr - dirp->start;
958 Renew(dirp->start, dirp->size, char);
959 dirp->curr = dirp->start + curpos;
961 strcpy(dirp->start + endpos, buffer);
962 dirp->end = dirp->start + newsize;
967 if (dirp->handle != INVALID_HANDLE_VALUE) {
968 FindClose(dirp->handle);
969 dirp->handle = INVALID_HANDLE_VALUE;
973 return &(dirp->dirstr);
979 /* Telldir returns the current string pointer position */
981 win32_telldir(DIR *dirp)
983 return dirp->curr ? (dirp->curr - dirp->start) : -1;
987 /* Seekdir moves the string pointer to a previously saved position
988 * (returned by telldir).
991 win32_seekdir(DIR *dirp, long loc)
993 dirp->curr = loc == -1 ? NULL : dirp->start + loc;
996 /* Rewinddir resets the string pointer to the start */
998 win32_rewinddir(DIR *dirp)
1000 dirp->curr = dirp->start;
1003 /* free the memory allocated by opendir */
1005 win32_closedir(DIR *dirp)
1007 if (dirp->handle != INVALID_HANDLE_VALUE)
1008 FindClose(dirp->handle);
1009 Safefree(dirp->start);
1014 /* duplicate a open DIR* for interpreter cloning */
1016 win32_dirp_dup(DIR *const dirp, CLONE_PARAMS *const param)
1019 PerlInterpreter *const from = param->proto_perl;
1020 PerlInterpreter *const to = (PerlInterpreter *)PERL_GET_THX;
1025 /* switch back to original interpreter because win32_readdir()
1026 * might Renew(dirp->start).
1032 /* mark current position; read all remaining entries into the
1033 * cache, and then restore to current position.
1035 pos = win32_telldir(dirp);
1036 while (win32_readdir(dirp)) {
1037 /* read all entries into cache */
1039 win32_seekdir(dirp, pos);
1041 /* switch back to new interpreter to allocate new DIR structure */
1047 memcpy(dup, dirp, sizeof(DIR));
1049 Newx(dup->start, dirp->size, char);
1050 memcpy(dup->start, dirp->start, dirp->size);
1052 dup->end = dup->start + (dirp->end - dirp->start);
1054 dup->curr = dup->start + (dirp->curr - dirp->start);
1066 * Just pretend that everyone is a superuser. NT will let us know if
1067 * we don\'t really have permission to do something.
1070 #define ROOT_UID ((uid_t)0)
1071 #define ROOT_GID ((gid_t)0)
1100 return (auid == ROOT_UID ? 0 : -1);
1106 return (agid == ROOT_GID ? 0 : -1);
1113 char *buf = w32_getlogin_buffer;
1114 DWORD size = sizeof(w32_getlogin_buffer);
1115 if (GetUserName(buf,&size))
1121 chown(const char *path, uid_t owner, gid_t group)
1128 * XXX this needs strengthening (for PerlIO)
1131 int mkstemp(const char *path)
1134 char buf[MAX_PATH+1];
1138 if (i++ > 10) { /* give up */
1142 if (!GetTempFileNameA((LPCSTR)path, "plr", 1, buf)) {
1146 fd = PerlLIO_open3(buf, O_CREAT|O_RDWR|O_EXCL, 0600);
1153 find_pid(pTHX_ int pid)
1155 long child = w32_num_children;
1156 while (--child >= 0) {
1157 if ((int)w32_child_pids[child] == pid)
1164 remove_dead_process(long child)
1168 CloseHandle(w32_child_handles[child]);
1169 Move(&w32_child_handles[child+1], &w32_child_handles[child],
1170 (w32_num_children-child-1), HANDLE);
1171 Move(&w32_child_pids[child+1], &w32_child_pids[child],
1172 (w32_num_children-child-1), DWORD);
1179 find_pseudo_pid(pTHX_ int pid)
1181 long child = w32_num_pseudo_children;
1182 while (--child >= 0) {
1183 if ((int)w32_pseudo_child_pids[child] == pid)
1190 remove_dead_pseudo_process(long child)
1194 CloseHandle(w32_pseudo_child_handles[child]);
1195 Move(&w32_pseudo_child_handles[child+1], &w32_pseudo_child_handles[child],
1196 (w32_num_pseudo_children-child-1), HANDLE);
1197 Move(&w32_pseudo_child_pids[child+1], &w32_pseudo_child_pids[child],
1198 (w32_num_pseudo_children-child-1), DWORD);
1199 Move(&w32_pseudo_child_message_hwnds[child+1], &w32_pseudo_child_message_hwnds[child],
1200 (w32_num_pseudo_children-child-1), HWND);
1201 Move(&w32_pseudo_child_sigterm[child+1], &w32_pseudo_child_sigterm[child],
1202 (w32_num_pseudo_children-child-1), char);
1203 w32_num_pseudo_children--;
1208 win32_wait_for_children(pTHX)
1210 if (w32_pseudo_children && w32_num_pseudo_children) {
1213 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
1215 for (child = 0; child < w32_num_pseudo_children; ++child) {
1216 if (!w32_pseudo_child_sigterm[child])
1217 handles[count++] = w32_pseudo_child_handles[child];
1219 /* XXX should use MsgWaitForMultipleObjects() to continue
1220 * XXX processing messages while we wait.
1222 WaitForMultipleObjects(count, handles, TRUE, INFINITE);
1224 while (w32_num_pseudo_children)
1225 CloseHandle(w32_pseudo_child_handles[--w32_num_pseudo_children]);
1231 terminate_process(DWORD pid, HANDLE process_handle, int sig)
1235 /* "Does process exist?" use of kill */
1238 if (GenerateConsoleCtrlEvent(CTRL_C_EVENT, pid))
1243 if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pid))
1246 default: /* For now be backwards compatible with perl 5.6 */
1248 /* Note that we will only be able to kill processes owned by the
1249 * current process owner, even when we are running as an administrator.
1250 * To kill processes of other owners we would need to set the
1251 * 'SeDebugPrivilege' privilege before obtaining the process handle.
1253 if (TerminateProcess(process_handle, sig))
1261 killpg(int pid, int sig)
1263 HANDLE process_handle;
1264 HANDLE snapshot_handle;
1267 process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
1268 if (process_handle == NULL)
1271 killed += terminate_process(pid, process_handle, sig);
1273 snapshot_handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
1274 if (snapshot_handle != INVALID_HANDLE_VALUE) {
1275 PROCESSENTRY32 entry;
1277 entry.dwSize = sizeof(entry);
1278 if (Process32First(snapshot_handle, &entry)) {
1280 if (entry.th32ParentProcessID == (DWORD)pid)
1281 killed += killpg(entry.th32ProcessID, sig);
1282 entry.dwSize = sizeof(entry);
1284 while (Process32Next(snapshot_handle, &entry));
1286 CloseHandle(snapshot_handle);
1288 CloseHandle(process_handle);
1293 my_kill(int pid, int sig)
1296 HANDLE process_handle;
1299 return killpg(pid, -sig);
1301 process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
1302 /* OpenProcess() returns NULL on error, *not* INVALID_HANDLE_VALUE */
1303 if (process_handle != NULL) {
1304 retval = terminate_process(pid, process_handle, sig);
1305 CloseHandle(process_handle);
1311 /* Get a child pseudo-process HWND, with retrying and delaying/yielding.
1312 * The "tries" parameter is the number of retries to make, with a Sleep(1)
1313 * (waiting and yielding the time slot) between each try. Specifying 0 causes
1314 * only Sleep(0) (no waiting and potentially no yielding) to be used, so is not
1316 * Returns an hwnd != INVALID_HANDLE_VALUE (so be aware that NULL can be
1317 * returned) or croaks if the child pseudo-process doesn't schedule and deliver
1318 * a HWND in the time period allowed.
1321 get_hwnd_delay(pTHX, long child, DWORD tries)
1323 HWND hwnd = w32_pseudo_child_message_hwnds[child];
1324 if (hwnd != INVALID_HANDLE_VALUE) return hwnd;
1326 /* Pseudo-process has not yet properly initialized since hwnd isn't set.
1327 * Fast sleep: On some NT kernels/systems, a Sleep(0) won't deschedule a
1328 * thread 100% of the time since threads are attached to a CPU for NUMA and
1329 * caching reasons, and the child thread was attached to a different CPU
1330 * therefore there is no workload on that CPU and Sleep(0) returns control
1331 * without yielding the time slot.
1332 * https://rt.perl.org/rt3/Ticket/Display.html?id=88840
1335 win32_async_check(aTHX);
1336 hwnd = w32_pseudo_child_message_hwnds[child];
1337 if (hwnd != INVALID_HANDLE_VALUE) return hwnd;
1340 unsigned int count = 0;
1341 /* No Sleep(1) if tries==0, just fail instead if we get this far. */
1342 while (count++ < tries) {
1344 win32_async_check(aTHX);
1345 hwnd = w32_pseudo_child_message_hwnds[child];
1346 if (hwnd != INVALID_HANDLE_VALUE) return hwnd;
1350 Perl_croak(aTHX_ "panic: child pseudo-process was never scheduled");
1355 win32_kill(int pid, int sig)
1361 /* it is a pseudo-forked child */
1362 child = find_pseudo_pid(aTHX_ -pid);
1364 HANDLE hProcess = w32_pseudo_child_handles[child];
1367 /* "Does process exist?" use of kill */
1371 /* kill -9 style un-graceful exit */
1372 /* Do a wait to make sure child starts and isn't in DLL
1374 HWND hwnd = get_hwnd_delay(aTHX, child, 5);
1375 if (TerminateThread(hProcess, sig)) {
1376 /* Allow the scheduler to finish cleaning up the other
1378 * Otherwise, if we ExitProcess() before another context
1379 * switch happens we will end up with a process exit
1380 * code of "sig" instead of our own exit status.
1381 * https://rt.cpan.org/Ticket/Display.html?id=66016#txn-908976
1384 remove_dead_pseudo_process(child);
1391 HWND hwnd = get_hwnd_delay(aTHX, child, 5);
1392 /* We fake signals to pseudo-processes using Win32
1394 if ((hwnd != NULL && PostMessage(hwnd, WM_USER_KILL, sig, 0)) ||
1395 PostThreadMessage(-pid, WM_USER_KILL, sig, 0))
1397 /* Don't wait for child process to terminate after we send a
1398 * SIGTERM because the child may be blocked in a system call
1399 * and never receive the signal.
1401 if (sig == SIGTERM) {
1403 w32_pseudo_child_sigterm[child] = 1;
1405 /* It might be us ... */
1417 child = find_pid(aTHX_ pid);
1419 if (my_kill(pid, sig)) {
1421 if (GetExitCodeProcess(w32_child_handles[child], &exitcode) &&
1422 exitcode != STILL_ACTIVE)
1424 remove_dead_process(child);
1430 if (my_kill(pid, sig))
1439 win32_stat(const char *path, Stat_t *sbuf)
1441 char buffer[MAX_PATH+1];
1442 int l = strlen(path);
1446 BOOL expect_dir = FALSE;
1448 GV *gv_sloppy = gv_fetchpvs("\027IN32_SLOPPY_STAT",
1449 GV_NOTQUAL, SVt_PV);
1450 BOOL sloppy = gv_sloppy && SvTRUE(GvSV(gv_sloppy));
1453 switch(path[l - 1]) {
1454 /* FindFirstFile() and stat() are buggy with a trailing
1455 * slashes, except for the root directory of a drive */
1458 if (l > sizeof(buffer)) {
1459 errno = ENAMETOOLONG;
1463 strncpy(buffer, path, l);
1464 /* remove additional trailing slashes */
1465 while (l > 1 && (buffer[l-1] == '/' || buffer[l-1] == '\\'))
1467 /* add back slash if we otherwise end up with just a drive letter */
1468 if (l == 2 && isALPHA(buffer[0]) && buffer[1] == ':')
1475 /* FindFirstFile() is buggy with "x:", so add a dot :-( */
1477 if (l == 2 && isALPHA(path[0])) {
1478 buffer[0] = path[0];
1489 path = PerlDir_mapA(path);
1493 /* We must open & close the file once; otherwise file attribute changes */
1494 /* might not yet have propagated to "other" hard links of the same file. */
1495 /* This also gives us an opportunity to determine the number of links. */
1496 HANDLE handle = CreateFileA(path, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
1497 if (handle != INVALID_HANDLE_VALUE) {
1498 BY_HANDLE_FILE_INFORMATION bhi;
1499 if (GetFileInformationByHandle(handle, &bhi))
1500 nlink = bhi.nNumberOfLinks;
1501 CloseHandle(handle);
1505 /* path will be mapped correctly above */
1506 #if defined(WIN64) || defined(USE_LARGE_FILES)
1507 res = _stati64(path, sbuf);
1509 res = stat(path, sbuf);
1511 sbuf->st_nlink = nlink;
1514 /* CRT is buggy on sharenames, so make sure it really isn't.
1515 * XXX using GetFileAttributesEx() will enable us to set
1516 * sbuf->st_*time (but note that's not available on the
1517 * Windows of 1995) */
1518 DWORD r = GetFileAttributesA(path);
1519 if (r != 0xffffffff && (r & FILE_ATTRIBUTE_DIRECTORY)) {
1520 /* sbuf may still contain old garbage since stat() failed */
1521 Zero(sbuf, 1, Stat_t);
1522 sbuf->st_mode = S_IFDIR | S_IREAD;
1524 if (!(r & FILE_ATTRIBUTE_READONLY))
1525 sbuf->st_mode |= S_IWRITE | S_IEXEC;
1530 if (l == 3 && isALPHA(path[0]) && path[1] == ':'
1531 && (path[2] == '\\' || path[2] == '/'))
1533 /* The drive can be inaccessible, some _stat()s are buggy */
1534 if (!GetVolumeInformationA(path,NULL,0,NULL,NULL,NULL,NULL,0)) {
1539 if (expect_dir && !S_ISDIR(sbuf->st_mode)) {
1543 if (S_ISDIR(sbuf->st_mode)) {
1544 /* Ensure the "write" bit is switched off in the mode for
1545 * directories with the read-only attribute set. Some compilers
1546 * switch it on for directories, which is technically correct
1547 * (directories are indeed always writable unless denied by DACLs),
1548 * but we want stat() and -w to reflect the state of the read-only
1549 * attribute for symmetry with chmod(). */
1550 DWORD r = GetFileAttributesA(path);
1551 if (r != 0xffffffff && (r & FILE_ATTRIBUTE_READONLY)) {
1552 sbuf->st_mode &= ~S_IWRITE;
1559 #define isSLASH(c) ((c) == '/' || (c) == '\\')
1560 #define SKIP_SLASHES(s) \
1562 while (*(s) && isSLASH(*(s))) \
1565 #define COPY_NONSLASHES(d,s) \
1567 while (*(s) && !isSLASH(*(s))) \
1571 /* Find the longname of a given path. path is destructively modified.
1572 * It should have space for at least MAX_PATH characters. */
1574 win32_longpath(char *path)
1576 WIN32_FIND_DATA fdata;
1578 char tmpbuf[MAX_PATH+1];
1579 char *tmpstart = tmpbuf;
1586 if (isALPHA(path[0]) && path[1] == ':') {
1588 *tmpstart++ = path[0];
1592 else if (isSLASH(path[0]) && isSLASH(path[1])) {
1594 *tmpstart++ = path[0];
1595 *tmpstart++ = path[1];
1596 SKIP_SLASHES(start);
1597 COPY_NONSLASHES(tmpstart,start); /* copy machine name */
1599 *tmpstart++ = *start++;
1600 SKIP_SLASHES(start);
1601 COPY_NONSLASHES(tmpstart,start); /* copy share name */
1606 /* copy initial slash, if any */
1607 if (isSLASH(*start)) {
1608 *tmpstart++ = *start++;
1610 SKIP_SLASHES(start);
1613 /* FindFirstFile() expands "." and "..", so we need to pass
1614 * those through unmolested */
1616 && (!start[1] || isSLASH(start[1])
1617 || (start[1] == '.' && (!start[2] || isSLASH(start[2])))))
1619 COPY_NONSLASHES(tmpstart,start); /* copy "." or ".." */
1624 /* if this is the end, bust outta here */
1628 /* now we're at a non-slash; walk up to next slash */
1629 while (*start && !isSLASH(*start))
1632 /* stop and find full name of component */
1635 fhand = FindFirstFile(path,&fdata);
1637 if (fhand != INVALID_HANDLE_VALUE) {
1638 STRLEN len = strlen(fdata.cFileName);
1639 if ((STRLEN)(tmpbuf + sizeof(tmpbuf) - tmpstart) > len) {
1640 strcpy(tmpstart, fdata.cFileName);
1651 /* failed a step, just return without side effects */
1652 /*PerlIO_printf(Perl_debug_log, "Failed to find %s\n", path);*/
1657 strcpy(path,tmpbuf);
1670 win32_croak_not_implemented(const char * fname)
1672 PERL_ARGS_ASSERT_WIN32_CROAK_NOT_IMPLEMENTED;
1674 Perl_croak_nocontext("%s not implemented!\n", fname);
1677 /* Converts a wide character (UTF-16) string to the Windows ANSI code page,
1678 * potentially using the system's default replacement character for any
1679 * unrepresentable characters. The caller must free() the returned string. */
1681 wstr_to_str(const wchar_t* wstr)
1683 BOOL used_default = FALSE;
1684 size_t wlen = wcslen(wstr) + 1;
1685 int len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wstr, wlen,
1686 NULL, 0, NULL, NULL);
1687 char* str = (char*)malloc(len);
1690 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wstr, wlen,
1691 str, len, NULL, &used_default);
1695 /* The win32_ansipath() function takes a Unicode filename and converts it
1696 * into the current Windows codepage. If some characters cannot be mapped,
1697 * then it will convert the short name instead.
1699 * The buffer to the ansi pathname must be freed with win32_free() when it
1700 * it no longer needed.
1702 * The argument to win32_ansipath() must exist before this function is
1703 * called; otherwise there is no way to determine the short path name.
1705 * Ideas for future refinement:
1706 * - Only convert those segments of the path that are not in the current
1707 * codepage, but leave the other segments in their long form.
1708 * - If the resulting name is longer than MAX_PATH, start converting
1709 * additional path segments into short names until the full name
1710 * is shorter than MAX_PATH. Shorten the filename part last!
1713 win32_ansipath(const WCHAR *widename)
1716 BOOL use_default = FALSE;
1717 size_t widelen = wcslen(widename)+1;
1718 int len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, widename, widelen,
1719 NULL, 0, NULL, NULL);
1720 name = (char*)win32_malloc(len);
1724 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, widename, widelen,
1725 name, len, NULL, &use_default);
1727 DWORD shortlen = GetShortPathNameW(widename, NULL, 0);
1729 WCHAR *shortname = (WCHAR*)win32_malloc(shortlen*sizeof(WCHAR));
1732 shortlen = GetShortPathNameW(widename, shortname, shortlen)+1;
1734 len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, shortname, shortlen,
1735 NULL, 0, NULL, NULL);
1736 name = (char*)win32_realloc(name, len);
1739 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, shortname, shortlen,
1740 name, len, NULL, NULL);
1741 win32_free(shortname);
1747 /* the returned string must be freed with win32_freeenvironmentstrings which is
1748 * implemented as a macro
1749 * void win32_freeenvironmentstrings(void* block)
1752 win32_getenvironmentstrings(void)
1754 LPWSTR lpWStr, lpWTmp;
1756 DWORD env_len, wenvstrings_len = 0, aenvstrings_len = 0;
1758 /* Get the process environment strings */
1759 lpWTmp = lpWStr = (LPWSTR) GetEnvironmentStringsW();
1760 for (wenvstrings_len = 1; *lpWTmp != '\0'; lpWTmp += env_len + 1) {
1761 env_len = wcslen(lpWTmp);
1762 /* calculate the size of the environment strings */
1763 wenvstrings_len += env_len + 1;
1766 /* Get the number of bytes required to store the ACP encoded string */
1767 aenvstrings_len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
1768 lpWStr, wenvstrings_len, NULL, 0, NULL, NULL);
1769 lpTmp = lpStr = (char *)win32_calloc(aenvstrings_len, sizeof(char));
1773 /* Convert the string from UTF-16 encoding to ACP encoding */
1774 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, lpWStr, wenvstrings_len, lpStr,
1775 aenvstrings_len, NULL, NULL);
1781 win32_getenv(const char *name)
1788 needlen = GetEnvironmentVariableA(name,NULL,0);
1790 curitem = sv_2mortal(newSVpvn("", 0));
1792 SvGROW(curitem, needlen+1);
1793 needlen = GetEnvironmentVariableA(name,SvPVX(curitem),
1795 } while (needlen >= SvLEN(curitem));
1796 SvCUR_set(curitem, needlen);
1799 last_err = GetLastError();
1800 if (last_err == ERROR_NOT_ENOUGH_MEMORY) {
1801 /* It appears the variable is in the env, but the Win32 API
1802 doesn't have a canned way of getting it. So we fall back to
1803 grabbing the whole env and pulling this value out if possible */
1804 char *envv = GetEnvironmentStrings();
1808 char *end = strchr(cur,'=');
1809 if (end && end != cur) {
1811 if (!strcmp(cur,name)) {
1812 curitem = sv_2mortal(newSVpv(end+1,0));
1817 cur = end + strlen(end+1)+2;
1819 else if ((len = strlen(cur)))
1822 FreeEnvironmentStrings(envv);
1825 /* last ditch: allow any environment variables that begin with 'PERL'
1826 to be obtained from the registry, if found there */
1827 if (strncmp(name, "PERL", 4) == 0)
1828 (void)get_regstr(name, &curitem);
1831 if (curitem && SvCUR(curitem))
1832 return SvPVX(curitem);
1838 win32_putenv(const char *name)
1845 curitem = (char *) win32_malloc(strlen(name)+1);
1846 strcpy(curitem, name);
1847 val = strchr(curitem, '=');
1849 /* The sane way to deal with the environment.
1850 * Has these advantages over putenv() & co.:
1851 * * enables us to store a truly empty value in the
1852 * environment (like in UNIX).
1853 * * we don't have to deal with RTL globals, bugs and leaks
1854 * (specifically, see http://support.microsoft.com/kb/235601).
1856 * Why you may want to use the RTL environment handling
1857 * (previously enabled by USE_WIN32_RTL_ENV):
1858 * * environ[] and RTL functions will not reflect changes,
1859 * which might be an issue if extensions want to access
1860 * the env. via RTL. This cuts both ways, since RTL will
1861 * not see changes made by extensions that call the Win32
1862 * functions directly, either.
1866 if (SetEnvironmentVariableA(curitem, *val ? val : NULL))
1869 win32_free(curitem);
1875 filetime_to_clock(PFILETIME ft)
1877 __int64 qw = ft->dwHighDateTime;
1879 qw |= ft->dwLowDateTime;
1880 qw /= 10000; /* File time ticks at 0.1uS, clock at 1mS */
1885 win32_times(struct tms *timebuf)
1890 clock_t process_time_so_far = clock();
1891 if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy,
1893 timebuf->tms_utime = filetime_to_clock(&user);
1894 timebuf->tms_stime = filetime_to_clock(&kernel);
1895 timebuf->tms_cutime = 0;
1896 timebuf->tms_cstime = 0;
1898 /* That failed - e.g. Win95 fallback to clock() */
1899 timebuf->tms_utime = process_time_so_far;
1900 timebuf->tms_stime = 0;
1901 timebuf->tms_cutime = 0;
1902 timebuf->tms_cstime = 0;
1904 return process_time_so_far;
1907 /* fix utime() so it works on directories in NT */
1909 filetime_from_time(PFILETIME pFileTime, time_t Time)
1911 struct tm *pTM = localtime(&Time);
1912 SYSTEMTIME SystemTime;
1918 SystemTime.wYear = pTM->tm_year + 1900;
1919 SystemTime.wMonth = pTM->tm_mon + 1;
1920 SystemTime.wDay = pTM->tm_mday;
1921 SystemTime.wHour = pTM->tm_hour;
1922 SystemTime.wMinute = pTM->tm_min;
1923 SystemTime.wSecond = pTM->tm_sec;
1924 SystemTime.wMilliseconds = 0;
1926 return SystemTimeToFileTime(&SystemTime, &LocalTime) &&
1927 LocalFileTimeToFileTime(&LocalTime, pFileTime);
1931 win32_unlink(const char *filename)
1937 filename = PerlDir_mapA(filename);
1938 attrs = GetFileAttributesA(filename);
1939 if (attrs == 0xFFFFFFFF) {
1943 if (attrs & FILE_ATTRIBUTE_READONLY) {
1944 (void)SetFileAttributesA(filename, attrs & ~FILE_ATTRIBUTE_READONLY);
1945 ret = unlink(filename);
1947 (void)SetFileAttributesA(filename, attrs);
1950 ret = unlink(filename);
1955 win32_utime(const char *filename, struct utimbuf *times)
1962 struct utimbuf TimeBuffer;
1965 filename = PerlDir_mapA(filename);
1966 rc = utime(filename, times);
1968 /* EACCES: path specifies directory or readonly file */
1969 if (rc == 0 || errno != EACCES)
1972 if (times == NULL) {
1973 times = &TimeBuffer;
1974 time(×->actime);
1975 times->modtime = times->actime;
1978 /* This will (and should) still fail on readonly files */
1979 handle = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE,
1980 FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
1981 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1982 if (handle == INVALID_HANDLE_VALUE)
1985 if (GetFileTime(handle, &ftCreate, &ftAccess, &ftWrite) &&
1986 filetime_from_time(&ftAccess, times->actime) &&
1987 filetime_from_time(&ftWrite, times->modtime) &&
1988 SetFileTime(handle, &ftCreate, &ftAccess, &ftWrite))
1993 CloseHandle(handle);
1998 unsigned __int64 ft_i64;
2003 #define Const64(x) x##LL
2005 #define Const64(x) x##i64
2007 /* Number of 100 nanosecond units from 1/1/1601 to 1/1/1970 */
2008 #define EPOCH_BIAS Const64(116444736000000000)
2010 /* NOTE: This does not compute the timezone info (doing so can be expensive,
2011 * and appears to be unsupported even by glibc) */
2013 win32_gettimeofday(struct timeval *tp, void *not_used)
2017 /* this returns time in 100-nanosecond units (i.e. tens of usecs) */
2018 GetSystemTimeAsFileTime(&ft.ft_val);
2020 /* seconds since epoch */
2021 tp->tv_sec = (long)((ft.ft_i64 - EPOCH_BIAS) / Const64(10000000));
2023 /* microseconds remaining */
2024 tp->tv_usec = (long)((ft.ft_i64 / Const64(10)) % Const64(1000000));
2030 win32_uname(struct utsname *name)
2032 struct hostent *hep;
2033 STRLEN nodemax = sizeof(name->nodename)-1;
2036 switch (g_osver.dwPlatformId) {
2037 case VER_PLATFORM_WIN32_WINDOWS:
2038 strcpy(name->sysname, "Windows");
2040 case VER_PLATFORM_WIN32_NT:
2041 strcpy(name->sysname, "Windows NT");
2043 case VER_PLATFORM_WIN32s:
2044 strcpy(name->sysname, "Win32s");
2047 strcpy(name->sysname, "Win32 Unknown");
2052 sprintf(name->release, "%d.%d",
2053 g_osver.dwMajorVersion, g_osver.dwMinorVersion);
2056 sprintf(name->version, "Build %d",
2057 g_osver.dwPlatformId == VER_PLATFORM_WIN32_NT
2058 ? g_osver.dwBuildNumber : (g_osver.dwBuildNumber & 0xffff));
2059 if (g_osver.szCSDVersion[0]) {
2060 char *buf = name->version + strlen(name->version);
2061 sprintf(buf, " (%s)", g_osver.szCSDVersion);
2065 hep = win32_gethostbyname("localhost");
2067 STRLEN len = strlen(hep->h_name);
2068 if (len <= nodemax) {
2069 strcpy(name->nodename, hep->h_name);
2072 strncpy(name->nodename, hep->h_name, nodemax);
2073 name->nodename[nodemax] = '\0';
2078 if (!GetComputerName(name->nodename, &sz))
2079 *name->nodename = '\0';
2082 /* machine (architecture) */
2087 GetSystemInfo(&info);
2089 #if (defined(__MINGW32__) && !defined(_ANONYMOUS_UNION) && !defined(__MINGW_EXTENSION))
2090 procarch = info.u.s.wProcessorArchitecture;
2092 procarch = info.wProcessorArchitecture;
2095 case PROCESSOR_ARCHITECTURE_INTEL:
2096 arch = "x86"; break;
2097 case PROCESSOR_ARCHITECTURE_IA64:
2098 arch = "ia64"; break;
2099 case PROCESSOR_ARCHITECTURE_AMD64:
2100 arch = "amd64"; break;
2101 case PROCESSOR_ARCHITECTURE_UNKNOWN:
2102 arch = "unknown"; break;
2104 sprintf(name->machine, "unknown(0x%x)", procarch);
2105 arch = name->machine;
2108 if (name->machine != arch)
2109 strcpy(name->machine, arch);
2114 /* Timing related stuff */
2117 do_raise(pTHX_ int sig)
2119 if (sig < SIG_SIZE) {
2120 Sighandler_t handler = w32_sighandler[sig];
2121 if (handler == SIG_IGN) {
2124 else if (handler != SIG_DFL) {
2129 /* Choose correct default behaviour */
2145 /* Tell caller to exit thread/process as approriate */
2150 sig_terminate(pTHX_ int sig)
2152 Perl_warn(aTHX_ "Terminating on signal SIG%s(%d)\n",PL_sig_name[sig], sig);
2153 /* exit() seems to be safe, my_exit() or die() is a problem in ^C
2160 win32_async_check(pTHX)
2163 HWND hwnd = w32_message_hwnd;
2165 /* Reset w32_poll_count before doing anything else, incase we dispatch
2166 * messages that end up calling back into perl */
2169 if (hwnd != INVALID_HANDLE_VALUE) {
2170 /* Passing PeekMessage -1 as HWND (2nd arg) only gets PostThreadMessage() messages
2171 * and ignores window messages - should co-exist better with windows apps e.g. Tk
2176 while (PeekMessage(&msg, hwnd, WM_TIMER, WM_TIMER, PM_REMOVE|PM_NOYIELD) ||
2177 PeekMessage(&msg, hwnd, WM_USER_MIN, WM_USER_MAX, PM_REMOVE|PM_NOYIELD))
2179 /* re-post a WM_QUIT message (we'll mark it as read later) */
2180 if(msg.message == WM_QUIT) {
2181 PostQuitMessage((int)msg.wParam);
2185 if(!CallMsgFilter(&msg, MSGF_USER))
2187 TranslateMessage(&msg);
2188 DispatchMessage(&msg);
2193 /* Call PeekMessage() to mark all pending messages in the queue as "old".
2194 * This is necessary when we are being called by win32_msgwait() to
2195 * make sure MsgWaitForMultipleObjects() stops reporting the same waiting
2196 * message over and over. An example how this can happen is when
2197 * Perl is calling win32_waitpid() inside a GUI application and the GUI
2198 * is generating messages before the process terminated.
2200 PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE|PM_NOYIELD);
2202 /* Above or other stuff may have set a signal flag */
2209 /* This function will not return until the timeout has elapsed, or until
2210 * one of the handles is ready. */
2212 win32_msgwait(pTHX_ DWORD count, LPHANDLE handles, DWORD timeout, LPDWORD resultp)
2214 /* We may need several goes at this - so compute when we stop */
2216 unsigned __int64 endtime = timeout;
2217 if (timeout != INFINITE) {
2218 GetSystemTimeAsFileTime(&ticks.ft_val);
2219 ticks.ft_i64 /= 10000;
2220 endtime += ticks.ft_i64;
2222 /* This was a race condition. Do not let a non INFINITE timeout to
2223 * MsgWaitForMultipleObjects roll under 0 creating a near
2224 * infinity/~(UINT32)0 timeout which will appear as a deadlock to the
2225 * user who did a CORE perl function with a non infinity timeout,
2226 * sleep for example. This is 64 to 32 truncation minefield.
2228 * This scenario can only be created if the timespan from the return of
2229 * MsgWaitForMultipleObjects to GetSystemTimeAsFileTime exceeds 1 ms. To
2230 * generate the scenario, manual breakpoints in a C debugger are required,
2231 * or a context switch occured in win32_async_check in PeekMessage, or random
2232 * messages are delivered to the *thread* message queue of the Perl thread
2233 * from another process (msctf.dll doing IPC among its instances, VS debugger
2234 * causes msctf.dll to be loaded into Perl by kernel), see [perl #33096].
2236 while (ticks.ft_i64 <= endtime) {
2237 /* if timeout's type is lengthened, remember to split 64b timeout
2238 * into multiple non-infinity runs of MWFMO */
2239 DWORD result = MsgWaitForMultipleObjects(count, handles, FALSE,
2240 (DWORD)(endtime - ticks.ft_i64),
2241 QS_POSTMESSAGE|QS_TIMER|QS_SENDMESSAGE);
2244 if (result == WAIT_TIMEOUT) {
2245 /* Ran out of time - explicit return of zero to avoid -ve if we
2246 have scheduling issues
2250 if (timeout != INFINITE) {
2251 GetSystemTimeAsFileTime(&ticks.ft_val);
2252 ticks.ft_i64 /= 10000;
2254 if (result == WAIT_OBJECT_0 + count) {
2255 /* Message has arrived - check it */
2256 (void)win32_async_check(aTHX);
2259 /* Not timeout or message - one of handles is ready */
2263 /* If we are past the end say zero */
2264 if (!ticks.ft_i64 || ticks.ft_i64 > endtime)
2266 /* compute time left to wait */
2267 ticks.ft_i64 = endtime - ticks.ft_i64;
2268 /* if more ms than DWORD, then return max DWORD */
2269 return ticks.ft_i64 <= UINT_MAX ? (DWORD)ticks.ft_i64 : UINT_MAX;
2273 win32_internal_wait(pTHX_ int *status, DWORD timeout)
2275 /* XXX this wait emulation only knows about processes
2276 * spawned via win32_spawnvp(P_NOWAIT, ...).
2279 DWORD exitcode, waitcode;
2282 if (w32_num_pseudo_children) {
2283 win32_msgwait(aTHX_ w32_num_pseudo_children, w32_pseudo_child_handles,
2284 timeout, &waitcode);
2285 /* Time out here if there are no other children to wait for. */
2286 if (waitcode == WAIT_TIMEOUT) {
2287 if (!w32_num_children) {
2291 else if (waitcode != WAIT_FAILED) {
2292 if (waitcode >= WAIT_ABANDONED_0
2293 && waitcode < WAIT_ABANDONED_0 + w32_num_pseudo_children)
2294 i = waitcode - WAIT_ABANDONED_0;
2296 i = waitcode - WAIT_OBJECT_0;
2297 if (GetExitCodeThread(w32_pseudo_child_handles[i], &exitcode)) {
2298 *status = (int)((exitcode & 0xff) << 8);
2299 retval = (int)w32_pseudo_child_pids[i];
2300 remove_dead_pseudo_process(i);
2307 if (!w32_num_children) {
2312 /* if a child exists, wait for it to die */
2313 win32_msgwait(aTHX_ w32_num_children, w32_child_handles, timeout, &waitcode);
2314 if (waitcode == WAIT_TIMEOUT) {
2317 if (waitcode != WAIT_FAILED) {
2318 if (waitcode >= WAIT_ABANDONED_0
2319 && waitcode < WAIT_ABANDONED_0 + w32_num_children)
2320 i = waitcode - WAIT_ABANDONED_0;
2322 i = waitcode - WAIT_OBJECT_0;
2323 if (GetExitCodeProcess(w32_child_handles[i], &exitcode) ) {
2324 *status = (int)((exitcode & 0xff) << 8);
2325 retval = (int)w32_child_pids[i];
2326 remove_dead_process(i);
2331 errno = GetLastError();
2336 win32_waitpid(int pid, int *status, int flags)
2339 DWORD timeout = (flags & WNOHANG) ? 0 : INFINITE;
2342 if (pid == -1) /* XXX threadid == 1 ? */
2343 return win32_internal_wait(aTHX_ status, timeout);
2346 child = find_pseudo_pid(aTHX_ -pid);
2348 HANDLE hThread = w32_pseudo_child_handles[child];
2350 win32_msgwait(aTHX_ 1, &hThread, timeout, &waitcode);
2351 if (waitcode == WAIT_TIMEOUT) {
2354 else if (waitcode == WAIT_OBJECT_0) {
2355 if (GetExitCodeThread(hThread, &waitcode)) {
2356 *status = (int)((waitcode & 0xff) << 8);
2357 retval = (int)w32_pseudo_child_pids[child];
2358 remove_dead_pseudo_process(child);
2370 child = find_pid(aTHX_ pid);
2372 hProcess = w32_child_handles[child];
2373 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
2374 if (waitcode == WAIT_TIMEOUT) {
2377 else if (waitcode == WAIT_OBJECT_0) {
2378 if (GetExitCodeProcess(hProcess, &waitcode)) {
2379 *status = (int)((waitcode & 0xff) << 8);
2380 retval = (int)w32_child_pids[child];
2381 remove_dead_process(child);
2389 hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
2391 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
2392 if (waitcode == WAIT_TIMEOUT) {
2393 CloseHandle(hProcess);
2396 else if (waitcode == WAIT_OBJECT_0) {
2397 if (GetExitCodeProcess(hProcess, &waitcode)) {
2398 *status = (int)((waitcode & 0xff) << 8);
2399 CloseHandle(hProcess);
2403 CloseHandle(hProcess);
2409 return retval >= 0 ? pid : retval;
2413 win32_wait(int *status)
2416 return win32_internal_wait(aTHX_ status, INFINITE);
2419 DllExport unsigned int
2420 win32_sleep(unsigned int t)
2423 /* Win32 times are in ms so *1000 in and /1000 out */
2424 if (t > UINT_MAX / 1000) {
2425 Perl_ck_warner(aTHX_ packWARN(WARN_OVERFLOW),
2426 "sleep(%lu) too large", t);
2428 return win32_msgwait(aTHX_ 0, NULL, t * 1000, NULL) / 1000;
2431 DllExport unsigned int
2432 win32_alarm(unsigned int sec)
2435 * the 'obvious' implentation is SetTimer() with a callback
2436 * which does whatever receiving SIGALRM would do
2437 * we cannot use SIGALRM even via raise() as it is not
2438 * one of the supported codes in <signal.h>
2442 if (w32_message_hwnd == INVALID_HANDLE_VALUE)
2443 w32_message_hwnd = win32_create_message_window();
2446 if (w32_message_hwnd == NULL)
2447 w32_timerid = SetTimer(NULL, w32_timerid, sec*1000, NULL);
2450 SetTimer(w32_message_hwnd, w32_timerid, sec*1000, NULL);
2455 KillTimer(w32_message_hwnd, w32_timerid);
2462 extern char * des_fcrypt(const char *txt, const char *salt, char *cbuf);
2465 win32_crypt(const char *txt, const char *salt)
2468 return des_fcrypt(txt, salt, w32_crypt_buffer);
2471 /* simulate flock by locking a range on the file */
2473 #define LK_LEN 0xffff0000
2476 win32_flock(int fd, int oper)
2482 fh = (HANDLE)_get_osfhandle(fd);
2483 if (fh == (HANDLE)-1) /* _get_osfhandle() already sets errno to EBADF */
2486 memset(&o, 0, sizeof(o));
2489 case LOCK_SH: /* shared lock */
2490 if (LockFileEx(fh, 0, 0, LK_LEN, 0, &o))
2493 case LOCK_EX: /* exclusive lock */
2494 if (LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o))
2497 case LOCK_SH|LOCK_NB: /* non-blocking shared lock */
2498 if (LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o))
2501 case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */
2502 if (LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
2506 case LOCK_UN: /* unlock lock */
2507 if (UnlockFileEx(fh, 0, LK_LEN, 0, &o))
2510 default: /* unknown */
2515 if (GetLastError() == ERROR_LOCK_VIOLATION)
2516 errno = WSAEWOULDBLOCK;
2526 * redirected io subsystem for all XS modules
2539 return (&(_environ));
2542 /* the rest are the remapped stdio routines */
2562 win32_ferror(FILE *fp)
2564 return (ferror(fp));
2569 win32_feof(FILE *fp)
2575 * Since the errors returned by the socket error function
2576 * WSAGetLastError() are not known by the library routine strerror
2577 * we have to roll our own.
2581 win32_strerror(int e)
2583 #if !defined __MINGW32__ /* compiler intolerance */
2584 extern int sys_nerr;
2587 if (e < 0 || e > sys_nerr) {
2592 aTHXa(PERL_GET_THX);
2593 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
2594 |FORMAT_MESSAGE_IGNORE_INSERTS, NULL, e, 0,
2595 w32_strerror_buffer, sizeof(w32_strerror_buffer),
2598 strcpy(w32_strerror_buffer, "Unknown Error");
2600 return w32_strerror_buffer;
2604 #define strerror win32_strerror
2608 win32_str_os_error(void *sv, DWORD dwErr)
2612 dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
2613 |FORMAT_MESSAGE_IGNORE_INSERTS
2614 |FORMAT_MESSAGE_FROM_SYSTEM, NULL,
2615 dwErr, 0, (char *)&sMsg, 1, NULL);
2616 /* strip trailing whitespace and period */
2619 --dwLen; /* dwLen doesn't include trailing null */
2620 } while (0 < dwLen && isSPACE(sMsg[dwLen]));
2621 if ('.' != sMsg[dwLen])
2626 sMsg = (char*)LocalAlloc(0, 64/**sizeof(TCHAR)*/);
2628 dwLen = sprintf(sMsg,
2629 "Unknown error #0x%lX (lookup 0x%lX)",
2630 dwErr, GetLastError());
2634 sv_setpvn((SV*)sv, sMsg, dwLen);
2640 win32_fprintf(FILE *fp, const char *format, ...)
2643 va_start(marker, format); /* Initialize variable arguments. */
2645 return (vfprintf(fp, format, marker));
2649 win32_printf(const char *format, ...)
2652 va_start(marker, format); /* Initialize variable arguments. */
2654 return (vprintf(format, marker));
2658 win32_vfprintf(FILE *fp, const char *format, va_list args)
2660 return (vfprintf(fp, format, args));
2664 win32_vprintf(const char *format, va_list args)
2666 return (vprintf(format, args));
2670 win32_fread(void *buf, size_t size, size_t count, FILE *fp)
2672 return fread(buf, size, count, fp);
2676 win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
2678 return fwrite(buf, size, count, fp);
2681 #define MODE_SIZE 10
2684 win32_fopen(const char *filename, const char *mode)
2692 if (stricmp(filename, "/dev/null")==0)
2695 aTHXa(PERL_GET_THX);
2696 f = fopen(PerlDir_mapA(filename), mode);
2697 /* avoid buffering headaches for child processes */
2698 if (f && *mode == 'a')
2699 win32_fseek(f, 0, SEEK_END);
2704 win32_fdopen(int handle, const char *mode)
2707 f = fdopen(handle, (char *) mode);
2708 /* avoid buffering headaches for child processes */
2709 if (f && *mode == 'a')
2710 win32_fseek(f, 0, SEEK_END);
2715 win32_freopen(const char *path, const char *mode, FILE *stream)
2718 if (stricmp(path, "/dev/null")==0)
2721 aTHXa(PERL_GET_THX);
2722 return freopen(PerlDir_mapA(path), mode, stream);
2726 win32_fclose(FILE *pf)
2728 #ifdef WIN32_NO_SOCKETS
2731 return my_fclose(pf); /* defined in win32sck.c */
2736 win32_fputs(const char *s,FILE *pf)
2738 return fputs(s, pf);
2742 win32_fputc(int c,FILE *pf)
2748 win32_ungetc(int c,FILE *pf)
2750 return ungetc(c,pf);
2754 win32_getc(FILE *pf)
2760 win32_fileno(FILE *pf)
2766 win32_clearerr(FILE *pf)
2773 win32_fflush(FILE *pf)
2779 win32_ftell(FILE *pf)
2781 #if defined(WIN64) || defined(USE_LARGE_FILES)
2783 if (fgetpos(pf, &pos))
2792 win32_fseek(FILE *pf, Off_t offset,int origin)
2794 #if defined(WIN64) || defined(USE_LARGE_FILES)
2798 if (fgetpos(pf, &pos))
2803 fseek(pf, 0, SEEK_END);
2804 pos = _telli64(fileno(pf));
2813 return fsetpos(pf, &offset);
2815 return fseek(pf, (long)offset, origin);
2820 win32_fgetpos(FILE *pf,fpos_t *p)
2822 return fgetpos(pf, p);
2826 win32_fsetpos(FILE *pf,const fpos_t *p)
2828 return fsetpos(pf, p);
2832 win32_rewind(FILE *pf)
2841 char prefix[MAX_PATH+1];
2842 char filename[MAX_PATH+1];
2843 DWORD len = GetTempPath(MAX_PATH, prefix);
2844 if (len && len < MAX_PATH) {
2845 if (GetTempFileName(prefix, "plx", 0, filename)) {
2846 HANDLE fh = CreateFile(filename,
2847 DELETE | GENERIC_READ | GENERIC_WRITE,
2851 FILE_ATTRIBUTE_NORMAL
2852 | FILE_FLAG_DELETE_ON_CLOSE,
2854 if (fh != INVALID_HANDLE_VALUE) {
2855 int fd = win32_open_osfhandle((intptr_t)fh, 0);
2858 DEBUG_p(PerlIO_printf(Perl_debug_log,
2859 "Created tmpfile=%s\n",filename));
2871 int fd = win32_tmpfd();
2873 return win32_fdopen(fd, "w+b");
2885 win32_fstat(int fd, Stat_t *sbufptr)
2887 #if defined(WIN64) || defined(USE_LARGE_FILES)
2888 return _fstati64(fd, sbufptr);
2890 return fstat(fd, sbufptr);
2895 win32_pipe(int *pfd, unsigned int size, int mode)
2897 return _pipe(pfd, size, mode);
2901 win32_popenlist(const char *mode, IV narg, SV **args)
2903 Perl_croak_nocontext("List form of pipe open not implemented");
2908 * a popen() clone that respects PERL5SHELL
2910 * changed to return PerlIO* rather than FILE * by BKS, 11-11-2000
2914 win32_popen(const char *command, const char *mode)
2916 #ifdef USE_RTL_POPEN
2917 return _popen(command, mode);
2928 /* establish which ends read and write */
2929 if (strchr(mode,'w')) {
2930 stdfd = 0; /* stdin */
2933 nhandle = STD_INPUT_HANDLE;
2935 else if (strchr(mode,'r')) {
2936 stdfd = 1; /* stdout */
2939 nhandle = STD_OUTPUT_HANDLE;
2944 /* set the correct mode */
2945 if (strchr(mode,'b'))
2947 else if (strchr(mode,'t'))
2950 ourmode = _fmode & (O_TEXT | O_BINARY);
2952 /* the child doesn't inherit handles */
2953 ourmode |= O_NOINHERIT;
2955 if (win32_pipe(p, 512, ourmode) == -1)
2958 /* save the old std handle (this needs to happen before the
2959 * dup2(), since that might call SetStdHandle() too) */
2962 old_h = GetStdHandle(nhandle);
2964 /* save current stdfd */
2965 if ((oldfd = win32_dup(stdfd)) == -1)
2968 /* make stdfd go to child end of pipe (implicitly closes stdfd) */
2969 /* stdfd will be inherited by the child */
2970 if (win32_dup2(p[child], stdfd) == -1)
2973 /* close the child end in parent */
2974 win32_close(p[child]);
2976 /* set the new std handle (in case dup2() above didn't) */
2977 SetStdHandle(nhandle, (HANDLE)_get_osfhandle(stdfd));
2979 /* start the child */
2982 if ((childpid = do_spawn_nowait((char*)command)) == -1)
2985 /* revert stdfd to whatever it was before */
2986 if (win32_dup2(oldfd, stdfd) == -1)
2989 /* close saved handle */
2992 /* restore the old std handle (this needs to happen after the
2993 * dup2(), since that might call SetStdHandle() too */
2995 SetStdHandle(nhandle, old_h);
3000 sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid);
3002 /* set process id so that it can be returned by perl's open() */
3003 PL_forkprocess = childpid;
3006 /* we have an fd, return a file stream */
3007 return (PerlIO_fdopen(p[parent], (char *)mode));
3010 /* we don't need to check for errors here */
3014 win32_dup2(oldfd, stdfd);
3018 SetStdHandle(nhandle, old_h);
3024 #endif /* USE_RTL_POPEN */
3032 win32_pclose(PerlIO *pf)
3034 #ifdef USE_RTL_POPEN
3038 int childpid, status;
3041 sv = *av_fetch(w32_fdpid, PerlIO_fileno(pf), TRUE);
3044 childpid = SvIVX(sv);
3060 if (win32_waitpid(childpid, &status, 0) == -1)
3065 #endif /* USE_RTL_POPEN */
3069 win32_link(const char *oldname, const char *newname)
3072 WCHAR wOldName[MAX_PATH+1];
3073 WCHAR wNewName[MAX_PATH+1];
3075 if (MultiByteToWideChar(CP_ACP, 0, oldname, -1, wOldName, MAX_PATH+1) &&
3076 MultiByteToWideChar(CP_ACP, 0, newname, -1, wNewName, MAX_PATH+1) &&
3077 ((aTHXa(PERL_GET_THX)), wcscpy(wOldName, PerlDir_mapW(wOldName)),
3078 CreateHardLinkW(PerlDir_mapW(wNewName), wOldName, NULL)))
3082 /* This isn't perfect, eg. Win32 returns ERROR_ACCESS_DENIED for
3083 both permissions errors and if the source is a directory, while
3084 POSIX wants EACCES and EPERM respectively.
3086 Determined by experimentation on Windows 7 x64 SP1, since MS
3087 don't document what error codes are returned.
3089 switch (GetLastError()) {
3090 case ERROR_BAD_NET_NAME:
3091 case ERROR_BAD_NETPATH:
3092 case ERROR_BAD_PATHNAME:
3093 case ERROR_FILE_NOT_FOUND:
3094 case ERROR_FILENAME_EXCED_RANGE:
3095 case ERROR_INVALID_DRIVE:
3096 case ERROR_PATH_NOT_FOUND:
3099 case ERROR_ALREADY_EXISTS:
3102 case ERROR_ACCESS_DENIED:
3105 case ERROR_NOT_SAME_DEVICE:
3109 /* ERROR_INVALID_FUNCTION - eg. on a FAT volume */
3117 win32_rename(const char *oname, const char *newname)
3119 char szOldName[MAX_PATH+1];
3121 DWORD dwFlags = MOVEFILE_COPY_ALLOWED;
3124 if (stricmp(newname, oname))
3125 dwFlags |= MOVEFILE_REPLACE_EXISTING;
3126 strcpy(szOldName, PerlDir_mapA(oname));
3128 bResult = MoveFileExA(szOldName,PerlDir_mapA(newname), dwFlags);
3130 DWORD err = GetLastError();
3132 case ERROR_BAD_NET_NAME:
3133 case ERROR_BAD_NETPATH:
3134 case ERROR_BAD_PATHNAME:
3135 case ERROR_FILE_NOT_FOUND:
3136 case ERROR_FILENAME_EXCED_RANGE:
3137 case ERROR_INVALID_DRIVE:
3138 case ERROR_NO_MORE_FILES:
3139 case ERROR_PATH_NOT_FOUND:
3152 win32_setmode(int fd, int mode)
3154 return setmode(fd, mode);
3158 win32_chsize(int fd, Off_t size)
3160 #if defined(WIN64) || defined(USE_LARGE_FILES)
3162 Off_t cur, end, extend;
3164 cur = win32_tell(fd);
3167 end = win32_lseek(fd, 0, SEEK_END);
3170 extend = size - end;
3174 else if (extend > 0) {
3175 /* must grow the file, padding with nulls */
3177 int oldmode = win32_setmode(fd, O_BINARY);
3179 memset(b, '\0', sizeof(b));
3181 count = extend >= sizeof(b) ? sizeof(b) : (size_t)extend;
3182 count = win32_write(fd, b, count);
3183 if ((int)count < 0) {
3187 } while ((extend -= count) > 0);
3188 win32_setmode(fd, oldmode);
3191 /* shrink the file */
3192 win32_lseek(fd, size, SEEK_SET);
3193 if (!SetEndOfFile((HANDLE)_get_osfhandle(fd))) {
3199 win32_lseek(fd, cur, SEEK_SET);
3202 return chsize(fd, (long)size);
3207 win32_lseek(int fd, Off_t offset, int origin)
3209 #if defined(WIN64) || defined(USE_LARGE_FILES)
3210 return _lseeki64(fd, offset, origin);
3212 return lseek(fd, (long)offset, origin);
3219 #if defined(WIN64) || defined(USE_LARGE_FILES)
3220 return _telli64(fd);
3227 win32_open(const char *path, int flag, ...)
3234 pmode = va_arg(ap, int);
3237 if (stricmp(path, "/dev/null")==0)
3240 aTHXa(PERL_GET_THX);
3241 return open(PerlDir_mapA(path), flag, pmode);
3244 /* close() that understands socket */
3245 extern int my_close(int); /* in win32sck.c */
3250 #ifdef WIN32_NO_SOCKETS
3253 return my_close(fd);
3264 win32_isatty(int fd)
3266 /* The Microsoft isatty() function returns true for *all*
3267 * character mode devices, including "nul". Our implementation
3268 * should only return true if the handle has a console buffer.
3271 HANDLE fh = (HANDLE)_get_osfhandle(fd);
3272 if (fh == (HANDLE)-1) {
3273 /* errno is already set to EBADF */
3277 if (GetConsoleMode(fh, &mode))
3291 win32_dup2(int fd1,int fd2)
3293 return dup2(fd1,fd2);
3297 win32_read(int fd, void *buf, unsigned int cnt)
3299 return read(fd, buf, cnt);
3303 win32_write(int fd, const void *buf, unsigned int cnt)
3305 return write(fd, buf, cnt);
3309 win32_mkdir(const char *dir, int mode)
3312 return mkdir(PerlDir_mapA(dir)); /* just ignore mode */
3316 win32_rmdir(const char *dir)
3319 return rmdir(PerlDir_mapA(dir));
3323 win32_chdir(const char *dir)
3333 win32_access(const char *path, int mode)
3336 return access(PerlDir_mapA(path), mode);
3340 win32_chmod(const char *path, int mode)
3343 return chmod(PerlDir_mapA(path), mode);
3348 create_command_line(char *cname, STRLEN clen, const char * const *args)
3355 bool bat_file = FALSE;
3356 bool cmd_shell = FALSE;
3357 bool dumb_shell = FALSE;
3358 bool extra_quotes = FALSE;
3359 bool quote_next = FALSE;
3362 cname = (char*)args[0];
3364 /* The NT cmd.exe shell has the following peculiarity that needs to be
3365 * worked around. It strips a leading and trailing dquote when any
3366 * of the following is true:
3367 * 1. the /S switch was used
3368 * 2. there are more than two dquotes
3369 * 3. there is a special character from this set: &<>()@^|
3370 * 4. no whitespace characters within the two dquotes
3371 * 5. string between two dquotes isn't an executable file
3372 * To work around this, we always add a leading and trailing dquote
3373 * to the string, if the first argument is either "cmd.exe" or "cmd",
3374 * and there were at least two or more arguments passed to cmd.exe
3375 * (not including switches).
3376 * XXX the above rules (from "cmd /?") don't seem to be applied
3377 * always, making for the convolutions below :-(
3381 clen = strlen(cname);
3384 && (stricmp(&cname[clen-4], ".bat") == 0
3385 || (stricmp(&cname[clen-4], ".cmd") == 0)))
3391 char *exe = strrchr(cname, '/');
3392 char *exe2 = strrchr(cname, '\\');
3399 if (stricmp(exe, "cmd.exe") == 0 || stricmp(exe, "cmd") == 0) {
3403 else if (stricmp(exe, "command.com") == 0
3404 || stricmp(exe, "command") == 0)
3411 DEBUG_p(PerlIO_printf(Perl_debug_log, "Args "));
3412 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3413 STRLEN curlen = strlen(arg);
3414 if (!(arg[0] == '"' && arg[curlen-1] == '"'))
3415 len += 2; /* assume quoting needed (worst case) */
3417 DEBUG_p(PerlIO_printf(Perl_debug_log, "[%s]",arg));
3419 DEBUG_p(PerlIO_printf(Perl_debug_log, "\n"));
3422 Newx(cmd, len, char);
3427 extra_quotes = TRUE;
3430 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3432 STRLEN curlen = strlen(arg);
3434 /* we want to protect empty arguments and ones with spaces with
3435 * dquotes, but only if they aren't already there */
3440 else if (quote_next) {
3441 /* see if it really is multiple arguments pretending to
3442 * be one and force a set of quotes around it */
3443 if (*find_next_space(arg))
3446 else if (!(arg[0] == '"' && curlen > 1 && arg[curlen-1] == '"')) {
3448 while (i < curlen) {
3449 if (isSPACE(arg[i])) {
3452 else if (arg[i] == '"') {
3476 && *arg == '/' /* see if arg is "/c", "/x/c", "/x/d/c" etc. */
3477 && stricmp(arg+curlen-2, "/c") == 0)
3479 /* is there a next argument? */
3480 if (args[index+1]) {
3481 /* are there two or more next arguments? */
3482 if (args[index+2]) {
3484 extra_quotes = TRUE;
3487 /* single argument, force quoting if it has spaces */
3503 qualified_path(const char *cmd)
3506 char *fullcmd, *curfullcmd;
3512 fullcmd = (char*)cmd;
3514 if (*fullcmd == '/' || *fullcmd == '\\')
3523 pathstr = PerlEnv_getenv("PATH");
3525 /* worst case: PATH is a single directory; we need additional space
3526 * to append "/", ".exe" and trailing "\0" */
3527 Newx(fullcmd, (pathstr ? strlen(pathstr) : 0) + cmdlen + 6, char);
3528 curfullcmd = fullcmd;
3533 /* start by appending the name to the current prefix */
3534 strcpy(curfullcmd, cmd);
3535 curfullcmd += cmdlen;
3537 /* if it doesn't end with '.', or has no extension, try adding
3538 * a trailing .exe first */
3539 if (cmd[cmdlen-1] != '.'
3540 && (cmdlen < 4 || cmd[cmdlen-4] != '.'))
3542 strcpy(curfullcmd, ".exe");
3543 res = GetFileAttributes(fullcmd);
3544 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3549 /* that failed, try the bare name */
3550 res = GetFileAttributes(fullcmd);
3551 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3554 /* quit if no other path exists, or if cmd already has path */
3555 if (!pathstr || !*pathstr || has_slash)
3558 /* skip leading semis */
3559 while (*pathstr == ';')
3562 /* build a new prefix from scratch */
3563 curfullcmd = fullcmd;
3564 while (*pathstr && *pathstr != ';') {
3565 if (*pathstr == '"') { /* foo;"baz;etc";bar */
3566 pathstr++; /* skip initial '"' */
3567 while (*pathstr && *pathstr != '"') {
3568 *curfullcmd++ = *pathstr++;
3571 pathstr++; /* skip trailing '"' */
3574 *curfullcmd++ = *pathstr++;
3578 pathstr++; /* skip trailing semi */
3579 if (curfullcmd > fullcmd /* append a dir separator */
3580 && curfullcmd[-1] != '/' && curfullcmd[-1] != '\\')
3582 *curfullcmd++ = '\\';
3590 /* The following are just place holders.
3591 * Some hosts may provide and environment that the OS is
3592 * not tracking, therefore, these host must provide that
3593 * environment and the current directory to CreateProcess
3597 win32_get_childenv(void)
3603 win32_free_childenv(void* d)
3608 win32_clearenv(void)
3610 char *envv = GetEnvironmentStrings();
3614 char *end = strchr(cur,'=');
3615 if (end && end != cur) {
3617 SetEnvironmentVariable(cur, NULL);
3619 cur = end + strlen(end+1)+2;
3621 else if ((len = strlen(cur)))
3624 FreeEnvironmentStrings(envv);
3628 win32_get_childdir(void)
3631 char szfilename[MAX_PATH+1];
3633 GetCurrentDirectoryA(MAX_PATH+1, szfilename);
3634 Newx(ptr, strlen(szfilename)+1, char);
3635 strcpy(ptr, szfilename);
3640 win32_free_childdir(char* d)
3646 /* XXX this needs to be made more compatible with the spawnvp()
3647 * provided by the various RTLs. In particular, searching for
3648 * *.{com,bat,cmd} files (as done by the RTLs) is unimplemented.
3649 * This doesn't significantly affect perl itself, because we
3650 * always invoke things using PERL5SHELL if a direct attempt to
3651 * spawn the executable fails.
3653 * XXX splitting and rejoining the commandline between do_aspawn()
3654 * and win32_spawnvp() could also be avoided.
3658 win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
3660 #ifdef USE_RTL_SPAWNVP
3661 return spawnvp(mode, cmdname, (char * const *)argv);
3668 STARTUPINFO StartupInfo;
3669 PROCESS_INFORMATION ProcessInformation;
3672 char *fullcmd = NULL;
3673 char *cname = (char *)cmdname;
3677 clen = strlen(cname);
3678 /* if command name contains dquotes, must remove them */
3679 if (strchr(cname, '"')) {
3681 Newx(cname,clen+1,char);
3694 cmd = create_command_line(cname, clen, argv);
3696 aTHXa(PERL_GET_THX);
3697 env = PerlEnv_get_childenv();
3698 dir = PerlEnv_get_childdir();
3701 case P_NOWAIT: /* asynch + remember result */
3702 if (w32_num_children >= MAXIMUM_WAIT_OBJECTS) {
3707 /* Create a new process group so we can use GenerateConsoleCtrlEvent()
3710 create |= CREATE_NEW_PROCESS_GROUP;
3713 case P_WAIT: /* synchronous execution */
3715 default: /* invalid mode */
3720 memset(&StartupInfo,0,sizeof(StartupInfo));
3721 StartupInfo.cb = sizeof(StartupInfo);
3722 memset(&tbl,0,sizeof(tbl));
3723 PerlEnv_get_child_IO(&tbl);
3724 StartupInfo.dwFlags = tbl.dwFlags;
3725 StartupInfo.dwX = tbl.dwX;
3726 StartupInfo.dwY = tbl.dwY;
3727 StartupInfo.dwXSize = tbl.dwXSize;
3728 StartupInfo.dwYSize = tbl.dwYSize;
3729 StartupInfo.dwXCountChars = tbl.dwXCountChars;
3730 StartupInfo.dwYCountChars = tbl.dwYCountChars;
3731 StartupInfo.dwFillAttribute = tbl.dwFillAttribute;
3732 StartupInfo.wShowWindow = tbl.wShowWindow;
3733 StartupInfo.hStdInput = tbl.childStdIn;
3734 StartupInfo.hStdOutput = tbl.childStdOut;
3735 StartupInfo.hStdError = tbl.childStdErr;
3736 if (StartupInfo.hStdInput == INVALID_HANDLE_VALUE &&
3737 StartupInfo.hStdOutput == INVALID_HANDLE_VALUE &&
3738 StartupInfo.hStdError == INVALID_HANDLE_VALUE)
3740 create |= CREATE_NEW_CONSOLE;
3743 StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
3745 if (w32_use_showwindow) {
3746 StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
3747 StartupInfo.wShowWindow = w32_showwindow;
3750 DEBUG_p(PerlIO_printf(Perl_debug_log, "Spawning [%s] with [%s]\n",
3753 if (!CreateProcess(cname, /* search PATH to find executable */
3754 cmd, /* executable, and its arguments */
3755 NULL, /* process attributes */
3756 NULL, /* thread attributes */
3757 TRUE, /* inherit handles */
3758 create, /* creation flags */
3759 (LPVOID)env, /* inherit environment */
3760 dir, /* inherit cwd */
3762 &ProcessInformation))
3764 /* initial NULL argument to CreateProcess() does a PATH
3765 * search, but it always first looks in the directory
3766 * where the current process was started, which behavior
3767 * is undesirable for backward compatibility. So we
3768 * jump through our own hoops by picking out the path
3769 * we really want it to use. */
3771 fullcmd = qualified_path(cname);
3773 if (cname != cmdname)
3776 DEBUG_p(PerlIO_printf(Perl_debug_log,
3777 "Retrying [%s] with same args\n",
3787 if (mode == P_NOWAIT) {
3788 /* asynchronous spawn -- store handle, return PID */
3789 ret = (int)ProcessInformation.dwProcessId;
3791 w32_child_handles[w32_num_children] = ProcessInformation.hProcess;
3792 w32_child_pids[w32_num_children] = (DWORD)ret;
3797 win32_msgwait(aTHX_ 1, &ProcessInformation.hProcess, INFINITE, NULL);
3798 /* FIXME: if msgwait returned due to message perhaps forward the
3799 "signal" to the process
3801 GetExitCodeProcess(ProcessInformation.hProcess, &status);
3803 CloseHandle(ProcessInformation.hProcess);
3806 CloseHandle(ProcessInformation.hThread);
3809 PerlEnv_free_childenv(env);
3810 PerlEnv_free_childdir(dir);
3812 if (cname != cmdname)
3819 win32_execv(const char *cmdname, const char *const *argv)
3823 /* if this is a pseudo-forked child, we just want to spawn
3824 * the new program, and return */
3826 return spawnv(P_WAIT, cmdname, argv);
3828 return execv(cmdname, argv);
3832 win32_execvp(const char *cmdname, const char *const *argv)
3836 /* if this is a pseudo-forked child, we just want to spawn
3837 * the new program, and return */
3838 if (w32_pseudo_id) {
3839 int status = win32_spawnvp(P_WAIT, cmdname, (const char *const *)argv);
3848 return execvp(cmdname, argv);
3852 win32_perror(const char *str)
3858 win32_setbuf(FILE *pf, char *buf)
3864 win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
3866 return setvbuf(pf, buf, type, size);
3870 win32_flushall(void)
3876 win32_fcloseall(void)
3882 win32_fgets(char *s, int n, FILE *pf)
3884 return fgets(s, n, pf);
3894 win32_fgetc(FILE *pf)
3900 win32_putc(int c, FILE *pf)
3906 win32_puts(const char *s)
3918 win32_putchar(int c)
3925 #ifndef USE_PERL_SBRK
3927 static char *committed = NULL; /* XXX threadead */
3928 static char *base = NULL; /* XXX threadead */
3929 static char *reserved = NULL; /* XXX threadead */
3930 static char *brk = NULL; /* XXX threadead */
3931 static DWORD pagesize = 0; /* XXX threadead */
3934 sbrk(ptrdiff_t need)
3939 GetSystemInfo(&info);
3940 /* Pretend page size is larger so we don't perpetually
3941 * call the OS to commit just one page ...
3943 pagesize = info.dwPageSize << 3;
3945 if (brk+need >= reserved)
3947 DWORD size = brk+need-reserved;
3949 char *prev_committed = NULL;
3950 if (committed && reserved && committed < reserved)
3952 /* Commit last of previous chunk cannot span allocations */
3953 addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
3956 /* Remember where we committed from in case we want to decommit later */
3957 prev_committed = committed;
3958 committed = reserved;
3961 /* Reserve some (more) space
3962 * Contiguous blocks give us greater efficiency, so reserve big blocks -
3963 * this is only address space not memory...
3964 * Note this is a little sneaky, 1st call passes NULL as reserved
3965 * so lets system choose where we start, subsequent calls pass
3966 * the old end address so ask for a contiguous block
3969 if (size < 64*1024*1024)
3970 size = 64*1024*1024;
3971 size = ((size + pagesize - 1) / pagesize) * pagesize;
3972 addr = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
3975 reserved = addr+size;
3985 /* The existing block could not be extended far enough, so decommit
3986 * anything that was just committed above and start anew */
3989 if (!VirtualFree(prev_committed,reserved-prev_committed,MEM_DECOMMIT))
3992 reserved = base = committed = brk = NULL;
4003 if (brk > committed)
4005 DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
4007 if (committed+size > reserved)
4008 size = reserved-committed;
4009 addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
4022 win32_malloc(size_t size)
4024 return malloc(size);
4028 win32_calloc(size_t numitems, size_t size)
4030 return calloc(numitems,size);
4034 win32_realloc(void *block, size_t size)
4036 return realloc(block,size);
4040 win32_free(void *block)
4047 win32_open_osfhandle(intptr_t handle, int flags)
4049 return _open_osfhandle(handle, flags);
4053 win32_get_osfhandle(int fd)
4055 return (intptr_t)_get_osfhandle(fd);
4059 win32_fdupopen(FILE *pf)
4064 int fileno = win32_dup(win32_fileno(pf));
4066 /* open the file in the same mode */
4067 if((pf)->_flag & _IOREAD) {
4071 else if((pf)->_flag & _IOWRT) {
4075 else if((pf)->_flag & _IORW) {
4081 /* it appears that the binmode is attached to the
4082 * file descriptor so binmode files will be handled
4085 pfdup = win32_fdopen(fileno, mode);
4087 /* move the file pointer to the same position */
4088 if (!fgetpos(pf, &pos)) {
4089 fsetpos(pfdup, &pos);
4095 win32_dynaload(const char* filename)
4098 char buf[MAX_PATH+1];
4101 /* LoadLibrary() doesn't recognize forward slashes correctly,
4102 * so turn 'em back. */
4103 first = strchr(filename, '/');
4105 STRLEN len = strlen(filename);
4106 if (len <= MAX_PATH) {
4107 strcpy(buf, filename);
4108 filename = &buf[first - filename];
4110 if (*filename == '/')
4111 *(char*)filename = '\\';
4117 aTHXa(PERL_GET_THX);
4118 return LoadLibraryExA(PerlDir_mapA(filename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
4121 XS(w32_SetChildShowWindow)
4124 BOOL use_showwindow = w32_use_showwindow;
4125 /* use "unsigned short" because Perl has redefined "WORD" */
4126 unsigned short showwindow = w32_showwindow;
4129 Perl_croak(aTHX_ "usage: Win32::SetChildShowWindow($showwindow)");
4131 if (items == 0 || !SvOK(ST(0)))
4132 w32_use_showwindow = FALSE;
4134 w32_use_showwindow = TRUE;
4135 w32_showwindow = (unsigned short)SvIV(ST(0));
4140 ST(0) = sv_2mortal(newSViv(showwindow));
4142 ST(0) = &PL_sv_undef;
4147 Perl_init_os_extras(void)
4150 char *file = __FILE__;
4152 /* Initialize Win32CORE if it has been statically linked. */
4153 #ifndef PERL_IS_MINIPERL
4154 void (*pfn_init)(pTHX);
4155 pfn_init = (void (*)(pTHX))GetProcAddress((HMODULE)w32_perldll_handle, "init_Win32CORE");
4156 aTHXa(PERL_GET_THX);
4160 aTHXa(PERL_GET_THX);
4163 newXS("Win32::SetChildShowWindow", w32_SetChildShowWindow, file);
4167 win32_signal_context(void)
4172 my_perl = PL_curinterp;
4173 PERL_SET_THX(my_perl);
4177 return PL_curinterp;
4183 win32_ctrlhandler(DWORD dwCtrlType)
4186 dTHXa(PERL_GET_SIG_CONTEXT);
4192 switch(dwCtrlType) {
4193 case CTRL_CLOSE_EVENT:
4194 /* A signal that the system sends to all processes attached to a console when
4195 the user closes the console (either by choosing the Close command from the
4196 console window's System menu, or by choosing the End Task command from the
4199 if (do_raise(aTHX_ 1)) /* SIGHUP */
4200 sig_terminate(aTHX_ 1);
4204 /* A CTRL+c signal was received */
4205 if (do_raise(aTHX_ SIGINT))
4206 sig_terminate(aTHX_ SIGINT);
4209 case CTRL_BREAK_EVENT:
4210 /* A CTRL+BREAK signal was received */
4211 if (do_raise(aTHX_ SIGBREAK))
4212 sig_terminate(aTHX_ SIGBREAK);
4215 case CTRL_LOGOFF_EVENT:
4216 /* A signal that the system sends to all console processes when a user is logging
4217 off. This signal does not indicate which user is logging off, so no
4218 assumptions can be made.
4221 case CTRL_SHUTDOWN_EVENT:
4222 /* A signal that the system sends to all console processes when the system is
4225 if (do_raise(aTHX_ SIGTERM))
4226 sig_terminate(aTHX_ SIGTERM);
4235 #ifdef SET_INVALID_PARAMETER_HANDLER
4236 # include <crtdbg.h>
4247 /* fetch Unicode version of PATH */
4249 wide_path = (WCHAR*)win32_malloc(len*sizeof(WCHAR));
4251 size_t newlen = GetEnvironmentVariableW(L"PATH", wide_path, len);
4253 win32_free(wide_path);
4259 wide_path = (WCHAR*)win32_realloc(wide_path, len*sizeof(WCHAR));
4264 /* convert to ANSI pathnames */
4265 wide_dir = wide_path;
4268 WCHAR *sep = wcschr(wide_dir, ';');
4276 /* remove quotes around pathname */
4277 if (*wide_dir == '"')
4279 wide_len = wcslen(wide_dir);
4280 if (wide_len && wide_dir[wide_len-1] == '"')
4281 wide_dir[wide_len-1] = '\0';
4283 /* append ansi_dir to ansi_path */
4284 ansi_dir = win32_ansipath(wide_dir);
4285 ansi_len = strlen(ansi_dir);
4287 size_t newlen = len + 1 + ansi_len;
4288 ansi_path = (char*)win32_realloc(ansi_path, newlen+1);
4291 ansi_path[len] = ';';
4292 memcpy(ansi_path+len+1, ansi_dir, ansi_len+1);
4297 ansi_path = (char*)win32_malloc(5+len+1);
4300 memcpy(ansi_path, "PATH=", 5);
4301 memcpy(ansi_path+5, ansi_dir, len+1);
4304 win32_free(ansi_dir);
4309 /* Update C RTL environ array. This will only have full effect if
4310 * perl_parse() is later called with `environ` as the `env` argument.
4311 * Otherwise S_init_postdump_symbols() will overwrite PATH again.
4313 * We do have to ansify() the PATH before Perl has been fully
4314 * initialized because S_find_script() uses the PATH when perl
4315 * is being invoked with the -S option. This happens before %ENV
4316 * is initialized in S_init_postdump_symbols().
4318 * XXX Is this a bug? Should S_find_script() use the environment
4319 * XXX passed in the `env` arg to parse_perl()?
4322 /* Keep system environment in sync because S_init_postdump_symbols()
4323 * will not call mg_set() if it initializes %ENV from `environ`.
4325 SetEnvironmentVariableA("PATH", ansi_path+5);
4326 /* We are intentionally leaking the ansi_path string here because
4327 * the some runtime libraries puts it directly into the environ
4328 * array. The Microsoft runtime library seems to make a copy,
4329 * but will leak the copy should it be replaced again later.
4330 * Since this code is only called once during PERL_SYS_INIT this
4331 * shouldn't really matter.
4334 win32_free(wide_path);
4338 Perl_win32_init(int *argcp, char ***argvp)
4340 #ifdef SET_INVALID_PARAMETER_HANDLER
4341 _invalid_parameter_handler oldHandler, newHandler;
4342 newHandler = my_invalid_parameter_handler;
4343 oldHandler = _set_invalid_parameter_handler(newHandler);
4344 _CrtSetReportMode(_CRT_ASSERT, 0);
4346 /* Disable floating point errors, Perl will trap the ones we
4347 * care about. VC++ RTL defaults to switching these off
4348 * already, but some RTLs don't. Since we don't
4349 * want to be at the vendor's whim on the default, we set
4350 * it explicitly here.
4352 #if !defined(__GNUC__)
4353 _control87(MCW_EM, MCW_EM);
4357 /* When the manifest resource requests Common-Controls v6 then
4358 * user32.dll no longer registers all the Windows classes used for
4359 * standard controls but leaves some of them to be registered by
4360 * comctl32.dll. InitCommonControls() doesn't do anything but calling
4361 * it makes sure comctl32.dll gets loaded into the process and registers
4362 * the standard control classes. Without this even normal Windows APIs
4363 * like MessageBox() can fail under some versions of Windows XP.
4365 InitCommonControls();
4367 g_osver.dwOSVersionInfoSize = sizeof(g_osver);
4368 GetVersionEx(&g_osver);
4374 Perl_win32_term(void)
4383 win32_get_child_IO(child_IO_table* ptbl)
4385 ptbl->childStdIn = GetStdHandle(STD_INPUT_HANDLE);
4386 ptbl->childStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
4387 ptbl->childStdErr = GetStdHandle(STD_ERROR_HANDLE);
4391 win32_signal(int sig, Sighandler_t subcode)
4394 if (sig < SIG_SIZE) {
4395 int save_errno = errno;
4396 Sighandler_t result;
4397 #ifdef SET_INVALID_PARAMETER_HANDLER
4398 /* Silence our invalid parameter handler since we expect to make some
4399 * calls with invalid signal numbers giving a SIG_ERR result. */
4400 BOOL oldvalue = set_silent_invalid_parameter_handler(TRUE);
4402 result = signal(sig, subcode);
4403 #ifdef SET_INVALID_PARAMETER_HANDLER
4404 set_silent_invalid_parameter_handler(oldvalue);
4406 aTHXa(PERL_GET_THX);
4407 if (result == SIG_ERR) {
4408 result = w32_sighandler[sig];
4411 w32_sighandler[sig] = subcode;
4420 /* The PerlMessageWindowClass's WindowProc */
4422 win32_message_window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
4424 return win32_process_message(hwnd, msg, wParam, lParam) ?
4425 0 : DefWindowProc(hwnd, msg, wParam, lParam);
4428 /* The real message handler. Can be called with
4429 * hwnd == NULL to process our thread messages. Returns TRUE for any messages
4430 * that it processes */
4432 win32_process_message(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
4434 /* BEWARE. The context retrieved using dTHX; is the context of the
4435 * 'parent' thread during the CreateWindow() phase - i.e. for all messages
4436 * up to and including WM_CREATE. If it ever happens that you need the
4437 * 'child' context before this, then it needs to be passed into
4438 * win32_create_message_window(), and passed to the WM_NCCREATE handler
4439 * from the lparam of CreateWindow(). It could then be stored/retrieved
4440 * using [GS]etWindowLongPtr(... GWLP_USERDATA ...), possibly eliminating
4441 * the dTHX calls here. */
4442 /* XXX For now it is assumed that the overhead of the dTHX; for what
4443 * are relativley infrequent code-paths, is better than the added
4444 * complexity of getting the correct context passed into
4445 * win32_create_message_window() */
4451 case WM_USER_MESSAGE: {
4452 long child = find_pseudo_pid(aTHX_ (int)wParam);
4454 w32_pseudo_child_message_hwnds[child] = (HWND)lParam;
4461 case WM_USER_KILL: {
4462 /* We use WM_USER_KILL to fake kill() with other signals */
4463 int sig = (int)wParam;
4464 if (do_raise(aTHX_ sig))
4465 sig_terminate(aTHX_ sig);
4471 /* alarm() is a one-shot but SetTimer() repeats so kill it */
4472 if (w32_timerid && w32_timerid==(UINT)wParam) {
4473 KillTimer(w32_message_hwnd, w32_timerid);
4476 /* Now fake a call to signal handler */
4477 if (do_raise(aTHX_ 14))
4478 sig_terminate(aTHX_ 14);
4490 /* Above or other stuff may have set a signal flag, and we may not have
4491 * been called from win32_async_check() (e.g. some other GUI's message
4492 * loop. BUT DON'T dispatch signals here: If someone has set a SIGALRM
4493 * handler that die's, and the message loop that calls here is wrapped
4494 * in an eval, then you may well end up with orphaned windows - signals
4495 * are dispatched by win32_async_check() */
4501 win32_create_message_window_class(void)
4503 /* create the window class for "message only" windows */
4507 wc.lpfnWndProc = win32_message_window_proc;
4508 wc.hInstance = (HINSTANCE)GetModuleHandle(NULL);
4509 wc.lpszClassName = "PerlMessageWindowClass";
4511 /* second and subsequent calls will fail, but class
4512 * will already be registered */
4517 win32_create_message_window(void)
4519 win32_create_message_window_class();
4520 return CreateWindow("PerlMessageWindowClass", "PerlMessageWindow",
4521 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
4524 #ifdef HAVE_INTERP_INTERN
4527 win32_csighandler(int sig)
4530 dTHXa(PERL_GET_SIG_CONTEXT);
4531 Perl_warn(aTHX_ "Got signal %d",sig);
4536 #if defined(__MINGW32__) && defined(__cplusplus)
4537 #define CAST_HWND__(x) (HWND__*)(x)
4539 #define CAST_HWND__(x) x
4543 Perl_sys_intern_init(pTHX)
4547 w32_perlshell_tokens = NULL;
4548 w32_perlshell_vec = (char**)NULL;
4549 w32_perlshell_items = 0;
4550 w32_fdpid = newAV();
4551 Newx(w32_children, 1, child_tab);
4552 w32_num_children = 0;
4553 # ifdef USE_ITHREADS
4555 Newx(w32_pseudo_children, 1, pseudo_child_tab);
4556 w32_num_pseudo_children = 0;
4559 w32_message_hwnd = CAST_HWND__(INVALID_HANDLE_VALUE);
4561 for (i=0; i < SIG_SIZE; i++) {
4562 w32_sighandler[i] = SIG_DFL;
4564 # ifdef MULTIPLICITY
4565 if (my_perl == PL_curinterp) {
4569 /* Force C runtime signal stuff to set its console handler */
4570 signal(SIGINT,win32_csighandler);
4571 signal(SIGBREAK,win32_csighandler);
4573 /* We spawn asynchronous processes with the CREATE_NEW_PROCESS_GROUP
4574 * flag. This has the side-effect of disabling Ctrl-C events in all
4575 * processes in this group.
4576 * We re-enable Ctrl-C handling by calling SetConsoleCtrlHandler()
4577 * with a NULL handler.
4579 SetConsoleCtrlHandler(NULL,FALSE);
4581 /* Push our handler on top */
4582 SetConsoleCtrlHandler(win32_ctrlhandler,TRUE);
4587 Perl_sys_intern_clear(pTHX)
4589 Safefree(w32_perlshell_tokens);
4590 Safefree(w32_perlshell_vec);
4591 /* NOTE: w32_fdpid is freed by sv_clean_all() */
4592 Safefree(w32_children);
4594 KillTimer(w32_message_hwnd, w32_timerid);
4597 if (w32_message_hwnd != NULL && w32_message_hwnd != INVALID_HANDLE_VALUE)
4598 DestroyWindow(w32_message_hwnd);
4599 # ifdef MULTIPLICITY
4600 if (my_perl == PL_curinterp) {
4604 SetConsoleCtrlHandler(win32_ctrlhandler,FALSE);
4606 # ifdef USE_ITHREADS
4607 Safefree(w32_pseudo_children);
4611 # ifdef USE_ITHREADS
4614 Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
4616 PERL_ARGS_ASSERT_SYS_INTERN_DUP;
4618 dst->perlshell_tokens = NULL;
4619 dst->perlshell_vec = (char**)NULL;
4620 dst->perlshell_items = 0;
4621 dst->fdpid = newAV();
4622 Newxz(dst->children, 1, child_tab);
4624 Newxz(dst->pseudo_children, 1, pseudo_child_tab);
4626 dst->message_hwnd = CAST_HWND__(INVALID_HANDLE_VALUE);
4627 dst->poll_count = 0;
4628 Copy(src->sigtable,dst->sigtable,SIG_SIZE,Sighandler_t);
4630 # endif /* USE_ITHREADS */
4631 #endif /* HAVE_INTERP_INTERN */