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);
1621 /* Can't use PerlIO to write as it allocates memory */
1622 PerlLIO_write(PerlIO_fileno(Perl_error_log),
1623 PL_no_mem, strlen(PL_no_mem));
1629 /* The win32_ansipath() function takes a Unicode filename and converts it
1630 * into the current Windows codepage. If some characters cannot be mapped,
1631 * then it will convert the short name instead.
1633 * The buffer to the ansi pathname must be freed with win32_free() when it
1634 * it no longer needed.
1636 * The argument to win32_ansipath() must exist before this function is
1637 * called; otherwise there is no way to determine the short path name.
1639 * Ideas for future refinement:
1640 * - Only convert those segments of the path that are not in the current
1641 * codepage, but leave the other segments in their long form.
1642 * - If the resulting name is longer than MAX_PATH, start converting
1643 * additional path segments into short names until the full name
1644 * is shorter than MAX_PATH. Shorten the filename part last!
1647 win32_ansipath(const WCHAR *widename)
1650 BOOL use_default = FALSE;
1651 size_t widelen = wcslen(widename)+1;
1652 int len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, widename, widelen,
1653 NULL, 0, NULL, NULL);
1654 name = win32_malloc(len);
1658 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, widename, widelen,
1659 name, len, NULL, &use_default);
1661 DWORD shortlen = GetShortPathNameW(widename, NULL, 0);
1663 WCHAR *shortname = win32_malloc(shortlen*sizeof(WCHAR));
1666 shortlen = GetShortPathNameW(widename, shortname, shortlen)+1;
1668 len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, shortname, shortlen,
1669 NULL, 0, NULL, NULL);
1670 name = win32_realloc(name, len);
1673 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, shortname, shortlen,
1674 name, len, NULL, NULL);
1675 win32_free(shortname);
1682 win32_getenv(const char *name)
1686 SV *curitem = Nullsv;
1688 needlen = GetEnvironmentVariableA(name,NULL,0);
1690 curitem = sv_2mortal(newSVpvn("", 0));
1692 SvGROW(curitem, needlen+1);
1693 needlen = GetEnvironmentVariableA(name,SvPVX(curitem),
1695 } while (needlen >= SvLEN(curitem));
1696 SvCUR_set(curitem, needlen);
1699 /* allow any environment variables that begin with 'PERL'
1700 to be stored in the registry */
1701 if (strncmp(name, "PERL", 4) == 0)
1702 (void)get_regstr(name, &curitem);
1704 if (curitem && SvCUR(curitem))
1705 return SvPVX(curitem);
1711 win32_putenv(const char *name)
1719 Newx(curitem,strlen(name)+1,char);
1720 strcpy(curitem, name);
1721 val = strchr(curitem, '=');
1723 /* The sane way to deal with the environment.
1724 * Has these advantages over putenv() & co.:
1725 * * enables us to store a truly empty value in the
1726 * environment (like in UNIX).
1727 * * we don't have to deal with RTL globals, bugs and leaks.
1729 * Why you may want to enable USE_WIN32_RTL_ENV:
1730 * * environ[] and RTL functions will not reflect changes,
1731 * which might be an issue if extensions want to access
1732 * the env. via RTL. This cuts both ways, since RTL will
1733 * not see changes made by extensions that call the Win32
1734 * functions directly, either.
1738 if (SetEnvironmentVariableA(curitem, *val ? val : NULL))
1747 filetime_to_clock(PFILETIME ft)
1749 __int64 qw = ft->dwHighDateTime;
1751 qw |= ft->dwLowDateTime;
1752 qw /= 10000; /* File time ticks at 0.1uS, clock at 1mS */
1757 win32_times(struct tms *timebuf)
1762 clock_t process_time_so_far = clock();
1763 if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy,
1765 timebuf->tms_utime = filetime_to_clock(&user);
1766 timebuf->tms_stime = filetime_to_clock(&kernel);
1767 timebuf->tms_cutime = 0;
1768 timebuf->tms_cstime = 0;
1770 /* That failed - e.g. Win95 fallback to clock() */
1771 timebuf->tms_utime = process_time_so_far;
1772 timebuf->tms_stime = 0;
1773 timebuf->tms_cutime = 0;
1774 timebuf->tms_cstime = 0;
1776 return process_time_so_far;
1779 /* fix utime() so it works on directories in NT */
1781 filetime_from_time(PFILETIME pFileTime, time_t Time)
1783 struct tm *pTM = localtime(&Time);
1784 SYSTEMTIME SystemTime;
1790 SystemTime.wYear = pTM->tm_year + 1900;
1791 SystemTime.wMonth = pTM->tm_mon + 1;
1792 SystemTime.wDay = pTM->tm_mday;
1793 SystemTime.wHour = pTM->tm_hour;
1794 SystemTime.wMinute = pTM->tm_min;
1795 SystemTime.wSecond = pTM->tm_sec;
1796 SystemTime.wMilliseconds = 0;
1798 return SystemTimeToFileTime(&SystemTime, &LocalTime) &&
1799 LocalFileTimeToFileTime(&LocalTime, pFileTime);
1803 win32_unlink(const char *filename)
1809 filename = PerlDir_mapA(filename);
1810 attrs = GetFileAttributesA(filename);
1811 if (attrs == 0xFFFFFFFF) {
1815 if (attrs & FILE_ATTRIBUTE_READONLY) {
1816 (void)SetFileAttributesA(filename, attrs & ~FILE_ATTRIBUTE_READONLY);
1817 ret = unlink(filename);
1819 (void)SetFileAttributesA(filename, attrs);
1822 ret = unlink(filename);
1827 win32_utime(const char *filename, struct utimbuf *times)
1834 struct utimbuf TimeBuffer;
1837 filename = PerlDir_mapA(filename);
1838 rc = utime(filename, times);
1840 /* EACCES: path specifies directory or readonly file */
1841 if (rc == 0 || errno != EACCES /* || !IsWinNT() */)
1844 if (times == NULL) {
1845 times = &TimeBuffer;
1846 time(×->actime);
1847 times->modtime = times->actime;
1850 /* This will (and should) still fail on readonly files */
1851 handle = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE,
1852 FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
1853 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1854 if (handle == INVALID_HANDLE_VALUE)
1857 if (GetFileTime(handle, &ftCreate, &ftAccess, &ftWrite) &&
1858 filetime_from_time(&ftAccess, times->actime) &&
1859 filetime_from_time(&ftWrite, times->modtime) &&
1860 SetFileTime(handle, &ftCreate, &ftAccess, &ftWrite))
1865 CloseHandle(handle);
1870 unsigned __int64 ft_i64;
1875 #define Const64(x) x##LL
1877 #define Const64(x) x##i64
1879 /* Number of 100 nanosecond units from 1/1/1601 to 1/1/1970 */
1880 #define EPOCH_BIAS Const64(116444736000000000)
1882 /* NOTE: This does not compute the timezone info (doing so can be expensive,
1883 * and appears to be unsupported even by glibc) */
1885 win32_gettimeofday(struct timeval *tp, void *not_used)
1889 /* this returns time in 100-nanosecond units (i.e. tens of usecs) */
1890 GetSystemTimeAsFileTime(&ft.ft_val);
1892 /* seconds since epoch */
1893 tp->tv_sec = (long)((ft.ft_i64 - EPOCH_BIAS) / Const64(10000000));
1895 /* microseconds remaining */
1896 tp->tv_usec = (long)((ft.ft_i64 / Const64(10)) % Const64(1000000));
1902 win32_uname(struct utsname *name)
1904 struct hostent *hep;
1905 STRLEN nodemax = sizeof(name->nodename)-1;
1908 switch (g_osver.dwPlatformId) {
1909 case VER_PLATFORM_WIN32_WINDOWS:
1910 strcpy(name->sysname, "Windows");
1912 case VER_PLATFORM_WIN32_NT:
1913 strcpy(name->sysname, "Windows NT");
1915 case VER_PLATFORM_WIN32s:
1916 strcpy(name->sysname, "Win32s");
1919 strcpy(name->sysname, "Win32 Unknown");
1924 sprintf(name->release, "%d.%d",
1925 g_osver.dwMajorVersion, g_osver.dwMinorVersion);
1928 sprintf(name->version, "Build %d",
1929 g_osver.dwPlatformId == VER_PLATFORM_WIN32_NT
1930 ? g_osver.dwBuildNumber : (g_osver.dwBuildNumber & 0xffff));
1931 if (g_osver.szCSDVersion[0]) {
1932 char *buf = name->version + strlen(name->version);
1933 sprintf(buf, " (%s)", g_osver.szCSDVersion);
1937 hep = win32_gethostbyname("localhost");
1939 STRLEN len = strlen(hep->h_name);
1940 if (len <= nodemax) {
1941 strcpy(name->nodename, hep->h_name);
1944 strncpy(name->nodename, hep->h_name, nodemax);
1945 name->nodename[nodemax] = '\0';
1950 if (!GetComputerName(name->nodename, &sz))
1951 *name->nodename = '\0';
1954 /* machine (architecture) */
1959 GetSystemInfo(&info);
1961 #if (defined(__BORLANDC__)&&(__BORLANDC__<=0x520)) \
1962 || (defined(__MINGW32__) && !defined(_ANONYMOUS_UNION))
1963 procarch = info.u.s.wProcessorArchitecture;
1965 procarch = info.wProcessorArchitecture;
1968 case PROCESSOR_ARCHITECTURE_INTEL:
1969 arch = "x86"; break;
1970 case PROCESSOR_ARCHITECTURE_MIPS:
1971 arch = "mips"; break;
1972 case PROCESSOR_ARCHITECTURE_ALPHA:
1973 arch = "alpha"; break;
1974 case PROCESSOR_ARCHITECTURE_PPC:
1975 arch = "ppc"; break;
1976 #ifdef PROCESSOR_ARCHITECTURE_SHX
1977 case PROCESSOR_ARCHITECTURE_SHX:
1978 arch = "shx"; break;
1980 #ifdef PROCESSOR_ARCHITECTURE_ARM
1981 case PROCESSOR_ARCHITECTURE_ARM:
1982 arch = "arm"; break;
1984 #ifdef PROCESSOR_ARCHITECTURE_IA64
1985 case PROCESSOR_ARCHITECTURE_IA64:
1986 arch = "ia64"; break;
1988 #ifdef PROCESSOR_ARCHITECTURE_ALPHA64
1989 case PROCESSOR_ARCHITECTURE_ALPHA64:
1990 arch = "alpha64"; break;
1992 #ifdef PROCESSOR_ARCHITECTURE_MSIL
1993 case PROCESSOR_ARCHITECTURE_MSIL:
1994 arch = "msil"; break;
1996 #ifdef PROCESSOR_ARCHITECTURE_AMD64
1997 case PROCESSOR_ARCHITECTURE_AMD64:
1998 arch = "amd64"; break;
2000 #ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
2001 case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
2002 arch = "ia32-64"; break;
2004 #ifdef PROCESSOR_ARCHITECTURE_UNKNOWN
2005 case PROCESSOR_ARCHITECTURE_UNKNOWN:
2006 arch = "unknown"; break;
2009 sprintf(name->machine, "unknown(0x%x)", procarch);
2010 arch = name->machine;
2013 if (name->machine != arch)
2014 strcpy(name->machine, arch);
2019 /* Timing related stuff */
2022 do_raise(pTHX_ int sig)
2024 if (sig < SIG_SIZE) {
2025 Sighandler_t handler = w32_sighandler[sig];
2026 if (handler == SIG_IGN) {
2029 else if (handler != SIG_DFL) {
2034 /* Choose correct default behaviour */
2050 /* Tell caller to exit thread/process as approriate */
2055 sig_terminate(pTHX_ int sig)
2057 Perl_warn(aTHX_ "Terminating on signal SIG%s(%d)\n",PL_sig_name[sig], sig);
2058 /* exit() seems to be safe, my_exit() or die() is a problem in ^C
2065 win32_async_check(pTHX)
2068 HWND hwnd = w32_message_hwnd;
2072 if (hwnd == INVALID_HANDLE_VALUE) {
2073 /* Call PeekMessage() to mark all pending messages in the queue as "old".
2074 * This is necessary when we are being called by win32_msgwait() to
2075 * make sure MsgWaitForMultipleObjects() stops reporting the same waiting
2076 * message over and over. An example how this can happen is when
2077 * Perl is calling win32_waitpid() inside a GUI application and the GUI
2078 * is generating messages before the process terminated.
2080 PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE|PM_NOYIELD);
2086 /* Passing PeekMessage -1 as HWND (2nd arg) only get PostThreadMessage() messages
2087 * and ignores window messages - should co-exist better with windows apps e.g. Tk
2092 while (PeekMessage(&msg, hwnd, WM_TIMER, WM_TIMER, PM_REMOVE|PM_NOYIELD) ||
2093 PeekMessage(&msg, hwnd, WM_USER_MIN, WM_USER_MAX, PM_REMOVE|PM_NOYIELD))
2095 switch (msg.message) {
2097 case WM_USER_MESSAGE: {
2098 int child = find_pseudo_pid(msg.wParam);
2100 w32_pseudo_child_message_hwnds[child] = (HWND)msg.lParam;
2105 case WM_USER_KILL: {
2106 /* We use WM_USER to fake kill() with other signals */
2107 int sig = msg.wParam;
2108 if (do_raise(aTHX_ sig))
2109 sig_terminate(aTHX_ sig);
2114 /* alarm() is a one-shot but SetTimer() repeats so kill it */
2115 if (w32_timerid && w32_timerid==msg.wParam) {
2116 KillTimer(w32_message_hwnd, w32_timerid);
2119 /* Now fake a call to signal handler */
2120 if (do_raise(aTHX_ 14))
2121 sig_terminate(aTHX_ 14);
2128 /* Above or other stuff may have set a signal flag */
2129 if (PL_sig_pending) {
2135 /* This function will not return until the timeout has elapsed, or until
2136 * one of the handles is ready. */
2138 win32_msgwait(pTHX_ DWORD count, LPHANDLE handles, DWORD timeout, LPDWORD resultp)
2140 /* We may need several goes at this - so compute when we stop */
2142 if (timeout != INFINITE) {
2143 ticks = GetTickCount();
2147 DWORD result = MsgWaitForMultipleObjects(count,handles,FALSE,timeout-ticks, QS_ALLEVENTS);
2150 if (result == WAIT_TIMEOUT) {
2151 /* Ran out of time - explicit return of zero to avoid -ve if we
2152 have scheduling issues
2156 if (timeout != INFINITE) {
2157 ticks = GetTickCount();
2159 if (result == WAIT_OBJECT_0 + count) {
2160 /* Message has arrived - check it */
2161 (void)win32_async_check(aTHX);
2164 /* Not timeout or message - one of handles is ready */
2168 /* compute time left to wait */
2169 ticks = timeout - ticks;
2170 /* If we are past the end say zero */
2171 return (ticks > 0) ? ticks : 0;
2175 win32_internal_wait(int *status, DWORD timeout)
2177 /* XXX this wait emulation only knows about processes
2178 * spawned via win32_spawnvp(P_NOWAIT, ...).
2182 DWORD exitcode, waitcode;
2185 if (w32_num_pseudo_children) {
2186 win32_msgwait(aTHX_ w32_num_pseudo_children, w32_pseudo_child_handles,
2187 timeout, &waitcode);
2188 /* Time out here if there are no other children to wait for. */
2189 if (waitcode == WAIT_TIMEOUT) {
2190 if (!w32_num_children) {
2194 else if (waitcode != WAIT_FAILED) {
2195 if (waitcode >= WAIT_ABANDONED_0
2196 && waitcode < WAIT_ABANDONED_0 + w32_num_pseudo_children)
2197 i = waitcode - WAIT_ABANDONED_0;
2199 i = waitcode - WAIT_OBJECT_0;
2200 if (GetExitCodeThread(w32_pseudo_child_handles[i], &exitcode)) {
2201 *status = (int)((exitcode & 0xff) << 8);
2202 retval = (int)w32_pseudo_child_pids[i];
2203 remove_dead_pseudo_process(i);
2210 if (!w32_num_children) {
2215 /* if a child exists, wait for it to die */
2216 win32_msgwait(aTHX_ w32_num_children, w32_child_handles, timeout, &waitcode);
2217 if (waitcode == WAIT_TIMEOUT) {
2220 if (waitcode != WAIT_FAILED) {
2221 if (waitcode >= WAIT_ABANDONED_0
2222 && waitcode < WAIT_ABANDONED_0 + w32_num_children)
2223 i = waitcode - WAIT_ABANDONED_0;
2225 i = waitcode - WAIT_OBJECT_0;
2226 if (GetExitCodeProcess(w32_child_handles[i], &exitcode) ) {
2227 *status = (int)((exitcode & 0xff) << 8);
2228 retval = (int)w32_child_pids[i];
2229 remove_dead_process(i);
2234 errno = GetLastError();
2239 win32_waitpid(int pid, int *status, int flags)
2242 DWORD timeout = (flags & WNOHANG) ? 0 : INFINITE;
2245 if (pid == -1) /* XXX threadid == 1 ? */
2246 return win32_internal_wait(status, timeout);
2249 child = find_pseudo_pid(-pid);
2251 HANDLE hThread = w32_pseudo_child_handles[child];
2253 win32_msgwait(aTHX_ 1, &hThread, timeout, &waitcode);
2254 if (waitcode == WAIT_TIMEOUT) {
2257 else if (waitcode == WAIT_OBJECT_0) {
2258 if (GetExitCodeThread(hThread, &waitcode)) {
2259 *status = (int)((waitcode & 0xff) << 8);
2260 retval = (int)w32_pseudo_child_pids[child];
2261 remove_dead_pseudo_process(child);
2268 else if (IsWin95()) {
2277 child = find_pid(pid);
2279 hProcess = w32_child_handles[child];
2280 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
2281 if (waitcode == WAIT_TIMEOUT) {
2284 else if (waitcode == WAIT_OBJECT_0) {
2285 if (GetExitCodeProcess(hProcess, &waitcode)) {
2286 *status = (int)((waitcode & 0xff) << 8);
2287 retval = (int)w32_child_pids[child];
2288 remove_dead_process(child);
2297 hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE,
2298 (IsWin95() ? -pid : pid));
2300 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
2301 if (waitcode == WAIT_TIMEOUT) {
2302 CloseHandle(hProcess);
2305 else if (waitcode == WAIT_OBJECT_0) {
2306 if (GetExitCodeProcess(hProcess, &waitcode)) {
2307 *status = (int)((waitcode & 0xff) << 8);
2308 CloseHandle(hProcess);
2312 CloseHandle(hProcess);
2318 return retval >= 0 ? pid : retval;
2322 win32_wait(int *status)
2324 return win32_internal_wait(status, INFINITE);
2327 DllExport unsigned int
2328 win32_sleep(unsigned int t)
2331 /* Win32 times are in ms so *1000 in and /1000 out */
2332 return win32_msgwait(aTHX_ 0, NULL, t*1000, NULL)/1000;
2335 DllExport unsigned int
2336 win32_alarm(unsigned int sec)
2339 * the 'obvious' implentation is SetTimer() with a callback
2340 * which does whatever receiving SIGALRM would do
2341 * we cannot use SIGALRM even via raise() as it is not
2342 * one of the supported codes in <signal.h>
2346 if (w32_message_hwnd == INVALID_HANDLE_VALUE)
2347 w32_message_hwnd = win32_create_message_window();
2350 if (w32_message_hwnd == NULL)
2351 w32_timerid = SetTimer(NULL, w32_timerid, sec*1000, NULL);
2354 SetTimer(w32_message_hwnd, w32_timerid, sec*1000, NULL);
2359 KillTimer(w32_message_hwnd, w32_timerid);
2366 #ifdef HAVE_DES_FCRYPT
2367 extern char * des_fcrypt(const char *txt, const char *salt, char *cbuf);
2371 win32_crypt(const char *txt, const char *salt)
2374 #ifdef HAVE_DES_FCRYPT
2375 return des_fcrypt(txt, salt, w32_crypt_buffer);
2377 Perl_croak(aTHX_ "The crypt() function is unimplemented due to excessive paranoia.");
2382 #ifdef USE_FIXED_OSFHANDLE
2384 #define FOPEN 0x01 /* file handle open */
2385 #define FNOINHERIT 0x10 /* file handle opened O_NOINHERIT */
2386 #define FAPPEND 0x20 /* file handle opened O_APPEND */
2387 #define FDEV 0x40 /* file handle refers to device */
2388 #define FTEXT 0x80 /* file handle is in text mode */
2391 *int my_open_osfhandle(intptr_t osfhandle, int flags) - open C Runtime file handle
2394 * This function allocates a free C Runtime file handle and associates
2395 * it with the Win32 HANDLE specified by the first parameter. This is a
2396 * temperary fix for WIN95's brain damage GetFileType() error on socket
2397 * we just bypass that call for socket
2399 * This works with MSVC++ 4.0+ or GCC/Mingw32
2402 * intptr_t osfhandle - Win32 HANDLE to associate with C Runtime file handle.
2403 * int flags - flags to associate with C Runtime file handle.
2406 * returns index of entry in fh, if successful
2407 * return -1, if no free entry is found
2411 *******************************************************************************/
2414 * we fake up some parts of the CRT that aren't exported by MSVCRT.dll
2415 * this lets sockets work on Win9X with GCC and should fix the problems
2420 /* create an ioinfo entry, kill its handle, and steal the entry */
2425 HANDLE hF = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
2426 int fh = _open_osfhandle((intptr_t)hF, 0);
2430 EnterCriticalSection(&(_pioinfo(fh)->lock));
2435 my_open_osfhandle(intptr_t osfhandle, int flags)
2438 char fileflags; /* _osfile flags */
2440 /* copy relevant flags from second parameter */
2443 if (flags & O_APPEND)
2444 fileflags |= FAPPEND;
2449 if (flags & O_NOINHERIT)
2450 fileflags |= FNOINHERIT;
2452 /* attempt to allocate a C Runtime file handle */
2453 if ((fh = _alloc_osfhnd()) == -1) {
2454 errno = EMFILE; /* too many open files */
2455 _doserrno = 0L; /* not an OS error */
2456 return -1; /* return error to caller */
2459 /* the file is open. now, set the info in _osfhnd array */
2460 _set_osfhnd(fh, osfhandle);
2462 fileflags |= FOPEN; /* mark as open */
2464 _osfile(fh) = fileflags; /* set osfile entry */
2465 LeaveCriticalSection(&_pioinfo(fh)->lock);
2467 return fh; /* return handle */
2470 #endif /* USE_FIXED_OSFHANDLE */
2472 /* simulate flock by locking a range on the file */
2474 #define LK_ERR(f,i) ((f) ? (i = 0) : (errno = GetLastError()))
2475 #define LK_LEN 0xffff0000
2478 win32_flock(int fd, int oper)
2486 Perl_croak_nocontext("flock() unimplemented on this platform");
2489 fh = (HANDLE)_get_osfhandle(fd);
2490 memset(&o, 0, sizeof(o));
2493 case LOCK_SH: /* shared lock */
2494 LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, 0, &o),i);
2496 case LOCK_EX: /* exclusive lock */
2497 LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o),i);
2499 case LOCK_SH|LOCK_NB: /* non-blocking shared lock */
2500 LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o),i);
2502 case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */
2503 LK_ERR(LockFileEx(fh,
2504 LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
2505 0, LK_LEN, 0, &o),i);
2507 case LOCK_UN: /* unlock lock */
2508 LK_ERR(UnlockFileEx(fh, 0, LK_LEN, 0, &o),i);
2510 default: /* unknown */
2521 * redirected io subsystem for all XS modules
2534 return (&(_environ));
2537 /* the rest are the remapped stdio routines */
2557 win32_ferror(FILE *fp)
2559 return (ferror(fp));
2564 win32_feof(FILE *fp)
2570 * Since the errors returned by the socket error function
2571 * WSAGetLastError() are not known by the library routine strerror
2572 * we have to roll our own.
2576 win32_strerror(int e)
2578 #if !defined __BORLANDC__ && !defined __MINGW32__ /* compiler intolerance */
2579 extern int sys_nerr;
2583 if (e < 0 || e > sys_nerr) {
2588 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0,
2589 w32_strerror_buffer,
2590 sizeof(w32_strerror_buffer), NULL) == 0)
2591 strcpy(w32_strerror_buffer, "Unknown Error");
2593 return w32_strerror_buffer;
2599 win32_str_os_error(void *sv, DWORD dwErr)
2603 dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
2604 |FORMAT_MESSAGE_IGNORE_INSERTS
2605 |FORMAT_MESSAGE_FROM_SYSTEM, NULL,
2606 dwErr, 0, (char *)&sMsg, 1, NULL);
2607 /* strip trailing whitespace and period */
2610 --dwLen; /* dwLen doesn't include trailing null */
2611 } while (0 < dwLen && isSPACE(sMsg[dwLen]));
2612 if ('.' != sMsg[dwLen])
2617 sMsg = (char*)LocalAlloc(0, 64/**sizeof(TCHAR)*/);
2619 dwLen = sprintf(sMsg,
2620 "Unknown error #0x%lX (lookup 0x%lX)",
2621 dwErr, GetLastError());
2625 sv_setpvn((SV*)sv, sMsg, dwLen);
2631 win32_fprintf(FILE *fp, const char *format, ...)
2634 va_start(marker, format); /* Initialize variable arguments. */
2636 return (vfprintf(fp, format, marker));
2640 win32_printf(const char *format, ...)
2643 va_start(marker, format); /* Initialize variable arguments. */
2645 return (vprintf(format, marker));
2649 win32_vfprintf(FILE *fp, const char *format, va_list args)
2651 return (vfprintf(fp, format, args));
2655 win32_vprintf(const char *format, va_list args)
2657 return (vprintf(format, args));
2661 win32_fread(void *buf, size_t size, size_t count, FILE *fp)
2663 return fread(buf, size, count, fp);
2667 win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
2669 return fwrite(buf, size, count, fp);
2672 #define MODE_SIZE 10
2675 win32_fopen(const char *filename, const char *mode)
2683 if (stricmp(filename, "/dev/null")==0)
2686 f = fopen(PerlDir_mapA(filename), mode);
2687 /* avoid buffering headaches for child processes */
2688 if (f && *mode == 'a')
2689 win32_fseek(f, 0, SEEK_END);
2693 #ifndef USE_SOCKETS_AS_HANDLES
2695 #define fdopen my_fdopen
2699 win32_fdopen(int handle, const char *mode)
2703 f = fdopen(handle, (char *) mode);
2704 /* avoid buffering headaches for child processes */
2705 if (f && *mode == 'a')
2706 win32_fseek(f, 0, SEEK_END);
2711 win32_freopen(const char *path, const char *mode, FILE *stream)
2714 if (stricmp(path, "/dev/null")==0)
2717 return freopen(PerlDir_mapA(path), mode, stream);
2721 win32_fclose(FILE *pf)
2723 return my_fclose(pf); /* defined in win32sck.c */
2727 win32_fputs(const char *s,FILE *pf)
2729 return fputs(s, pf);
2733 win32_fputc(int c,FILE *pf)
2739 win32_ungetc(int c,FILE *pf)
2741 return ungetc(c,pf);
2745 win32_getc(FILE *pf)
2751 win32_fileno(FILE *pf)
2757 win32_clearerr(FILE *pf)
2764 win32_fflush(FILE *pf)
2770 win32_ftell(FILE *pf)
2772 #if defined(WIN64) || defined(USE_LARGE_FILES)
2773 #if defined(__BORLANDC__) /* buk */
2774 return win32_tell( fileno( pf ) );
2777 if (fgetpos(pf, &pos))
2787 win32_fseek(FILE *pf, Off_t offset,int origin)
2789 #if defined(WIN64) || defined(USE_LARGE_FILES)
2790 #if defined(__BORLANDC__) /* buk */
2800 if (fgetpos(pf, &pos))
2805 fseek(pf, 0, SEEK_END);
2806 pos = _telli64(fileno(pf));
2815 return fsetpos(pf, &offset);
2818 return fseek(pf, (long)offset, origin);
2823 win32_fgetpos(FILE *pf,fpos_t *p)
2825 #if defined(__BORLANDC__) && defined(USE_LARGE_FILES) /* buk */
2826 if( win32_tell(fileno(pf)) == -1L ) {
2832 return fgetpos(pf, p);
2837 win32_fsetpos(FILE *pf,const fpos_t *p)
2839 #if defined(__BORLANDC__) && defined(USE_LARGE_FILES) /* buk */
2840 return win32_lseek(fileno(pf), *p, SEEK_CUR);
2842 return fsetpos(pf, p);
2847 win32_rewind(FILE *pf)
2857 char prefix[MAX_PATH+1];
2858 char filename[MAX_PATH+1];
2859 DWORD len = GetTempPath(MAX_PATH, prefix);
2860 if (len && len < MAX_PATH) {
2861 if (GetTempFileName(prefix, "plx", 0, filename)) {
2862 HANDLE fh = CreateFile(filename,
2863 DELETE | GENERIC_READ | GENERIC_WRITE,
2867 FILE_ATTRIBUTE_NORMAL
2868 | FILE_FLAG_DELETE_ON_CLOSE,
2870 if (fh != INVALID_HANDLE_VALUE) {
2871 int fd = win32_open_osfhandle((intptr_t)fh, 0);
2873 #if defined(__BORLANDC__)
2874 setmode(fd,O_BINARY);
2876 DEBUG_p(PerlIO_printf(Perl_debug_log,
2877 "Created tmpfile=%s\n",filename));
2889 int fd = win32_tmpfd();
2891 return win32_fdopen(fd, "w+b");
2903 win32_fstat(int fd, Stat_t *sbufptr)
2906 /* A file designated by filehandle is not shown as accessible
2907 * for write operations, probably because it is opened for reading.
2910 BY_HANDLE_FILE_INFORMATION bhfi;
2911 #if defined(WIN64) || defined(USE_LARGE_FILES)
2912 /* Borland 5.5.1 has a 64-bit stat, but only a 32-bit fstat */
2914 int rc = fstat(fd,&tmp);
2916 sbufptr->st_dev = tmp.st_dev;
2917 sbufptr->st_ino = tmp.st_ino;
2918 sbufptr->st_mode = tmp.st_mode;
2919 sbufptr->st_nlink = tmp.st_nlink;
2920 sbufptr->st_uid = tmp.st_uid;
2921 sbufptr->st_gid = tmp.st_gid;
2922 sbufptr->st_rdev = tmp.st_rdev;
2923 sbufptr->st_size = tmp.st_size;
2924 sbufptr->st_atime = tmp.st_atime;
2925 sbufptr->st_mtime = tmp.st_mtime;
2926 sbufptr->st_ctime = tmp.st_ctime;
2928 int rc = fstat(fd,sbufptr);
2931 if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &bhfi)) {
2932 #if defined(WIN64) || defined(USE_LARGE_FILES)
2933 sbufptr->st_size = (bhfi.nFileSizeHigh << 32) + bhfi.nFileSizeLow ;
2935 sbufptr->st_mode &= 0xFE00;
2936 if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
2937 sbufptr->st_mode |= (S_IREAD + (S_IREAD >> 3) + (S_IREAD >> 6));
2939 sbufptr->st_mode |= ((S_IREAD|S_IWRITE) + ((S_IREAD|S_IWRITE) >> 3)
2940 + ((S_IREAD|S_IWRITE) >> 6));
2944 return my_fstat(fd,sbufptr);
2949 win32_pipe(int *pfd, unsigned int size, int mode)
2951 return _pipe(pfd, size, mode);
2955 win32_popenlist(const char *mode, IV narg, SV **args)
2958 Perl_croak(aTHX_ "List form of pipe open not implemented");
2963 * a popen() clone that respects PERL5SHELL
2965 * changed to return PerlIO* rather than FILE * by BKS, 11-11-2000
2969 win32_popen(const char *command, const char *mode)
2971 #ifdef USE_RTL_POPEN
2972 return _popen(command, mode);
2984 /* establish which ends read and write */
2985 if (strchr(mode,'w')) {
2986 stdfd = 0; /* stdin */
2989 nhandle = STD_INPUT_HANDLE;
2991 else if (strchr(mode,'r')) {
2992 stdfd = 1; /* stdout */
2995 nhandle = STD_OUTPUT_HANDLE;
3000 /* set the correct mode */
3001 if (strchr(mode,'b'))
3003 else if (strchr(mode,'t'))
3006 ourmode = _fmode & (O_TEXT | O_BINARY);
3008 /* the child doesn't inherit handles */
3009 ourmode |= O_NOINHERIT;
3011 if (win32_pipe(p, 512, ourmode) == -1)
3014 /* save the old std handle (this needs to happen before the
3015 * dup2(), since that might call SetStdHandle() too) */
3018 old_h = GetStdHandle(nhandle);
3020 /* save current stdfd */
3021 if ((oldfd = win32_dup(stdfd)) == -1)
3024 /* make stdfd go to child end of pipe (implicitly closes stdfd) */
3025 /* stdfd will be inherited by the child */
3026 if (win32_dup2(p[child], stdfd) == -1)
3029 /* close the child end in parent */
3030 win32_close(p[child]);
3032 /* set the new std handle (in case dup2() above didn't) */
3033 SetStdHandle(nhandle, (HANDLE)_get_osfhandle(stdfd));
3035 /* start the child */
3038 if ((childpid = do_spawn_nowait((char*)command)) == -1)
3041 /* revert stdfd to whatever it was before */
3042 if (win32_dup2(oldfd, stdfd) == -1)
3045 /* close saved handle */
3048 /* restore the old std handle (this needs to happen after the
3049 * dup2(), since that might call SetStdHandle() too */
3051 SetStdHandle(nhandle, old_h);
3057 sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid);
3060 /* set process id so that it can be returned by perl's open() */
3061 PL_forkprocess = childpid;
3064 /* we have an fd, return a file stream */
3065 return (PerlIO_fdopen(p[parent], (char *)mode));
3068 /* we don't need to check for errors here */
3072 win32_dup2(oldfd, stdfd);
3076 SetStdHandle(nhandle, old_h);
3082 #endif /* USE_RTL_POPEN */
3090 win32_pclose(PerlIO *pf)
3092 #ifdef USE_RTL_POPEN
3096 int childpid, status;
3100 sv = *av_fetch(w32_fdpid, PerlIO_fileno(pf), TRUE);
3103 childpid = SvIVX(sv);
3121 if (win32_waitpid(childpid, &status, 0) == -1)
3126 #endif /* USE_RTL_POPEN */
3132 LPCWSTR lpExistingFileName,
3133 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
3136 WCHAR wFullName[MAX_PATH+1];
3137 LPVOID lpContext = NULL;
3138 WIN32_STREAM_ID StreamId;
3139 DWORD dwSize = (char*)&StreamId.cStreamName - (char*)&StreamId;
3144 BOOL (__stdcall *pfnBackupWrite)(HANDLE, LPBYTE, DWORD, LPDWORD,
3145 BOOL, BOOL, LPVOID*) =
3146 (BOOL (__stdcall *)(HANDLE, LPBYTE, DWORD, LPDWORD,
3147 BOOL, BOOL, LPVOID*))
3148 GetProcAddress(GetModuleHandle("kernel32.dll"), "BackupWrite");
3149 if (pfnBackupWrite == NULL)
3152 dwLen = GetFullPathNameW(lpFileName, MAX_PATH, wFullName, NULL);
3155 dwLen = (dwLen+1)*sizeof(WCHAR);
3157 handle = CreateFileW(lpExistingFileName, FILE_WRITE_ATTRIBUTES,
3158 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
3159 NULL, OPEN_EXISTING, 0, NULL);
3160 if (handle == INVALID_HANDLE_VALUE)
3163 StreamId.dwStreamId = BACKUP_LINK;
3164 StreamId.dwStreamAttributes = 0;
3165 StreamId.dwStreamNameSize = 0;
3166 #if defined(__BORLANDC__) \
3167 ||(defined(__MINGW32__) && !defined(_ANONYMOUS_UNION))
3168 StreamId.Size.u.HighPart = 0;
3169 StreamId.Size.u.LowPart = dwLen;
3171 StreamId.Size.HighPart = 0;
3172 StreamId.Size.LowPart = dwLen;
3175 bSuccess = pfnBackupWrite(handle, (LPBYTE)&StreamId, dwSize, &dwWritten,
3176 FALSE, FALSE, &lpContext);
3178 bSuccess = pfnBackupWrite(handle, (LPBYTE)wFullName, dwLen, &dwWritten,
3179 FALSE, FALSE, &lpContext);
3180 pfnBackupWrite(handle, NULL, 0, &dwWritten, TRUE, FALSE, &lpContext);
3183 CloseHandle(handle);
3188 win32_link(const char *oldname, const char *newname)
3191 BOOL (__stdcall *pfnCreateHardLinkW)(LPCWSTR,LPCWSTR,LPSECURITY_ATTRIBUTES);
3192 WCHAR wOldName[MAX_PATH+1];
3193 WCHAR wNewName[MAX_PATH+1];
3196 Perl_croak(aTHX_ PL_no_func, "link");
3198 pfnCreateHardLinkW =
3199 (BOOL (__stdcall *)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES))
3200 GetProcAddress(GetModuleHandle("kernel32.dll"), "CreateHardLinkW");
3201 if (pfnCreateHardLinkW == NULL)
3202 pfnCreateHardLinkW = Nt4CreateHardLinkW;
3204 if (MultiByteToWideChar(CP_ACP, 0, oldname, -1, wOldName, MAX_PATH+1) &&
3205 MultiByteToWideChar(CP_ACP, 0, newname, -1, wNewName, MAX_PATH+1) &&
3206 (wcscpy(wOldName, PerlDir_mapW(wOldName)),
3207 pfnCreateHardLinkW(PerlDir_mapW(wNewName), wOldName, NULL)))
3211 errno = (GetLastError() == ERROR_FILE_NOT_FOUND) ? ENOENT : EINVAL;
3216 win32_rename(const char *oname, const char *newname)
3218 char szOldName[MAX_PATH+1];
3219 char szNewName[MAX_PATH+1];
3223 /* XXX despite what the documentation says about MoveFileEx(),
3224 * it doesn't work under Windows95!
3227 DWORD dwFlags = MOVEFILE_COPY_ALLOWED;
3228 if (stricmp(newname, oname))
3229 dwFlags |= MOVEFILE_REPLACE_EXISTING;
3230 strcpy(szOldName, PerlDir_mapA(oname));
3231 bResult = MoveFileExA(szOldName,PerlDir_mapA(newname), dwFlags);
3233 DWORD err = GetLastError();
3235 case ERROR_BAD_NET_NAME:
3236 case ERROR_BAD_NETPATH:
3237 case ERROR_BAD_PATHNAME:
3238 case ERROR_FILE_NOT_FOUND:
3239 case ERROR_FILENAME_EXCED_RANGE:
3240 case ERROR_INVALID_DRIVE:
3241 case ERROR_NO_MORE_FILES:
3242 case ERROR_PATH_NOT_FOUND:
3255 char szTmpName[MAX_PATH+1];
3256 char dname[MAX_PATH+1];
3257 char *endname = Nullch;
3259 DWORD from_attr, to_attr;
3261 strcpy(szOldName, PerlDir_mapA(oname));
3262 strcpy(szNewName, PerlDir_mapA(newname));
3264 /* if oname doesn't exist, do nothing */
3265 from_attr = GetFileAttributes(szOldName);
3266 if (from_attr == 0xFFFFFFFF) {
3271 /* if newname exists, rename it to a temporary name so that we
3272 * don't delete it in case oname happens to be the same file
3273 * (but perhaps accessed via a different path)
3275 to_attr = GetFileAttributes(szNewName);
3276 if (to_attr != 0xFFFFFFFF) {
3277 /* if newname is a directory, we fail
3278 * XXX could overcome this with yet more convoluted logic */
3279 if (to_attr & FILE_ATTRIBUTE_DIRECTORY) {
3283 tmplen = strlen(szNewName);
3284 strcpy(szTmpName,szNewName);
3285 endname = szTmpName+tmplen;
3286 for (; endname > szTmpName ; --endname) {
3287 if (*endname == '/' || *endname == '\\') {
3292 if (endname > szTmpName)
3293 endname = strcpy(dname,szTmpName);
3297 /* get a temporary filename in same directory
3298 * XXX is this really the best we can do? */
3299 if (!GetTempFileName((LPCTSTR)endname, "plr", 0, szTmpName)) {
3303 DeleteFile(szTmpName);
3305 retval = rename(szNewName, szTmpName);
3312 /* rename oname to newname */
3313 retval = rename(szOldName, szNewName);
3315 /* if we created a temporary file before ... */
3316 if (endname != Nullch) {
3317 /* ...and rename succeeded, delete temporary file/directory */
3319 DeleteFile(szTmpName);
3320 /* else restore it to what it was */
3322 (void)rename(szTmpName, szNewName);
3329 win32_setmode(int fd, int mode)
3331 return setmode(fd, mode);
3335 win32_chsize(int fd, Off_t size)
3337 #if defined(WIN64) || defined(USE_LARGE_FILES)
3339 Off_t cur, end, extend;
3341 cur = win32_tell(fd);
3344 end = win32_lseek(fd, 0, SEEK_END);
3347 extend = size - end;
3351 else if (extend > 0) {
3352 /* must grow the file, padding with nulls */
3354 int oldmode = win32_setmode(fd, O_BINARY);
3356 memset(b, '\0', sizeof(b));
3358 count = extend >= sizeof(b) ? sizeof(b) : (size_t)extend;
3359 count = win32_write(fd, b, count);
3360 if ((int)count < 0) {
3364 } while ((extend -= count) > 0);
3365 win32_setmode(fd, oldmode);
3368 /* shrink the file */
3369 win32_lseek(fd, size, SEEK_SET);
3370 if (!SetEndOfFile((HANDLE)_get_osfhandle(fd))) {
3376 win32_lseek(fd, cur, SEEK_SET);
3379 return chsize(fd, (long)size);
3384 win32_lseek(int fd, Off_t offset, int origin)
3386 #if defined(WIN64) || defined(USE_LARGE_FILES)
3387 #if defined(__BORLANDC__) /* buk */
3389 pos.QuadPart = offset;
3390 pos.LowPart = SetFilePointer(
3391 (HANDLE)_get_osfhandle(fd),
3396 if (pos.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
3400 return pos.QuadPart;
3402 return _lseeki64(fd, offset, origin);
3405 return lseek(fd, (long)offset, origin);
3412 #if defined(WIN64) || defined(USE_LARGE_FILES)
3413 #if defined(__BORLANDC__) /* buk */
3416 pos.LowPart = SetFilePointer(
3417 (HANDLE)_get_osfhandle(fd),
3422 if (pos.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
3426 return pos.QuadPart;
3427 /* return tell(fd); */
3429 return _telli64(fd);
3437 win32_open(const char *path, int flag, ...)
3444 pmode = va_arg(ap, int);
3447 if (stricmp(path, "/dev/null")==0)
3450 return open(PerlDir_mapA(path), flag, pmode);
3453 /* close() that understands socket */
3454 extern int my_close(int); /* in win32sck.c */
3459 return my_close(fd);
3475 win32_dup2(int fd1,int fd2)
3477 return dup2(fd1,fd2);
3480 #ifdef PERL_MSVCRT_READFIX
3482 #define LF 10 /* line feed */
3483 #define CR 13 /* carriage return */
3484 #define CTRLZ 26 /* ctrl-z means eof for text */
3485 #define FOPEN 0x01 /* file handle open */
3486 #define FEOFLAG 0x02 /* end of file has been encountered */
3487 #define FCRLF 0x04 /* CR-LF across read buffer (in text mode) */
3488 #define FPIPE 0x08 /* file handle refers to a pipe */
3489 #define FAPPEND 0x20 /* file handle opened O_APPEND */
3490 #define FDEV 0x40 /* file handle refers to device */
3491 #define FTEXT 0x80 /* file handle is in text mode */
3492 #define MAX_DESCRIPTOR_COUNT (64*32) /* this is the maximun that MSVCRT can handle */
3495 _fixed_read(int fh, void *buf, unsigned cnt)
3497 int bytes_read; /* number of bytes read */
3498 char *buffer; /* buffer to read to */
3499 int os_read; /* bytes read on OS call */
3500 char *p, *q; /* pointers into buffer */
3501 char peekchr; /* peek-ahead character */
3502 ULONG filepos; /* file position after seek */
3503 ULONG dosretval; /* o.s. return value */
3505 /* validate handle */
3506 if (((unsigned)fh >= (unsigned)MAX_DESCRIPTOR_COUNT) ||
3507 !(_osfile(fh) & FOPEN))
3509 /* out of range -- return error */
3511 _doserrno = 0; /* not o.s. error */
3516 * If lockinitflag is FALSE, assume fd is device
3517 * lockinitflag is set to TRUE by open.
3519 if (_pioinfo(fh)->lockinitflag)
3520 EnterCriticalSection(&(_pioinfo(fh)->lock)); /* lock file */
3522 bytes_read = 0; /* nothing read yet */
3523 buffer = (char*)buf;
3525 if (cnt == 0 || (_osfile(fh) & FEOFLAG)) {
3526 /* nothing to read or at EOF, so return 0 read */
3530 if ((_osfile(fh) & (FPIPE|FDEV)) && _pipech(fh) != LF) {
3531 /* a pipe/device and pipe lookahead non-empty: read the lookahead
3533 *buffer++ = _pipech(fh);
3536 _pipech(fh) = LF; /* mark as empty */
3541 if (!ReadFile((HANDLE)_osfhnd(fh), buffer, cnt, (LPDWORD)&os_read, NULL))
3543 /* ReadFile has reported an error. recognize two special cases.
3545 * 1. map ERROR_ACCESS_DENIED to EBADF
3547 * 2. just return 0 if ERROR_BROKEN_PIPE has occurred. it
3548 * means the handle is a read-handle on a pipe for which
3549 * all write-handles have been closed and all data has been
3552 if ((dosretval = GetLastError()) == ERROR_ACCESS_DENIED) {
3553 /* wrong read/write mode should return EBADF, not EACCES */
3555 _doserrno = dosretval;
3559 else if (dosretval == ERROR_BROKEN_PIPE) {
3569 bytes_read += os_read; /* update bytes read */
3571 if (_osfile(fh) & FTEXT) {
3572 /* now must translate CR-LFs to LFs in the buffer */
3574 /* set CRLF flag to indicate LF at beginning of buffer */
3575 /* if ((os_read != 0) && (*(char *)buf == LF)) */
3576 /* _osfile(fh) |= FCRLF; */
3578 /* _osfile(fh) &= ~FCRLF; */
3580 _osfile(fh) &= ~FCRLF;
3582 /* convert chars in the buffer: p is src, q is dest */
3584 while (p < (char *)buf + bytes_read) {
3586 /* if fh is not a device, set ctrl-z flag */
3587 if (!(_osfile(fh) & FDEV))
3588 _osfile(fh) |= FEOFLAG;
3589 break; /* stop translating */
3594 /* *p is CR, so must check next char for LF */
3595 if (p < (char *)buf + bytes_read - 1) {
3598 *q++ = LF; /* convert CR-LF to LF */
3601 *q++ = *p++; /* store char normally */
3604 /* This is the hard part. We found a CR at end of
3605 buffer. We must peek ahead to see if next char
3610 if (!ReadFile((HANDLE)_osfhnd(fh), &peekchr, 1,
3611 (LPDWORD)&os_read, NULL))
3612 dosretval = GetLastError();
3614 if (dosretval != 0 || os_read == 0) {
3615 /* couldn't read ahead, store CR */
3619 /* peekchr now has the extra character -- we now
3620 have several possibilities:
3621 1. disk file and char is not LF; just seek back
3623 2. disk file and char is LF; store LF, don't seek back
3624 3. pipe/device and char is LF; store LF.
3625 4. pipe/device and char isn't LF, store CR and
3626 put char in pipe lookahead buffer. */
3627 if (_osfile(fh) & (FDEV|FPIPE)) {
3628 /* non-seekable device */
3633 _pipech(fh) = peekchr;
3638 if (peekchr == LF) {
3639 /* nothing read yet; must make some
3642 /* turn on this flag for tell routine */
3643 _osfile(fh) |= FCRLF;
3646 HANDLE osHandle; /* o.s. handle value */
3648 if ((osHandle = (HANDLE)_get_osfhandle(fh)) != (HANDLE)-1)
3650 if ((filepos = SetFilePointer(osHandle, -1, NULL, FILE_CURRENT)) == -1)
3651 dosretval = GetLastError();
3662 /* we now change bytes_read to reflect the true number of chars
3664 bytes_read = q - (char *)buf;
3668 if (_pioinfo(fh)->lockinitflag)
3669 LeaveCriticalSection(&(_pioinfo(fh)->lock)); /* unlock file */
3674 #endif /* PERL_MSVCRT_READFIX */
3677 win32_read(int fd, void *buf, unsigned int cnt)
3679 #ifdef PERL_MSVCRT_READFIX
3680 return _fixed_read(fd, buf, cnt);
3682 return read(fd, buf, cnt);
3687 win32_write(int fd, const void *buf, unsigned int cnt)
3689 return write(fd, buf, cnt);
3693 win32_mkdir(const char *dir, int mode)
3696 return mkdir(PerlDir_mapA(dir)); /* just ignore mode */
3700 win32_rmdir(const char *dir)
3703 return rmdir(PerlDir_mapA(dir));
3707 win32_chdir(const char *dir)
3718 win32_access(const char *path, int mode)
3721 return access(PerlDir_mapA(path), mode);
3725 win32_chmod(const char *path, int mode)
3728 return chmod(PerlDir_mapA(path), mode);
3733 create_command_line(char *cname, STRLEN clen, const char * const *args)
3740 bool bat_file = FALSE;
3741 bool cmd_shell = FALSE;
3742 bool dumb_shell = FALSE;
3743 bool extra_quotes = FALSE;
3744 bool quote_next = FALSE;
3747 cname = (char*)args[0];
3749 /* The NT cmd.exe shell has the following peculiarity that needs to be
3750 * worked around. It strips a leading and trailing dquote when any
3751 * of the following is true:
3752 * 1. the /S switch was used
3753 * 2. there are more than two dquotes
3754 * 3. there is a special character from this set: &<>()@^|
3755 * 4. no whitespace characters within the two dquotes
3756 * 5. string between two dquotes isn't an executable file
3757 * To work around this, we always add a leading and trailing dquote
3758 * to the string, if the first argument is either "cmd.exe" or "cmd",
3759 * and there were at least two or more arguments passed to cmd.exe
3760 * (not including switches).
3761 * XXX the above rules (from "cmd /?") don't seem to be applied
3762 * always, making for the convolutions below :-(
3766 clen = strlen(cname);
3769 && (stricmp(&cname[clen-4], ".bat") == 0
3770 || (IsWinNT() && stricmp(&cname[clen-4], ".cmd") == 0)))
3777 char *exe = strrchr(cname, '/');
3778 char *exe2 = strrchr(cname, '\\');
3785 if (stricmp(exe, "cmd.exe") == 0 || stricmp(exe, "cmd") == 0) {
3789 else if (stricmp(exe, "command.com") == 0
3790 || stricmp(exe, "command") == 0)
3797 DEBUG_p(PerlIO_printf(Perl_debug_log, "Args "));
3798 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3799 STRLEN curlen = strlen(arg);
3800 if (!(arg[0] == '"' && arg[curlen-1] == '"'))
3801 len += 2; /* assume quoting needed (worst case) */
3803 DEBUG_p(PerlIO_printf(Perl_debug_log, "[%s]",arg));
3805 DEBUG_p(PerlIO_printf(Perl_debug_log, "\n"));
3808 Newx(cmd, len, char);
3811 if (bat_file && !IsWin95()) {
3813 extra_quotes = TRUE;
3816 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3818 STRLEN curlen = strlen(arg);
3820 /* we want to protect empty arguments and ones with spaces with
3821 * dquotes, but only if they aren't already there */
3826 else if (quote_next) {
3827 /* see if it really is multiple arguments pretending to
3828 * be one and force a set of quotes around it */
3829 if (*find_next_space(arg))
3832 else if (!(arg[0] == '"' && curlen > 1 && arg[curlen-1] == '"')) {
3834 while (i < curlen) {
3835 if (isSPACE(arg[i])) {
3838 else if (arg[i] == '"') {
3862 && *arg == '/' /* see if arg is "/c", "/x/c", "/x/d/c" etc. */
3863 && stricmp(arg+curlen-2, "/c") == 0)
3865 /* is there a next argument? */
3866 if (args[index+1]) {
3867 /* are there two or more next arguments? */
3868 if (args[index+2]) {
3870 extra_quotes = TRUE;
3873 /* single argument, force quoting if it has spaces */
3889 qualified_path(const char *cmd)
3893 char *fullcmd, *curfullcmd;
3899 fullcmd = (char*)cmd;
3901 if (*fullcmd == '/' || *fullcmd == '\\')
3908 pathstr = PerlEnv_getenv("PATH");
3910 /* worst case: PATH is a single directory; we need additional space
3911 * to append "/", ".exe" and trailing "\0" */
3912 Newx(fullcmd, (pathstr ? strlen(pathstr) : 0) + cmdlen + 6, char);
3913 curfullcmd = fullcmd;
3918 /* start by appending the name to the current prefix */
3919 strcpy(curfullcmd, cmd);
3920 curfullcmd += cmdlen;
3922 /* if it doesn't end with '.', or has no extension, try adding
3923 * a trailing .exe first */
3924 if (cmd[cmdlen-1] != '.'
3925 && (cmdlen < 4 || cmd[cmdlen-4] != '.'))
3927 strcpy(curfullcmd, ".exe");
3928 res = GetFileAttributes(fullcmd);
3929 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3934 /* that failed, try the bare name */
3935 res = GetFileAttributes(fullcmd);
3936 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3939 /* quit if no other path exists, or if cmd already has path */
3940 if (!pathstr || !*pathstr || has_slash)
3943 /* skip leading semis */
3944 while (*pathstr == ';')
3947 /* build a new prefix from scratch */
3948 curfullcmd = fullcmd;
3949 while (*pathstr && *pathstr != ';') {
3950 if (*pathstr == '"') { /* foo;"baz;etc";bar */
3951 pathstr++; /* skip initial '"' */
3952 while (*pathstr && *pathstr != '"') {
3953 *curfullcmd++ = *pathstr++;
3956 pathstr++; /* skip trailing '"' */
3959 *curfullcmd++ = *pathstr++;
3963 pathstr++; /* skip trailing semi */
3964 if (curfullcmd > fullcmd /* append a dir separator */
3965 && curfullcmd[-1] != '/' && curfullcmd[-1] != '\\')
3967 *curfullcmd++ = '\\';
3975 /* The following are just place holders.
3976 * Some hosts may provide and environment that the OS is
3977 * not tracking, therefore, these host must provide that
3978 * environment and the current directory to CreateProcess
3982 win32_get_childenv(void)
3988 win32_free_childenv(void* d)
3993 win32_clearenv(void)
3995 char *envv = GetEnvironmentStrings();
3999 char *end = strchr(cur,'=');
4000 if (end && end != cur) {
4002 SetEnvironmentVariable(cur, NULL);
4004 cur = end + strlen(end+1)+2;
4006 else if ((len = strlen(cur)))
4009 FreeEnvironmentStrings(envv);
4013 win32_get_childdir(void)
4017 char szfilename[MAX_PATH+1];
4019 GetCurrentDirectoryA(MAX_PATH+1, szfilename);
4020 Newx(ptr, strlen(szfilename)+1, char);
4021 strcpy(ptr, szfilename);
4026 win32_free_childdir(char* d)
4033 /* XXX this needs to be made more compatible with the spawnvp()
4034 * provided by the various RTLs. In particular, searching for
4035 * *.{com,bat,cmd} files (as done by the RTLs) is unimplemented.
4036 * This doesn't significantly affect perl itself, because we
4037 * always invoke things using PERL5SHELL if a direct attempt to
4038 * spawn the executable fails.
4040 * XXX splitting and rejoining the commandline between do_aspawn()
4041 * and win32_spawnvp() could also be avoided.
4045 win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
4047 #ifdef USE_RTL_SPAWNVP
4048 return spawnvp(mode, cmdname, (char * const *)argv);
4055 STARTUPINFO StartupInfo;
4056 PROCESS_INFORMATION ProcessInformation;
4059 char *fullcmd = Nullch;
4060 char *cname = (char *)cmdname;
4064 clen = strlen(cname);
4065 /* if command name contains dquotes, must remove them */
4066 if (strchr(cname, '"')) {
4068 Newx(cname,clen+1,char);
4081 cmd = create_command_line(cname, clen, argv);
4083 env = PerlEnv_get_childenv();
4084 dir = PerlEnv_get_childdir();
4087 case P_NOWAIT: /* asynch + remember result */
4088 if (w32_num_children >= MAXIMUM_WAIT_OBJECTS) {
4093 /* Create a new process group so we can use GenerateConsoleCtrlEvent()
4096 create |= CREATE_NEW_PROCESS_GROUP;
4099 case P_WAIT: /* synchronous execution */
4101 default: /* invalid mode */
4106 memset(&StartupInfo,0,sizeof(StartupInfo));
4107 StartupInfo.cb = sizeof(StartupInfo);
4108 memset(&tbl,0,sizeof(tbl));
4109 PerlEnv_get_child_IO(&tbl);
4110 StartupInfo.dwFlags = tbl.dwFlags;
4111 StartupInfo.dwX = tbl.dwX;
4112 StartupInfo.dwY = tbl.dwY;
4113 StartupInfo.dwXSize = tbl.dwXSize;
4114 StartupInfo.dwYSize = tbl.dwYSize;
4115 StartupInfo.dwXCountChars = tbl.dwXCountChars;
4116 StartupInfo.dwYCountChars = tbl.dwYCountChars;
4117 StartupInfo.dwFillAttribute = tbl.dwFillAttribute;
4118 StartupInfo.wShowWindow = tbl.wShowWindow;
4119 StartupInfo.hStdInput = tbl.childStdIn;
4120 StartupInfo.hStdOutput = tbl.childStdOut;
4121 StartupInfo.hStdError = tbl.childStdErr;
4122 if (StartupInfo.hStdInput == INVALID_HANDLE_VALUE &&
4123 StartupInfo.hStdOutput == INVALID_HANDLE_VALUE &&
4124 StartupInfo.hStdError == INVALID_HANDLE_VALUE)
4126 create |= CREATE_NEW_CONSOLE;
4129 StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
4131 if (w32_use_showwindow) {
4132 StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
4133 StartupInfo.wShowWindow = w32_showwindow;
4136 DEBUG_p(PerlIO_printf(Perl_debug_log, "Spawning [%s] with [%s]\n",
4139 if (!CreateProcess(cname, /* search PATH to find executable */
4140 cmd, /* executable, and its arguments */
4141 NULL, /* process attributes */
4142 NULL, /* thread attributes */
4143 TRUE, /* inherit handles */
4144 create, /* creation flags */
4145 (LPVOID)env, /* inherit environment */
4146 dir, /* inherit cwd */
4148 &ProcessInformation))
4150 /* initial NULL argument to CreateProcess() does a PATH
4151 * search, but it always first looks in the directory
4152 * where the current process was started, which behavior
4153 * is undesirable for backward compatibility. So we
4154 * jump through our own hoops by picking out the path
4155 * we really want it to use. */
4157 fullcmd = qualified_path(cname);
4159 if (cname != cmdname)
4162 DEBUG_p(PerlIO_printf(Perl_debug_log,
4163 "Retrying [%s] with same args\n",
4173 if (mode == P_NOWAIT) {
4174 /* asynchronous spawn -- store handle, return PID */
4175 ret = (int)ProcessInformation.dwProcessId;
4176 if (IsWin95() && ret < 0)
4179 w32_child_handles[w32_num_children] = ProcessInformation.hProcess;
4180 w32_child_pids[w32_num_children] = (DWORD)ret;
4185 win32_msgwait(aTHX_ 1, &ProcessInformation.hProcess, INFINITE, NULL);
4186 /* FIXME: if msgwait returned due to message perhaps forward the
4187 "signal" to the process
4189 GetExitCodeProcess(ProcessInformation.hProcess, &status);
4191 CloseHandle(ProcessInformation.hProcess);
4194 CloseHandle(ProcessInformation.hThread);
4197 PerlEnv_free_childenv(env);
4198 PerlEnv_free_childdir(dir);
4200 if (cname != cmdname)
4207 win32_execv(const char *cmdname, const char *const *argv)
4211 /* if this is a pseudo-forked child, we just want to spawn
4212 * the new program, and return */
4214 # ifdef __BORLANDC__
4215 return spawnv(P_WAIT, cmdname, (char *const *)argv);
4217 return spawnv(P_WAIT, cmdname, argv);
4221 return execv(cmdname, (char *const *)argv);
4223 return execv(cmdname, argv);
4228 win32_execvp(const char *cmdname, const char *const *argv)
4232 /* if this is a pseudo-forked child, we just want to spawn
4233 * the new program, and return */
4234 if (w32_pseudo_id) {
4235 int status = win32_spawnvp(P_WAIT, cmdname, (const char *const *)argv);
4245 return execvp(cmdname, (char *const *)argv);
4247 return execvp(cmdname, argv);
4252 win32_perror(const char *str)
4258 win32_setbuf(FILE *pf, char *buf)
4264 win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
4266 return setvbuf(pf, buf, type, size);
4270 win32_flushall(void)
4276 win32_fcloseall(void)
4282 win32_fgets(char *s, int n, FILE *pf)
4284 return fgets(s, n, pf);
4294 win32_fgetc(FILE *pf)
4300 win32_putc(int c, FILE *pf)
4306 win32_puts(const char *s)
4318 win32_putchar(int c)
4325 #ifndef USE_PERL_SBRK
4327 static char *committed = NULL; /* XXX threadead */
4328 static char *base = NULL; /* XXX threadead */
4329 static char *reserved = NULL; /* XXX threadead */
4330 static char *brk = NULL; /* XXX threadead */
4331 static DWORD pagesize = 0; /* XXX threadead */
4334 sbrk(ptrdiff_t need)
4339 GetSystemInfo(&info);
4340 /* Pretend page size is larger so we don't perpetually
4341 * call the OS to commit just one page ...
4343 pagesize = info.dwPageSize << 3;
4345 if (brk+need >= reserved)
4347 DWORD size = brk+need-reserved;
4349 char *prev_committed = NULL;
4350 if (committed && reserved && committed < reserved)
4352 /* Commit last of previous chunk cannot span allocations */
4353 addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
4356 /* Remember where we committed from in case we want to decommit later */
4357 prev_committed = committed;
4358 committed = reserved;
4361 /* Reserve some (more) space
4362 * Contiguous blocks give us greater efficiency, so reserve big blocks -
4363 * this is only address space not memory...
4364 * Note this is a little sneaky, 1st call passes NULL as reserved
4365 * so lets system choose where we start, subsequent calls pass
4366 * the old end address so ask for a contiguous block
4369 if (size < 64*1024*1024)
4370 size = 64*1024*1024;
4371 size = ((size + pagesize - 1) / pagesize) * pagesize;
4372 addr = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
4375 reserved = addr+size;
4385 /* The existing block could not be extended far enough, so decommit
4386 * anything that was just committed above and start anew */
4389 if (!VirtualFree(prev_committed,reserved-prev_committed,MEM_DECOMMIT))
4392 reserved = base = committed = brk = NULL;
4403 if (brk > committed)
4405 DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
4407 if (committed+size > reserved)
4408 size = reserved-committed;
4409 addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
4422 win32_malloc(size_t size)
4424 return malloc(size);
4428 win32_calloc(size_t numitems, size_t size)
4430 return calloc(numitems,size);
4434 win32_realloc(void *block, size_t size)
4436 return realloc(block,size);
4440 win32_free(void *block)
4447 win32_open_osfhandle(intptr_t handle, int flags)
4449 #ifdef USE_FIXED_OSFHANDLE
4451 return my_open_osfhandle(handle, flags);
4453 return _open_osfhandle(handle, flags);
4457 win32_get_osfhandle(int fd)
4459 return (intptr_t)_get_osfhandle(fd);
4463 win32_fdupopen(FILE *pf)
4468 int fileno = win32_dup(win32_fileno(pf));
4470 /* open the file in the same mode */
4472 if((pf)->flags & _F_READ) {
4476 else if((pf)->flags & _F_WRIT) {
4480 else if((pf)->flags & _F_RDWR) {
4486 if((pf)->_flag & _IOREAD) {
4490 else if((pf)->_flag & _IOWRT) {
4494 else if((pf)->_flag & _IORW) {
4501 /* it appears that the binmode is attached to the
4502 * file descriptor so binmode files will be handled
4505 pfdup = win32_fdopen(fileno, mode);
4507 /* move the file pointer to the same position */
4508 if (!fgetpos(pf, &pos)) {
4509 fsetpos(pfdup, &pos);
4515 win32_dynaload(const char* filename)
4518 char buf[MAX_PATH+1];
4521 /* LoadLibrary() doesn't recognize forward slashes correctly,
4522 * so turn 'em back. */
4523 first = strchr(filename, '/');
4525 STRLEN len = strlen(filename);
4526 if (len <= MAX_PATH) {
4527 strcpy(buf, filename);
4528 filename = &buf[first - filename];
4530 if (*filename == '/')
4531 *(char*)filename = '\\';
4537 return LoadLibraryExA(PerlDir_mapA(filename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
4540 XS(w32_SetChildShowWindow)
4543 BOOL use_showwindow = w32_use_showwindow;
4544 /* use "unsigned short" because Perl has redefined "WORD" */
4545 unsigned short showwindow = w32_showwindow;
4548 Perl_croak(aTHX_ "usage: Win32::SetChildShowWindow($showwindow)");
4550 if (items == 0 || !SvOK(ST(0)))
4551 w32_use_showwindow = FALSE;
4553 w32_use_showwindow = TRUE;
4554 w32_showwindow = (unsigned short)SvIV(ST(0));
4559 ST(0) = sv_2mortal(newSViv(showwindow));
4561 ST(0) = &PL_sv_undef;
4566 forward(pTHX_ const char *function)
4569 Perl_load_module(aTHX_ PERL_LOADMOD_NOIMPORT, newSVpvn("Win32",5), newSVnv(0.27));
4572 call_pv(function, GIMME_V);
4575 #define FORWARD(function) XS(w32_##function){ forward(aTHX_ "Win32::"#function); }
4578 FORWARD(GetNextAvailDrive)
4579 FORWARD(GetLastError)
4580 FORWARD(SetLastError)
4585 FORWARD(GetOSVersion)
4588 FORWARD(FormatMessage)
4590 FORWARD(GetTickCount)
4591 FORWARD(GetShortPathName)
4592 FORWARD(GetFullPathName)
4593 FORWARD(GetLongPathName)
4597 /* Don't forward Win32::SetChildShowWindow(). It accesses the internal variable
4598 * w32_showwindow in thread_intern and is therefore not implemented in Win32.xs.
4600 /* FORWARD(SetChildShowWindow) */
4605 Perl_init_os_extras(void)
4608 char *file = __FILE__;
4611 /* these names are Activeware compatible */
4612 newXS("Win32::GetCwd", w32_GetCwd, file);
4613 newXS("Win32::SetCwd", w32_SetCwd, file);
4614 newXS("Win32::GetNextAvailDrive", w32_GetNextAvailDrive, file);
4615 newXS("Win32::GetLastError", w32_GetLastError, file);
4616 newXS("Win32::SetLastError", w32_SetLastError, file);
4617 newXS("Win32::LoginName", w32_LoginName, file);
4618 newXS("Win32::NodeName", w32_NodeName, file);
4619 newXS("Win32::DomainName", w32_DomainName, file);
4620 newXS("Win32::FsType", w32_FsType, file);
4621 newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
4622 newXS("Win32::IsWinNT", w32_IsWinNT, file);
4623 newXS("Win32::IsWin95", w32_IsWin95, file);
4624 newXS("Win32::FormatMessage", w32_FormatMessage, file);
4625 newXS("Win32::Spawn", w32_Spawn, file);
4626 newXS("Win32::GetTickCount", w32_GetTickCount, file);
4627 newXS("Win32::GetShortPathName", w32_GetShortPathName, file);
4628 newXS("Win32::GetFullPathName", w32_GetFullPathName, file);
4629 newXS("Win32::GetLongPathName", w32_GetLongPathName, file);
4630 newXS("Win32::CopyFile", w32_CopyFile, file);
4631 newXS("Win32::Sleep", w32_Sleep, file);
4632 newXS("Win32::SetChildShowWindow", w32_SetChildShowWindow, file);
4636 win32_signal_context(void)
4641 my_perl = PL_curinterp;
4642 PERL_SET_THX(my_perl);
4646 return PL_curinterp;
4652 win32_ctrlhandler(DWORD dwCtrlType)
4655 dTHXa(PERL_GET_SIG_CONTEXT);
4661 switch(dwCtrlType) {
4662 case CTRL_CLOSE_EVENT:
4663 /* A signal that the system sends to all processes attached to a console when
4664 the user closes the console (either by choosing the Close command from the
4665 console window's System menu, or by choosing the End Task command from the
4668 if (do_raise(aTHX_ 1)) /* SIGHUP */
4669 sig_terminate(aTHX_ 1);
4673 /* A CTRL+c signal was received */
4674 if (do_raise(aTHX_ SIGINT))
4675 sig_terminate(aTHX_ SIGINT);
4678 case CTRL_BREAK_EVENT:
4679 /* A CTRL+BREAK signal was received */
4680 if (do_raise(aTHX_ SIGBREAK))
4681 sig_terminate(aTHX_ SIGBREAK);
4684 case CTRL_LOGOFF_EVENT:
4685 /* A signal that the system sends to all console processes when a user is logging
4686 off. This signal does not indicate which user is logging off, so no
4687 assumptions can be made.
4690 case CTRL_SHUTDOWN_EVENT:
4691 /* A signal that the system sends to all console processes when the system is
4694 if (do_raise(aTHX_ SIGTERM))
4695 sig_terminate(aTHX_ SIGTERM);
4704 #if _MSC_VER >= 1400
4705 # include <crtdbg.h>
4709 Perl_win32_init(int *argcp, char ***argvp)
4713 #if _MSC_VER >= 1400
4714 _invalid_parameter_handler oldHandler, newHandler;
4715 newHandler = my_invalid_parameter_handler;
4716 oldHandler = _set_invalid_parameter_handler(newHandler);
4717 _CrtSetReportMode(_CRT_ASSERT, 0);
4719 /* Disable floating point errors, Perl will trap the ones we
4720 * care about. VC++ RTL defaults to switching these off
4721 * already, but the Borland RTL doesn't. Since we don't
4722 * want to be at the vendor's whim on the default, we set
4723 * it explicitly here.
4725 #if !defined(_ALPHA_) && !defined(__GNUC__)
4726 _control87(MCW_EM, MCW_EM);
4730 module = GetModuleHandle("ntdll.dll");
4732 *(FARPROC*)&pfnZwQuerySystemInformation = GetProcAddress(module, "ZwQuerySystemInformation");
4735 module = GetModuleHandle("kernel32.dll");
4737 *(FARPROC*)&pfnCreateToolhelp32Snapshot = GetProcAddress(module, "CreateToolhelp32Snapshot");
4738 *(FARPROC*)&pfnProcess32First = GetProcAddress(module, "Process32First");
4739 *(FARPROC*)&pfnProcess32Next = GetProcAddress(module, "Process32Next");
4744 Perl_win32_term(void)
4754 win32_get_child_IO(child_IO_table* ptbl)
4756 ptbl->childStdIn = GetStdHandle(STD_INPUT_HANDLE);
4757 ptbl->childStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
4758 ptbl->childStdErr = GetStdHandle(STD_ERROR_HANDLE);
4762 win32_signal(int sig, Sighandler_t subcode)
4765 if (sig < SIG_SIZE) {
4766 int save_errno = errno;
4767 Sighandler_t result = signal(sig, subcode);
4768 if (result == SIG_ERR) {
4769 result = w32_sighandler[sig];
4772 w32_sighandler[sig] = subcode;
4782 #ifdef HAVE_INTERP_INTERN
4787 OSVERSIONINFO osver; /* g_osver may not yet be initialized */
4793 /* there is no Unicode environment on Windows 9X */
4794 osver.dwOSVersionInfoSize = sizeof(osver);
4795 GetVersionEx(&osver);
4796 if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
4799 /* fetch Unicode version of PATH */
4801 wide_path = win32_malloc(len*sizeof(WCHAR));
4803 size_t newlen = GetEnvironmentVariableW(L"PATH", wide_path, len);
4807 wide_path = win32_realloc(wide_path, len*sizeof(WCHAR));
4812 /* convert to ANSI pathnames */
4813 wide_dir = wide_path;
4816 WCHAR *sep = wcschr(wide_dir, ';');
4824 /* remove quotes around pathname */
4825 if (*wide_dir == '"')
4827 wide_len = wcslen(wide_dir);
4828 if (wide_len && wide_dir[wide_len-1] == '"')
4829 wide_dir[wide_len-1] = '\0';
4831 /* append ansi_dir to ansi_path */
4832 ansi_dir = win32_ansipath(wide_dir);
4833 ansi_len = strlen(ansi_dir);
4835 size_t newlen = len + 1 + ansi_len;
4836 ansi_path = win32_realloc(ansi_path, newlen+1);
4839 ansi_path[len] = ';';
4840 memcpy(ansi_path+len+1, ansi_dir, ansi_len+1);
4845 ansi_path = win32_malloc(5+le