3 * (c) 1995 Microsoft Corporation. All rights reserved.
4 * Developed by hip communications inc., http://info.hip.com/info/
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
19 # define HWND_MESSAGE ((HWND)-3)
21 #ifndef WC_NO_BEST_FIT_CHARS
22 # define WC_NO_BEST_FIT_CHARS 0x00000400
29 #define SystemProcessesAndThreadsInformation 5
31 /* Inline some definitions from the DDK */
42 LARGE_INTEGER CreateTime;
43 LARGE_INTEGER UserTime;
44 LARGE_INTEGER KernelTime;
45 UNICODE_STRING ProcessName;
48 ULONG InheritedFromProcessId;
49 /* Remainder of the structure depends on the Windows version,
50 * but we don't need those additional fields anyways... */
53 /* #include "config.h" */
55 #if !defined(PERLIO_IS_STDIO) && !defined(USE_SFIO)
63 /* GCC-2.95.2/Mingw32-1.1 forgot the WINAPI on CommandLineToArgvW() */
64 #if defined(__MINGW32__) && (__MINGW32_MAJOR_VERSION==1)
65 # include <shellapi.h>
67 EXTERN_C LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCommandLine, int * pNumArgs);
71 #define PERL_NO_GET_CONTEXT
77 /* assert.h conflicts with #define of assert in perl.h */
84 #if defined(_MSC_VER) || defined(__MINGW32__)
85 #include <sys/utime.h>
90 /* Mingw32 defaults to globing command line
91 * So we turn it off like this:
96 #if defined(__MINGW32__) && (__MINGW32_MAJOR_VERSION==1)
97 /* Mingw32-1.1 is missing some prototypes */
99 FILE * _wfopen(LPCWSTR wszFileName, LPCWSTR wszMode);
100 FILE * _wfdopen(int nFd, LPCWSTR wszMode);
101 FILE * _freopen(LPCWSTR wszFileName, LPCWSTR wszMode, FILE * pOldStream);
107 #if defined(__BORLANDC__)
109 # define _utimbuf utimbuf
113 #define EXECF_SPAWN 2
114 #define EXECF_SPAWN_NOWAIT 3
116 #if defined(PERL_IMPLICIT_SYS)
117 # undef win32_get_privlib
118 # define win32_get_privlib g_win32_get_privlib
119 # undef win32_get_sitelib
120 # define win32_get_sitelib g_win32_get_sitelib
121 # undef win32_get_vendorlib
122 # define win32_get_vendorlib g_win32_get_vendorlib
124 # define getlogin g_getlogin
127 static void get_shell(void);
128 static long tokenize(const char *str, char **dest, char ***destv);
129 static int do_spawn2(pTHX_ const char *cmd, int exectype);
130 static BOOL has_shell_metachars(const char *ptr);
131 static long filetime_to_clock(PFILETIME ft);
132 static BOOL filetime_from_time(PFILETIME ft, time_t t);
133 static char * get_emd_part(SV **leading, char *trailing, ...);
134 static void remove_dead_process(long deceased);
135 static long find_pid(int pid);
136 static char * qualified_path(const char *cmd);
137 static char * win32_get_xlib(const char *pl, const char *xlib,
138 const char *libname);
141 static void remove_dead_pseudo_process(long child);
142 static long find_pseudo_pid(int pid);
146 HANDLE w32_perldll_handle = INVALID_HANDLE_VALUE;
147 char w32_module_name[MAX_PATH+1];
150 static OSVERSIONINFO g_osver = {0, 0, 0, 0, 0, ""};
152 static HANDLE (WINAPI *pfnCreateToolhelp32Snapshot)(DWORD, DWORD) = NULL;
153 static BOOL (WINAPI *pfnProcess32First)(HANDLE, PROCESSENTRY32*) = NULL;
154 static BOOL (WINAPI *pfnProcess32Next)(HANDLE, PROCESSENTRY32*) = NULL;
155 static LONG (WINAPI *pfnZwQuerySystemInformation)(UINT, PVOID, ULONG, PULONG);
158 /* Silence STDERR grumblings from Borland's math library. */
160 _matherr(struct _exception *a)
168 void my_invalid_parameter_handler(const wchar_t* expression,
169 const wchar_t* function,
175 wprintf(L"Invalid parameter detected in function %s."
176 L" File: %s Line: %d\n", function, file, line);
177 wprintf(L"Expression: %s\n", expression);
185 return (g_osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
191 return (g_osver.dwPlatformId == VER_PLATFORM_WIN32_NT);
195 set_w32_module_name(void)
197 /* this function may be called at DLL_PROCESS_ATTACH time */
199 HMODULE module = (HMODULE)((w32_perldll_handle == INVALID_HANDLE_VALUE)
200 ? GetModuleHandle(NULL)
201 : w32_perldll_handle);
203 OSVERSIONINFO osver; /* g_osver may not yet be initialized */
204 osver.dwOSVersionInfoSize = sizeof(osver);
205 GetVersionEx(&osver);
207 if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
208 WCHAR modulename[MAX_PATH];
209 WCHAR fullname[MAX_PATH];
212 GetModuleFileNameW(module, modulename, sizeof(modulename)/sizeof(WCHAR));
214 /* Make sure we get an absolute pathname in case the module was loaded
215 * explicitly by LoadLibrary() with a relative path. */
216 GetFullPathNameW(modulename, sizeof(fullname)/sizeof(WCHAR), fullname, NULL);
218 /* remove \\?\ prefix */
219 if (memcmp(fullname, L"\\\\?\\", 4*sizeof(WCHAR)) == 0)
220 memmove(fullname, fullname+4, (wcslen(fullname+4)+1)*sizeof(WCHAR));
222 ansi = win32_ansipath(fullname);
223 my_strlcpy(w32_module_name, ansi, sizeof(w32_module_name));
227 GetModuleFileName(module, w32_module_name, sizeof(w32_module_name));
229 /* remove \\?\ prefix */
230 if (memcmp(w32_module_name, "\\\\?\\", 4) == 0)
231 memmove(w32_module_name, w32_module_name+4, strlen(w32_module_name+4)+1);
233 /* try to get full path to binary (which may be mangled when perl is
234 * run from a 16-bit app) */
235 /*PerlIO_printf(Perl_debug_log, "Before %s\n", w32_module_name);*/
236 win32_longpath(w32_module_name);
237 /*PerlIO_printf(Perl_debug_log, "After %s\n", w32_module_name);*/
240 /* normalize to forward slashes */
241 ptr = w32_module_name;
249 /* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
251 get_regstr_from(HKEY hkey, const char *valuename, SV **svp)
253 /* Retrieve a REG_SZ or REG_EXPAND_SZ from the registry */
256 const char *subkey = "Software\\Perl";
260 retval = RegOpenKeyEx(hkey, subkey, 0, KEY_READ, &handle);
261 if (retval == ERROR_SUCCESS) {
263 retval = RegQueryValueEx(handle, valuename, 0, &type, NULL, &datalen);
264 if (retval == ERROR_SUCCESS
265 && (type == REG_SZ || type == REG_EXPAND_SZ))
269 *svp = sv_2mortal(newSVpvn("",0));
270 SvGROW(*svp, datalen);
271 retval = RegQueryValueEx(handle, valuename, 0, NULL,
272 (PBYTE)SvPVX(*svp), &datalen);
273 if (retval == ERROR_SUCCESS) {
275 SvCUR_set(*svp,datalen-1);
283 /* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
285 get_regstr(const char *valuename, SV **svp)
287 char *str = get_regstr_from(HKEY_CURRENT_USER, valuename, svp);
289 str = get_regstr_from(HKEY_LOCAL_MACHINE, valuename, svp);
293 /* *prev_pathp (if non-NULL) is expected to be POK (valid allocated SvPVX(sv)) */
295 get_emd_part(SV **prev_pathp, char *trailing_path, ...)
299 char mod_name[MAX_PATH+1];
305 va_start(ap, trailing_path);
306 strip = va_arg(ap, char *);
308 sprintf(base, "%d.%d", (int)PERL_REVISION, (int)PERL_VERSION);
309 baselen = strlen(base);
311 if (!*w32_module_name) {
312 set_w32_module_name();
314 strcpy(mod_name, w32_module_name);
315 ptr = strrchr(mod_name, '/');
316 while (ptr && strip) {
317 /* look for directories to skip back */
320 ptr = strrchr(mod_name, '/');
321 /* avoid stripping component if there is no slash,
322 * or it doesn't match ... */
323 if (!ptr || stricmp(ptr+1, strip) != 0) {
324 /* ... but not if component matches m|5\.$patchlevel.*| */
325 if (!ptr || !(*strip == '5' && *(ptr+1) == '5'
326 && strncmp(strip, base, baselen) == 0
327 && strncmp(ptr+1, base, baselen) == 0))
333 strip = va_arg(ap, char *);
341 strcpy(++ptr, trailing_path);
343 /* only add directory if it exists */
344 if (GetFileAttributes(mod_name) != (DWORD) -1) {
345 /* directory exists */
348 *prev_pathp = sv_2mortal(newSVpvn("",0));
349 else if (SvPVX(*prev_pathp))
350 sv_catpvn(*prev_pathp, ";", 1);
351 sv_catpv(*prev_pathp, mod_name);
352 return SvPVX(*prev_pathp);
359 win32_get_privlib(const char *pl)
362 char *stdlib = "lib";
363 char buffer[MAX_PATH+1];
366 /* $stdlib = $HKCU{"lib-$]"} || $HKLM{"lib-$]"} || $HKCU{"lib"} || $HKLM{"lib"} || ""; */
367 sprintf(buffer, "%s-%s", stdlib, pl);
368 if (!get_regstr(buffer, &sv))
369 (void)get_regstr(stdlib, &sv);
371 /* $stdlib .= ";$EMD/../../lib" */
372 return get_emd_part(&sv, stdlib, ARCHNAME, "bin", Nullch);
376 win32_get_xlib(const char *pl, const char *xlib, const char *libname)
380 char pathstr[MAX_PATH+1];
384 /* $HKCU{"$xlib-$]"} || $HKLM{"$xlib-$]"} . ---; */
385 sprintf(regstr, "%s-%s", xlib, pl);
386 (void)get_regstr(regstr, &sv1);
389 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/$]/lib"; */
390 sprintf(pathstr, "%s/%s/lib", libname, pl);
391 (void)get_emd_part(&sv1, pathstr, ARCHNAME, "bin", pl, Nullch);
393 /* $HKCU{$xlib} || $HKLM{$xlib} . ---; */
394 (void)get_regstr(xlib, &sv2);
397 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/lib"; */
398 sprintf(pathstr, "%s/lib", libname);
399 (void)get_emd_part(&sv2, pathstr, ARCHNAME, "bin", pl, Nullch);
408 sv_catpvn(sv1, ";", 1);
415 win32_get_sitelib(const char *pl)
417 return win32_get_xlib(pl, "sitelib", "site");
420 #ifndef PERL_VENDORLIB_NAME
421 # define PERL_VENDORLIB_NAME "vendor"
425 win32_get_vendorlib(const char *pl)
427 return win32_get_xlib(pl, "vendorlib", PERL_VENDORLIB_NAME);
431 has_shell_metachars(const char *ptr)
437 * Scan string looking for redirection (< or >) or pipe
438 * characters (|) that are not in a quoted string.
439 * Shell variable interpolation (%VAR%) can also happen inside strings.
471 #if !defined(PERL_IMPLICIT_SYS)
472 /* since the current process environment is being updated in util.c
473 * the library functions will get the correct environment
476 Perl_my_popen(pTHX_ const char *cmd, const char *mode)
479 #define fixcmd(x) { \
480 char *pspace = strchr((x),' '); \
483 while (p < pspace) { \
494 PERL_FLUSHALL_FOR_CHILD;
495 return win32_popen(cmd, mode);
499 Perl_my_pclose(pTHX_ PerlIO *fp)
501 return win32_pclose(fp);
505 DllExport unsigned long
508 return (unsigned long)g_osver.dwPlatformId;
518 return -((int)w32_pseudo_id);
521 /* Windows 9x appears to always reports a pid for threads and processes
522 * that has the high bit set. So we treat the lower 31 bits as the
523 * "real" PID for Perl's purposes. */
524 if (IsWin95() && pid < 0)
529 /* Tokenize a string. Words are null-separated, and the list
530 * ends with a doubled null. Any character (except null and
531 * including backslash) may be escaped by preceding it with a
532 * backslash (the backslash will be stripped).
533 * Returns number of words in result buffer.
536 tokenize(const char *str, char **dest, char ***destv)
538 char *retstart = Nullch;
539 char **retvstart = 0;
543 int slen = strlen(str);
545 register char **retv;
546 Newx(ret, slen+2, char);
547 Newx(retv, (slen+3)/2, char*);
555 if (*ret == '\\' && *str)
557 else if (*ret == ' ') {
573 retvstart[items] = Nullch;
586 if (!w32_perlshell_tokens) {
587 /* we don't use COMSPEC here for two reasons:
588 * 1. the same reason perl on UNIX doesn't use SHELL--rampant and
589 * uncontrolled unportability of the ensuing scripts.
590 * 2. PERL5SHELL could be set to a shell that may not be fit for
591 * interactive use (which is what most programs look in COMSPEC
594 const char* defaultshell = (IsWinNT()
595 ? "cmd.exe /x/d/c" : "command.com /c");
596 const char *usershell = PerlEnv_getenv("PERL5SHELL");
597 w32_perlshell_items = tokenize(usershell ? usershell : defaultshell,
598 &w32_perlshell_tokens,
604 Perl_do_aspawn(pTHX_ SV *really, SV **mark, SV **sp)
616 Newx(argv, (sp - mark) + w32_perlshell_items + 2, char*);
618 if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
623 while (++mark <= sp) {
624 if (*mark && (str = SvPV_nolen(*mark)))
631 status = win32_spawnvp(flag,
632 (const char*)(really ? SvPV_nolen(really) : argv[0]),
633 (const char* const*)argv);
635 if (status < 0 && (errno == ENOEXEC || errno == ENOENT)) {
636 /* possible shell-builtin, invoke with shell */
638 sh_items = w32_perlshell_items;
640 argv[index+sh_items] = argv[index];
641 while (--sh_items >= 0)
642 argv[sh_items] = w32_perlshell_vec[sh_items];
644 status = win32_spawnvp(flag,
645 (const char*)(really ? SvPV_nolen(really) : argv[0]),
646 (const char* const*)argv);
649 if (flag == P_NOWAIT) {
651 PL_statusvalue = -1; /* >16bits hint for pp_system() */
655 if (ckWARN(WARN_EXEC))
656 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't spawn \"%s\": %s", argv[0], strerror(errno));
661 PL_statusvalue = status;
667 /* returns pointer to the next unquoted space or the end of the string */
669 find_next_space(const char *s)
671 bool in_quotes = FALSE;
673 /* ignore doubled backslashes, or backslash+quote */
674 if (*s == '\\' && (s[1] == '\\' || s[1] == '"')) {
677 /* keep track of when we're within quotes */
678 else if (*s == '"') {
680 in_quotes = !in_quotes;
682 /* break it up only at spaces that aren't in quotes */
683 else if (!in_quotes && isSPACE(*s))
692 do_spawn2(pTHX_ const char *cmd, int exectype)
698 BOOL needToTry = TRUE;
701 /* Save an extra exec if possible. See if there are shell
702 * metacharacters in it */
703 if (!has_shell_metachars(cmd)) {
704 Newx(argv, strlen(cmd) / 2 + 2, char*);
705 Newx(cmd2, strlen(cmd) + 1, char);
708 for (s = cmd2; *s;) {
709 while (*s && isSPACE(*s))
713 s = find_next_space(s);
721 status = win32_spawnvp(P_WAIT, argv[0],
722 (const char* const*)argv);
724 case EXECF_SPAWN_NOWAIT:
725 status = win32_spawnvp(P_NOWAIT, argv[0],
726 (const char* const*)argv);
729 status = win32_execvp(argv[0], (const char* const*)argv);
732 if (status != -1 || errno == 0)
742 Newx(argv, w32_perlshell_items + 2, char*);
743 while (++i < w32_perlshell_items)
744 argv[i] = w32_perlshell_vec[i];
745 argv[i++] = (char *)cmd;
749 status = win32_spawnvp(P_WAIT, argv[0],
750 (const char* const*)argv);
752 case EXECF_SPAWN_NOWAIT:
753 status = win32_spawnvp(P_NOWAIT, argv[0],
754 (const char* const*)argv);
757 status = win32_execvp(argv[0], (const char* const*)argv);
763 if (exectype == EXECF_SPAWN_NOWAIT) {
765 PL_statusvalue = -1; /* >16bits hint for pp_system() */
769 if (ckWARN(WARN_EXEC))
770 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s \"%s\": %s",
771 (exectype == EXECF_EXEC ? "exec" : "spawn"),
772 cmd, strerror(errno));
777 PL_statusvalue = status;
783 Perl_do_spawn(pTHX_ char *cmd)
785 return do_spawn2(aTHX_ cmd, EXECF_SPAWN);
789 Perl_do_spawn_nowait(pTHX_ char *cmd)
791 return do_spawn2(aTHX_ cmd, EXECF_SPAWN_NOWAIT);
795 Perl_do_exec(pTHX_ const char *cmd)
797 do_spawn2(aTHX_ cmd, EXECF_EXEC);
801 /* The idea here is to read all the directory names into a string table
802 * (separated by nulls) and when one of the other dir functions is called
803 * return the pointer to the current file name.
806 win32_opendir(const char *filename)
812 char scanname[MAX_PATH+3];
814 WIN32_FIND_DATAA aFindData;
815 WIN32_FIND_DATAW wFindData;
817 char buffer[MAX_PATH*2];
820 len = strlen(filename);
824 /* check to see if filename is a directory */
825 if (win32_stat(filename, &sbuf) < 0 || !S_ISDIR(sbuf.st_mode))
828 /* Get us a DIR structure */
831 /* Create the search pattern */
832 strcpy(scanname, filename);
834 /* bare drive name means look in cwd for drive */
835 if (len == 2 && isALPHA(scanname[0]) && scanname[1] == ':') {
836 scanname[len++] = '.';
837 scanname[len++] = '/';
839 else if (scanname[len-1] != '/' && scanname[len-1] != '\\') {
840 scanname[len++] = '/';
842 scanname[len++] = '*';
843 scanname[len] = '\0';
845 /* do the FindFirstFile call */
847 WCHAR wscanname[sizeof(scanname)];
848 MultiByteToWideChar(CP_ACP, 0, scanname, -1, wscanname, sizeof(wscanname)/sizeof(WCHAR));
849 dirp->handle = FindFirstFileW(PerlDir_mapW(wscanname), &wFindData);
853 dirp->handle = FindFirstFileA(PerlDir_mapA(scanname), &aFindData);
855 if (dirp->handle == INVALID_HANDLE_VALUE) {
856 DWORD err = GetLastError();
857 /* FindFirstFile() fails on empty drives! */
859 case ERROR_FILE_NOT_FOUND:
861 case ERROR_NO_MORE_FILES:
862 case ERROR_PATH_NOT_FOUND:
865 case ERROR_NOT_ENOUGH_MEMORY:
877 BOOL use_default = FALSE;
878 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
879 wFindData.cFileName, -1,
880 buffer, sizeof(buffer), NULL, &use_default);
881 if (use_default && *wFindData.cAlternateFileName) {
882 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
883 wFindData.cAlternateFileName, -1,
884 buffer, sizeof(buffer), NULL, NULL);
889 ptr = aFindData.cFileName;
891 /* now allocate the first part of the string table for
892 * the filenames that we find.
899 Newx(dirp->start, dirp->size, char);
900 strcpy(dirp->start, ptr);
902 dirp->end = dirp->curr = dirp->start;
908 /* Readdir just returns the current string pointer and bumps the
909 * string pointer to the nDllExport entry.
911 DllExport struct direct *
912 win32_readdir(DIR *dirp)
917 /* first set up the structure to return */
918 len = strlen(dirp->curr);
919 strcpy(dirp->dirstr.d_name, dirp->curr);
920 dirp->dirstr.d_namlen = len;
923 dirp->dirstr.d_ino = dirp->curr - dirp->start;
925 /* Now set up for the next call to readdir */
926 dirp->curr += len + 1;
927 if (dirp->curr >= dirp->end) {
930 WIN32_FIND_DATAA aFindData;
931 char buffer[MAX_PATH*2];
934 /* finding the next file that matches the wildcard
935 * (which should be all of them in this directory!).
938 WIN32_FIND_DATAW wFindData;
939 res = FindNextFileW(dirp->handle, &wFindData);
941 BOOL use_default = FALSE;
942 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
943 wFindData.cFileName, -1,
944 buffer, sizeof(buffer), NULL, &use_default);
945 if (use_default && *wFindData.cAlternateFileName) {
946 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
947 wFindData.cAlternateFileName, -1,
948 buffer, sizeof(buffer), NULL, NULL);
954 res = FindNextFileA(dirp->handle, &aFindData);
955 ptr = aFindData.cFileName;
958 long endpos = dirp->end - dirp->start;
959 long newsize = endpos + strlen(ptr) + 1;
960 /* bump the string table size by enough for the
961 * new name and its null terminator */
962 while (newsize > dirp->size) {
963 long curpos = dirp->curr - dirp->start;
965 Renew(dirp->start, dirp->size, char);
966 dirp->curr = dirp->start + curpos;
968 strcpy(dirp->start + endpos, ptr);
969 dirp->end = dirp->start + newsize;
975 return &(dirp->dirstr);
981 /* Telldir returns the current string pointer position */
983 win32_telldir(DIR *dirp)
985 return (dirp->curr - dirp->start);
989 /* Seekdir moves the string pointer to a previously saved position
990 * (returned by telldir).
993 win32_seekdir(DIR *dirp, long loc)
995 dirp->curr = dirp->start + loc;
998 /* Rewinddir resets the string pointer to the start */
1000 win32_rewinddir(DIR *dirp)
1002 dirp->curr = dirp->start;
1005 /* free the memory allocated by opendir */
1007 win32_closedir(DIR *dirp)
1010 if (dirp->handle != INVALID_HANDLE_VALUE)
1011 FindClose(dirp->handle);
1012 Safefree(dirp->start);
1025 * Just pretend that everyone is a superuser. NT will let us know if
1026 * we don\'t really have permission to do something.
1029 #define ROOT_UID ((uid_t)0)
1030 #define ROOT_GID ((gid_t)0)
1059 return (auid == ROOT_UID ? 0 : -1);
1065 return (agid == ROOT_GID ? 0 : -1);
1072 char *buf = w32_getlogin_buffer;
1073 DWORD size = sizeof(w32_getlogin_buffer);
1074 if (GetUserName(buf,&size))
1080 chown(const char *path, uid_t owner, gid_t group)
1087 * XXX this needs strengthening (for PerlIO)
1090 int mkstemp(const char *path)
1093 char buf[MAX_PATH+1];
1097 if (i++ > 10) { /* give up */
1101 if (!GetTempFileNameA((LPCSTR)path, "plr", 1, buf)) {
1105 fd = PerlLIO_open3(buf, O_CREAT|O_RDWR|O_EXCL, 0600);
1115 long child = w32_num_children;
1116 while (--child >= 0) {
1117 if ((int)w32_child_pids[child] == pid)
1124 remove_dead_process(long child)
1128 CloseHandle(w32_child_handles[child]);
1129 Move(&w32_child_handles[child+1], &w32_child_handles[child],
1130 (w32_num_children-child-1), HANDLE);
1131 Move(&w32_child_pids[child+1], &w32_child_pids[child],
1132 (w32_num_children-child-1), DWORD);
1139 find_pseudo_pid(int pid)
1142 long child = w32_num_pseudo_children;
1143 while (--child >= 0) {
1144 if ((int)w32_pseudo_child_pids[child] == pid)
1151 remove_dead_pseudo_process(long child)
1155 CloseHandle(w32_pseudo_child_handles[child]);
1156 Move(&w32_pseudo_child_handles[child+1], &w32_pseudo_child_handles[child],
1157 (w32_num_pseudo_children-child-1), HANDLE);
1158 Move(&w32_pseudo_child_pids[child+1], &w32_pseudo_child_pids[child],
1159 (w32_num_pseudo_children-child-1), DWORD);
1160 Move(&w32_pseudo_child_message_hwnds[child+1], &w32_pseudo_child_message_hwnds[child],
1161 (w32_num_pseudo_children-child-1), HWND);
1162 w32_num_pseudo_children--;
1168 terminate_process(DWORD pid, HANDLE process_handle, int sig)
1172 /* "Does process exist?" use of kill */
1175 if (GenerateConsoleCtrlEvent(CTRL_C_EVENT, pid))
1180 if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pid))
1183 default: /* For now be backwards compatible with perl 5.6 */
1185 /* Note that we will only be able to kill processes owned by the
1186 * current process owner, even when we are running as an administrator.
1187 * To kill processes of other owners we would need to set the
1188 * 'SeDebugPrivilege' privilege before obtaining the process handle.
1190 if (TerminateProcess(process_handle, sig))
1197 /* Traverse process tree using ToolHelp functions */
1199 kill_process_tree_toolhelp(DWORD pid, int sig)
1201 HANDLE process_handle;
1202 HANDLE snapshot_handle;
1205 process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
1206 if (process_handle == INVALID_HANDLE_VALUE)
1209 killed += terminate_process(pid, process_handle, sig);
1211 snapshot_handle = pfnCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
1212 if (snapshot_handle != INVALID_HANDLE_VALUE) {
1213 PROCESSENTRY32 entry;
1215 entry.dwSize = sizeof(entry);
1216 if (pfnProcess32First(snapshot_handle, &entry)) {
1218 if (entry.th32ParentProcessID == pid)
1219 killed += kill_process_tree_toolhelp(entry.th32ProcessID, sig);
1220 entry.dwSize = sizeof(entry);
1222 while (pfnProcess32Next(snapshot_handle, &entry));
1224 CloseHandle(snapshot_handle);
1226 CloseHandle(process_handle);
1230 /* Traverse process tree using undocumented system information structures.
1231 * This is only necessary on Windows NT, which lacks the ToolHelp functions.
1234 kill_process_tree_sysinfo(SYSTEM_PROCESSES *process_info, DWORD pid, int sig)
1236 HANDLE process_handle;
1237 SYSTEM_PROCESSES *p = process_info;
1240 process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
1241 if (process_handle == INVALID_HANDLE_VALUE)
1244 killed += terminate_process(pid, process_handle, sig);
1247 if (p->InheritedFromProcessId == (DWORD)pid)
1248 killed += kill_process_tree_sysinfo(process_info, p->ProcessId, sig);
1250 if (p->NextEntryDelta == 0)
1253 p = (SYSTEM_PROCESSES*)((char*)p + p->NextEntryDelta);
1256 CloseHandle(process_handle);
1261 killpg(int pid, int sig)
1263 /* Use "documented" method whenever available */
1264 if (pfnCreateToolhelp32Snapshot && pfnProcess32First && pfnProcess32Next) {
1265 return kill_process_tree_toolhelp((DWORD)pid, sig);
1268 /* Fall back to undocumented Windows internals on Windows NT */
1269 if (pfnZwQuerySystemInformation) {
1274 pfnZwQuerySystemInformation(SystemProcessesAndThreadsInformation, NULL, 0, &size);
1275 Newx(buffer, size, char);
1277 if (pfnZwQuerySystemInformation(SystemProcessesAndThreadsInformation, buffer, size, NULL) >= 0) {
1278 int killed = kill_process_tree_sysinfo((SYSTEM_PROCESSES*)buffer, (DWORD)pid, sig);
1287 my_kill(int pid, int sig)
1290 HANDLE process_handle;
1293 return killpg(pid, -sig);
1295 process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
1296 if (process_handle != INVALID_HANDLE_VALUE) {
1297 retval = terminate_process(pid, process_handle, sig);
1298 CloseHandle(process_handle);
1304 win32_kill(int pid, int sig)
1311 /* it is a pseudo-forked child */
1312 child = find_pseudo_pid(-pid);
1314 HWND hwnd = w32_pseudo_child_message_hwnds[child];
1315 hProcess = w32_pseudo_child_handles[child];
1318 /* "Does process exist?" use of kill */
1322 /* kill -9 style un-graceful exit */
1323 if (TerminateThread(hProcess, sig)) {
1324 remove_dead_pseudo_process(child);
1331 /* pseudo-process has not yet properly initialized if hwnd isn't set */
1332 while (hwnd == INVALID_HANDLE_VALUE && count < 5) {
1333 /* Yield and wait for the other thread to send us its message_hwnd */
1335 win32_async_check(aTHX);
1338 if (hwnd != INVALID_HANDLE_VALUE) {
1339 /* We fake signals to pseudo-processes using Win32
1340 * message queue. In Win9X the pids are negative already. */
1341 if ((hwnd != NULL && PostMessage(hwnd, WM_USER_KILL, sig, 0)) ||
1342 PostThreadMessage(IsWin95() ? pid : -pid, WM_USER_KILL, sig, 0))
1344 /* It might be us ... */
1353 else if (IsWin95()) {
1361 child = find_pid(pid);
1363 if (my_kill(pid, sig)) {
1365 if (GetExitCodeProcess(w32_child_handles[child], &exitcode) &&
1366 exitcode != STILL_ACTIVE)
1368 remove_dead_process(child);
1375 if (my_kill((IsWin95() ? -pid : pid), sig))
1384 win32_stat(const char *path, Stat_t *sbuf)
1387 char buffer[MAX_PATH+1];
1388 int l = strlen(path);
1391 BOOL expect_dir = FALSE;
1393 GV *gv_sloppy = gv_fetchpvs("\027IN32_SLOPPY_STAT",
1394 GV_NOTQUAL, SVt_PV);
1395 BOOL sloppy = gv_sloppy && SvTRUE(GvSV(gv_sloppy));
1398 switch(path[l - 1]) {
1399 /* FindFirstFile() and stat() are buggy with a trailing
1400 * slashes, except for the root directory of a drive */
1403 if (l > sizeof(buffer)) {
1404 errno = ENAMETOOLONG;
1408 strncpy(buffer, path, l);
1409 /* remove additional trailing slashes */
1410 while (l > 1 && (buffer[l-1] == '/' || buffer[l-1] == '\\'))
1412 /* add back slash if we otherwise end up with just a drive letter */
1413 if (l == 2 && isALPHA(buffer[0]) && buffer[1] == ':')
1420 /* FindFirstFile() is buggy with "x:", so add a dot :-( */
1422 if (l == 2 && isALPHA(path[0])) {
1423 buffer[0] = path[0];
1434 path = PerlDir_mapA(path);
1438 /* We must open & close the file once; otherwise file attribute changes */
1439 /* might not yet have propagated to "other" hard links of the same file. */
1440 /* This also gives us an opportunity to determine the number of links. */
1441 HANDLE handle = CreateFileA(path, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
1442 if (handle != INVALID_HANDLE_VALUE) {
1443 BY_HANDLE_FILE_INFORMATION bhi;
1444 if (GetFileInformationByHandle(handle, &bhi))
1445 nlink = bhi.nNumberOfLinks;
1446 CloseHandle(handle);
1450 /* path will be mapped correctly above */
1451 #if defined(WIN64) || defined(USE_LARGE_FILES)
1452 res = _stati64(path, sbuf);
1454 res = stat(path, sbuf);
1456 sbuf->st_nlink = nlink;
1459 /* CRT is buggy on sharenames, so make sure it really isn't.
1460 * XXX using GetFileAttributesEx() will enable us to set
1461 * sbuf->st_*time (but note that's not available on the
1462 * Windows of 1995) */
1463 DWORD r = GetFileAttributesA(path);
1464 if (r != 0xffffffff && (r & FILE_ATTRIBUTE_DIRECTORY)) {
1465 /* sbuf may still contain old garbage since stat() failed */
1466 Zero(sbuf, 1, Stat_t);
1467 sbuf->st_mode = S_IFDIR | S_IREAD;
1469 if (!(r & FILE_ATTRIBUTE_READONLY))
1470 sbuf->st_mode |= S_IWRITE | S_IEXEC;
1475 if (l == 3 && isALPHA(path[0]) && path[1] == ':'
1476 && (path[2] == '\\' || path[2] == '/'))
1478 /* The drive can be inaccessible, some _stat()s are buggy */
1479 if (!GetVolumeInformationA(path,NULL,0,NULL,NULL,NULL,NULL,0)) {
1484 if (expect_dir && !S_ISDIR(sbuf->st_mode)) {
1489 if (S_ISDIR(sbuf->st_mode))
1490 sbuf->st_mode |= S_IWRITE | S_IEXEC;
1491 else if (S_ISREG(sbuf->st_mode)) {
1493 if (l >= 4 && path[l-4] == '.') {
1494 const char *e = path + l - 3;
1495 if (strnicmp(e,"exe",3)
1496 && strnicmp(e,"bat",3)
1497 && strnicmp(e,"com",3)
1498 && (IsWin95() || strnicmp(e,"cmd",3)))
1499 sbuf->st_mode &= ~S_IEXEC;
1501 sbuf->st_mode |= S_IEXEC;
1504 sbuf->st_mode &= ~S_IEXEC;
1505 /* Propagate permissions to _group_ and _others_ */
1506 perms = sbuf->st_mode & (S_IREAD|S_IWRITE|S_IEXEC);
1507 sbuf->st_mode |= (perms>>3) | (perms>>6);
1514 #define isSLASH(c) ((c) == '/' || (c) == '\\')
1515 #define SKIP_SLASHES(s) \
1517 while (*(s) && isSLASH(*(s))) \
1520 #define COPY_NONSLASHES(d,s) \
1522 while (*(s) && !isSLASH(*(s))) \
1526 /* Find the longname of a given path. path is destructively modified.
1527 * It should have space for at least MAX_PATH characters. */
1529 win32_longpath(char *path)
1531 WIN32_FIND_DATA fdata;
1533 char tmpbuf[MAX_PATH+1];
1534 char *tmpstart = tmpbuf;
1541 if (isALPHA(path[0]) && path[1] == ':') {
1543 *tmpstart++ = path[0];
1547 else if (isSLASH(path[0]) && isSLASH(path[1])) {
1549 *tmpstart++ = path[0];
1550 *tmpstart++ = path[1];
1551 SKIP_SLASHES(start);
1552 COPY_NONSLASHES(tmpstart,start); /* copy machine name */
1554 *tmpstart++ = *start++;
1555 SKIP_SLASHES(start);
1556 COPY_NONSLASHES(tmpstart,start); /* copy share name */
1561 /* copy initial slash, if any */
1562 if (isSLASH(*start)) {
1563 *tmpstart++ = *start++;
1565 SKIP_SLASHES(start);
1568 /* FindFirstFile() expands "." and "..", so we need to pass
1569 * those through unmolested */
1571 && (!start[1] || isSLASH(start[1])
1572 || (start[1] == '.' && (!start[2] || isSLASH(start[2])))))
1574 COPY_NONSLASHES(tmpstart,start); /* copy "." or ".." */
1579 /* if this is the end, bust outta here */
1583 /* now we're at a non-slash; walk up to next slash */
1584 while (*start && !isSLASH(*start))
1587 /* stop and find full name of component */
1590 fhand = FindFirstFile(path,&fdata);
1592 if (fhand != INVALID_HANDLE_VALUE) {
1593 STRLEN len = strlen(fdata.cFileName);
1594 if ((STRLEN)(tmpbuf + sizeof(tmpbuf) - tmpstart) > len) {
1595 strcpy(tmpstart, fdata.cFileName);
1606 /* failed a step, just return without side effects */
1607 /*PerlIO_printf(Perl_debug_log, "Failed to find %s\n", path);*/
1612 strcpy(path,tmpbuf);
1620 /* Can't use PerlIO to write as it allocates memory */
1621 PerlLIO_write(PerlIO_fileno(Perl_error_log),
1622 PL_no_mem, strlen(PL_no_mem));
1626 /* The win32_ansipath() function takes a Unicode filename and converts it
1627 * into the current Windows codepage. If some characters cannot be mapped,
1628 * then it will convert the short name instead.
1630 * The buffer to the ansi pathname must be freed with win32_free() when it
1631 * it no longer needed.
1633 * The argument to win32_ansipath() must exist before this function is
1634 * called; otherwise there is no way to determine the short path name.
1636 * Ideas for future refinement:
1637 * - Only convert those segments of the path that are not in the current
1638 * codepage, but leave the other segments in their long form.
1639 * - If the resulting name is longer than MAX_PATH, start converting
1640 * additional path segments into short names until the full name
1641 * is shorter than MAX_PATH. Shorten the filename part last!
1644 win32_ansipath(const WCHAR *widename)
1647 BOOL use_default = FALSE;
1648 size_t widelen = wcslen(widename)+1;
1649 int len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, widename, widelen,
1650 NULL, 0, NULL, NULL);
1651 name = win32_malloc(len);
1655 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, widename, widelen,
1656 name, len, NULL, &use_default);
1659 DWORD shortlen = GetShortPathNameW(widename, NULL, 0);
1660 shortname = win32_malloc(shortlen*sizeof(WCHAR));
1663 shortlen = GetShortPathNameW(widename, shortname, shortlen)+1;
1665 len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, shortname, shortlen,
1666 NULL, 0, NULL, NULL);
1667 name = win32_realloc(name, len);
1670 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, shortname, shortlen,
1671 name, len, NULL, NULL);
1672 win32_free(shortname);
1678 win32_getenv(const char *name)
1682 SV *curitem = Nullsv;
1684 needlen = GetEnvironmentVariableA(name,NULL,0);
1686 curitem = sv_2mortal(newSVpvn("", 0));
1688 SvGROW(curitem, needlen+1);
1689 needlen = GetEnvironmentVariableA(name,SvPVX(curitem),
1691 } while (needlen >= SvLEN(curitem));
1692 SvCUR_set(curitem, needlen);
1695 /* allow any environment variables that begin with 'PERL'
1696 to be stored in the registry */
1697 if (strncmp(name, "PERL", 4) == 0)
1698 (void)get_regstr(name, &curitem);
1700 if (curitem && SvCUR(curitem))
1701 return SvPVX(curitem);
1707 win32_putenv(const char *name)
1715 Newx(curitem,strlen(name)+1,char);
1716 strcpy(curitem, name);
1717 val = strchr(curitem, '=');
1719 /* The sane way to deal with the environment.
1720 * Has these advantages over putenv() & co.:
1721 * * enables us to store a truly empty value in the
1722 * environment (like in UNIX).
1723 * * we don't have to deal with RTL globals, bugs and leaks.
1725 * Why you may want to enable USE_WIN32_RTL_ENV:
1726 * * environ[] and RTL functions will not reflect changes,
1727 * which might be an issue if extensions want to access
1728 * the env. via RTL. This cuts both ways, since RTL will
1729 * not see changes made by extensions that call the Win32
1730 * functions directly, either.
1734 if (SetEnvironmentVariableA(curitem, *val ? val : NULL))
1743 filetime_to_clock(PFILETIME ft)
1745 __int64 qw = ft->dwHighDateTime;
1747 qw |= ft->dwLowDateTime;
1748 qw /= 10000; /* File time ticks at 0.1uS, clock at 1mS */
1753 win32_times(struct tms *timebuf)
1758 clock_t process_time_so_far = clock();
1759 if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy,
1761 timebuf->tms_utime = filetime_to_clock(&user);
1762 timebuf->tms_stime = filetime_to_clock(&kernel);
1763 timebuf->tms_cutime = 0;
1764 timebuf->tms_cstime = 0;
1766 /* That failed - e.g. Win95 fallback to clock() */
1767 timebuf->tms_utime = process_time_so_far;
1768 timebuf->tms_stime = 0;
1769 timebuf->tms_cutime = 0;
1770 timebuf->tms_cstime = 0;
1772 return process_time_so_far;
1775 /* fix utime() so it works on directories in NT */
1777 filetime_from_time(PFILETIME pFileTime, time_t Time)
1779 struct tm *pTM = localtime(&Time);
1780 SYSTEMTIME SystemTime;
1786 SystemTime.wYear = pTM->tm_year + 1900;
1787 SystemTime.wMonth = pTM->tm_mon + 1;
1788 SystemTime.wDay = pTM->tm_mday;
1789 SystemTime.wHour = pTM->tm_hour;
1790 SystemTime.wMinute = pTM->tm_min;
1791 SystemTime.wSecond = pTM->tm_sec;
1792 SystemTime.wMilliseconds = 0;
1794 return SystemTimeToFileTime(&SystemTime, &LocalTime) &&
1795 LocalFileTimeToFileTime(&LocalTime, pFileTime);
1799 win32_unlink(const char *filename)
1805 filename = PerlDir_mapA(filename);
1806 attrs = GetFileAttributesA(filename);
1807 if (attrs == 0xFFFFFFFF) {
1811 if (attrs & FILE_ATTRIBUTE_READONLY) {
1812 (void)SetFileAttributesA(filename, attrs & ~FILE_ATTRIBUTE_READONLY);
1813 ret = unlink(filename);
1815 (void)SetFileAttributesA(filename, attrs);
1818 ret = unlink(filename);
1823 win32_utime(const char *filename, struct utimbuf *times)
1830 struct utimbuf TimeBuffer;
1833 filename = PerlDir_mapA(filename);
1834 rc = utime(filename, times);
1836 /* EACCES: path specifies directory or readonly file */
1837 if (rc == 0 || errno != EACCES /* || !IsWinNT() */)
1840 if (times == NULL) {
1841 times = &TimeBuffer;
1842 time(×->actime);
1843 times->modtime = times->actime;
1846 /* This will (and should) still fail on readonly files */
1847 handle = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE,
1848 FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
1849 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1850 if (handle == INVALID_HANDLE_VALUE)
1853 if (GetFileTime(handle, &ftCreate, &ftAccess, &ftWrite) &&
1854 filetime_from_time(&ftAccess, times->actime) &&
1855 filetime_from_time(&ftWrite, times->modtime) &&
1856 SetFileTime(handle, &ftCreate, &ftAccess, &ftWrite))
1861 CloseHandle(handle);
1866 unsigned __int64 ft_i64;
1871 #define Const64(x) x##LL
1873 #define Const64(x) x##i64
1875 /* Number of 100 nanosecond units from 1/1/1601 to 1/1/1970 */
1876 #define EPOCH_BIAS Const64(116444736000000000)
1878 /* NOTE: This does not compute the timezone info (doing so can be expensive,
1879 * and appears to be unsupported even by glibc) */
1881 win32_gettimeofday(struct timeval *tp, void *not_used)
1885 /* this returns time in 100-nanosecond units (i.e. tens of usecs) */
1886 GetSystemTimeAsFileTime(&ft.ft_val);
1888 /* seconds since epoch */
1889 tp->tv_sec = (long)((ft.ft_i64 - EPOCH_BIAS) / Const64(10000000));
1891 /* microseconds remaining */
1892 tp->tv_usec = (long)((ft.ft_i64 / Const64(10)) % Const64(1000000));
1898 win32_uname(struct utsname *name)
1900 struct hostent *hep;
1901 STRLEN nodemax = sizeof(name->nodename)-1;
1904 switch (g_osver.dwPlatformId) {
1905 case VER_PLATFORM_WIN32_WINDOWS:
1906 strcpy(name->sysname, "Windows");
1908 case VER_PLATFORM_WIN32_NT:
1909 strcpy(name->sysname, "Windows NT");
1911 case VER_PLATFORM_WIN32s:
1912 strcpy(name->sysname, "Win32s");
1915 strcpy(name->sysname, "Win32 Unknown");
1920 sprintf(name->release, "%d.%d",
1921 g_osver.dwMajorVersion, g_osver.dwMinorVersion);
1924 sprintf(name->version, "Build %d",
1925 g_osver.dwPlatformId == VER_PLATFORM_WIN32_NT
1926 ? g_osver.dwBuildNumber : (g_osver.dwBuildNumber & 0xffff));
1927 if (g_osver.szCSDVersion[0]) {
1928 char *buf = name->version + strlen(name->version);
1929 sprintf(buf, " (%s)", g_osver.szCSDVersion);
1933 hep = win32_gethostbyname("localhost");
1935 STRLEN len = strlen(hep->h_name);
1936 if (len <= nodemax) {
1937 strcpy(name->nodename, hep->h_name);
1940 strncpy(name->nodename, hep->h_name, nodemax);
1941 name->nodename[nodemax] = '\0';
1946 if (!GetComputerName(name->nodename, &sz))
1947 *name->nodename = '\0';
1950 /* machine (architecture) */
1955 GetSystemInfo(&info);
1957 #if (defined(__BORLANDC__)&&(__BORLANDC__<=0x520)) \
1958 || (defined(__MINGW32__) && !defined(_ANONYMOUS_UNION))
1959 procarch = info.u.s.wProcessorArchitecture;
1961 procarch = info.wProcessorArchitecture;
1964 case PROCESSOR_ARCHITECTURE_INTEL:
1965 arch = "x86"; break;
1966 case PROCESSOR_ARCHITECTURE_MIPS:
1967 arch = "mips"; break;
1968 case PROCESSOR_ARCHITECTURE_ALPHA:
1969 arch = "alpha"; break;
1970 case PROCESSOR_ARCHITECTURE_PPC:
1971 arch = "ppc"; break;
1972 #ifdef PROCESSOR_ARCHITECTURE_SHX
1973 case PROCESSOR_ARCHITECTURE_SHX:
1974 arch = "shx"; break;
1976 #ifdef PROCESSOR_ARCHITECTURE_ARM
1977 case PROCESSOR_ARCHITECTURE_ARM:
1978 arch = "arm"; break;
1980 #ifdef PROCESSOR_ARCHITECTURE_IA64
1981 case PROCESSOR_ARCHITECTURE_IA64:
1982 arch = "ia64"; break;
1984 #ifdef PROCESSOR_ARCHITECTURE_ALPHA64
1985 case PROCESSOR_ARCHITECTURE_ALPHA64:
1986 arch = "alpha64"; break;
1988 #ifdef PROCESSOR_ARCHITECTURE_MSIL
1989 case PROCESSOR_ARCHITECTURE_MSIL:
1990 arch = "msil"; break;
1992 #ifdef PROCESSOR_ARCHITECTURE_AMD64
1993 case PROCESSOR_ARCHITECTURE_AMD64:
1994 arch = "amd64"; break;
1996 #ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
1997 case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
1998 arch = "ia32-64"; break;
2000 #ifdef PROCESSOR_ARCHITECTURE_UNKNOWN
2001 case PROCESSOR_ARCHITECTURE_UNKNOWN:
2002 arch = "unknown"; break;
2005 sprintf(name->machine, "unknown(0x%x)", procarch);
2006 arch = name->machine;
2009 if (name->machine != arch)
2010 strcpy(name->machine, arch);
2015 /* Timing related stuff */
2018 do_raise(pTHX_ int sig)
2020 if (sig < SIG_SIZE) {
2021 Sighandler_t handler = w32_sighandler[sig];
2022 if (handler == SIG_IGN) {
2025 else if (handler != SIG_DFL) {
2030 /* Choose correct default behaviour */
2046 /* Tell caller to exit thread/process as approriate */
2051 sig_terminate(pTHX_ int sig)
2053 Perl_warn(aTHX_ "Terminating on signal SIG%s(%d)\n",PL_sig_name[sig], sig);
2054 /* exit() seems to be safe, my_exit() or die() is a problem in ^C
2061 win32_async_check(pTHX)
2064 HWND hwnd = w32_message_hwnd;
2068 if (hwnd == INVALID_HANDLE_VALUE) {
2069 /* Call PeekMessage() to mark all pending messages in the queue as "old".
2070 * This is necessary when we are being called by win32_msgwait() to
2071 * make sure MsgWaitForMultipleObjects() stops reporting the same waiting
2072 * message over and over. An example how this can happen is when
2073 * Perl is calling win32_waitpid() inside a GUI application and the GUI
2074 * is generating messages before the process terminated.
2076 PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE|PM_NOYIELD);
2082 /* Passing PeekMessage -1 as HWND (2nd arg) only get PostThreadMessage() messages
2083 * and ignores window messages - should co-exist better with windows apps e.g. Tk
2088 while (PeekMessage(&msg, hwnd, WM_TIMER, WM_TIMER, PM_REMOVE|PM_NOYIELD) ||
2089 PeekMessage(&msg, hwnd, WM_USER_MIN, WM_USER_MAX, PM_REMOVE|PM_NOYIELD))
2091 switch (msg.message) {
2093 case WM_USER_MESSAGE: {
2094 int child = find_pseudo_pid(msg.wParam);
2096 w32_pseudo_child_message_hwnds[child] = (HWND)msg.lParam;
2101 case WM_USER_KILL: {
2102 /* We use WM_USER to fake kill() with other signals */
2103 int sig = msg.wParam;
2104 if (do_raise(aTHX_ sig))
2105 sig_terminate(aTHX_ sig);
2110 /* alarm() is a one-shot but SetTimer() repeats so kill it */
2111 if (w32_timerid && w32_timerid==msg.wParam) {
2112 KillTimer(w32_message_hwnd, w32_timerid);
2115 /* Now fake a call to signal handler */
2116 if (do_raise(aTHX_ 14))
2117 sig_terminate(aTHX_ 14);
2124 /* Above or other stuff may have set a signal flag */
2125 if (PL_sig_pending) {
2131 /* This function will not return until the timeout has elapsed, or until
2132 * one of the handles is ready. */
2134 win32_msgwait(pTHX_ DWORD count, LPHANDLE handles, DWORD timeout, LPDWORD resultp)
2136 /* We may need several goes at this - so compute when we stop */
2138 if (timeout != INFINITE) {
2139 ticks = GetTickCount();
2143 DWORD result = MsgWaitForMultipleObjects(count,handles,FALSE,timeout-ticks, QS_ALLEVENTS);
2146 if (result == WAIT_TIMEOUT) {
2147 /* Ran out of time - explicit return of zero to avoid -ve if we
2148 have scheduling issues
2152 if (timeout != INFINITE) {
2153 ticks = GetTickCount();
2155 if (result == WAIT_OBJECT_0 + count) {
2156 /* Message has arrived - check it */
2157 (void)win32_async_check(aTHX);
2160 /* Not timeout or message - one of handles is ready */
2164 /* compute time left to wait */
2165 ticks = timeout - ticks;
2166 /* If we are past the end say zero */
2167 return (ticks > 0) ? ticks : 0;
2171 win32_internal_wait(int *status, DWORD timeout)
2173 /* XXX this wait emulation only knows about processes
2174 * spawned via win32_spawnvp(P_NOWAIT, ...).
2178 DWORD exitcode, waitcode;
2181 if (w32_num_pseudo_children) {
2182 win32_msgwait(aTHX_ w32_num_pseudo_children, w32_pseudo_child_handles,
2183 timeout, &waitcode);
2184 /* Time out here if there are no other children to wait for. */
2185 if (waitcode == WAIT_TIMEOUT) {
2186 if (!w32_num_children) {
2190 else if (waitcode != WAIT_FAILED) {
2191 if (waitcode >= WAIT_ABANDONED_0
2192 && waitcode < WAIT_ABANDONED_0 + w32_num_pseudo_children)
2193 i = waitcode - WAIT_ABANDONED_0;
2195 i = waitcode - WAIT_OBJECT_0;
2196 if (GetExitCodeThread(w32_pseudo_child_handles[i], &exitcode)) {
2197 *status = (int)((exitcode & 0xff) << 8);
2198 retval = (int)w32_pseudo_child_pids[i];
2199 remove_dead_pseudo_process(i);
2206 if (!w32_num_children) {
2211 /* if a child exists, wait for it to die */
2212 win32_msgwait(aTHX_ w32_num_children, w32_child_handles, timeout, &waitcode);
2213 if (waitcode == WAIT_TIMEOUT) {
2216 if (waitcode != WAIT_FAILED) {
2217 if (waitcode >= WAIT_ABANDONED_0
2218 && waitcode < WAIT_ABANDONED_0 + w32_num_children)
2219 i = waitcode - WAIT_ABANDONED_0;
2221 i = waitcode - WAIT_OBJECT_0;
2222 if (GetExitCodeProcess(w32_child_handles[i], &exitcode) ) {
2223 *status = (int)((exitcode & 0xff) << 8);
2224 retval = (int)w32_child_pids[i];
2225 remove_dead_process(i);
2230 errno = GetLastError();
2235 win32_waitpid(int pid, int *status, int flags)
2238 DWORD timeout = (flags & WNOHANG) ? 0 : INFINITE;
2241 if (pid == -1) /* XXX threadid == 1 ? */
2242 return win32_internal_wait(status, timeout);
2245 child = find_pseudo_pid(-pid);
2247 HANDLE hThread = w32_pseudo_child_handles[child];
2249 win32_msgwait(aTHX_ 1, &hThread, timeout, &waitcode);
2250 if (waitcode == WAIT_TIMEOUT) {
2253 else if (waitcode == WAIT_OBJECT_0) {
2254 if (GetExitCodeThread(hThread, &waitcode)) {
2255 *status = (int)((waitcode & 0xff) << 8);
2256 retval = (int)w32_pseudo_child_pids[child];
2257 remove_dead_pseudo_process(child);
2264 else if (IsWin95()) {
2273 child = find_pid(pid);
2275 hProcess = w32_child_handles[child];
2276 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
2277 if (waitcode == WAIT_TIMEOUT) {
2280 else if (waitcode == WAIT_OBJECT_0) {
2281 if (GetExitCodeProcess(hProcess, &waitcode)) {
2282 *status = (int)((waitcode & 0xff) << 8);
2283 retval = (int)w32_child_pids[child];
2284 remove_dead_process(child);
2293 hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE,
2294 (IsWin95() ? -pid : pid));
2296 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
2297 if (waitcode == WAIT_TIMEOUT) {
2298 CloseHandle(hProcess);
2301 else if (waitcode == WAIT_OBJECT_0) {
2302 if (GetExitCodeProcess(hProcess, &waitcode)) {
2303 *status = (int)((waitcode & 0xff) << 8);
2304 CloseHandle(hProcess);
2308 CloseHandle(hProcess);
2314 return retval >= 0 ? pid : retval;
2318 win32_wait(int *status)
2320 return win32_internal_wait(status, INFINITE);
2323 DllExport unsigned int
2324 win32_sleep(unsigned int t)
2327 /* Win32 times are in ms so *1000 in and /1000 out */
2328 return win32_msgwait(aTHX_ 0, NULL, t*1000, NULL)/1000;
2331 DllExport unsigned int
2332 win32_alarm(unsigned int sec)
2335 * the 'obvious' implentation is SetTimer() with a callback
2336 * which does whatever receiving SIGALRM would do
2337 * we cannot use SIGALRM even via raise() as it is not
2338 * one of the supported codes in <signal.h>
2342 if (w32_message_hwnd == INVALID_HANDLE_VALUE)
2343 w32_message_hwnd = win32_create_message_window();
2346 if (w32_message_hwnd == NULL)
2347 w32_timerid = SetTimer(NULL, w32_timerid, sec*1000, NULL);
2350 SetTimer(w32_message_hwnd, w32_timerid, sec*1000, NULL);
2355 KillTimer(w32_message_hwnd, w32_timerid);
2362 #ifdef HAVE_DES_FCRYPT
2363 extern char * des_fcrypt(const char *txt, const char *salt, char *cbuf);
2367 win32_crypt(const char *txt, const char *salt)
2370 #ifdef HAVE_DES_FCRYPT
2371 return des_fcrypt(txt, salt, w32_crypt_buffer);
2373 Perl_croak(aTHX_ "The crypt() function is unimplemented due to excessive paranoia.");
2378 #ifdef USE_FIXED_OSFHANDLE
2380 #define FOPEN 0x01 /* file handle open */
2381 #define FNOINHERIT 0x10 /* file handle opened O_NOINHERIT */
2382 #define FAPPEND 0x20 /* file handle opened O_APPEND */
2383 #define FDEV 0x40 /* file handle refers to device */
2384 #define FTEXT 0x80 /* file handle is in text mode */
2387 *int my_open_osfhandle(intptr_t osfhandle, int flags) - open C Runtime file handle
2390 * This function allocates a free C Runtime file handle and associates
2391 * it with the Win32 HANDLE specified by the first parameter. This is a
2392 * temperary fix for WIN95's brain damage GetFileType() error on socket
2393 * we just bypass that call for socket
2395 * This works with MSVC++ 4.0+ or GCC/Mingw32
2398 * intptr_t osfhandle - Win32 HANDLE to associate with C Runtime file handle.
2399 * int flags - flags to associate with C Runtime file handle.
2402 * returns index of entry in fh, if successful
2403 * return -1, if no free entry is found
2407 *******************************************************************************/
2410 * we fake up some parts of the CRT that aren't exported by MSVCRT.dll
2411 * this lets sockets work on Win9X with GCC and should fix the problems
2416 /* create an ioinfo entry, kill its handle, and steal the entry */
2421 HANDLE hF = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
2422 int fh = _open_osfhandle((intptr_t)hF, 0);
2426 EnterCriticalSection(&(_pioinfo(fh)->lock));
2431 my_open_osfhandle(intptr_t osfhandle, int flags)
2434 char fileflags; /* _osfile flags */
2436 /* copy relevant flags from second parameter */
2439 if (flags & O_APPEND)
2440 fileflags |= FAPPEND;
2445 if (flags & O_NOINHERIT)
2446 fileflags |= FNOINHERIT;
2448 /* attempt to allocate a C Runtime file handle */
2449 if ((fh = _alloc_osfhnd()) == -1) {
2450 errno = EMFILE; /* too many open files */
2451 _doserrno = 0L; /* not an OS error */
2452 return -1; /* return error to caller */
2455 /* the file is open. now, set the info in _osfhnd array */
2456 _set_osfhnd(fh, osfhandle);
2458 fileflags |= FOPEN; /* mark as open */
2460 _osfile(fh) = fileflags; /* set osfile entry */
2461 LeaveCriticalSection(&_pioinfo(fh)->lock);
2463 return fh; /* return handle */
2466 #endif /* USE_FIXED_OSFHANDLE */
2468 /* simulate flock by locking a range on the file */
2470 #define LK_ERR(f,i) ((f) ? (i = 0) : (errno = GetLastError()))
2471 #define LK_LEN 0xffff0000
2474 win32_flock(int fd, int oper)
2482 Perl_croak_nocontext("flock() unimplemented on this platform");
2485 fh = (HANDLE)_get_osfhandle(fd);
2486 memset(&o, 0, sizeof(o));
2489 case LOCK_SH: /* shared lock */
2490 LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, 0, &o),i);
2492 case LOCK_EX: /* exclusive lock */
2493 LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o),i);
2495 case LOCK_SH|LOCK_NB: /* non-blocking shared lock */
2496 LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o),i);
2498 case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */
2499 LK_ERR(LockFileEx(fh,
2500 LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
2501 0, LK_LEN, 0, &o),i);
2503 case LOCK_UN: /* unlock lock */
2504 LK_ERR(UnlockFileEx(fh, 0, LK_LEN, 0, &o),i);
2506 default: /* unknown */
2517 * redirected io subsystem for all XS modules
2530 return (&(_environ));
2533 /* the rest are the remapped stdio routines */
2553 win32_ferror(FILE *fp)
2555 return (ferror(fp));
2560 win32_feof(FILE *fp)
2566 * Since the errors returned by the socket error function
2567 * WSAGetLastError() are not known by the library routine strerror
2568 * we have to roll our own.
2572 win32_strerror(int e)
2574 #if !defined __BORLANDC__ && !defined __MINGW32__ /* compiler intolerance */
2575 extern int sys_nerr;
2579 if (e < 0 || e > sys_nerr) {
2584 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0,
2585 w32_strerror_buffer,
2586 sizeof(w32_strerror_buffer), NULL) == 0)
2587 strcpy(w32_strerror_buffer, "Unknown Error");
2589 return w32_strerror_buffer;
2595 win32_str_os_error(void *sv, DWORD dwErr)
2599 dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
2600 |FORMAT_MESSAGE_IGNORE_INSERTS
2601 |FORMAT_MESSAGE_FROM_SYSTEM, NULL,
2602 dwErr, 0, (char *)&sMsg, 1, NULL);
2603 /* strip trailing whitespace and period */
2606 --dwLen; /* dwLen doesn't include trailing null */
2607 } while (0 < dwLen && isSPACE(sMsg[dwLen]));
2608 if ('.' != sMsg[dwLen])
2613 sMsg = (char*)LocalAlloc(0, 64/**sizeof(TCHAR)*/);
2615 dwLen = sprintf(sMsg,
2616 "Unknown error #0x%lX (lookup 0x%lX)",
2617 dwErr, GetLastError());
2621 sv_setpvn((SV*)sv, sMsg, dwLen);
2627 win32_fprintf(FILE *fp, const char *format, ...)
2630 va_start(marker, format); /* Initialize variable arguments. */
2632 return (vfprintf(fp, format, marker));
2636 win32_printf(const char *format, ...)
2639 va_start(marker, format); /* Initialize variable arguments. */
2641 return (vprintf(format, marker));
2645 win32_vfprintf(FILE *fp, const char *format, va_list args)
2647 return (vfprintf(fp, format, args));
2651 win32_vprintf(const char *format, va_list args)
2653 return (vprintf(format, args));
2657 win32_fread(void *buf, size_t size, size_t count, FILE *fp)
2659 return fread(buf, size, count, fp);
2663 win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
2665 return fwrite(buf, size, count, fp);
2668 #define MODE_SIZE 10
2671 win32_fopen(const char *filename, const char *mode)
2679 if (stricmp(filename, "/dev/null")==0)
2682 f = fopen(PerlDir_mapA(filename), mode);
2683 /* avoid buffering headaches for child processes */
2684 if (f && *mode == 'a')
2685 win32_fseek(f, 0, SEEK_END);
2689 #ifndef USE_SOCKETS_AS_HANDLES
2691 #define fdopen my_fdopen
2695 win32_fdopen(int handle, const char *mode)
2699 f = fdopen(handle, (char *) mode);
2700 /* avoid buffering headaches for child processes */
2701 if (f && *mode == 'a')
2702 win32_fseek(f, 0, SEEK_END);
2707 win32_freopen(const char *path, const char *mode, FILE *stream)
2710 if (stricmp(path, "/dev/null")==0)
2713 return freopen(PerlDir_mapA(path), mode, stream);
2717 win32_fclose(FILE *pf)
2719 return my_fclose(pf); /* defined in win32sck.c */
2723 win32_fputs(const char *s,FILE *pf)
2725 return fputs(s, pf);
2729 win32_fputc(int c,FILE *pf)
2735 win32_ungetc(int c,FILE *pf)
2737 return ungetc(c,pf);
2741 win32_getc(FILE *pf)
2747 win32_fileno(FILE *pf)
2753 win32_clearerr(FILE *pf)
2760 win32_fflush(FILE *pf)
2766 win32_ftell(FILE *pf)
2768 #if defined(WIN64) || defined(USE_LARGE_FILES)
2769 #if defined(__BORLANDC__) /* buk */
2770 return win32_tell( fileno( pf ) );
2773 if (fgetpos(pf, &pos))
2783 win32_fseek(FILE *pf, Off_t offset,int origin)
2785 #if defined(WIN64) || defined(USE_LARGE_FILES)
2786 #if defined(__BORLANDC__) /* buk */
2796 if (fgetpos(pf, &pos))
2801 fseek(pf, 0, SEEK_END);
2802 pos = _telli64(fileno(pf));
2811 return fsetpos(pf, &offset);
2814 return fseek(pf, (long)offset, origin);
2819 win32_fgetpos(FILE *pf,fpos_t *p)
2821 #if defined(__BORLANDC__) && defined(USE_LARGE_FILES) /* buk */
2822 if( win32_tell(fileno(pf)) == -1L ) {
2828 return fgetpos(pf, p);
2833 win32_fsetpos(FILE *pf,const fpos_t *p)
2835 #if defined(__BORLANDC__) && defined(USE_LARGE_FILES) /* buk */
2836 return win32_lseek(fileno(pf), *p, SEEK_CUR);
2838 return fsetpos(pf, p);
2843 win32_rewind(FILE *pf)
2853 char prefix[MAX_PATH+1];
2854 char filename[MAX_PATH+1];
2855 DWORD len = GetTempPath(MAX_PATH, prefix);
2856 if (len && len < MAX_PATH) {
2857 if (GetTempFileName(prefix, "plx", 0, filename)) {
2858 HANDLE fh = CreateFile(filename,
2859 DELETE | GENERIC_READ | GENERIC_WRITE,
2863 FILE_ATTRIBUTE_NORMAL
2864 | FILE_FLAG_DELETE_ON_CLOSE,
2866 if (fh != INVALID_HANDLE_VALUE) {
2867 int fd = win32_open_osfhandle((intptr_t)fh, 0);
2869 #if defined(__BORLANDC__)
2870 setmode(fd,O_BINARY);
2872 DEBUG_p(PerlIO_printf(Perl_debug_log,
2873 "Created tmpfile=%s\n",filename));
2885 int fd = win32_tmpfd();
2887 return win32_fdopen(fd, "w+b");
2899 win32_fstat(int fd, Stat_t *sbufptr)
2902 /* A file designated by filehandle is not shown as accessible
2903 * for write operations, probably because it is opened for reading.
2906 BY_HANDLE_FILE_INFORMATION bhfi;
2907 #if defined(WIN64) || defined(USE_LARGE_FILES)
2908 /* Borland 5.5.1 has a 64-bit stat, but only a 32-bit fstat */
2910 int rc = fstat(fd,&tmp);
2912 sbufptr->st_dev = tmp.st_dev;
2913 sbufptr->st_ino = tmp.st_ino;
2914 sbufptr->st_mode = tmp.st_mode;
2915 sbufptr->st_nlink = tmp.st_nlink;
2916 sbufptr->st_uid = tmp.st_uid;
2917 sbufptr->st_gid = tmp.st_gid;
2918 sbufptr->st_rdev = tmp.st_rdev;
2919 sbufptr->st_size = tmp.st_size;
2920 sbufptr->st_atime = tmp.st_atime;
2921 sbufptr->st_mtime = tmp.st_mtime;
2922 sbufptr->st_ctime = tmp.st_ctime;
2924 int rc = fstat(fd,sbufptr);
2927 if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &bhfi)) {
2928 #if defined(WIN64) || defined(USE_LARGE_FILES)
2929 sbufptr->st_size = (bhfi.nFileSizeHigh << 32) + bhfi.nFileSizeLow ;
2931 sbufptr->st_mode &= 0xFE00;
2932 if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
2933 sbufptr->st_mode |= (S_IREAD + (S_IREAD >> 3) + (S_IREAD >> 6));
2935 sbufptr->st_mode |= ((S_IREAD|S_IWRITE) + ((S_IREAD|S_IWRITE) >> 3)
2936 + ((S_IREAD|S_IWRITE) >> 6));
2940 return my_fstat(fd,sbufptr);
2945 win32_pipe(int *pfd, unsigned int size, int mode)
2947 return _pipe(pfd, size, mode);
2951 win32_popenlist(const char *mode, IV narg, SV **args)
2954 Perl_croak(aTHX_ "List form of pipe open not implemented");
2959 * a popen() clone that respects PERL5SHELL
2961 * changed to return PerlIO* rather than FILE * by BKS, 11-11-2000
2965 win32_popen(const char *command, const char *mode)
2967 #ifdef USE_RTL_POPEN
2968 return _popen(command, mode);
2980 /* establish which ends read and write */
2981 if (strchr(mode,'w')) {
2982 stdfd = 0; /* stdin */
2985 nhandle = STD_INPUT_HANDLE;
2987 else if (strchr(mode,'r')) {
2988 stdfd = 1; /* stdout */
2991 nhandle = STD_OUTPUT_HANDLE;
2996 /* set the correct mode */
2997 if (strchr(mode,'b'))
2999 else if (strchr(mode,'t'))
3002 ourmode = _fmode & (O_TEXT | O_BINARY);
3004 /* the child doesn't inherit handles */
3005 ourmode |= O_NOINHERIT;
3007 if (win32_pipe(p, 512, ourmode) == -1)
3010 /* save the old std handle (this needs to happen before the
3011 * dup2(), since that might call SetStdHandle() too) */
3014 old_h = GetStdHandle(nhandle);
3016 /* save current stdfd */
3017 if ((oldfd = win32_dup(stdfd)) == -1)
3020 /* make stdfd go to child end of pipe (implicitly closes stdfd) */
3021 /* stdfd will be inherited by the child */
3022 if (win32_dup2(p[child], stdfd) == -1)
3025 /* close the child end in parent */
3026 win32_close(p[child]);
3028 /* set the new std handle (in case dup2() above didn't) */
3029 SetStdHandle(nhandle, (HANDLE)_get_osfhandle(stdfd));
3031 /* start the child */
3034 if ((childpid = do_spawn_nowait((char*)command)) == -1)
3037 /* revert stdfd to whatever it was before */
3038 if (win32_dup2(oldfd, stdfd) == -1)
3041 /* close saved handle */
3044 /* restore the old std handle (this needs to happen after the
3045 * dup2(), since that might call SetStdHandle() too */
3047 SetStdHandle(nhandle, old_h);
3053 sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid);
3056 /* set process id so that it can be returned by perl's open() */
3057 PL_forkprocess = childpid;
3060 /* we have an fd, return a file stream */
3061 return (PerlIO_fdopen(p[parent], (char *)mode));
3064 /* we don't need to check for errors here */
3068 win32_dup2(oldfd, stdfd);
3072 SetStdHandle(nhandle, old_h);
3078 #endif /* USE_RTL_POPEN */
3086 win32_pclose(PerlIO *pf)
3088 #ifdef USE_RTL_POPEN
3092 int childpid, status;
3096 sv = *av_fetch(w32_fdpid, PerlIO_fileno(pf), TRUE);
3099 childpid = SvIVX(sv);
3117 if (win32_waitpid(childpid, &status, 0) == -1)
3122 #endif /* USE_RTL_POPEN */
3128 LPCWSTR lpExistingFileName,
3129 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
3132 WCHAR wFullName[MAX_PATH+1];
3133 LPVOID lpContext = NULL;
3134 WIN32_STREAM_ID StreamId;
3135 DWORD dwSize = (char*)&StreamId.cStreamName - (char*)&StreamId;
3140 BOOL (__stdcall *pfnBackupWrite)(HANDLE, LPBYTE, DWORD, LPDWORD,
3141 BOOL, BOOL, LPVOID*) =
3142 (BOOL (__stdcall *)(HANDLE, LPBYTE, DWORD, LPDWORD,
3143 BOOL, BOOL, LPVOID*))
3144 GetProcAddress(GetModuleHandle("kernel32.dll"), "BackupWrite");
3145 if (pfnBackupWrite == NULL)
3148 dwLen = GetFullPathNameW(lpFileName, MAX_PATH, wFullName, NULL);
3151 dwLen = (dwLen+1)*sizeof(WCHAR);
3153 handle = CreateFileW(lpExistingFileName, FILE_WRITE_ATTRIBUTES,
3154 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
3155 NULL, OPEN_EXISTING, 0, NULL);
3156 if (handle == INVALID_HANDLE_VALUE)
3159 StreamId.dwStreamId = BACKUP_LINK;
3160 StreamId.dwStreamAttributes = 0;
3161 StreamId.dwStreamNameSize = 0;
3162 #if defined(__BORLANDC__) \
3163 ||(defined(__MINGW32__) && !defined(_ANONYMOUS_UNION))
3164 StreamId.Size.u.HighPart = 0;
3165 StreamId.Size.u.LowPart = dwLen;
3167 StreamId.Size.HighPart = 0;
3168 StreamId.Size.LowPart = dwLen;
3171 bSuccess = pfnBackupWrite(handle, (LPBYTE)&StreamId, dwSize, &dwWritten,
3172 FALSE, FALSE, &lpContext);
3174 bSuccess = pfnBackupWrite(handle, (LPBYTE)wFullName, dwLen, &dwWritten,
3175 FALSE, FALSE, &lpContext);
3176 pfnBackupWrite(handle, NULL, 0, &dwWritten, TRUE, FALSE, &lpContext);
3179 CloseHandle(handle);
3184 win32_link(const char *oldname, const char *newname)
3187 BOOL (__stdcall *pfnCreateHardLinkW)(LPCWSTR,LPCWSTR,LPSECURITY_ATTRIBUTES);
3188 WCHAR wOldName[MAX_PATH+1];
3189 WCHAR wNewName[MAX_PATH+1];
3192 Perl_croak(aTHX_ PL_no_func, "link");
3194 pfnCreateHardLinkW =
3195 (BOOL (__stdcall *)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES))
3196 GetProcAddress(GetModuleHandle("kernel32.dll"), "CreateHardLinkW");
3197 if (pfnCreateHardLinkW == NULL)
3198 pfnCreateHardLinkW = Nt4CreateHardLinkW;
3200 if (MultiByteToWideChar(CP_ACP, 0, oldname, -1, wOldName, MAX_PATH+1) &&
3201 MultiByteToWideChar(CP_ACP, 0, newname, -1, wNewName, MAX_PATH+1) &&
3202 (wcscpy(wOldName, PerlDir_mapW(wOldName)),
3203 pfnCreateHardLinkW(PerlDir_mapW(wNewName), wOldName, NULL)))
3207 errno = (GetLastError() == ERROR_FILE_NOT_FOUND) ? ENOENT : EINVAL;
3212 win32_rename(const char *oname, const char *newname)
3214 char szOldName[MAX_PATH+1];
3215 char szNewName[MAX_PATH+1];
3219 /* XXX despite what the documentation says about MoveFileEx(),
3220 * it doesn't work under Windows95!
3223 DWORD dwFlags = MOVEFILE_COPY_ALLOWED;
3224 if (stricmp(newname, oname))
3225 dwFlags |= MOVEFILE_REPLACE_EXISTING;
3226 strcpy(szOldName, PerlDir_mapA(oname));
3227 bResult = MoveFileExA(szOldName,PerlDir_mapA(newname), dwFlags);
3229 DWORD err = GetLastError();
3231 case ERROR_BAD_NET_NAME:
3232 case ERROR_BAD_NETPATH:
3233 case ERROR_BAD_PATHNAME:
3234 case ERROR_FILE_NOT_FOUND:
3235 case ERROR_FILENAME_EXCED_RANGE:
3236 case ERROR_INVALID_DRIVE:
3237 case ERROR_NO_MORE_FILES:
3238 case ERROR_PATH_NOT_FOUND:
3251 char szTmpName[MAX_PATH+1];
3252 char dname[MAX_PATH+1];
3253 char *endname = Nullch;
3255 DWORD from_attr, to_attr;
3257 strcpy(szOldName, PerlDir_mapA(oname));
3258 strcpy(szNewName, PerlDir_mapA(newname));
3260 /* if oname doesn't exist, do nothing */
3261 from_attr = GetFileAttributes(szOldName);
3262 if (from_attr == 0xFFFFFFFF) {
3267 /* if newname exists, rename it to a temporary name so that we
3268 * don't delete it in case oname happens to be the same file
3269 * (but perhaps accessed via a different path)
3271 to_attr = GetFileAttributes(szNewName);
3272 if (to_attr != 0xFFFFFFFF) {
3273 /* if newname is a directory, we fail
3274 * XXX could overcome this with yet more convoluted logic */
3275 if (to_attr & FILE_ATTRIBUTE_DIRECTORY) {
3279 tmplen = strlen(szNewName);
3280 strcpy(szTmpName,szNewName);
3281 endname = szTmpName+tmplen;
3282 for (; endname > szTmpName ; --endname) {
3283 if (*endname == '/' || *endname == '\\') {
3288 if (endname > szTmpName)
3289 endname = strcpy(dname,szTmpName);
3293 /* get a temporary filename in same directory
3294 * XXX is this really the best we can do? */
3295 if (!GetTempFileName((LPCTSTR)endname, "plr", 0, szTmpName)) {
3299 DeleteFile(szTmpName);
3301 retval = rename(szNewName, szTmpName);
3308 /* rename oname to newname */
3309 retval = rename(szOldName, szNewName);
3311 /* if we created a temporary file before ... */
3312 if (endname != Nullch) {
3313 /* ...and rename succeeded, delete temporary file/directory */
3315 DeleteFile(szTmpName);
3316 /* else restore it to what it was */
3318 (void)rename(szTmpName, szNewName);
3325 win32_setmode(int fd, int mode)
3327 return setmode(fd, mode);
3331 win32_chsize(int fd, Off_t size)
3333 #if defined(WIN64) || defined(USE_LARGE_FILES)
3335 Off_t cur, end, extend;
3337 cur = win32_tell(fd);
3340 end = win32_lseek(fd, 0, SEEK_END);
3343 extend = size - end;
3347 else if (extend > 0) {
3348 /* must grow the file, padding with nulls */
3350 int oldmode = win32_setmode(fd, O_BINARY);
3352 memset(b, '\0', sizeof(b));
3354 count = extend >= sizeof(b) ? sizeof(b) : (size_t)extend;
3355 count = win32_write(fd, b, count);
3356 if ((int)count < 0) {
3360 } while ((extend -= count) > 0);
3361 win32_setmode(fd, oldmode);
3364 /* shrink the file */
3365 win32_lseek(fd, size, SEEK_SET);
3366 if (!SetEndOfFile((HANDLE)_get_osfhandle(fd))) {
3372 win32_lseek(fd, cur, SEEK_SET);
3375 return chsize(fd, (long)size);
3380 win32_lseek(int fd, Off_t offset, int origin)
3382 #if defined(WIN64) || defined(USE_LARGE_FILES)
3383 #if defined(__BORLANDC__) /* buk */
3385 pos.QuadPart = offset;
3386 pos.LowPart = SetFilePointer(
3387 (HANDLE)_get_osfhandle(fd),
3392 if (pos.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
3396 return pos.QuadPart;
3398 return _lseeki64(fd, offset, origin);
3401 return lseek(fd, (long)offset, origin);
3408 #if defined(WIN64) || defined(USE_LARGE_FILES)
3409 #if defined(__BORLANDC__) /* buk */
3412 pos.LowPart = SetFilePointer(
3413 (HANDLE)_get_osfhandle(fd),
3418 if (pos.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
3422 return pos.QuadPart;
3423 /* return tell(fd); */
3425 return _telli64(fd);
3433 win32_open(const char *path, int flag, ...)
3440 pmode = va_arg(ap, int);
3443 if (stricmp(path, "/dev/null")==0)
3446 return open(PerlDir_mapA(path), flag, pmode);
3449 /* close() that understands socket */
3450 extern int my_close(int); /* in win32sck.c */
3455 return my_close(fd);
3471 win32_dup2(int fd1,int fd2)
3473 return dup2(fd1,fd2);
3476 #ifdef PERL_MSVCRT_READFIX
3478 #define LF 10 /* line feed */
3479 #define CR 13 /* carriage return */
3480 #define CTRLZ 26 /* ctrl-z means eof for text */
3481 #define FOPEN 0x01 /* file handle open */
3482 #define FEOFLAG 0x02 /* end of file has been encountered */
3483 #define FCRLF 0x04 /* CR-LF across read buffer (in text mode) */
3484 #define FPIPE 0x08 /* file handle refers to a pipe */
3485 #define FAPPEND 0x20 /* file handle opened O_APPEND */
3486 #define FDEV 0x40 /* file handle refers to device */
3487 #define FTEXT 0x80 /* file handle is in text mode */
3488 #define MAX_DESCRIPTOR_COUNT (64*32) /* this is the maximun that MSVCRT can handle */
3491 _fixed_read(int fh, void *buf, unsigned cnt)
3493 int bytes_read; /* number of bytes read */
3494 char *buffer; /* buffer to read to */
3495 int os_read; /* bytes read on OS call */
3496 char *p, *q; /* pointers into buffer */
3497 char peekchr; /* peek-ahead character */
3498 ULONG filepos; /* file position after seek */
3499 ULONG dosretval; /* o.s. return value */
3501 /* validate handle */
3502 if (((unsigned)fh >= (unsigned)MAX_DESCRIPTOR_COUNT) ||
3503 !(_osfile(fh) & FOPEN))
3505 /* out of range -- return error */
3507 _doserrno = 0; /* not o.s. error */
3512 * If lockinitflag is FALSE, assume fd is device
3513 * lockinitflag is set to TRUE by open.
3515 if (_pioinfo(fh)->lockinitflag)
3516 EnterCriticalSection(&(_pioinfo(fh)->lock)); /* lock file */
3518 bytes_read = 0; /* nothing read yet */
3519 buffer = (char*)buf;
3521 if (cnt == 0 || (_osfile(fh) & FEOFLAG)) {
3522 /* nothing to read or at EOF, so return 0 read */
3526 if ((_osfile(fh) & (FPIPE|FDEV)) && _pipech(fh) != LF) {
3527 /* a pipe/device and pipe lookahead non-empty: read the lookahead
3529 *buffer++ = _pipech(fh);
3532 _pipech(fh) = LF; /* mark as empty */
3537 if (!ReadFile((HANDLE)_osfhnd(fh), buffer, cnt, (LPDWORD)&os_read, NULL))
3539 /* ReadFile has reported an error. recognize two special cases.
3541 * 1. map ERROR_ACCESS_DENIED to EBADF
3543 * 2. just return 0 if ERROR_BROKEN_PIPE has occurred. it
3544 * means the handle is a read-handle on a pipe for which
3545 * all write-handles have been closed and all data has been
3548 if ((dosretval = GetLastError()) == ERROR_ACCESS_DENIED) {
3549 /* wrong read/write mode should return EBADF, not EACCES */
3551 _doserrno = dosretval;
3555 else if (dosretval == ERROR_BROKEN_PIPE) {
3565 bytes_read += os_read; /* update bytes read */
3567 if (_osfile(fh) & FTEXT) {
3568 /* now must translate CR-LFs to LFs in the buffer */
3570 /* set CRLF flag to indicate LF at beginning of buffer */
3571 /* if ((os_read != 0) && (*(char *)buf == LF)) */
3572 /* _osfile(fh) |= FCRLF; */
3574 /* _osfile(fh) &= ~FCRLF; */
3576 _osfile(fh) &= ~FCRLF;
3578 /* convert chars in the buffer: p is src, q is dest */
3580 while (p < (char *)buf + bytes_read) {
3582 /* if fh is not a device, set ctrl-z flag */
3583 if (!(_osfile(fh) & FDEV))
3584 _osfile(fh) |= FEOFLAG;
3585 break; /* stop translating */
3590 /* *p is CR, so must check next char for LF */
3591 if (p < (char *)buf + bytes_read - 1) {
3594 *q++ = LF; /* convert CR-LF to LF */
3597 *q++ = *p++; /* store char normally */
3600 /* This is the hard part. We found a CR at end of
3601 buffer. We must peek ahead to see if next char
3606 if (!ReadFile((HANDLE)_osfhnd(fh), &peekchr, 1,
3607 (LPDWORD)&os_read, NULL))
3608 dosretval = GetLastError();
3610 if (dosretval != 0 || os_read == 0) {
3611 /* couldn't read ahead, store CR */
3615 /* peekchr now has the extra character -- we now
3616 have several possibilities:
3617 1. disk file and char is not LF; just seek back
3619 2. disk file and char is LF; store LF, don't seek back
3620 3. pipe/device and char is LF; store LF.
3621 4. pipe/device and char isn't LF, store CR and
3622 put char in pipe lookahead buffer. */
3623 if (_osfile(fh) & (FDEV|FPIPE)) {
3624 /* non-seekable device */
3629 _pipech(fh) = peekchr;
3634 if (peekchr == LF) {
3635 /* nothing read yet; must make some
3638 /* turn on this flag for tell routine */
3639 _osfile(fh) |= FCRLF;
3642 HANDLE osHandle; /* o.s. handle value */
3644 if ((osHandle = (HANDLE)_get_osfhandle(fh)) != (HANDLE)-1)
3646 if ((filepos = SetFilePointer(osHandle, -1, NULL, FILE_CURRENT)) == -1)
3647 dosretval = GetLastError();
3658 /* we now change bytes_read to reflect the true number of chars
3660 bytes_read = q - (char *)buf;
3664 if (_pioinfo(fh)->lockinitflag)
3665 LeaveCriticalSection(&(_pioinfo(fh)->lock)); /* unlock file */
3670 #endif /* PERL_MSVCRT_READFIX */
3673 win32_read(int fd, void *buf, unsigned int cnt)
3675 #ifdef PERL_MSVCRT_READFIX
3676 return _fixed_read(fd, buf, cnt);
3678 return read(fd, buf, cnt);
3683 win32_write(int fd, const void *buf, unsigned int cnt)
3685 return write(fd, buf, cnt);
3689 win32_mkdir(const char *dir, int mode)
3692 return mkdir(PerlDir_mapA(dir)); /* just ignore mode */
3696 win32_rmdir(const char *dir)
3699 return rmdir(PerlDir_mapA(dir));
3703 win32_chdir(const char *dir)
3714 win32_access(const char *path, int mode)
3717 return access(PerlDir_mapA(path), mode);
3721 win32_chmod(const char *path, int mode)
3724 return chmod(PerlDir_mapA(path), mode);
3729 create_command_line(char *cname, STRLEN clen, const char * const *args)
3736 bool bat_file = FALSE;
3737 bool cmd_shell = FALSE;
3738 bool dumb_shell = FALSE;
3739 bool extra_quotes = FALSE;
3740 bool quote_next = FALSE;
3743 cname = (char*)args[0];
3745 /* The NT cmd.exe shell has the following peculiarity that needs to be
3746 * worked around. It strips a leading and trailing dquote when any
3747 * of the following is true:
3748 * 1. the /S switch was used
3749 * 2. there are more than two dquotes
3750 * 3. there is a special character from this set: &<>()@^|
3751 * 4. no whitespace characters within the two dquotes
3752 * 5. string between two dquotes isn't an executable file
3753 * To work around this, we always add a leading and trailing dquote
3754 * to the string, if the first argument is either "cmd.exe" or "cmd",
3755 * and there were at least two or more arguments passed to cmd.exe
3756 * (not including switches).
3757 * XXX the above rules (from "cmd /?") don't seem to be applied
3758 * always, making for the convolutions below :-(
3762 clen = strlen(cname);
3765 && (stricmp(&cname[clen-4], ".bat") == 0
3766 || (IsWinNT() && stricmp(&cname[clen-4], ".cmd") == 0)))
3773 char *exe = strrchr(cname, '/');
3774 char *exe2 = strrchr(cname, '\\');
3781 if (stricmp(exe, "cmd.exe") == 0 || stricmp(exe, "cmd") == 0) {
3785 else if (stricmp(exe, "command.com") == 0
3786 || stricmp(exe, "command") == 0)
3793 DEBUG_p(PerlIO_printf(Perl_debug_log, "Args "));
3794 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3795 STRLEN curlen = strlen(arg);
3796 if (!(arg[0] == '"' && arg[curlen-1] == '"'))
3797 len += 2; /* assume quoting needed (worst case) */
3799 DEBUG_p(PerlIO_printf(Perl_debug_log, "[%s]",arg));
3801 DEBUG_p(PerlIO_printf(Perl_debug_log, "\n"));
3804 Newx(cmd, len, char);
3807 if (bat_file && !IsWin95()) {
3809 extra_quotes = TRUE;
3812 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3814 STRLEN curlen = strlen(arg);
3816 /* we want to protect empty arguments and ones with spaces with
3817 * dquotes, but only if they aren't already there */
3822 else if (quote_next) {
3823 /* see if it really is multiple arguments pretending to
3824 * be one and force a set of quotes around it */
3825 if (*find_next_space(arg))
3828 else if (!(arg[0] == '"' && curlen > 1 && arg[curlen-1] == '"')) {
3830 while (i < curlen) {
3831 if (isSPACE(arg[i])) {
3834 else if (arg[i] == '"') {
3858 && *arg == '/' /* see if arg is "/c", "/x/c", "/x/d/c" etc. */
3859 && stricmp(arg+curlen-2, "/c") == 0)
3861 /* is there a next argument? */
3862 if (args[index+1]) {
3863 /* are there two or more next arguments? */
3864 if (args[index+2]) {
3866 extra_quotes = TRUE;
3869 /* single argument, force quoting if it has spaces */
3885 qualified_path(const char *cmd)
3889 char *fullcmd, *curfullcmd;
3895 fullcmd = (char*)cmd;
3897 if (*fullcmd == '/' || *fullcmd == '\\')
3904 pathstr = PerlEnv_getenv("PATH");
3906 /* worst case: PATH is a single directory; we need additional space
3907 * to append "/", ".exe" and trailing "\0" */
3908 Newx(fullcmd, (pathstr ? strlen(pathstr) : 0) + cmdlen + 6, char);
3909 curfullcmd = fullcmd;
3914 /* start by appending the name to the current prefix */
3915 strcpy(curfullcmd, cmd);
3916 curfullcmd += cmdlen;
3918 /* if it doesn't end with '.', or has no extension, try adding
3919 * a trailing .exe first */
3920 if (cmd[cmdlen-1] != '.'
3921 && (cmdlen < 4 || cmd[cmdlen-4] != '.'))
3923 strcpy(curfullcmd, ".exe");
3924 res = GetFileAttributes(fullcmd);
3925 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3930 /* that failed, try the bare name */
3931 res = GetFileAttributes(fullcmd);
3932 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3935 /* quit if no other path exists, or if cmd already has path */
3936 if (!pathstr || !*pathstr || has_slash)
3939 /* skip leading semis */
3940 while (*pathstr == ';')
3943 /* build a new prefix from scratch */
3944 curfullcmd = fullcmd;
3945 while (*pathstr && *pathstr != ';') {
3946 if (*pathstr == '"') { /* foo;"baz;etc";bar */
3947 pathstr++; /* skip initial '"' */
3948 while (*pathstr && *pathstr != '"') {
3949 *curfullcmd++ = *pathstr++;
3952 pathstr++; /* skip trailing '"' */
3955 *curfullcmd++ = *pathstr++;
3959 pathstr++; /* skip trailing semi */
3960 if (curfullcmd > fullcmd /* append a dir separator */
3961 && curfullcmd[-1] != '/' && curfullcmd[-1] != '\\')
3963 *curfullcmd++ = '\\';
3971 /* The following are just place holders.
3972 * Some hosts may provide and environment that the OS is
3973 * not tracking, therefore, these host must provide that
3974 * environment and the current directory to CreateProcess
3978 win32_get_childenv(void)
3984 win32_free_childenv(void* d)
3989 win32_clearenv(void)
3991 char *envv = GetEnvironmentStrings();
3995 char *end = strchr(cur,'=');
3996 if (end && end != cur) {
3998 SetEnvironmentVariable(cur, NULL);
4000 cur = end + strlen(end+1)+2;
4002 else if ((len = strlen(cur)))
4005 FreeEnvironmentStrings(envv);
4009 win32_get_childdir(void)
4013 char szfilename[MAX_PATH+1];
4015 GetCurrentDirectoryA(MAX_PATH+1, szfilename);
4016 Newx(ptr, strlen(szfilename)+1, char);
4017 strcpy(ptr, szfilename);
4022 win32_free_childdir(char* d)
4029 /* XXX this needs to be made more compatible with the spawnvp()
4030 * provided by the various RTLs. In particular, searching for
4031 * *.{com,bat,cmd} files (as done by the RTLs) is unimplemented.
4032 * This doesn't significantly affect perl itself, because we
4033 * always invoke things using PERL5SHELL if a direct attempt to
4034 * spawn the executable fails.
4036 * XXX splitting and rejoining the commandline between do_aspawn()
4037 * and win32_spawnvp() could also be avoided.
4041 win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
4043 #ifdef USE_RTL_SPAWNVP
4044 return spawnvp(mode, cmdname, (char * const *)argv);
4051 STARTUPINFO StartupInfo;
4052 PROCESS_INFORMATION ProcessInformation;
4055 char *fullcmd = Nullch;
4056 char *cname = (char *)cmdname;
4060 clen = strlen(cname);
4061 /* if command name contains dquotes, must remove them */
4062 if (strchr(cname, '"')) {
4064 Newx(cname,clen+1,char);
4077 cmd = create_command_line(cname, clen, argv);
4079 env = PerlEnv_get_childenv();
4080 dir = PerlEnv_get_childdir();
4083 case P_NOWAIT: /* asynch + remember result */
4084 if (w32_num_children >= MAXIMUM_WAIT_OBJECTS) {
4089 /* Create a new process group so we can use GenerateConsoleCtrlEvent()
4092 create |= CREATE_NEW_PROCESS_GROUP;
4095 case P_WAIT: /* synchronous execution */
4097 default: /* invalid mode */
4102 memset(&StartupInfo,0,sizeof(StartupInfo));
4103 StartupInfo.cb = sizeof(StartupInfo);
4104 memset(&tbl,0,sizeof(tbl));
4105 PerlEnv_get_child_IO(&tbl);
4106 StartupInfo.dwFlags = tbl.dwFlags;
4107 StartupInfo.dwX = tbl.dwX;
4108 StartupInfo.dwY = tbl.dwY;
4109 StartupInfo.dwXSize = tbl.dwXSize;
4110 StartupInfo.dwYSize = tbl.dwYSize;
4111 StartupInfo.dwXCountChars = tbl.dwXCountChars;
4112 StartupInfo.dwYCountChars = tbl.dwYCountChars;
4113 StartupInfo.dwFillAttribute = tbl.dwFillAttribute;
4114 StartupInfo.wShowWindow = tbl.wShowWindow;
4115 StartupInfo.hStdInput = tbl.childStdIn;
4116 StartupInfo.hStdOutput = tbl.childStdOut;
4117 StartupInfo.hStdError = tbl.childStdErr;
4118 if (StartupInfo.hStdInput == INVALID_HANDLE_VALUE &&
4119 StartupInfo.hStdOutput == INVALID_HANDLE_VALUE &&
4120 StartupInfo.hStdError == INVALID_HANDLE_VALUE)
4122 create |= CREATE_NEW_CONSOLE;
4125 StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
4127 if (w32_use_showwindow) {
4128 StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
4129 StartupInfo.wShowWindow = w32_showwindow;
4132 DEBUG_p(PerlIO_printf(Perl_debug_log, "Spawning [%s] with [%s]\n",
4135 if (!CreateProcess(cname, /* search PATH to find executable */
4136 cmd, /* executable, and its arguments */
4137 NULL, /* process attributes */
4138 NULL, /* thread attributes */
4139 TRUE, /* inherit handles */
4140 create, /* creation flags */
4141 (LPVOID)env, /* inherit environment */
4142 dir, /* inherit cwd */
4144 &ProcessInformation))
4146 /* initial NULL argument to CreateProcess() does a PATH
4147 * search, but it always first looks in the directory
4148 * where the current process was started, which behavior
4149 * is undesirable for backward compatibility. So we
4150 * jump through our own hoops by picking out the path
4151 * we really want it to use. */
4153 fullcmd = qualified_path(cname);
4155 if (cname != cmdname)
4158 DEBUG_p(PerlIO_printf(Perl_debug_log,
4159 "Retrying [%s] with same args\n",
4169 if (mode == P_NOWAIT) {
4170 /* asynchronous spawn -- store handle, return PID */
4171 ret = (int)ProcessInformation.dwProcessId;
4172 if (IsWin95() && ret < 0)
4175 w32_child_handles[w32_num_children] = ProcessInformation.hProcess;
4176 w32_child_pids[w32_num_children] = (DWORD)ret;
4181 win32_msgwait(aTHX_ 1, &ProcessInformation.hProcess, INFINITE, NULL);
4182 /* FIXME: if msgwait returned due to message perhaps forward the
4183 "signal" to the process
4185 GetExitCodeProcess(ProcessInformation.hProcess, &status);
4187 CloseHandle(ProcessInformation.hProcess);
4190 CloseHandle(ProcessInformation.hThread);
4193 PerlEnv_free_childenv(env);
4194 PerlEnv_free_childdir(dir);
4196 if (cname != cmdname)
4203 win32_execv(const char *cmdname, const char *const *argv)
4207 /* if this is a pseudo-forked child, we just want to spawn
4208 * the new program, and return */
4210 # ifdef __BORLANDC__
4211 return spawnv(P_WAIT, cmdname, (char *const *)argv);
4213 return spawnv(P_WAIT, cmdname, argv);
4217 return execv(cmdname, (char *const *)argv);
4219 return execv(cmdname, argv);
4224 win32_execvp(const char *cmdname, const char *const *argv)
4228 /* if this is a pseudo-forked child, we just want to spawn
4229 * the new program, and return */
4230 if (w32_pseudo_id) {
4231 int status = win32_spawnvp(P_WAIT, cmdname, (const char *const *)argv);
4241 return execvp(cmdname, (char *const *)argv);
4243 return execvp(cmdname, argv);
4248 win32_perror(const char *str)
4254 win32_setbuf(FILE *pf, char *buf)
4260 win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
4262 return setvbuf(pf, buf, type, size);
4266 win32_flushall(void)
4272 win32_fcloseall(void)
4278 win32_fgets(char *s, int n, FILE *pf)
4280 return fgets(s, n, pf);
4290 win32_fgetc(FILE *pf)
4296 win32_putc(int c, FILE *pf)
4302 win32_puts(const char *s)
4314 win32_putchar(int c)
4321 #ifndef USE_PERL_SBRK
4323 static char *committed = NULL; /* XXX threadead */
4324 static char *base = NULL; /* XXX threadead */
4325 static char *reserved = NULL; /* XXX threadead */
4326 static char *brk = NULL; /* XXX threadead */
4327 static DWORD pagesize = 0; /* XXX threadead */
4330 sbrk(ptrdiff_t need)
4335 GetSystemInfo(&info);
4336 /* Pretend page size is larger so we don't perpetually
4337 * call the OS to commit just one page ...
4339 pagesize = info.dwPageSize << 3;
4341 if (brk+need >= reserved)
4343 DWORD size = brk+need-reserved;
4345 char *prev_committed = NULL;
4346 if (committed && reserved && committed < reserved)
4348 /* Commit last of previous chunk cannot span allocations */
4349 addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
4352 /* Remember where we committed from in case we want to decommit later */
4353 prev_committed = committed;
4354 committed = reserved;
4357 /* Reserve some (more) space
4358 * Contiguous blocks give us greater efficiency, so reserve big blocks -
4359 * this is only address space not memory...
4360 * Note this is a little sneaky, 1st call passes NULL as reserved
4361 * so lets system choose where we start, subsequent calls pass
4362 * the old end address so ask for a contiguous block
4365 if (size < 64*1024*1024)
4366 size = 64*1024*1024;
4367 size = ((size + pagesize - 1) / pagesize) * pagesize;
4368 addr = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
4371 reserved = addr+size;
4381 /* The existing block could not be extended far enough, so decommit
4382 * anything that was just committed above and start anew */
4385 if (!VirtualFree(prev_committed,reserved-prev_committed,MEM_DECOMMIT))
4388 reserved = base = committed = brk = NULL;
4399 if (brk > committed)
4401 DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
4403 if (committed+size > reserved)
4404 size = reserved-committed;
4405 addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
4418 win32_malloc(size_t size)
4420 return malloc(size);
4424 win32_calloc(size_t numitems, size_t size)
4426 return calloc(numitems,size);
4430 win32_realloc(void *block, size_t size)
4432 return realloc(block,size);
4436 win32_free(void *block)
4443 win32_open_osfhandle(intptr_t handle, int flags)
4445 #ifdef USE_FIXED_OSFHANDLE
4447 return my_open_osfhandle(handle, flags);
4449 return _open_osfhandle(handle, flags);
4453 win32_get_osfhandle(int fd)
4455 return (intptr_t)_get_osfhandle(fd);
4459 win32_fdupopen(FILE *pf)
4464 int fileno = win32_dup(win32_fileno(pf));
4466 /* open the file in the same mode */
4468 if((pf)->flags & _F_READ) {
4472 else if((pf)->flags & _F_WRIT) {
4476 else if((pf)->flags & _F_RDWR) {
4482 if((pf)->_flag & _IOREAD) {
4486 else if((pf)->_flag & _IOWRT) {
4490 else if((pf)->_flag & _IORW) {
4497 /* it appears that the binmode is attached to the
4498 * file descriptor so binmode files will be handled
4501 pfdup = win32_fdopen(fileno, mode);
4503 /* move the file pointer to the same position */
4504 if (!fgetpos(pf, &pos)) {
4505 fsetpos(pfdup, &pos);
4511 win32_dynaload(const char* filename)
4514 char buf[MAX_PATH+1];
4517 /* LoadLibrary() doesn't recognize forward slashes correctly,
4518 * so turn 'em back. */
4519 first = strchr(filename, '/');
4521 STRLEN len = strlen(filename);
4522 if (len <= MAX_PATH) {
4523 strcpy(buf, filename);
4524 filename = &buf[first - filename];
4526 if (*filename == '/')
4527 *(char*)filename = '\\';
4533 return LoadLibraryExA(PerlDir_mapA(filename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
4536 XS(w32_SetChildShowWindow)
4539 BOOL use_showwindow = w32_use_showwindow;
4540 /* use "unsigned short" because Perl has redefined "WORD" */
4541 unsigned short showwindow = w32_showwindow;
4544 Perl_croak(aTHX_ "usage: Win32::SetChildShowWindow($showwindow)");
4546 if (items == 0 || !SvOK(ST(0)))
4547 w32_use_showwindow = FALSE;
4549 w32_use_showwindow = TRUE;
4550 w32_showwindow = (unsigned short)SvIV(ST(0));
4555 ST(0) = sv_2mortal(newSViv(showwindow));
4557 ST(0) = &PL_sv_undef;
4562 forward(pTHX_ const char *function)
4565 Perl_load_module(aTHX_ PERL_LOADMOD_NOIMPORT, newSVpvn("Win32",5), newSVnv(0.27));
4568 call_pv(function, GIMME_V);
4571 #define FORWARD(function) XS(w32_##function){ forward(aTHX_ "Win32::"#function); }
4574 FORWARD(GetNextAvailDrive)
4575 FORWARD(GetLastError)
4576 FORWARD(SetLastError)
4581 FORWARD(GetOSVersion)
4584 FORWARD(FormatMessage)
4586 FORWARD(GetTickCount)
4587 FORWARD(GetShortPathName)
4588 FORWARD(GetFullPathName)
4589 FORWARD(GetLongPathName)
4593 /* Don't forward Win32::SetChildShowWindow(). It accesses the internal variable
4594 * w32_showwindow in thread_intern and is therefore not implemented in Win32.xs.
4596 /* FORWARD(SetChildShowWindow) */
4601 Perl_init_os_extras(void)
4604 char *file = __FILE__;
4607 /* these names are Activeware compatible */
4608 newXS("Win32::GetCwd", w32_GetCwd, file);
4609 newXS("Win32::SetCwd", w32_SetCwd, file);
4610 newXS("Win32::GetNextAvailDrive", w32_GetNextAvailDrive, file);
4611 newXS("Win32::GetLastError", w32_GetLastError, file);
4612 newXS("Win32::SetLastError", w32_SetLastError, file);
4613 newXS("Win32::LoginName", w32_LoginName, file);
4614 newXS("Win32::NodeName", w32_NodeName, file);
4615 newXS("Win32::DomainName", w32_DomainName, file);
4616 newXS("Win32::FsType", w32_FsType, file);
4617 newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
4618 newXS("Win32::IsWinNT", w32_IsWinNT, file);
4619 newXS("Win32::IsWin95", w32_IsWin95, file);
4620 newXS("Win32::FormatMessage", w32_FormatMessage, file);
4621 newXS("Win32::Spawn", w32_Spawn, file);
4622 newXS("Win32::GetTickCount", w32_GetTickCount, file);
4623 newXS("Win32::GetShortPathName", w32_GetShortPathName, file);
4624 newXS("Win32::GetFullPathName", w32_GetFullPathName, file);
4625 newXS("Win32::GetLongPathName", w32_GetLongPathName, file);
4626 newXS("Win32::CopyFile", w32_CopyFile, file);
4627 newXS("Win32::Sleep", w32_Sleep, file);
4628 newXS("Win32::SetChildShowWindow", w32_SetChildShowWindow, file);
4632 win32_signal_context(void)
4637 my_perl = PL_curinterp;
4638 PERL_SET_THX(my_perl);
4642 return PL_curinterp;
4648 win32_ctrlhandler(DWORD dwCtrlType)
4651 dTHXa(PERL_GET_SIG_CONTEXT);
4657 switch(dwCtrlType) {
4658 case CTRL_CLOSE_EVENT:
4659 /* A signal that the system sends to all processes attached to a console when
4660 the user closes the console (either by choosing the Close command from the
4661 console window's System menu, or by choosing the End Task command from the
4664 if (do_raise(aTHX_ 1)) /* SIGHUP */
4665 sig_terminate(aTHX_ 1);
4669 /* A CTRL+c signal was received */
4670 if (do_raise(aTHX_ SIGINT))
4671 sig_terminate(aTHX_ SIGINT);
4674 case CTRL_BREAK_EVENT:
4675 /* A CTRL+BREAK signal was received */
4676 if (do_raise(aTHX_ SIGBREAK))
4677 sig_terminate(aTHX_ SIGBREAK);
4680 case CTRL_LOGOFF_EVENT:
4681 /* A signal that the system sends to all console processes when a user is logging
4682 off. This signal does not indicate which user is logging off, so no
4683 assumptions can be made.
4686 case CTRL_SHUTDOWN_EVENT:
4687 /* A signal that the system sends to all console processes when the system is
4690 if (do_raise(aTHX_ SIGTERM))
4691 sig_terminate(aTHX_ SIGTERM);
4700 #if _MSC_VER >= 1400
4701 # include <crtdbg.h>
4705 Perl_win32_init(int *argcp, char ***argvp)
4709 #if _MSC_VER >= 1400
4710 _invalid_parameter_handler oldHandler, newHandler;
4711 newHandler = my_invalid_parameter_handler;
4712 oldHandler = _set_invalid_parameter_handler(newHandler);
4713 _CrtSetReportMode(_CRT_ASSERT, 0);
4715 /* Disable floating point errors, Perl will trap the ones we
4716 * care about. VC++ RTL defaults to switching these off
4717 * already, but the Borland RTL doesn't. Since we don't
4718 * want to be at the vendor's whim on the default, we set
4719 * it explicitly here.
4721 #if !defined(_ALPHA_) && !defined(__GNUC__)
4722 _control87(MCW_EM, MCW_EM);
4726 module = GetModuleHandle("ntdll.dll");
4728 *(FARPROC*)&pfnZwQuerySystemInformation = GetProcAddress(module, "ZwQuerySystemInformation");
4731 module = GetModuleHandle("kernel32.dll");
4733 *(FARPROC*)&pfnCreateToolhelp32Snapshot = GetProcAddress(module, "CreateToolhelp32Snapshot");
4734 *(FARPROC*)&pfnProcess32First = GetProcAddress(module, "Process32First");
4735 *(FARPROC*)&pfnProcess32Next = GetProcAddress(module, "Process32Next");
4740 Perl_win32_term(void)
4750 win32_get_child_IO(child_IO_table* ptbl)
4752 ptbl->childStdIn = GetStdHandle(STD_INPUT_HANDLE);
4753 ptbl->childStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
4754 ptbl->childStdErr = GetStdHandle(STD_ERROR_HANDLE);
4758 win32_signal(int sig, Sighandler_t subcode)
4761 if (sig < SIG_SIZE) {
4762 int save_errno = errno;
4763 Sighandler_t result = signal(sig, subcode);
4764 if (result == SIG_ERR) {
4765 result = w32_sighandler[sig];
4768 w32_sighandler[sig] = subcode;
4778 #ifdef HAVE_INTERP_INTERN
4782 win32_csighandler(int sig)
4785 dTHXa(PERL_GET_SIG_CONTEXT);
4786 Perl_warn(aTHX_ "Got signal %d",sig);
4792 win32_create_message_window()
4794 /* "message-only" windows have been implemented in Windows 2000 and later.
4795 * On earlier versions we'll continue to post messages to a specific
4796 * thread and use hwnd==NULL. This is brittle when either an embedding
4797 * application or an XS module is also posting messages to hwnd=NULL
4798 * because once removed from the queue they cannot be delivered to the
4799 * "right" place with DispatchMessage() anymore, as there is no WindowProc
4800 * if there is no window handle.
4802 if (g_osver.dwMajorVersion < 5)
4805 return CreateWindow("Static", "", 0, 0, 0, 0, 0, HWND_MESSAGE, 0, 0, NULL);
4808 #if defined(__MINGW32__) && defined(__cplusplus)
4809 #define CAST_HWND__(x) (HWND__*)(x)
4811 #define CAST_HWND__(x) x
4815 Perl_sys_intern_init(pTHX)
4819 if (g_osver.dwOSVersionInfoSize == 0) {
4820 g_osver.dwOSVersionInfoSize = sizeof(g_osver);
4821 GetVersionEx(&g_osver);
4824 w32_perlshell_tokens = Nullch;
4825 w32_perlshell_vec = (char**)NULL;
4826 w32_perlshell_items = 0;
4827 w32_fdpid = newAV();
4828 Newx(w32_children, 1, child_tab);
4829 w32_num_children = 0;
4830 # ifdef USE_ITHREADS
4832 Newx(w32_pseudo_children, 1, pseudo_child_tab);
4833 w32_num_pseudo_children = 0;
4836 w32_message_hwnd = CAST_HWND__(INVALID_HANDLE_VALUE);
4838 for (i=0; i < SIG_SIZE; i++) {
4839 w32_sighandler[i] = SIG_DFL;
4842 if (my_perl == PL_curinterp) {
4846 /* Force C runtime signal stuff to set its console handler */
4847 signal(SIGINT,win32_csighandler);
4848 signal(SIGBREAK,win32_csighandler);
4849 /* Push our handler on top */
4850 SetConsoleCtrlHandler(win32_ctrlhandler,TRUE);
4855 Perl_sys_intern_clear(pTHX)
4857 Safefree(w32_perlshell_tokens);
4858 Safefree(w32_perlshell_vec);
4859 /* NOTE: w32_fdpid is freed by sv_clean_all() */
4860 Safefree(w32_children);
4862 KillTimer(w32_message_hwnd, w32_timerid);
4865 if (w32_message_hwnd != NULL && w32_message_hwnd != INVALID_HANDLE_VALUE)
4866 DestroyWindow(w32_message_hwnd);
4867 # ifdef MULTIPLICITY
4868 if (my_perl == PL_curinterp) {
4872 SetConsoleCtrlHandler(win32_ctrlhandler,FALSE);
4874 # ifdef USE_ITHREADS
4875 Safefree(w32_pseudo_children);
4879 # ifdef USE_ITHREADS
4882 Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
4884 dst->perlshell_tokens = Nullch;
4885 dst->perlshell_vec = (char**)NULL;
4886 dst->perlshell_items = 0;
4887 dst->fdpid = newAV();
4888 Newxz(dst->children, 1, child_tab);
4890 Newxz(dst->pseudo_children, 1, pseudo_child_tab);
4892 dst->message_hwnd = CAST_HWND__(INVALID_HANDLE_VALUE);
4893 dst->poll_count = 0;
4894 Copy(src->sigtable,dst->sigtable,SIG_SIZE,Sighandler_t);
4896 # endif /* USE_ITHREADS */
4897 #endif /* HAVE_INTERP_INTERN */
4900 win32_free_argvw(pTHX_ void *ptr)
4902 char** argv = (char**)ptr;
4910 win32_argv2utf8(int argc, char** argv)
4915 LPWSTR* lpwStr = CommandLineToArgvW(GetCommandLineW(), &wargc);
4916 if (lpwStr && argc) {
4918 length = WideCharToMultiByte(CP_UTF8, 0, lpwStr[--wargc], -1, NULL, 0, NULL, NULL);
4919 Newxz(psz, length, char);
4920 WideCharToMultiByte(CP_UTF8, 0, lpwStr[wargc], -1, psz, length, NULL, NULL);
4923 call_atexit(win32_free_argvw, argv);
4925 GlobalFree((HGLOBAL)lpwStr);