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
18 #ifndef __MINGW32__ /* GCC/Mingw32-2.95.2 forgot the WINAPI on CommandLineToArgvW() */
19 # include <shellapi.h>
21 LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCommandLine, int * pNumArgs);
27 /* #include "config.h" */
29 #if !defined(PERLIO_IS_STDIO) && !defined(USE_SFIO)
38 #define PERL_NO_GET_CONTEXT
44 /* assert.h conflicts with #define of assert in perl.h */
51 #if defined(_MSC_VER) || defined(__MINGW32__)
52 #include <sys/utime.h>
57 /* Mingw32 defaults to globing command line
58 * So we turn it off like this:
63 #if defined(__MINGW32__)
64 /* Mingw32 is missing some prototypes */
65 FILE * _wfopen(LPCWSTR wszFileName, LPCWSTR wszMode);
66 FILE * _wfdopen(int nFd, LPCWSTR wszMode);
67 FILE * _freopen(LPCWSTR wszFileName, LPCWSTR wszMode, FILE * pOldStream);
72 #if defined(__BORLANDC__)
74 # define _utimbuf utimbuf
79 #define EXECF_SPAWN_NOWAIT 3
81 #if defined(PERL_IMPLICIT_SYS)
82 # undef win32_get_privlib
83 # define win32_get_privlib g_win32_get_privlib
84 # undef win32_get_sitelib
85 # define win32_get_sitelib g_win32_get_sitelib
86 # undef win32_get_vendorlib
87 # define win32_get_vendorlib g_win32_get_vendorlib
89 # define do_spawn g_do_spawn
91 # define getlogin g_getlogin
94 static void get_shell(void);
95 static long tokenize(const char *str, char **dest, char ***destv);
96 int do_spawn2(char *cmd, int exectype);
97 static BOOL has_shell_metachars(char *ptr);
98 static long filetime_to_clock(PFILETIME ft);
99 static BOOL filetime_from_time(PFILETIME ft, time_t t);
100 static char * get_emd_part(SV **leading, char *trailing, ...);
101 static void remove_dead_process(long deceased);
102 static long find_pid(int pid);
103 static char * qualified_path(const char *cmd);
104 static char * win32_get_xlib(const char *pl, const char *xlib,
105 const char *libname);
108 static void remove_dead_pseudo_process(long child);
109 static long find_pseudo_pid(int pid);
113 HANDLE w32_perldll_handle = INVALID_HANDLE_VALUE;
114 char w32_module_name[MAX_PATH+1];
117 static DWORD w32_platform = (DWORD)-1;
119 #define ONE_K_BUFSIZE 1024
124 return (win32_os_id() == VER_PLATFORM_WIN32_WINDOWS);
130 return (win32_os_id() == VER_PLATFORM_WIN32_NT);
134 set_w32_module_name(void)
137 GetModuleFileName((HMODULE)((w32_perldll_handle == INVALID_HANDLE_VALUE)
138 ? GetModuleHandle(NULL)
139 : w32_perldll_handle),
140 w32_module_name, sizeof(w32_module_name));
142 /* try to get full path to binary (which may be mangled when perl is
143 * run from a 16-bit app) */
144 /*PerlIO_printf(Perl_debug_log, "Before %s\n", w32_module_name);*/
145 (void)win32_longpath(w32_module_name);
146 /*PerlIO_printf(Perl_debug_log, "After %s\n", w32_module_name);*/
148 /* normalize to forward slashes */
149 ptr = w32_module_name;
157 /* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
159 get_regstr_from(HKEY hkey, const char *valuename, SV **svp)
161 /* Retrieve a REG_SZ or REG_EXPAND_SZ from the registry */
164 const char *subkey = "Software\\Perl";
168 retval = RegOpenKeyEx(hkey, subkey, 0, KEY_READ, &handle);
169 if (retval == ERROR_SUCCESS) {
171 retval = RegQueryValueEx(handle, valuename, 0, &type, NULL, &datalen);
172 if (retval == ERROR_SUCCESS
173 && (type == REG_SZ || type == REG_EXPAND_SZ))
177 *svp = sv_2mortal(newSVpvn("",0));
178 SvGROW(*svp, datalen);
179 retval = RegQueryValueEx(handle, valuename, 0, NULL,
180 (PBYTE)SvPVX(*svp), &datalen);
181 if (retval == ERROR_SUCCESS) {
183 SvCUR_set(*svp,datalen-1);
191 /* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
193 get_regstr(const char *valuename, SV **svp)
195 char *str = get_regstr_from(HKEY_CURRENT_USER, valuename, svp);
197 str = get_regstr_from(HKEY_LOCAL_MACHINE, valuename, svp);
201 /* *prev_pathp (if non-NULL) is expected to be POK (valid allocated SvPVX(sv)) */
203 get_emd_part(SV **prev_pathp, char *trailing_path, ...)
207 char mod_name[MAX_PATH+1];
211 int oldsize, newsize;
214 va_start(ap, trailing_path);
215 strip = va_arg(ap, char *);
217 sprintf(base, "%d.%d", (int)PERL_REVISION, (int)PERL_VERSION);
218 baselen = strlen(base);
220 if (!*w32_module_name) {
221 set_w32_module_name();
223 strcpy(mod_name, w32_module_name);
224 ptr = strrchr(mod_name, '/');
225 while (ptr && strip) {
226 /* look for directories to skip back */
229 ptr = strrchr(mod_name, '/');
230 /* avoid stripping component if there is no slash,
231 * or it doesn't match ... */
232 if (!ptr || stricmp(ptr+1, strip) != 0) {
233 /* ... but not if component matches m|5\.$patchlevel.*| */
234 if (!ptr || !(*strip == '5' && *(ptr+1) == '5'
235 && strncmp(strip, base, baselen) == 0
236 && strncmp(ptr+1, base, baselen) == 0))
242 strip = va_arg(ap, char *);
250 strcpy(++ptr, trailing_path);
252 /* only add directory if it exists */
253 if (GetFileAttributes(mod_name) != (DWORD) -1) {
254 /* directory exists */
257 *prev_pathp = sv_2mortal(newSVpvn("",0));
258 sv_catpvn(*prev_pathp, ";", 1);
259 sv_catpv(*prev_pathp, mod_name);
260 return SvPVX(*prev_pathp);
267 win32_get_privlib(const char *pl)
270 char *stdlib = "lib";
271 char buffer[MAX_PATH+1];
274 /* $stdlib = $HKCU{"lib-$]"} || $HKLM{"lib-$]"} || $HKCU{"lib"} || $HKLM{"lib"} || ""; */
275 sprintf(buffer, "%s-%s", stdlib, pl);
276 if (!get_regstr(buffer, &sv))
277 (void)get_regstr(stdlib, &sv);
279 /* $stdlib .= ";$EMD/../../lib" */
280 return get_emd_part(&sv, stdlib, ARCHNAME, "bin", Nullch);
284 win32_get_xlib(const char *pl, const char *xlib, const char *libname)
288 char pathstr[MAX_PATH+1];
294 /* $HKCU{"$xlib-$]"} || $HKLM{"$xlib-$]"} . ---; */
295 sprintf(regstr, "%s-%s", xlib, pl);
296 (void)get_regstr(regstr, &sv1);
299 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/$]/lib"; */
300 sprintf(pathstr, "%s/%s/lib", libname, pl);
301 (void)get_emd_part(&sv1, pathstr, ARCHNAME, "bin", pl, Nullch);
303 /* $HKCU{$xlib} || $HKLM{$xlib} . ---; */
304 (void)get_regstr(xlib, &sv2);
307 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/lib"; */
308 sprintf(pathstr, "%s/lib", libname);
309 (void)get_emd_part(&sv2, pathstr, ARCHNAME, "bin", pl, Nullch);
318 sv_catpvn(sv1, ";", 1);
325 win32_get_sitelib(const char *pl)
327 return win32_get_xlib(pl, "sitelib", "site");
330 #ifndef PERL_VENDORLIB_NAME
331 # define PERL_VENDORLIB_NAME "vendor"
335 win32_get_vendorlib(const char *pl)
337 return win32_get_xlib(pl, "vendorlib", PERL_VENDORLIB_NAME);
341 has_shell_metachars(char *ptr)
347 * Scan string looking for redirection (< or >) or pipe
348 * characters (|) that are not in a quoted string.
349 * Shell variable interpolation (%VAR%) can also happen inside strings.
381 #if !defined(PERL_IMPLICIT_SYS)
382 /* since the current process environment is being updated in util.c
383 * the library functions will get the correct environment
386 Perl_my_popen(pTHX_ char *cmd, char *mode)
389 #define fixcmd(x) { \
390 char *pspace = strchr((x),' '); \
393 while (p < pspace) { \
404 PERL_FLUSHALL_FOR_CHILD;
405 return win32_popen(cmd, mode);
409 Perl_my_pclose(pTHX_ PerlIO *fp)
411 return win32_pclose(fp);
415 DllExport unsigned long
418 static OSVERSIONINFO osver;
420 if (osver.dwPlatformId != w32_platform) {
421 memset(&osver, 0, sizeof(OSVERSIONINFO));
422 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
423 GetVersionEx(&osver);
424 w32_platform = osver.dwPlatformId;
426 return (unsigned long)w32_platform;
436 return -((int)w32_pseudo_id);
439 /* Windows 9x appears to always reports a pid for threads and processes
440 * that has the high bit set. So we treat the lower 31 bits as the
441 * "real" PID for Perl's purposes. */
442 if (IsWin95() && pid < 0)
447 /* Tokenize a string. Words are null-separated, and the list
448 * ends with a doubled null. Any character (except null and
449 * including backslash) may be escaped by preceding it with a
450 * backslash (the backslash will be stripped).
451 * Returns number of words in result buffer.
454 tokenize(const char *str, char **dest, char ***destv)
456 char *retstart = Nullch;
457 char **retvstart = 0;
461 int slen = strlen(str);
463 register char **retv;
464 New(1307, ret, slen+2, char);
465 New(1308, retv, (slen+3)/2, char*);
473 if (*ret == '\\' && *str)
475 else if (*ret == ' ') {
491 retvstart[items] = Nullch;
504 if (!w32_perlshell_tokens) {
505 /* we don't use COMSPEC here for two reasons:
506 * 1. the same reason perl on UNIX doesn't use SHELL--rampant and
507 * uncontrolled unportability of the ensuing scripts.
508 * 2. PERL5SHELL could be set to a shell that may not be fit for
509 * interactive use (which is what most programs look in COMSPEC
512 const char* defaultshell = (IsWinNT()
513 ? "cmd.exe /x/c" : "command.com /c");
514 const char *usershell = PerlEnv_getenv("PERL5SHELL");
515 w32_perlshell_items = tokenize(usershell ? usershell : defaultshell,
516 &w32_perlshell_tokens,
522 do_aspawn(void *vreally, void **vmark, void **vsp)
525 SV *really = (SV*)vreally;
526 SV **mark = (SV**)vmark;
538 New(1306, argv, (sp - mark) + w32_perlshell_items + 2, char*);
540 if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
545 while (++mark <= sp) {
546 if (*mark && (str = SvPV_nolen(*mark)))
553 status = win32_spawnvp(flag,
554 (const char*)(really ? SvPV_nolen(really) : argv[0]),
555 (const char* const*)argv);
557 if (status < 0 && (errno == ENOEXEC || errno == ENOENT)) {
558 /* possible shell-builtin, invoke with shell */
560 sh_items = w32_perlshell_items;
562 argv[index+sh_items] = argv[index];
563 while (--sh_items >= 0)
564 argv[sh_items] = w32_perlshell_vec[sh_items];
566 status = win32_spawnvp(flag,
567 (const char*)(really ? SvPV_nolen(really) : argv[0]),
568 (const char* const*)argv);
571 if (flag == P_NOWAIT) {
573 PL_statusvalue = -1; /* >16bits hint for pp_system() */
577 if (ckWARN(WARN_EXEC))
578 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't spawn \"%s\": %s", argv[0], strerror(errno));
583 PL_statusvalue = status;
589 /* returns pointer to the next unquoted space or the end of the string */
591 find_next_space(const char *s)
593 bool in_quotes = FALSE;
595 /* ignore doubled backslashes, or backslash+quote */
596 if (*s == '\\' && (s[1] == '\\' || s[1] == '"')) {
599 /* keep track of when we're within quotes */
600 else if (*s == '"') {
602 in_quotes = !in_quotes;
604 /* break it up only at spaces that aren't in quotes */
605 else if (!in_quotes && isSPACE(*s))
614 do_spawn2(char *cmd, int exectype)
621 BOOL needToTry = TRUE;
624 /* Save an extra exec if possible. See if there are shell
625 * metacharacters in it */
626 if (!has_shell_metachars(cmd)) {
627 New(1301,argv, strlen(cmd) / 2 + 2, char*);
628 New(1302,cmd2, strlen(cmd) + 1, char);
631 for (s = cmd2; *s;) {
632 while (*s && isSPACE(*s))
636 s = find_next_space(s);
644 status = win32_spawnvp(P_WAIT, argv[0],
645 (const char* const*)argv);
647 case EXECF_SPAWN_NOWAIT:
648 status = win32_spawnvp(P_NOWAIT, argv[0],
649 (const char* const*)argv);
652 status = win32_execvp(argv[0], (const char* const*)argv);
655 if (status != -1 || errno == 0)
665 New(1306, argv, w32_perlshell_items + 2, char*);
666 while (++i < w32_perlshell_items)
667 argv[i] = w32_perlshell_vec[i];
672 status = win32_spawnvp(P_WAIT, argv[0],
673 (const char* const*)argv);
675 case EXECF_SPAWN_NOWAIT:
676 status = win32_spawnvp(P_NOWAIT, argv[0],
677 (const char* const*)argv);
680 status = win32_execvp(argv[0], (const char* const*)argv);
686 if (exectype == EXECF_SPAWN_NOWAIT) {
688 PL_statusvalue = -1; /* >16bits hint for pp_system() */
692 if (ckWARN(WARN_EXEC))
693 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s \"%s\": %s",
694 (exectype == EXECF_EXEC ? "exec" : "spawn"),
695 cmd, strerror(errno));
700 PL_statusvalue = status;
708 return do_spawn2(cmd, EXECF_SPAWN);
712 do_spawn_nowait(char *cmd)
714 return do_spawn2(cmd, EXECF_SPAWN_NOWAIT);
718 Perl_do_exec(pTHX_ char *cmd)
720 do_spawn2(cmd, EXECF_EXEC);
724 /* The idea here is to read all the directory names into a string table
725 * (separated by nulls) and when one of the other dir functions is called
726 * return the pointer to the current file name.
729 win32_opendir(char *filename)
735 char scanname[MAX_PATH+3];
737 WIN32_FIND_DATAA aFindData;
738 WIN32_FIND_DATAW wFindData;
740 char buffer[MAX_PATH*2];
741 WCHAR wbuffer[MAX_PATH+1];
744 len = strlen(filename);
748 /* check to see if filename is a directory */
749 if (win32_stat(filename, &sbuf) < 0 || !S_ISDIR(sbuf.st_mode))
752 /* Get us a DIR structure */
753 Newz(1303, dirp, 1, DIR);
755 /* Create the search pattern */
756 strcpy(scanname, filename);
758 /* bare drive name means look in cwd for drive */
759 if (len == 2 && isALPHA(scanname[0]) && scanname[1] == ':') {
760 scanname[len++] = '.';
761 scanname[len++] = '/';
763 else if (scanname[len-1] != '/' && scanname[len-1] != '\\') {
764 scanname[len++] = '/';
766 scanname[len++] = '*';
767 scanname[len] = '\0';
769 /* do the FindFirstFile call */
771 A2WHELPER(scanname, wbuffer, sizeof(wbuffer));
772 fh = FindFirstFileW(PerlDir_mapW(wbuffer), &wFindData);
775 fh = FindFirstFileA(PerlDir_mapA(scanname), &aFindData);
778 if (fh == INVALID_HANDLE_VALUE) {
779 DWORD err = GetLastError();
780 /* FindFirstFile() fails on empty drives! */
782 case ERROR_FILE_NOT_FOUND:
784 case ERROR_NO_MORE_FILES:
785 case ERROR_PATH_NOT_FOUND:
788 case ERROR_NOT_ENOUGH_MEMORY:
799 /* now allocate the first part of the string table for
800 * the filenames that we find.
803 W2AHELPER(wFindData.cFileName, buffer, sizeof(buffer));
807 ptr = aFindData.cFileName;
814 New(1304, dirp->start, dirp->size, char);
815 strcpy(dirp->start, ptr);
817 dirp->end = dirp->curr = dirp->start;
823 /* Readdir just returns the current string pointer and bumps the
824 * string pointer to the nDllExport entry.
826 DllExport struct direct *
827 win32_readdir(DIR *dirp)
832 /* first set up the structure to return */
833 len = strlen(dirp->curr);
834 strcpy(dirp->dirstr.d_name, dirp->curr);
835 dirp->dirstr.d_namlen = len;
838 dirp->dirstr.d_ino = dirp->curr - dirp->start;
840 /* Now set up for the next call to readdir */
841 dirp->curr += len + 1;
842 if (dirp->curr >= dirp->end) {
846 WIN32_FIND_DATAW wFindData;
847 WIN32_FIND_DATAA aFindData;
848 char buffer[MAX_PATH*2];
850 /* finding the next file that matches the wildcard
851 * (which should be all of them in this directory!).
854 res = FindNextFileW(dirp->handle, &wFindData);
856 W2AHELPER(wFindData.cFileName, buffer, sizeof(buffer));
861 res = FindNextFileA(dirp->handle, &aFindData);
863 ptr = aFindData.cFileName;
866 long endpos = dirp->end - dirp->start;
867 long newsize = endpos + strlen(ptr) + 1;
868 /* bump the string table size by enough for the
869 * new name and its null terminator */
870 while (newsize > dirp->size) {
871 long curpos = dirp->curr - dirp->start;
873 Renew(dirp->start, dirp->size, char);
874 dirp->curr = dirp->start + curpos;
876 strcpy(dirp->start + endpos, ptr);
877 dirp->end = dirp->start + newsize;
883 return &(dirp->dirstr);
889 /* Telldir returns the current string pointer position */
891 win32_telldir(DIR *dirp)
893 return (dirp->curr - dirp->start);
897 /* Seekdir moves the string pointer to a previously saved position
898 * (returned by telldir).
901 win32_seekdir(DIR *dirp, long loc)
903 dirp->curr = dirp->start + loc;
906 /* Rewinddir resets the string pointer to the start */
908 win32_rewinddir(DIR *dirp)
910 dirp->curr = dirp->start;
913 /* free the memory allocated by opendir */
915 win32_closedir(DIR *dirp)
918 if (dirp->handle != INVALID_HANDLE_VALUE)
919 FindClose(dirp->handle);
920 Safefree(dirp->start);
933 * Just pretend that everyone is a superuser. NT will let us know if
934 * we don\'t really have permission to do something.
937 #define ROOT_UID ((uid_t)0)
938 #define ROOT_GID ((gid_t)0)
967 return (auid == ROOT_UID ? 0 : -1);
973 return (agid == ROOT_GID ? 0 : -1);
980 char *buf = w32_getlogin_buffer;
981 DWORD size = sizeof(w32_getlogin_buffer);
982 if (GetUserName(buf,&size))
988 chown(const char *path, uid_t owner, gid_t group)
995 * XXX this needs strengthening (for PerlIO)
998 int mkstemp(const char *path)
1001 char buf[MAX_PATH+1];
1005 if (i++ > 10) { /* give up */
1009 if (!GetTempFileNameA((LPCSTR)path, "plr", 1, buf)) {
1013 fd = PerlLIO_open3(buf, O_CREAT|O_RDWR|O_EXCL, 0600);
1023 long child = w32_num_children;
1024 while (--child >= 0) {
1025 if (w32_child_pids[child] == pid)
1032 remove_dead_process(long child)
1036 CloseHandle(w32_child_handles[child]);
1037 Move(&w32_child_handles[child+1], &w32_child_handles[child],
1038 (w32_num_children-child-1), HANDLE);
1039 Move(&w32_child_pids[child+1], &w32_child_pids[child],
1040 (w32_num_children-child-1), DWORD);
1047 find_pseudo_pid(int pid)
1050 long child = w32_num_pseudo_children;
1051 while (--child >= 0) {
1052 if (w32_pseudo_child_pids[child] == pid)
1059 remove_dead_pseudo_process(long child)
1063 CloseHandle(w32_pseudo_child_handles[child]);
1064 Move(&w32_pseudo_child_handles[child+1], &w32_pseudo_child_handles[child],
1065 (w32_num_pseudo_children-child-1), HANDLE);
1066 Move(&w32_pseudo_child_pids[child+1], &w32_pseudo_child_pids[child],
1067 (w32_num_pseudo_children-child-1), DWORD);
1068 w32_num_pseudo_children--;
1074 win32_kill(int pid, int sig)
1081 /* it is a pseudo-forked child */
1082 child = find_pseudo_pid(-pid);
1084 hProcess = w32_pseudo_child_handles[child];
1087 /* "Does process exist?" use of kill */
1090 /* kill -9 style un-graceful exit */
1091 if (TerminateThread(hProcess, sig)) {
1092 remove_dead_pseudo_process(child);
1097 /* We fake signals to pseudo-processes using Win32
1098 * message queue. In Win9X the pids are negative already. */
1099 if (PostThreadMessage(IsWin95() ? pid : -pid,WM_USER,sig,0)) {
1100 /* It might be us ... */
1107 else if (IsWin95()) {
1115 child = find_pid(pid);
1117 hProcess = w32_child_handles[child];
1120 /* "Does process exist?" use of kill */
1123 if (GenerateConsoleCtrlEvent(CTRL_C_EVENT,pid))
1126 default: /* For now be backwards compatible with perl5.6 */
1128 if (TerminateProcess(hProcess, sig)) {
1129 remove_dead_process(child);
1137 hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE,
1138 (IsWin95() ? -pid : pid));
1142 /* "Does process exist?" use of kill */
1145 if (GenerateConsoleCtrlEvent(CTRL_C_EVENT,pid))
1148 default: /* For now be backwards compatible with perl5.6 */
1150 if (TerminateProcess(hProcess, sig)) {
1151 CloseHandle(hProcess);
1163 win32_stat(const char *path, struct stat *sbuf)
1166 char buffer[MAX_PATH+1];
1167 int l = strlen(path);
1169 WCHAR wbuffer[MAX_PATH+1];
1175 switch(path[l - 1]) {
1176 /* FindFirstFile() and stat() are buggy with a trailing
1177 * backslash, so change it to a forward slash :-( */
1179 strncpy(buffer, path, l-1);
1180 buffer[l - 1] = '/';
1184 /* FindFirstFile() is buggy with "x:", so add a dot :-( */
1186 if (l == 2 && isALPHA(path[0])) {
1187 buffer[0] = path[0];
1198 /* We *must* open & close the file once; otherwise file attribute changes */
1199 /* might not yet have propagated to "other" hard links of the same file. */
1200 /* This also gives us an opportunity to determine the number of links. */
1202 A2WHELPER(path, wbuffer, sizeof(wbuffer));
1203 pwbuffer = PerlDir_mapW(wbuffer);
1204 handle = CreateFileW(pwbuffer, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
1207 path = PerlDir_mapA(path);
1209 handle = CreateFileA(path, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
1211 if (handle != INVALID_HANDLE_VALUE) {
1212 BY_HANDLE_FILE_INFORMATION bhi;
1213 if (GetFileInformationByHandle(handle, &bhi))
1214 nlink = bhi.nNumberOfLinks;
1215 CloseHandle(handle);
1218 /* pwbuffer or path will be mapped correctly above */
1220 res = _wstat(pwbuffer, (struct _stat *)sbuf);
1223 res = stat(path, sbuf);
1225 sbuf->st_nlink = nlink;
1228 /* CRT is buggy on sharenames, so make sure it really isn't.
1229 * XXX using GetFileAttributesEx() will enable us to set
1230 * sbuf->st_*time (but note that's not available on the
1231 * Windows of 1995) */
1234 r = GetFileAttributesW(pwbuffer);
1237 r = GetFileAttributesA(path);
1239 if (r != 0xffffffff && (r & FILE_ATTRIBUTE_DIRECTORY)) {
1240 /* sbuf may still contain old garbage since stat() failed */
1241 Zero(sbuf, 1, struct stat);
1242 sbuf->st_mode = S_IFDIR | S_IREAD;
1244 if (!(r & FILE_ATTRIBUTE_READONLY))
1245 sbuf->st_mode |= S_IWRITE | S_IEXEC;
1250 if (l == 3 && isALPHA(path[0]) && path[1] == ':'
1251 && (path[2] == '\\' || path[2] == '/'))
1253 /* The drive can be inaccessible, some _stat()s are buggy */
1255 ? !GetVolumeInformationW(pwbuffer,NULL,0,NULL,NULL,NULL,NULL,0)
1256 : !GetVolumeInformationA(path,NULL,0,NULL,NULL,NULL,NULL,0)) {
1262 if (S_ISDIR(sbuf->st_mode))
1263 sbuf->st_mode |= S_IWRITE | S_IEXEC;
1264 else if (S_ISREG(sbuf->st_mode)) {
1266 if (l >= 4 && path[l-4] == '.') {
1267 const char *e = path + l - 3;
1268 if (strnicmp(e,"exe",3)
1269 && strnicmp(e,"bat",3)
1270 && strnicmp(e,"com",3)
1271 && (IsWin95() || strnicmp(e,"cmd",3)))
1272 sbuf->st_mode &= ~S_IEXEC;
1274 sbuf->st_mode |= S_IEXEC;
1277 sbuf->st_mode &= ~S_IEXEC;
1278 /* Propagate permissions to _group_ and _others_ */
1279 perms = sbuf->st_mode & (S_IREAD|S_IWRITE|S_IEXEC);
1280 sbuf->st_mode |= (perms>>3) | (perms>>6);
1287 #define isSLASH(c) ((c) == '/' || (c) == '\\')
1288 #define SKIP_SLASHES(s) \
1290 while (*(s) && isSLASH(*(s))) \
1293 #define COPY_NONSLASHES(d,s) \
1295 while (*(s) && !isSLASH(*(s))) \
1299 /* Find the longname of a given path. path is destructively modified.
1300 * It should have space for at least MAX_PATH characters. */
1302 win32_longpath(char *path)
1304 WIN32_FIND_DATA fdata;
1306 char tmpbuf[MAX_PATH+1];
1307 char *tmpstart = tmpbuf;
1314 if (isALPHA(path[0]) && path[1] == ':') {
1316 *tmpstart++ = path[0];
1320 else if (isSLASH(path[0]) && isSLASH(path[1])) {
1322 *tmpstart++ = path[0];
1323 *tmpstart++ = path[1];
1324 SKIP_SLASHES(start);
1325 COPY_NONSLASHES(tmpstart,start); /* copy machine name */
1327 *tmpstart++ = *start++;
1328 SKIP_SLASHES(start);
1329 COPY_NONSLASHES(tmpstart,start); /* copy share name */
1334 /* copy initial slash, if any */
1335 if (isSLASH(*start)) {
1336 *tmpstart++ = *start++;
1338 SKIP_SLASHES(start);
1341 /* FindFirstFile() expands "." and "..", so we need to pass
1342 * those through unmolested */
1344 && (!start[1] || isSLASH(start[1])
1345 || (start[1] == '.' && (!start[2] || isSLASH(start[2])))))
1347 COPY_NONSLASHES(tmpstart,start); /* copy "." or ".." */
1352 /* if this is the end, bust outta here */
1356 /* now we're at a non-slash; walk up to next slash */
1357 while (*start && !isSLASH(*start))
1360 /* stop and find full name of component */
1363 fhand = FindFirstFile(path,&fdata);
1365 if (fhand != INVALID_HANDLE_VALUE) {
1366 STRLEN len = strlen(fdata.cFileName);
1367 if ((STRLEN)(tmpbuf + sizeof(tmpbuf) - tmpstart) > len) {
1368 strcpy(tmpstart, fdata.cFileName);
1379 /* failed a step, just return without side effects */
1380 /*PerlIO_printf(Perl_debug_log, "Failed to find %s\n", path);*/
1385 strcpy(path,tmpbuf);
1390 win32_getenv(const char *name)
1393 WCHAR wBuffer[MAX_PATH+1];
1395 SV *curitem = Nullsv;
1398 A2WHELPER(name, wBuffer, sizeof(wBuffer));
1399 needlen = GetEnvironmentVariableW(wBuffer, NULL, 0);
1402 needlen = GetEnvironmentVariableA(name,NULL,0);
1404 curitem = sv_2mortal(newSVpvn("", 0));
1408 SvGROW(curitem, (needlen+1)*sizeof(WCHAR));
1409 needlen = GetEnvironmentVariableW(wBuffer,
1410 (WCHAR*)SvPVX(curitem),
1412 } while (needlen >= SvLEN(curitem)/sizeof(WCHAR));
1413 SvCUR_set(curitem, (needlen*sizeof(WCHAR))+1);
1414 acuritem = sv_2mortal(newSVsv(curitem));
1415 W2AHELPER((WCHAR*)SvPVX(acuritem), SvPVX(curitem), SvCUR(curitem));
1419 SvGROW(curitem, needlen+1);
1420 needlen = GetEnvironmentVariableA(name,SvPVX(curitem),
1422 } while (needlen >= SvLEN(curitem));
1423 SvCUR_set(curitem, needlen);
1427 /* allow any environment variables that begin with 'PERL'
1428 to be stored in the registry */
1429 if (strncmp(name, "PERL", 4) == 0)
1430 (void)get_regstr(name, &curitem);
1432 if (curitem && SvCUR(curitem))
1433 return SvPVX(curitem);
1439 win32_putenv(const char *name)
1446 int length, relval = -1;
1450 length = strlen(name)+1;
1451 New(1309,wCuritem,length,WCHAR);
1452 A2WHELPER(name, wCuritem, length*sizeof(WCHAR));
1453 wVal = wcschr(wCuritem, '=');
1456 if (SetEnvironmentVariableW(wCuritem, *wVal ? wVal : NULL))
1462 New(1309,curitem,strlen(name)+1,char);
1463 strcpy(curitem, name);
1464 val = strchr(curitem, '=');
1466 /* The sane way to deal with the environment.
1467 * Has these advantages over putenv() & co.:
1468 * * enables us to store a truly empty value in the
1469 * environment (like in UNIX).
1470 * * we don't have to deal with RTL globals, bugs and leaks.
1472 * Why you may want to enable USE_WIN32_RTL_ENV:
1473 * * environ[] and RTL functions will not reflect changes,
1474 * which might be an issue if extensions want to access
1475 * the env. via RTL. This cuts both ways, since RTL will
1476 * not see changes made by extensions that call the Win32
1477 * functions directly, either.
1481 if (SetEnvironmentVariableA(curitem, *val ? val : NULL))
1491 filetime_to_clock(PFILETIME ft)
1493 __int64 qw = ft->dwHighDateTime;
1495 qw |= ft->dwLowDateTime;
1496 qw /= 10000; /* File time ticks at 0.1uS, clock at 1mS */
1501 win32_times(struct tms *timebuf)
1506 if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy,
1508 timebuf->tms_utime = filetime_to_clock(&user);
1509 timebuf->tms_stime = filetime_to_clock(&kernel);
1510 timebuf->tms_cutime = 0;
1511 timebuf->tms_cstime = 0;
1514 /* That failed - e.g. Win95 fallback to clock() */
1515 clock_t t = clock();
1516 timebuf->tms_utime = t;
1517 timebuf->tms_stime = 0;
1518 timebuf->tms_cutime = 0;
1519 timebuf->tms_cstime = 0;
1524 /* fix utime() so it works on directories in NT */
1526 filetime_from_time(PFILETIME pFileTime, time_t Time)
1528 struct tm *pTM = localtime(&Time);
1529 SYSTEMTIME SystemTime;
1535 SystemTime.wYear = pTM->tm_year + 1900;
1536 SystemTime.wMonth = pTM->tm_mon + 1;
1537 SystemTime.wDay = pTM->tm_mday;
1538 SystemTime.wHour = pTM->tm_hour;
1539 SystemTime.wMinute = pTM->tm_min;
1540 SystemTime.wSecond = pTM->tm_sec;
1541 SystemTime.wMilliseconds = 0;
1543 return SystemTimeToFileTime(&SystemTime, &LocalTime) &&
1544 LocalFileTimeToFileTime(&LocalTime, pFileTime);
1548 win32_unlink(const char *filename)
1555 WCHAR wBuffer[MAX_PATH+1];
1558 A2WHELPER(filename, wBuffer, sizeof(wBuffer));
1559 pwBuffer = PerlDir_mapW(wBuffer);
1560 attrs = GetFileAttributesW(pwBuffer);
1561 if (attrs == 0xFFFFFFFF)
1563 if (attrs & FILE_ATTRIBUTE_READONLY) {
1564 (void)SetFileAttributesW(pwBuffer, attrs & ~FILE_ATTRIBUTE_READONLY);
1565 ret = _wunlink(pwBuffer);
1567 (void)SetFileAttributesW(pwBuffer, attrs);
1570 ret = _wunlink(pwBuffer);
1573 filename = PerlDir_mapA(filename);
1574 attrs = GetFileAttributesA(filename);
1575 if (attrs == 0xFFFFFFFF)
1577 if (attrs & FILE_ATTRIBUTE_READONLY) {
1578 (void)SetFileAttributesA(filename, attrs & ~FILE_ATTRIBUTE_READONLY);
1579 ret = unlink(filename);
1581 (void)SetFileAttributesA(filename, attrs);
1584 ret = unlink(filename);
1593 win32_utime(const char *filename, struct utimbuf *times)
1600 struct utimbuf TimeBuffer;
1601 WCHAR wbuffer[MAX_PATH+1];
1606 A2WHELPER(filename, wbuffer, sizeof(wbuffer));
1607 pwbuffer = PerlDir_mapW(wbuffer);
1608 rc = _wutime(pwbuffer, (struct _utimbuf*)times);
1611 filename = PerlDir_mapA(filename);
1612 rc = utime(filename, times);
1614 /* EACCES: path specifies directory or readonly file */
1615 if (rc == 0 || errno != EACCES /* || !IsWinNT() */)
1618 if (times == NULL) {
1619 times = &TimeBuffer;
1620 time(×->actime);
1621 times->modtime = times->actime;
1624 /* This will (and should) still fail on readonly files */
1626 handle = CreateFileW(pwbuffer, GENERIC_READ | GENERIC_WRITE,
1627 FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
1628 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1631 handle = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE,
1632 FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
1633 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1635 if (handle == INVALID_HANDLE_VALUE)
1638 if (GetFileTime(handle, &ftCreate, &ftAccess, &ftWrite) &&
1639 filetime_from_time(&ftAccess, times->actime) &&
1640 filetime_from_time(&ftWrite, times->modtime) &&
1641 SetFileTime(handle, &ftCreate, &ftAccess, &ftWrite))
1646 CloseHandle(handle);
1651 win32_uname(struct utsname *name)
1653 struct hostent *hep;
1654 STRLEN nodemax = sizeof(name->nodename)-1;
1655 OSVERSIONINFO osver;
1657 memset(&osver, 0, sizeof(OSVERSIONINFO));
1658 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1659 if (GetVersionEx(&osver)) {
1661 switch (osver.dwPlatformId) {
1662 case VER_PLATFORM_WIN32_WINDOWS:
1663 strcpy(name->sysname, "Windows");
1665 case VER_PLATFORM_WIN32_NT:
1666 strcpy(name->sysname, "Windows NT");
1668 case VER_PLATFORM_WIN32s:
1669 strcpy(name->sysname, "Win32s");
1672 strcpy(name->sysname, "Win32 Unknown");
1677 sprintf(name->release, "%d.%d",
1678 osver.dwMajorVersion, osver.dwMinorVersion);
1681 sprintf(name->version, "Build %d",
1682 osver.dwPlatformId == VER_PLATFORM_WIN32_NT
1683 ? osver.dwBuildNumber : (osver.dwBuildNumber & 0xffff));
1684 if (osver.szCSDVersion[0]) {
1685 char *buf = name->version + strlen(name->version);
1686 sprintf(buf, " (%s)", osver.szCSDVersion);
1690 *name->sysname = '\0';
1691 *name->version = '\0';
1692 *name->release = '\0';
1696 hep = win32_gethostbyname("localhost");
1698 STRLEN len = strlen(hep->h_name);
1699 if (len <= nodemax) {
1700 strcpy(name->nodename, hep->h_name);
1703 strncpy(name->nodename, hep->h_name, nodemax);
1704 name->nodename[nodemax] = '\0';
1709 if (!GetComputerName(name->nodename, &sz))
1710 *name->nodename = '\0';
1713 /* machine (architecture) */
1717 GetSystemInfo(&info);
1719 #if (defined(__BORLANDC__)&&(__BORLANDC__<=0x520)) \
1720 || (defined(__MINGW32__) && !defined(_ANONYMOUS_UNION))
1721 switch (info.u.s.wProcessorArchitecture) {
1723 switch (info.wProcessorArchitecture) {
1725 case PROCESSOR_ARCHITECTURE_INTEL:
1726 arch = "x86"; break;
1727 case PROCESSOR_ARCHITECTURE_MIPS:
1728 arch = "mips"; break;
1729 case PROCESSOR_ARCHITECTURE_ALPHA:
1730 arch = "alpha"; break;
1731 case PROCESSOR_ARCHITECTURE_PPC:
1732 arch = "ppc"; break;
1734 arch = "unknown"; break;
1736 strcpy(name->machine, arch);
1741 /* Timing related stuff */
1744 do_raise(pTHX_ int sig)
1746 if (sig < SIG_SIZE) {
1747 Sighandler_t handler = w32_sighandler[sig];
1748 if (handler == SIG_IGN) {
1751 else if (handler != SIG_DFL) {
1756 /* Choose correct default behaviour */
1772 /* Tell caller to exit thread/process as approriate */
1777 sig_terminate(pTHX_ int sig)
1779 Perl_warn(aTHX_ "Terminating on signal SIG%s(%d)\n",PL_sig_name[sig], sig);
1780 /* exit() seems to be safe, my_exit() or die() is a problem in ^C
1787 win32_async_check(pTHX)
1791 /* Passing PeekMessage -1 as HWND (2nd arg) only get PostThreadMessage() messages
1792 * and ignores window messages - should co-exist better with windows apps e.g. Tk
1794 while (PeekMessage(&msg, (HWND)-1, 0, 0, PM_REMOVE|PM_NOYIELD)) {
1796 switch(msg.message) {
1799 /* Perhaps some other messages could map to signals ? ... */
1802 /* Treat WM_QUIT like SIGHUP? */
1808 /* We use WM_USER to fake kill() with other signals */
1812 if (do_raise(aTHX_ sig)) {
1813 sig_terminate(aTHX_ sig);
1819 /* alarm() is a one-shot but SetTimer() repeats so kill it */
1821 KillTimer(NULL,w32_timerid);
1824 /* Now fake a call to signal handler */
1825 if (do_raise(aTHX_ 14)) {
1826 sig_terminate(aTHX_ 14);
1831 /* Otherwise do normal Win32 thing - in case it is useful */
1833 TranslateMessage(&msg);
1834 DispatchMessage(&msg);
1841 /* Above or other stuff may have set a signal flag */
1842 if (PL_sig_pending) {
1849 win32_msgwait(pTHX_ DWORD count, LPHANDLE handles, DWORD timeout, LPDWORD resultp)
1851 /* We may need several goes at this - so compute when we stop */
1853 if (timeout != INFINITE) {
1854 ticks = GetTickCount();
1858 DWORD result = MsgWaitForMultipleObjects(count,handles,FALSE,timeout-ticks, QS_ALLEVENTS);
1861 if (result == WAIT_TIMEOUT) {
1862 /* Ran out of time - explicit return of zero to avoid -ve if we
1863 have scheduling issues
1867 if (timeout != INFINITE) {
1868 ticks = GetTickCount();
1870 if (result == WAIT_OBJECT_0 + count) {
1871 /* Message has arrived - check it */
1872 if (win32_async_check(aTHX)) {
1873 /* was one of ours */
1878 /* Not timeout or message - one of handles is ready */
1882 /* compute time left to wait */
1883 ticks = timeout - ticks;
1884 /* If we are past the end say zero */
1885 return (ticks > 0) ? ticks : 0;
1889 win32_internal_wait(int *status, DWORD timeout)
1891 /* XXX this wait emulation only knows about processes
1892 * spawned via win32_spawnvp(P_NOWAIT, ...).
1896 DWORD exitcode, waitcode;
1899 if (w32_num_pseudo_children) {
1900 win32_msgwait(aTHX_ w32_num_pseudo_children, w32_pseudo_child_handles,
1901 timeout, &waitcode);
1902 /* Time out here if there are no other children to wait for. */
1903 if (waitcode == WAIT_TIMEOUT) {
1904 if (!w32_num_children) {
1908 else if (waitcode != WAIT_FAILED) {
1909 if (waitcode >= WAIT_ABANDONED_0
1910 && waitcode < WAIT_ABANDONED_0 + w32_num_pseudo_children)
1911 i = waitcode - WAIT_ABANDONED_0;
1913 i = waitcode - WAIT_OBJECT_0;
1914 if (GetExitCodeThread(w32_pseudo_child_handles[i], &exitcode)) {
1915 *status = (int)((exitcode & 0xff) << 8);
1916 retval = (int)w32_pseudo_child_pids[i];
1917 remove_dead_pseudo_process(i);
1924 if (!w32_num_children) {
1929 /* if a child exists, wait for it to die */
1930 win32_msgwait(aTHX_ w32_num_children, w32_child_handles, timeout, &waitcode);
1931 if (waitcode == WAIT_TIMEOUT) {
1934 if (waitcode != WAIT_FAILED) {
1935 if (waitcode >= WAIT_ABANDONED_0
1936 && waitcode < WAIT_ABANDONED_0 + w32_num_children)
1937 i = waitcode - WAIT_ABANDONED_0;
1939 i = waitcode - WAIT_OBJECT_0;
1940 if (GetExitCodeProcess(w32_child_handles[i], &exitcode) ) {
1941 *status = (int)((exitcode & 0xff) << 8);
1942 retval = (int)w32_child_pids[i];
1943 remove_dead_process(i);
1949 errno = GetLastError();
1954 win32_waitpid(int pid, int *status, int flags)
1957 DWORD timeout = (flags & WNOHANG) ? 0 : INFINITE;
1960 if (pid == -1) /* XXX threadid == 1 ? */
1961 return win32_internal_wait(status, timeout);
1964 child = find_pseudo_pid(-pid);
1966 HANDLE hThread = w32_pseudo_child_handles[child];
1968 win32_msgwait(aTHX_ 1, &hThread, timeout, &waitcode);
1969 if (waitcode == WAIT_TIMEOUT) {
1972 else if (waitcode == WAIT_OBJECT_0) {
1973 if (GetExitCodeThread(hThread, &waitcode)) {
1974 *status = (int)((waitcode & 0xff) << 8);
1975 retval = (int)w32_pseudo_child_pids[child];
1976 remove_dead_pseudo_process(child);
1983 else if (IsWin95()) {
1992 child = find_pid(pid);
1994 hProcess = w32_child_handles[child];
1995 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
1996 if (waitcode == WAIT_TIMEOUT) {
1999 else if (waitcode == WAIT_OBJECT_0) {
2000 if (GetExitCodeProcess(hProcess, &waitcode)) {
2001 *status = (int)((waitcode & 0xff) << 8);
2002 retval = (int)w32_child_pids[child];
2003 remove_dead_process(child);
2012 hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE,
2013 (IsWin95() ? -pid : pid));
2015 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
2016 if (waitcode == WAIT_TIMEOUT) {
2019 else if (waitcode == WAIT_OBJECT_0) {
2020 if (GetExitCodeProcess(hProcess, &waitcode)) {
2021 *status = (int)((waitcode & 0xff) << 8);
2022 CloseHandle(hProcess);
2026 CloseHandle(hProcess);
2032 return retval >= 0 ? pid : retval;
2036 win32_wait(int *status)
2038 return win32_internal_wait(status, INFINITE);
2041 DllExport unsigned int
2042 win32_sleep(unsigned int t)
2045 /* Win32 times are in ms so *1000 in and /1000 out */
2046 return win32_msgwait(aTHX_ 0, NULL, t*1000, NULL)/1000;
2049 DllExport unsigned int
2050 win32_alarm(unsigned int sec)
2053 * the 'obvious' implentation is SetTimer() with a callback
2054 * which does whatever receiving SIGALRM would do
2055 * we cannot use SIGALRM even via raise() as it is not
2056 * one of the supported codes in <signal.h>
2060 w32_timerid = SetTimer(NULL,w32_timerid,sec*1000,NULL);
2064 KillTimer(NULL,w32_timerid);
2071 #ifdef HAVE_DES_FCRYPT
2072 extern char * des_fcrypt(const char *txt, const char *salt, char *cbuf);
2076 win32_crypt(const char *txt, const char *salt)
2079 #ifdef HAVE_DES_FCRYPT
2080 return des_fcrypt(txt, salt, w32_crypt_buffer);
2082 Perl_croak(aTHX_ "The crypt() function is unimplemented due to excessive paranoia.");
2087 #ifdef USE_FIXED_OSFHANDLE
2089 #define FOPEN 0x01 /* file handle open */
2090 #define FNOINHERIT 0x10 /* file handle opened O_NOINHERIT */
2091 #define FAPPEND 0x20 /* file handle opened O_APPEND */
2092 #define FDEV 0x40 /* file handle refers to device */
2093 #define FTEXT 0x80 /* file handle is in text mode */
2096 *int my_open_osfhandle(long osfhandle, int flags) - open C Runtime file handle
2099 * This function allocates a free C Runtime file handle and associates
2100 * it with the Win32 HANDLE specified by the first parameter. This is a
2101 * temperary fix for WIN95's brain damage GetFileType() error on socket
2102 * we just bypass that call for socket
2104 * This works with MSVC++ 4.0+ or GCC/Mingw32
2107 * long osfhandle - Win32 HANDLE to associate with C Runtime file handle.
2108 * int flags - flags to associate with C Runtime file handle.
2111 * returns index of entry in fh, if successful
2112 * return -1, if no free entry is found
2116 *******************************************************************************/
2119 * we fake up some parts of the CRT that aren't exported by MSVCRT.dll
2120 * this lets sockets work on Win9X with GCC and should fix the problems
2125 /* create an ioinfo entry, kill its handle, and steal the entry */
2130 HANDLE hF = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
2131 int fh = _open_osfhandle((long)hF, 0);
2135 EnterCriticalSection(&(_pioinfo(fh)->lock));
2140 my_open_osfhandle(long osfhandle, int flags)
2143 char fileflags; /* _osfile flags */
2145 /* copy relevant flags from second parameter */
2148 if (flags & O_APPEND)
2149 fileflags |= FAPPEND;
2154 if (flags & O_NOINHERIT)
2155 fileflags |= FNOINHERIT;
2157 /* attempt to allocate a C Runtime file handle */
2158 if ((fh = _alloc_osfhnd()) == -1) {
2159 errno = EMFILE; /* too many open files */
2160 _doserrno = 0L; /* not an OS error */
2161 return -1; /* return error to caller */
2164 /* the file is open. now, set the info in _osfhnd array */
2165 _set_osfhnd(fh, osfhandle);
2167 fileflags |= FOPEN; /* mark as open */
2169 _osfile(fh) = fileflags; /* set osfile entry */
2170 LeaveCriticalSection(&_pioinfo(fh)->lock);
2172 return fh; /* return handle */
2175 #endif /* USE_FIXED_OSFHANDLE */
2177 /* simulate flock by locking a range on the file */
2179 #define LK_ERR(f,i) ((f) ? (i = 0) : (errno = GetLastError()))
2180 #define LK_LEN 0xffff0000
2183 win32_flock(int fd, int oper)
2191 Perl_croak_nocontext("flock() unimplemented on this platform");
2194 fh = (HANDLE)_get_osfhandle(fd);
2195 memset(&o, 0, sizeof(o));
2198 case LOCK_SH: /* shared lock */
2199 LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, 0, &o),i);
2201 case LOCK_EX: /* exclusive lock */
2202 LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o),i);
2204 case LOCK_SH|LOCK_NB: /* non-blocking shared lock */
2205 LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o),i);
2207 case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */
2208 LK_ERR(LockFileEx(fh,
2209 LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
2210 0, LK_LEN, 0, &o),i);
2212 case LOCK_UN: /* unlock lock */
2213 LK_ERR(UnlockFileEx(fh, 0, LK_LEN, 0, &o),i);
2215 default: /* unknown */
2226 * redirected io subsystem for all XS modules
2239 return (&(_environ));
2242 /* the rest are the remapped stdio routines */
2262 win32_ferror(FILE *fp)
2264 return (ferror(fp));
2269 win32_feof(FILE *fp)
2275 * Since the errors returned by the socket error function
2276 * WSAGetLastError() are not known by the library routine strerror
2277 * we have to roll our own.
2281 win32_strerror(int e)
2283 #if !defined __BORLANDC__ && !defined __MINGW32__ /* compiler intolerance */
2284 extern int sys_nerr;
2288 if (e < 0 || e > sys_nerr) {
2293 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0,
2294 w32_strerror_buffer,
2295 sizeof(w32_strerror_buffer), NULL) == 0)
2296 strcpy(w32_strerror_buffer, "Unknown Error");
2298 return w32_strerror_buffer;
2304 win32_str_os_error(void *sv, DWORD dwErr)
2308 dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
2309 |FORMAT_MESSAGE_IGNORE_INSERTS
2310 |FORMAT_MESSAGE_FROM_SYSTEM, NULL,
2311 dwErr, 0, (char *)&sMsg, 1, NULL);
2312 /* strip trailing whitespace and period */
2315 --dwLen; /* dwLen doesn't include trailing null */
2316 } while (0 < dwLen && isSPACE(sMsg[dwLen]));
2317 if ('.' != sMsg[dwLen])
2322 sMsg = (char*)LocalAlloc(0, 64/**sizeof(TCHAR)*/);
2324 dwLen = sprintf(sMsg,
2325 "Unknown error #0x%lX (lookup 0x%lX)",
2326 dwErr, GetLastError());
2330 sv_setpvn((SV*)sv, sMsg, dwLen);
2336 win32_fprintf(FILE *fp, const char *format, ...)
2339 va_start(marker, format); /* Initialize variable arguments. */
2341 return (vfprintf(fp, format, marker));
2345 win32_printf(const char *format, ...)
2348 va_start(marker, format); /* Initialize variable arguments. */
2350 return (vprintf(format, marker));
2354 win32_vfprintf(FILE *fp, const char *format, va_list args)
2356 return (vfprintf(fp, format, args));
2360 win32_vprintf(const char *format, va_list args)
2362 return (vprintf(format, args));
2366 win32_fread(void *buf, size_t size, size_t count, FILE *fp)
2368 return fread(buf, size, count, fp);
2372 win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
2374 return fwrite(buf, size, count, fp);
2377 #define MODE_SIZE 10
2380 win32_fopen(const char *filename, const char *mode)
2383 WCHAR wMode[MODE_SIZE], wBuffer[MAX_PATH+1];
2389 if (stricmp(filename, "/dev/null")==0)
2393 A2WHELPER(mode, wMode, sizeof(wMode));
2394 A2WHELPER(filename, wBuffer, sizeof(wBuffer));
2395 f = _wfopen(PerlDir_mapW(wBuffer), wMode);
2398 f = fopen(PerlDir_mapA(filename), mode);
2399 /* avoid buffering headaches for child processes */
2400 if (f && *mode == 'a')
2401 win32_fseek(f, 0, SEEK_END);
2405 #ifndef USE_SOCKETS_AS_HANDLES
2407 #define fdopen my_fdopen
2411 win32_fdopen(int handle, const char *mode)
2414 WCHAR wMode[MODE_SIZE];
2417 A2WHELPER(mode, wMode, sizeof(wMode));
2418 f = _wfdopen(handle, wMode);
2421 f = fdopen(handle, (char *) mode);
2422 /* avoid buffering headaches for child processes */
2423 if (f && *mode == 'a')
2424 win32_fseek(f, 0, SEEK_END);
2429 win32_freopen(const char *path, const char *mode, FILE *stream)
2432 WCHAR wMode[MODE_SIZE], wBuffer[MAX_PATH+1];
2433 if (stricmp(path, "/dev/null")==0)
2437 A2WHELPER(mode, wMode, sizeof(wMode));
2438 A2WHELPER(path, wBuffer, sizeof(wBuffer));
2439 return _wfreopen(PerlDir_mapW(wBuffer), wMode, stream);
2441 return freopen(PerlDir_mapA(path), mode, stream);
2445 win32_fclose(FILE *pf)
2447 return my_fclose(pf); /* defined in win32sck.c */
2451 win32_fputs(const char *s,FILE *pf)
2453 return fputs(s, pf);
2457 win32_fputc(int c,FILE *pf)
2463 win32_ungetc(int c,FILE *pf)
2465 return ungetc(c,pf);
2469 win32_getc(FILE *pf)
2475 win32_fileno(FILE *pf)
2481 win32_clearerr(FILE *pf)
2488 win32_fflush(FILE *pf)
2494 win32_ftell(FILE *pf)
2500 win32_fseek(FILE *pf,long offset,int origin)
2502 return fseek(pf, offset, origin);
2506 win32_fgetpos(FILE *pf,fpos_t *p)
2508 return fgetpos(pf, p);
2512 win32_fsetpos(FILE *pf,const fpos_t *p)
2514 return fsetpos(pf, p);
2518 win32_rewind(FILE *pf)
2528 char prefix[MAX_PATH+1];
2529 char filename[MAX_PATH+1];
2530 DWORD len = GetTempPath(MAX_PATH, prefix);
2531 if (len && len < MAX_PATH) {
2532 if (GetTempFileName(prefix, "plx", 0, filename)) {
2533 HANDLE fh = CreateFile(filename,
2534 DELETE | GENERIC_READ | GENERIC_WRITE,
2538 FILE_ATTRIBUTE_NORMAL
2539 | FILE_FLAG_DELETE_ON_CLOSE,
2541 if (fh != INVALID_HANDLE_VALUE) {
2542 int fd = win32_open_osfhandle((long)fh, 0);
2544 DEBUG_p(PerlIO_printf(Perl_debug_log,
2545 "Created tmpfile=%s\n",filename));
2546 return fdopen(fd, "w+b");
2562 win32_fstat(int fd,struct stat *sbufptr)
2565 /* A file designated by filehandle is not shown as accessible
2566 * for write operations, probably because it is opened for reading.
2569 int rc = fstat(fd,sbufptr);
2570 BY_HANDLE_FILE_INFORMATION bhfi;
2571 if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &bhfi)) {
2572 sbufptr->st_mode &= 0xFE00;
2573 if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
2574 sbufptr->st_mode |= (S_IREAD + (S_IREAD >> 3) + (S_IREAD >> 6));
2576 sbufptr->st_mode |= ((S_IREAD|S_IWRITE) + ((S_IREAD|S_IWRITE) >> 3)
2577 + ((S_IREAD|S_IWRITE) >> 6));
2581 return my_fstat(fd,sbufptr);
2586 win32_pipe(int *pfd, unsigned int size, int mode)
2588 return _pipe(pfd, size, mode);
2592 win32_popenlist(const char *mode, IV narg, SV **args)
2595 Perl_croak(aTHX_ "List form of pipe open not implemented");
2600 * a popen() clone that respects PERL5SHELL
2602 * changed to return PerlIO* rather than FILE * by BKS, 11-11-2000
2606 win32_popen(const char *command, const char *mode)
2608 #ifdef USE_RTL_POPEN
2609 return _popen(command, mode);
2617 /* establish which ends read and write */
2618 if (strchr(mode,'w')) {
2619 stdfd = 0; /* stdin */
2623 else if (strchr(mode,'r')) {
2624 stdfd = 1; /* stdout */
2631 /* set the correct mode */
2632 if (strchr(mode,'b'))
2634 else if (strchr(mode,'t'))
2637 ourmode = _fmode & (O_TEXT | O_BINARY);
2639 /* the child doesn't inherit handles */
2640 ourmode |= O_NOINHERIT;
2642 if (win32_pipe( p, 512, ourmode) == -1)
2645 /* save current stdfd */
2646 if ((oldfd = win32_dup(stdfd)) == -1)
2649 /* make stdfd go to child end of pipe (implicitly closes stdfd) */
2650 /* stdfd will be inherited by the child */
2651 if (win32_dup2(p[child], stdfd) == -1)
2654 /* close the child end in parent */
2655 win32_close(p[child]);
2657 /* start the child */
2660 if ((childpid = do_spawn_nowait((char*)command)) == -1)
2663 /* revert stdfd to whatever it was before */
2664 if (win32_dup2(oldfd, stdfd) == -1)
2667 /* close saved handle */
2671 sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid);
2674 /* set process id so that it can be returned by perl's open() */
2675 PL_forkprocess = childpid;
2678 /* we have an fd, return a file stream */
2679 return (PerlIO_fdopen(p[parent], (char *)mode));
2682 /* we don't need to check for errors here */
2686 win32_dup2(oldfd, stdfd);
2691 #endif /* USE_RTL_POPEN */
2699 win32_pclose(PerlIO *pf)
2701 #ifdef USE_RTL_POPEN
2705 int childpid, status;
2709 sv = *av_fetch(w32_fdpid, PerlIO_fileno(pf), TRUE);
2712 childpid = SvIVX(sv);
2729 if (win32_waitpid(childpid, &status, 0) == -1)
2734 #endif /* USE_RTL_POPEN */
2740 LPCWSTR lpExistingFileName,
2741 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
2744 WCHAR wFullName[MAX_PATH+1];
2745 LPVOID lpContext = NULL;
2746 WIN32_STREAM_ID StreamId;
2747 DWORD dwSize = (char*)&StreamId.cStreamName - (char*)&StreamId;
2752 BOOL (__stdcall *pfnBackupWrite)(HANDLE, LPBYTE, DWORD, LPDWORD,
2753 BOOL, BOOL, LPVOID*) =
2754 (BOOL (__stdcall *)(HANDLE, LPBYTE, DWORD, LPDWORD,
2755 BOOL, BOOL, LPVOID*))
2756 GetProcAddress(GetModuleHandle("kernel32.dll"), "BackupWrite");
2757 if (pfnBackupWrite == NULL)
2760 dwLen = GetFullPathNameW(lpFileName, MAX_PATH, wFullName, NULL);
2763 dwLen = (dwLen+1)*sizeof(WCHAR);
2765 handle = CreateFileW(lpExistingFileName, FILE_WRITE_ATTRIBUTES,
2766 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2767 NULL, OPEN_EXISTING, 0, NULL);
2768 if (handle == INVALID_HANDLE_VALUE)
2771 StreamId.dwStreamId = BACKUP_LINK;
2772 StreamId.dwStreamAttributes = 0;
2773 StreamId.dwStreamNameSize = 0;
2774 #if defined(__BORLANDC__) \
2775 ||(defined(__MINGW32__) && !defined(_ANONYMOUS_UNION))
2776 StreamId.Size.u.HighPart = 0;
2777 StreamId.Size.u.LowPart = dwLen;
2779 StreamId.Size.HighPart = 0;
2780 StreamId.Size.LowPart = dwLen;
2783 bSuccess = pfnBackupWrite(handle, (LPBYTE)&StreamId, dwSize, &dwWritten,
2784 FALSE, FALSE, &lpContext);
2786 bSuccess = pfnBackupWrite(handle, (LPBYTE)wFullName, dwLen, &dwWritten,
2787 FALSE, FALSE, &lpContext);
2788 pfnBackupWrite(handle, NULL, 0, &dwWritten, TRUE, FALSE, &lpContext);
2791 CloseHandle(handle);
2796 win32_link(const char *oldname, const char *newname)
2799 BOOL (__stdcall *pfnCreateHardLinkW)(LPCWSTR,LPCWSTR,LPSECURITY_ATTRIBUTES);
2800 WCHAR wOldName[MAX_PATH+1];
2801 WCHAR wNewName[MAX_PATH+1];
2804 Perl_croak(aTHX_ PL_no_func, "link");
2806 pfnCreateHardLinkW =
2807 (BOOL (__stdcall *)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES))
2808 GetProcAddress(GetModuleHandle("kernel32.dll"), "CreateHardLinkW");
2809 if (pfnCreateHardLinkW == NULL)
2810 pfnCreateHardLinkW = Nt4CreateHardLinkW;
2812 if ((A2WHELPER(oldname, wOldName, sizeof(wOldName))) &&
2813 (A2WHELPER(newname, wNewName, sizeof(wNewName))) &&
2814 (wcscpy(wOldName, PerlDir_mapW(wOldName)),
2815 pfnCreateHardLinkW(PerlDir_mapW(wNewName), wOldName, NULL)))
2819 errno = (GetLastError() == ERROR_FILE_NOT_FOUND) ? ENOENT : EINVAL;
2824 win32_rename(const char *oname, const char *newname)
2826 WCHAR wOldName[MAX_PATH+1];
2827 WCHAR wNewName[MAX_PATH+1];
2828 char szOldName[MAX_PATH+1];
2829 char szNewName[MAX_PATH+1];
2833 /* XXX despite what the documentation says about MoveFileEx(),
2834 * it doesn't work under Windows95!
2837 DWORD dwFlags = MOVEFILE_COPY_ALLOWED;
2839 A2WHELPER(oname, wOldName, sizeof(wOldName));
2840 A2WHELPER(newname, wNewName, sizeof(wNewName));
2841 if (wcsicmp(wNewName, wOldName))
2842 dwFlags |= MOVEFILE_REPLACE_EXISTING;
2843 wcscpy(wOldName, PerlDir_mapW(wOldName));
2844 bResult = MoveFileExW(wOldName,PerlDir_mapW(wNewName), dwFlags);
2847 if (stricmp(newname, oname))
2848 dwFlags |= MOVEFILE_REPLACE_EXISTING;
2849 strcpy(szOldName, PerlDir_mapA(oname));
2850 bResult = MoveFileExA(szOldName,PerlDir_mapA(newname), dwFlags);
2853 DWORD err = GetLastError();
2855 case ERROR_BAD_NET_NAME:
2856 case ERROR_BAD_NETPATH:
2857 case ERROR_BAD_PATHNAME:
2858 case ERROR_FILE_NOT_FOUND:
2859 case ERROR_FILENAME_EXCED_RANGE:
2860 case ERROR_INVALID_DRIVE:
2861 case ERROR_NO_MORE_FILES:
2862 case ERROR_PATH_NOT_FOUND:
2875 char szTmpName[MAX_PATH+1];
2876 char dname[MAX_PATH+1];
2877 char *endname = Nullch;
2879 DWORD from_attr, to_attr;
2881 strcpy(szOldName, PerlDir_mapA(oname));
2882 strcpy(szNewName, PerlDir_mapA(newname));
2884 /* if oname doesn't exist, do nothing */
2885 from_attr = GetFileAttributes(szOldName);
2886 if (from_attr == 0xFFFFFFFF) {
2891 /* if newname exists, rename it to a temporary name so that we
2892 * don't delete it in case oname happens to be the same file
2893 * (but perhaps accessed via a different path)
2895 to_attr = GetFileAttributes(szNewName);
2896 if (to_attr != 0xFFFFFFFF) {
2897 /* if newname is a directory, we fail
2898 * XXX could overcome this with yet more convoluted logic */
2899 if (to_attr & FILE_ATTRIBUTE_DIRECTORY) {
2903 tmplen = strlen(szNewName);
2904 strcpy(szTmpName,szNewName);
2905 endname = szTmpName+tmplen;
2906 for (; endname > szTmpName ; --endname) {
2907 if (*endname == '/' || *endname == '\\') {
2912 if (endname > szTmpName)
2913 endname = strcpy(dname,szTmpName);
2917 /* get a temporary filename in same directory
2918 * XXX is this really the best we can do? */
2919 if (!GetTempFileName((LPCTSTR)endname, "plr", 0, szTmpName)) {
2923 DeleteFile(szTmpName);
2925 retval = rename(szNewName, szTmpName);
2932 /* rename oname to newname */
2933 retval = rename(szOldName, szNewName);
2935 /* if we created a temporary file before ... */
2936 if (endname != Nullch) {
2937 /* ...and rename succeeded, delete temporary file/directory */
2939 DeleteFile(szTmpName);
2940 /* else restore it to what it was */
2942 (void)rename(szTmpName, szNewName);
2949 win32_setmode(int fd, int mode)
2951 return setmode(fd, mode);
2955 win32_lseek(int fd, long offset, int origin)
2957 return lseek(fd, offset, origin);
2967 win32_open(const char *path, int flag, ...)
2972 WCHAR wBuffer[MAX_PATH+1];
2975 pmode = va_arg(ap, int);
2978 if (stricmp(path, "/dev/null")==0)
2982 A2WHELPER(path, wBuffer, sizeof(wBuffer));
2983 return _wopen(PerlDir_mapW(wBuffer), flag, pmode);
2985 return open(PerlDir_mapA(path), flag, pmode);
2988 /* close() that understands socket */
2989 extern int my_close(int); /* in win32sck.c */
2994 return my_close(fd);
3010 win32_dup2(int fd1,int fd2)
3012 return dup2(fd1,fd2);
3015 #ifdef PERL_MSVCRT_READFIX
3017 #define LF 10 /* line feed */
3018 #define CR 13 /* carriage return */
3019 #define CTRLZ 26 /* ctrl-z means eof for text */
3020 #define FOPEN 0x01 /* file handle open */
3021 #define FEOFLAG 0x02 /* end of file has been encountered */
3022 #define FCRLF 0x04 /* CR-LF across read buffer (in text mode) */
3023 #define FPIPE 0x08 /* file handle refers to a pipe */
3024 #define FAPPEND 0x20 /* file handle opened O_APPEND */
3025 #define FDEV 0x40 /* file handle refers to device */
3026 #define FTEXT 0x80 /* file handle is in text mode */
3027 #define MAX_DESCRIPTOR_COUNT (64*32) /* this is the maximun that MSVCRT can handle */
3030 _fixed_read(int fh, void *buf, unsigned cnt)
3032 int bytes_read; /* number of bytes read */
3033 char *buffer; /* buffer to read to */
3034 int os_read; /* bytes read on OS call */
3035 char *p, *q; /* pointers into buffer */
3036 char peekchr; /* peek-ahead character */
3037 ULONG filepos; /* file position after seek */
3038 ULONG dosretval; /* o.s. return value */
3040 /* validate handle */
3041 if (((unsigned)fh >= (unsigned)MAX_DESCRIPTOR_COUNT) ||
3042 !(_osfile(fh) & FOPEN))
3044 /* out of range -- return error */
3046 _doserrno = 0; /* not o.s. error */
3051 * If lockinitflag is FALSE, assume fd is device
3052 * lockinitflag is set to TRUE by open.
3054 if (_pioinfo(fh)->lockinitflag)
3055 EnterCriticalSection(&(_pioinfo(fh)->lock)); /* lock file */
3057 bytes_read = 0; /* nothing read yet */
3058 buffer = (char*)buf;
3060 if (cnt == 0 || (_osfile(fh) & FEOFLAG)) {
3061 /* nothing to read or at EOF, so return 0 read */
3065 if ((_osfile(fh) & (FPIPE|FDEV)) && _pipech(fh) != LF) {
3066 /* a pipe/device and pipe lookahead non-empty: read the lookahead
3068 *buffer++ = _pipech(fh);
3071 _pipech(fh) = LF; /* mark as empty */
3076 if (!ReadFile((HANDLE)_osfhnd(fh), buffer, cnt, (LPDWORD)&os_read, NULL))
3078 /* ReadFile has reported an error. recognize two special cases.
3080 * 1. map ERROR_ACCESS_DENIED to EBADF
3082 * 2. just return 0 if ERROR_BROKEN_PIPE has occurred. it
3083 * means the handle is a read-handle on a pipe for which
3084 * all write-handles have been closed and all data has been
3087 if ((dosretval = GetLastError()) == ERROR_ACCESS_DENIED) {
3088 /* wrong read/write mode should return EBADF, not EACCES */
3090 _doserrno = dosretval;
3094 else if (dosretval == ERROR_BROKEN_PIPE) {
3104 bytes_read += os_read; /* update bytes read */
3106 if (_osfile(fh) & FTEXT) {
3107 /* now must translate CR-LFs to LFs in the buffer */
3109 /* set CRLF flag to indicate LF at beginning of buffer */
3110 /* if ((os_read != 0) && (*(char *)buf == LF)) */
3111 /* _osfile(fh) |= FCRLF; */
3113 /* _osfile(fh) &= ~FCRLF; */
3115 _osfile(fh) &= ~FCRLF;
3117 /* convert chars in the buffer: p is src, q is dest */
3119 while (p < (char *)buf + bytes_read) {
3121 /* if fh is not a device, set ctrl-z flag */
3122 if (!(_osfile(fh) & FDEV))
3123 _osfile(fh) |= FEOFLAG;
3124 break; /* stop translating */
3129 /* *p is CR, so must check next char for LF */
3130 if (p < (char *)buf + bytes_read - 1) {
3133 *q++ = LF; /* convert CR-LF to LF */
3136 *q++ = *p++; /* store char normally */
3139 /* This is the hard part. We found a CR at end of
3140 buffer. We must peek ahead to see if next char
3145 if (!ReadFile((HANDLE)_osfhnd(fh), &peekchr, 1,
3146 (LPDWORD)&os_read, NULL))
3147 dosretval = GetLastError();
3149 if (dosretval != 0 || os_read == 0) {
3150 /* couldn't read ahead, store CR */
3154 /* peekchr now has the extra character -- we now
3155 have several possibilities:
3156 1. disk file and char is not LF; just seek back
3158 2. disk file and char is LF; store LF, don't seek back
3159 3. pipe/device and char is LF; store LF.
3160 4. pipe/device and char isn't LF, store CR and
3161 put char in pipe lookahead buffer. */
3162 if (_osfile(fh) & (FDEV|FPIPE)) {
3163 /* non-seekable device */
3168 _pipech(fh) = peekchr;
3173 if (peekchr == LF) {
3174 /* nothing read yet; must make some
3177 /* turn on this flag for tell routine */
3178 _osfile(fh) |= FCRLF;
3181 HANDLE osHandle; /* o.s. handle value */
3183 if ((osHandle = (HANDLE)_get_osfhandle(fh)) != (HANDLE)-1)
3185 if ((filepos = SetFilePointer(osHandle, -1, NULL, FILE_CURRENT)) == -1)
3186 dosretval = GetLastError();
3197 /* we now change bytes_read to reflect the true number of chars
3199 bytes_read = q - (char *)buf;
3203 if (_pioinfo(fh)->lockinitflag)
3204 LeaveCriticalSection(&(_pioinfo(fh)->lock)); /* unlock file */
3209 #endif /* PERL_MSVCRT_READFIX */
3212 win32_read(int fd, void *buf, unsigned int cnt)
3214 #ifdef PERL_MSVCRT_READFIX
3215 return _fixed_read(fd, buf, cnt);
3217 return read(fd, buf, cnt);
3222 win32_write(int fd, const void *buf, unsigned int cnt)
3224 return write(fd, buf, cnt);
3228 win32_mkdir(const char *dir, int mode)
3232 WCHAR wBuffer[MAX_PATH+1];
3233 A2WHELPER(dir, wBuffer, sizeof(wBuffer));
3234 return _wmkdir(PerlDir_mapW(wBuffer));
3236 return mkdir(PerlDir_mapA(dir)); /* just ignore mode */
3240 win32_rmdir(const char *dir)
3244 WCHAR wBuffer[MAX_PATH+1];
3245 A2WHELPER(dir, wBuffer, sizeof(wBuffer));
3246 return _wrmdir(PerlDir_mapW(wBuffer));
3248 return rmdir(PerlDir_mapA(dir));
3252 win32_chdir(const char *dir)
3260 WCHAR wBuffer[MAX_PATH+1];
3261 A2WHELPER(dir, wBuffer, sizeof(wBuffer));
3262 return _wchdir(wBuffer);
3268 win32_access(const char *path, int mode)
3272 WCHAR wBuffer[MAX_PATH+1];
3273 A2WHELPER(path, wBuffer, sizeof(wBuffer));
3274 return _waccess(PerlDir_mapW(wBuffer), mode);
3276 return access(PerlDir_mapA(path), mode);
3280 win32_chmod(const char *path, int mode)
3284 WCHAR wBuffer[MAX_PATH+1];
3285 A2WHELPER(path, wBuffer, sizeof(wBuffer));
3286 return _wchmod(PerlDir_mapW(wBuffer), mode);
3288 return chmod(PerlDir_mapA(path), mode);
3293 create_command_line(char *cname, STRLEN clen, const char * const *args)
3300 bool bat_file = FALSE;
3301 bool cmd_shell = FALSE;
3302 bool dumb_shell = FALSE;
3303 bool extra_quotes = FALSE;
3304 bool quote_next = FALSE;
3307 cname = (char*)args[0];
3309 /* The NT cmd.exe shell has the following peculiarity that needs to be
3310 * worked around. It strips a leading and trailing dquote when any
3311 * of the following is true:
3312 * 1. the /S switch was used
3313 * 2. there are more than two dquotes
3314 * 3. there is a special character from this set: &<>()@^|
3315 * 4. no whitespace characters within the two dquotes
3316 * 5. string between two dquotes isn't an executable file
3317 * To work around this, we always add a leading and trailing dquote
3318 * to the string, if the first argument is either "cmd.exe" or "cmd",
3319 * and there were at least two or more arguments passed to cmd.exe
3320 * (not including switches).
3321 * XXX the above rules (from "cmd /?") don't seem to be applied
3322 * always, making for the convolutions below :-(
3326 clen = strlen(cname);
3329 && (stricmp(&cname[clen-4], ".bat") == 0
3330 || (IsWinNT() && stricmp(&cname[clen-4], ".cmd") == 0)))
3336 char *exe = strrchr(cname, '/');
3337 char *exe2 = strrchr(cname, '\\');
3344 if (stricmp(exe, "cmd.exe") == 0 || stricmp(exe, "cmd") == 0) {
3348 else if (stricmp(exe, "command.com") == 0
3349 || stricmp(exe, "command") == 0)
3356 DEBUG_p(PerlIO_printf(Perl_debug_log, "Args "));
3357 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3358 STRLEN curlen = strlen(arg);
3359 if (!(arg[0] == '"' && arg[curlen-1] == '"'))
3360 len += 2; /* assume quoting needed (worst case) */
3362 DEBUG_p(PerlIO_printf(Perl_debug_log, "[%s]",arg));
3364 DEBUG_p(PerlIO_printf(Perl_debug_log, "\n"));
3367 New(1310, cmd, len, char);
3372 extra_quotes = TRUE;
3375 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3377 STRLEN curlen = strlen(arg);
3379 /* we want to protect empty arguments and ones with spaces with
3380 * dquotes, but only if they aren't already there */
3385 else if (quote_next) {
3386 /* see if it really is multiple arguments pretending to
3387 * be one and force a set of quotes around it */
3388 if (*find_next_space(arg))
3391 else if (!(arg[0] == '"' && curlen > 1 && arg[curlen-1] == '"')) {
3393 while (i < curlen) {
3394 if (isSPACE(arg[i])) {
3397 else if (arg[i] == '"') {
3420 && (stricmp(arg, "/x/c") == 0 || stricmp(arg, "/c") == 0))
3422 /* is there a next argument? */
3423 if (args[index+1]) {
3424 /* are there two or more next arguments? */
3425 if (args[index+2]) {
3427 extra_quotes = TRUE;
3430 /* single argument, force quoting if it has spaces */
3446 qualified_path(const char *cmd)
3450 char *fullcmd, *curfullcmd;
3456 fullcmd = (char*)cmd;
3458 if (*fullcmd == '/' || *fullcmd == '\\')
3465 pathstr = PerlEnv_getenv("PATH");
3466 New(0, fullcmd, MAX_PATH+1, char);
3467 curfullcmd = fullcmd;
3472 /* start by appending the name to the current prefix */
3473 strcpy(curfullcmd, cmd);
3474 curfullcmd += cmdlen;
3476 /* if it doesn't end with '.', or has no extension, try adding
3477 * a trailing .exe first */
3478 if (cmd[cmdlen-1] != '.'
3479 && (cmdlen < 4 || cmd[cmdlen-4] != '.'))
3481 strcpy(curfullcmd, ".exe");
3482 res = GetFileAttributes(fullcmd);
3483 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3488 /* that failed, try the bare name */
3489 res = GetFileAttributes(fullcmd);
3490 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3493 /* quit if no other path exists, or if cmd already has path */
3494 if (!pathstr || !*pathstr || has_slash)
3497 /* skip leading semis */
3498 while (*pathstr == ';')
3501 /* build a new prefix from scratch */
3502 curfullcmd = fullcmd;
3503 while (*pathstr && *pathstr != ';') {
3504 if (*pathstr == '"') { /* foo;"baz;etc";bar */
3505 pathstr++; /* skip initial '"' */
3506 while (*pathstr && *pathstr != '"') {
3507 if (curfullcmd-fullcmd < MAX_PATH-cmdlen-5)
3508 *curfullcmd++ = *pathstr;
3512 pathstr++; /* skip trailing '"' */
3515 if (curfullcmd-fullcmd < MAX_PATH-cmdlen-5)
3516 *curfullcmd++ = *pathstr;
3521 pathstr++; /* skip trailing semi */
3522 if (curfullcmd > fullcmd /* append a dir separator */
3523 && curfullcmd[-1] != '/' && curfullcmd[-1] != '\\')
3525 *curfullcmd++ = '\\';
3533 /* The following are just place holders.
3534 * Some hosts may provide and environment that the OS is
3535 * not tracking, therefore, these host must provide that
3536 * environment and the current directory to CreateProcess
3540 win32_get_childenv(void)
3546 win32_free_childenv(void* d)
3551 win32_clearenv(void)
3553 char *envv = GetEnvironmentStrings();
3557 char *end = strchr(cur,'=');
3558 if (end && end != cur) {
3560 SetEnvironmentVariable(cur, NULL);
3562 cur = end + strlen(end+1)+2;
3564 else if ((len = strlen(cur)))
3567 FreeEnvironmentStrings(envv);
3571 win32_get_childdir(void)
3575 char szfilename[(MAX_PATH+1)*2];
3577 WCHAR wfilename[MAX_PATH+1];
3578 GetCurrentDirectoryW(MAX_PATH+1, wfilename);
3579 W2AHELPER(wfilename, szfilename, sizeof(szfilename));
3582 GetCurrentDirectoryA(MAX_PATH+1, szfilename);
3585 New(0, ptr, strlen(szfilename)+1, char);
3586 strcpy(ptr, szfilename);
3591 win32_free_childdir(char* d)
3598 /* XXX this needs to be made more compatible with the spawnvp()
3599 * provided by the various RTLs. In particular, searching for
3600 * *.{com,bat,cmd} files (as done by the RTLs) is unimplemented.
3601 * This doesn't significantly affect perl itself, because we
3602 * always invoke things using PERL5SHELL if a direct attempt to
3603 * spawn the executable fails.
3605 * XXX splitting and rejoining the commandline between do_aspawn()
3606 * and win32_spawnvp() could also be avoided.
3610 win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
3612 #ifdef USE_RTL_SPAWNVP
3613 return spawnvp(mode, cmdname, (char * const *)argv);
3620 STARTUPINFO StartupInfo;
3621 PROCESS_INFORMATION ProcessInformation;
3624 char *fullcmd = Nullch;
3625 char *cname = (char *)cmdname;
3629 clen = strlen(cname);
3630 /* if command name contains dquotes, must remove them */
3631 if (strchr(cname, '"')) {
3633 New(0,cname,clen+1,char);
3646 cmd = create_command_line(cname, clen, argv);
3648 env = PerlEnv_get_childenv();
3649 dir = PerlEnv_get_childdir();
3652 case P_NOWAIT: /* asynch + remember result */
3653 if (w32_num_children >= MAXIMUM_WAIT_OBJECTS) {
3658 /* Create a new process group so we can use GenerateConsoleCtrlEvent()
3661 create |= CREATE_NEW_PROCESS_GROUP;
3664 case P_WAIT: /* synchronous execution */
3666 default: /* invalid mode */
3671 memset(&StartupInfo,0,sizeof(StartupInfo));
3672 StartupInfo.cb = sizeof(StartupInfo);
3673 memset(&tbl,0,sizeof(tbl));
3674 PerlEnv_get_child_IO(&tbl);
3675 StartupInfo.dwFlags = tbl.dwFlags;
3676 StartupInfo.dwX = tbl.dwX;
3677 StartupInfo.dwY = tbl.dwY;
3678 StartupInfo.dwXSize = tbl.dwXSize;
3679 StartupInfo.dwYSize = tbl.dwYSize;
3680 StartupInfo.dwXCountChars = tbl.dwXCountChars;
3681 StartupInfo.dwYCountChars = tbl.dwYCountChars;
3682 StartupInfo.dwFillAttribute = tbl.dwFillAttribute;
3683 StartupInfo.wShowWindow = tbl.wShowWindow;
3684 StartupInfo.hStdInput = tbl.childStdIn;
3685 StartupInfo.hStdOutput = tbl.childStdOut;
3686 StartupInfo.hStdError = tbl.childStdErr;
3687 if (StartupInfo.hStdInput != INVALID_HANDLE_VALUE &&
3688 StartupInfo.hStdOutput != INVALID_HANDLE_VALUE &&
3689 StartupInfo.hStdError != INVALID_HANDLE_VALUE)
3691 StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
3694 create |= CREATE_NEW_CONSOLE;
3696 if (w32_use_showwindow) {
3697 StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
3698 StartupInfo.wShowWindow = w32_showwindow;
3701 DEBUG_p(PerlIO_printf(Perl_debug_log, "Spawning [%s] with [%s]\n",
3704 if (!CreateProcess(cname, /* search PATH to find executable */
3705 cmd, /* executable, and its arguments */
3706 NULL, /* process attributes */
3707 NULL, /* thread attributes */
3708 TRUE, /* inherit handles */
3709 create, /* creation flags */
3710 (LPVOID)env, /* inherit environment */
3711 dir, /* inherit cwd */
3713 &ProcessInformation))
3715 /* initial NULL argument to CreateProcess() does a PATH
3716 * search, but it always first looks in the directory
3717 * where the current process was started, which behavior
3718 * is undesirable for backward compatibility. So we
3719 * jump through our own hoops by picking out the path
3720 * we really want it to use. */
3722 fullcmd = qualified_path(cname);
3724 if (cname != cmdname)
3727 DEBUG_p(PerlIO_printf(Perl_debug_log,
3728 "Retrying [%s] with same args\n",
3738 if (mode == P_NOWAIT) {
3739 /* asynchronous spawn -- store handle, return PID */
3740 ret = (int)ProcessInformation.dwProcessId;
3741 if (IsWin95() && ret < 0)
3744 w32_child_handles[w32_num_children] = ProcessInformation.hProcess;
3745 w32_child_pids[w32_num_children] = (DWORD)ret;
3750 win32_msgwait(aTHX_ 1, &ProcessInformation.hProcess, INFINITE, NULL);
3751 /* FIXME: if msgwait returned due to message perhaps forward the
3752 "signal" to the process
3754 GetExitCodeProcess(ProcessInformation.hProcess, &status);
3756 CloseHandle(ProcessInformation.hProcess);
3759 CloseHandle(ProcessInformation.hThread);
3762 PerlEnv_free_childenv(env);
3763 PerlEnv_free_childdir(dir);
3765 if (cname != cmdname)
3772 win32_execv(const char *cmdname, const char *const *argv)
3776 /* if this is a pseudo-forked child, we just want to spawn
3777 * the new program, and return */
3779 return spawnv(P_WAIT, cmdname, (char *const *)argv);
3781 return execv(cmdname, (char *const *)argv);
3785 win32_execvp(const char *cmdname, const char *const *argv)
3789 /* if this is a pseudo-forked child, we just want to spawn
3790 * the new program, and return */
3791 if (w32_pseudo_id) {
3792 int status = win32_spawnvp(P_WAIT, cmdname, (char *const *)argv);
3801 return execvp(cmdname, (char *const *)argv);
3805 win32_perror(const char *str)
3811 win32_setbuf(FILE *pf, char *buf)
3817 win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
3819 return setvbuf(pf, buf, type, size);
3823 win32_flushall(void)
3829 win32_fcloseall(void)
3835 win32_fgets(char *s, int n, FILE *pf)
3837 return fgets(s, n, pf);
3847 win32_fgetc(FILE *pf)
3853 win32_putc(int c, FILE *pf)
3859 win32_puts(const char *s)
3871 win32_putchar(int c)
3878 #ifndef USE_PERL_SBRK
3880 static char *committed = NULL; /* XXX threadead */
3881 static char *base = NULL; /* XXX threadead */
3882 static char *reserved = NULL; /* XXX threadead */
3883 static char *brk = NULL; /* XXX threadead */
3884 static DWORD pagesize = 0; /* XXX threadead */
3885 static DWORD allocsize = 0; /* XXX threadead */
3893 GetSystemInfo(&info);
3894 /* Pretend page size is larger so we don't perpetually
3895 * call the OS to commit just one page ...
3897 pagesize = info.dwPageSize << 3;
3898 allocsize = info.dwAllocationGranularity;
3900 /* This scheme fails eventually if request for contiguous
3901 * block is denied so reserve big blocks - this is only
3902 * address space not memory ...
3904 if (brk+need >= reserved)
3906 DWORD size = 64*1024*1024;
3908 if (committed && reserved && committed < reserved)
3910 /* Commit last of previous chunk cannot span allocations */
3911 addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
3913 committed = reserved;
3915 /* Reserve some (more) space
3916 * Note this is a little sneaky, 1st call passes NULL as reserved
3917 * so lets system choose where we start, subsequent calls pass
3918 * the old end address so ask for a contiguous block
3920 addr = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
3923 reserved = addr+size;
3938 if (brk > committed)
3940 DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
3941 char *addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
3956 win32_malloc(size_t size)
3958 return malloc(size);
3962 win32_calloc(size_t numitems, size_t size)
3964 return calloc(numitems,size);
3968 win32_realloc(void *block, size_t size)
3970 return realloc(block,size);
3974 win32_free(void *block)
3981 win32_open_osfhandle(long handle, int flags)
3983 #ifdef USE_FIXED_OSFHANDLE
3985 return my_open_osfhandle(handle, flags);
3987 return _open_osfhandle(handle, flags);
3991 win32_get_osfhandle(int fd)
3993 return _get_osfhandle(fd);
3997 win32_dynaload(const char* filename)
4001 char buf[MAX_PATH+1];
4004 /* LoadLibrary() doesn't recognize forward slashes correctly,
4005 * so turn 'em back. */
4006 first = strchr(filename, '/');
4008 STRLEN len = strlen(filename);
4009 if (len <= MAX_PATH) {
4010 strcpy(buf, filename);
4011 filename = &buf[first - filename];
4013 if (*filename == '/')
4014 *(char*)filename = '\\';
4021 WCHAR wfilename[MAX_PATH+1];
4022 A2WHELPER(filename, wfilename, sizeof(wfilename));
4023 hModule = LoadLibraryExW(PerlDir_mapW(wfilename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
4026 hModule = LoadLibraryExA(PerlDir_mapA(filename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
4036 XS(w32_SetChildShowWindow)
4039 BOOL use_showwindow = w32_use_showwindow;
4040 /* use "unsigned short" because Perl has redefined "WORD" */
4041 unsigned short showwindow = w32_showwindow;
4044 Perl_croak(aTHX_ "usage: Win32::SetChildShowWindow($showwindow)");
4046 if (items == 0 || !SvOK(ST(0)))
4047 w32_use_showwindow = FALSE;
4049 w32_use_showwindow = TRUE;
4050 w32_showwindow = (unsigned short)SvIV(ST(0));
4055 ST(0) = sv_2mortal(newSViv(showwindow));
4057 ST(0) = &PL_sv_undef;
4065 /* Make the host for current directory */
4066 char* ptr = PerlEnv_get_childdir();
4069 * then it worked, set PV valid,
4070 * else return 'undef'
4073 SV *sv = sv_newmortal();
4075 PerlEnv_free_childdir(ptr);
4077 #ifndef INCOMPLETE_TAINTS
4094 Perl_croak(aTHX_ "usage: Win32::SetCurrentDirectory($cwd)");
4095 if (!PerlDir_chdir(SvPV_nolen(ST(0))))
4102 XS(w32_GetNextAvailDrive)
4106 char root[] = "_:\\";
4111 if (GetDriveType(root) == 1) {
4120 XS(w32_GetLastError)
4124 XSRETURN_IV(GetLastError());
4128 XS(w32_SetLastError)
4132 Perl_croak(aTHX_ "usage: Win32::SetLastError($error)");
4133 SetLastError(SvIV(ST(0)));
4141 char *name = w32_getlogin_buffer;
4142 DWORD size = sizeof(w32_getlogin_buffer);
4144 if (GetUserName(name,&size)) {
4145 /* size includes NULL */
4146 ST(0) = sv_2mortal(newSVpvn(name,size-1));
4156 char name[MAX_COMPUTERNAME_LENGTH+1];
4157 DWORD size = sizeof(name);
4159 if (GetComputerName(name,&size)) {
4160 /* size does NOT include NULL :-( */
4161 ST(0) = sv_2mortal(newSVpvn(name,size));
4172 HINSTANCE hNetApi32 = LoadLibrary("netapi32.dll");
4173 DWORD (__stdcall *pfnNetApiBufferFree)(LPVOID Buffer);
4174 DWORD (__stdcall *pfnNetWkstaGetInfo)(LPWSTR servername, DWORD level,
4178 pfnNetApiBufferFree = (DWORD (__stdcall *)(void *))
4179 GetProcAddress(hNetApi32, "NetApiBufferFree");
4180 pfnNetWkstaGetInfo = (DWORD (__stdcall *)(LPWSTR, DWORD, void *))
4181 GetProcAddress(hNetApi32, "NetWkstaGetInfo");
4184 if (hNetApi32 && pfnNetWkstaGetInfo && pfnNetApiBufferFree) {
4185 /* this way is more reliable, in case user has a local account. */
4187 DWORD dnamelen = sizeof(dname);
4189 DWORD wki100_platform_id;
4190 LPWSTR wki100_computername;
4191 LPWSTR wki100_langroup;
4192 DWORD wki100_ver_major;
4193 DWORD wki100_ver_minor;
4195 /* NERR_Success *is* 0*/
4196 if (0 == pfnNetWkstaGetInfo(NULL, 100, &pwi)) {
4197 if (pwi->wki100_langroup && *(pwi->wki100_langroup)) {
4198 WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_langroup,
4199 -1, (LPSTR)dname, dnamelen, NULL, NULL);
4202 WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_computername,
4203 -1, (LPSTR)dname, dnamelen, NULL, NULL);
4205 pfnNetApiBufferFree(pwi);
4206 FreeLibrary(hNetApi32);
4209 FreeLibrary(hNetApi32);
4212 /* Win95 doesn't have NetWksta*(), so do it the old way */
4214 DWORD size = sizeof(name);
4216 FreeLibrary(hNetApi32);
4217 if (GetUserName(name,&size)) {
4218 char sid[ONE_K_BUFSIZE];
4219 DWORD sidlen = sizeof(sid);
4221 DWORD dnamelen = sizeof(dname);
4223 if (LookupAccountName(NULL, name, (PSID)&sid, &sidlen,
4224 dname, &dnamelen, &snu)) {
4225 XSRETURN_PV(dname); /* all that for this */
4237 DWORD flags, filecomplen;
4238 if (GetVolumeInformation(NULL, NULL, 0, NULL, &filecomplen,
4239 &flags, fsname, sizeof(fsname))) {
4240 if (GIMME_V == G_ARRAY) {
4241 XPUSHs(sv_2mortal(newSVpvn(fsname,strlen(fsname))));
4242 XPUSHs(sv_2mortal(newSViv(flags)));
4243 XPUSHs(sv_2mortal(newSViv(filecomplen)));
4248 XSRETURN_PV(fsname);
4254 XS(w32_GetOSVersion)
4257 OSVERSIONINFOA osver;
4260 OSVERSIONINFOW osverw;
4261 char szCSDVersion[sizeof(osverw.szCSDVersion)];
4262 osverw.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
4263 if (!GetVersionExW(&osverw)) {
4266 W2AHELPER(osverw.szCSDVersion, szCSDVersion, sizeof(szCSDVersion));
4267 XPUSHs(newSVpvn(szCSDVersion, strlen(szCSDVersion)));
4268 osver.dwMajorVersion = osverw.dwMajorVersion;
4269 osver.dwMinorVersion = osverw.dwMinorVersion;
4270 osver.dwBuildNumber = osverw.dwBuildNumber;
4271 osver.dwPlatformId = osverw.dwPlatformId;
4274 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
4275 if (!GetVersionExA(&osver)) {
4278 XPUSHs(newSVpvn(osver.szCSDVersion, strlen(osver.szCSDVersion)));
4280 XPUSHs(newSViv(osver.dwMajorVersion));
4281 XPUSHs(newSViv(osver.dwMinorVersion));
4282 XPUSHs(newSViv(osver.dwBuildNumber));
4283 XPUSHs(newSViv(osver.dwPlatformId));
4292 XSRETURN_IV(IsWinNT());
4300 XSRETURN_IV(IsWin95());
4304 XS(w32_FormatMessage)
4308 char msgbuf[ONE_K_BUFSIZE];
4311 Perl_croak(aTHX_ "usage: Win32::FormatMessage($errno)");
4314 WCHAR wmsgbuf[ONE_K_BUFSIZE];
4315 if (FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
4316 &source, SvIV(ST(0)), 0,
4317 wmsgbuf, ONE_K_BUFSIZE-1, NULL))
4319 W2AHELPER(wmsgbuf, msgbuf, sizeof(msgbuf));
4320 XSRETURN_PV(msgbuf);
4324 if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,
4325 &source, SvIV(ST(0)), 0,
4326 msgbuf, sizeof(msgbuf)-1, NULL))
4327 XSRETURN_PV(msgbuf);
4340 PROCESS_INFORMATION stProcInfo;
4341 STARTUPINFO stStartInfo;
4342 BOOL bSuccess = FALSE;
4345 Perl_croak(aTHX_ "usage: Win32::Spawn($cmdName, $args, $PID)");
4347 cmd = SvPV_nolen(ST(0));
4348 args = SvPV_nolen(ST(1));
4350 env = PerlEnv_get_childenv();
4351 dir = PerlEnv_get_childdir();
4353 memset(&stStartInfo, 0, sizeof(stStartInfo)); /* Clear the block */
4354 stStartInfo.cb = sizeof(stStartInfo); /* Set the structure size */
4355 stStartInfo.dwFlags = STARTF_USESHOWWINDOW; /* Enable wShowWindow control */
4356 stStartInfo.wShowWindow = SW_SHOWMINNOACTIVE; /* Start min (normal) */
4359 cmd, /* Image path */
4360 args, /* Arguments for command line */
4361 NULL, /* Default process security */
4362 NULL, /* Default thread security */
4363 FALSE, /* Must be TRUE to use std handles */
4364 NORMAL_PRIORITY_CLASS, /* No special scheduling */
4365 env, /* Inherit our environment block */
4366 dir, /* Inherit our currrent directory */
4367 &stStartInfo, /* -> Startup info */
4368 &stProcInfo)) /* <- Process info (if OK) */
4370 int pid = (int)stProcInfo.dwProcessId;
4371 if (IsWin95() && pid < 0)
4373 sv_setiv(ST(2), pid);
4374 CloseHandle(stProcInfo.hThread);/* library source code does this. */
4377 PerlEnv_free_childenv(env);
4378 PerlEnv_free_childdir(dir);
4379 XSRETURN_IV(bSuccess);
4383 XS(w32_GetTickCount)
4386 DWORD msec = GetTickCount();
4394 XS(w32_GetShortPathName)
4401 Perl_croak(aTHX_ "usage: Win32::GetShortPathName($longPathName)");
4403 shortpath = sv_mortalcopy(ST(0));
4404 SvUPGRADE(shortpath, SVt_PV);
4405 if (!SvPVX(shortpath) || !SvLEN(shortpath))
4408 /* src == target is allowed */
4410 len = GetShortPathName(SvPVX(shortpath),
4413 } while (len >= SvLEN(shortpath) && sv_grow(shortpath,len+1));
4415 SvCUR_set(shortpath,len);
4423 XS(w32_GetFullPathName)
4432 Perl_croak(aTHX_ "usage: Win32::GetFullPathName($filename)");
4435 fullpath = sv_mortalcopy(filename);
4436 SvUPGRADE(fullpath, SVt_PV);
4437 if (!SvPVX(fullpath) || !SvLEN(fullpath))
4441 len = GetFullPathName(SvPVX(filename),
4445 } while (len >= SvLEN(fullpath) && sv_grow(fullpath,len+1));
4447 if (GIMME_V == G_ARRAY) {
4449 XST_mPV(1,filepart);
4450 len = filepart - SvPVX(fullpath);
4453 SvCUR_set(fullpath,len);
4461 XS(w32_GetLongPathName)
4465 char tmpbuf[MAX_PATH+1];
4470 Perl_croak(aTHX_ "usage: Win32::GetLongPathName($pathname)");
4473 pathstr = SvPV(path,len);
4474 strcpy(tmpbuf, pathstr);
4475 pathstr = win32_longpath(tmpbuf);
4477 ST(0) = sv_2mortal(newSVpvn(pathstr, strlen(pathstr)));
4488 Perl_croak(aTHX_ "usage: Win32::Sleep($milliseconds)");
4499 Perl_croak(aTHX_ "usage: Win32::CopyFile($from, $to, $overwrite)");
4501 WCHAR wSourceFile[MAX_PATH+1];
4502 WCHAR wDestFile[MAX_PATH+1];
4503 A2WHELPER(SvPV_nolen(ST(0)), wSourceFile, sizeof(wSourceFile));
4504 wcscpy(wSourceFile, PerlDir_mapW(wSourceFile));
4505 A2WHELPER(SvPV_nolen(ST(1)), wDestFile, sizeof(wDestFile));
4506 bResult = CopyFileW(wSourceFile, PerlDir_mapW(wDestFile), !SvTRUE(ST(2)));
4509 char szSourceFile[MAX_PATH+1];
4510 strcpy(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(0))));
4511 bResult = CopyFileA(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(1))), !SvTRUE(ST(2)));
4520 Perl_init_os_extras(void)
4523 char *file = __FILE__;
4526 /* these names are Activeware compatible */
4527 newXS("Win32::GetCwd", w32_GetCwd, file);
4528 newXS("Win32::SetCwd", w32_SetCwd, file);
4529 newXS("Win32::GetNextAvailDrive", w32_GetNextAvailDrive, file);
4530 newXS("Win32::GetLastError", w32_GetLastError, file);
4531 newXS("Win32::SetLastError", w32_SetLastError, file);
4532 newXS("Win32::LoginName", w32_LoginName, file);
4533 newXS("Win32::NodeName", w32_NodeName, file);
4534 newXS("Win32::DomainName", w32_DomainName, file);
4535 newXS("Win32::FsType", w32_FsType, file);
4536 newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
4537 newXS("Win32::IsWinNT", w32_IsWinNT, file);
4538 newXS("Win32::IsWin95", w32_IsWin95, file);
4539 newXS("Win32::FormatMessage", w32_FormatMessage, file);
4540 newXS("Win32::Spawn", w32_Spawn, file);
4541 newXS("Win32::GetTickCount", w32_GetTickCount, file);
4542 newXS("Win32::GetShortPathName", w32_GetShortPathName, file);
4543 newXS("Win32::GetFullPathName", w32_GetFullPathName, file);
4544 newXS("Win32::GetLongPathName", w32_GetLongPathName, file);
4545 newXS("Win32::CopyFile", w32_CopyFile, file);
4546 newXS("Win32::Sleep", w32_Sleep, file);
4547 newXS("Win32::SetChildShowWindow", w32_SetChildShowWindow, file);
4549 /* XXX Bloat Alert! The following Activeware preloads really
4550 * ought to be part of Win32::Sys::*, so they're not included
4553 /* LookupAccountName
4555 * InitiateSystemShutdown
4556 * AbortSystemShutdown
4557 * ExpandEnvrironmentStrings
4564 win32_signal_context(void)
4568 my_perl = PL_curinterp;
4569 PERL_SET_THX(my_perl);
4577 win32_ctrlhandler(DWORD dwCtrlType)
4580 dTHXa(PERL_GET_SIG_CONTEXT);
4586 switch(dwCtrlType) {
4587 case CTRL_CLOSE_EVENT:
4588 /* A signal that the system sends to all processes attached to a console when
4589 the user closes the console (either by choosing the Close command from the
4590 console window's System menu, or by choosing the End Task command from the
4593 if (do_raise(aTHX_ 1)) /* SIGHUP */
4594 sig_terminate(aTHX_ 1);
4598 /* A CTRL+c signal was received */
4599 if (do_raise(aTHX_ SIGINT))
4600 sig_terminate(aTHX_ SIGINT);
4603 case CTRL_BREAK_EVENT:
4604 /* A CTRL+BREAK signal was received */
4605 if (do_raise(aTHX_ SIGBREAK))
4606 sig_terminate(aTHX_ SIGBREAK);
4609 case CTRL_LOGOFF_EVENT:
4610 /* A signal that the system sends to all console processes when a user is logging
4611 off. This signal does not indicate which user is logging off, so no
4612 assumptions can be made.
4615 case CTRL_SHUTDOWN_EVENT:
4616 /* A signal that the system sends to all console processes when the system is
4619 if (do_raise(aTHX_ SIGTERM))
4620 sig_terminate(aTHX_ SIGTERM);
4630 Perl_win32_init(int *argcp, char ***argvp)
4632 /* Disable floating point errors, Perl will trap the ones we
4633 * care about. VC++ RTL defaults to switching these off
4634 * already, but the Borland RTL doesn't. Since we don't
4635 * want to be at the vendor's whim on the default, we set
4636 * it explicitly here.
4638 #if !defined(_ALPHA_) && !defined(__GNUC__)
4639 _control87(MCW_EM, MCW_EM);
4645 win32_get_child_IO(child_IO_table* ptbl)
4647 ptbl->childStdIn = GetStdHandle(STD_INPUT_HANDLE);
4648 ptbl->childStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
4649 ptbl->childStdErr = GetStdHandle(STD_ERROR_HANDLE);
4653 win32_signal(int sig, Sighandler_t subcode)
4656 if (sig < SIG_SIZE) {
4657 int save_errno = errno;
4658 Sighandler_t result = signal(sig, subcode);
4659 if (result == SIG_ERR) {
4660 result = w32_sighandler[sig];
4663 w32_sighandler[sig] = subcode;
4673 #ifdef HAVE_INTERP_INTERN
4677 win32_csighandler(int sig)
4680 dTHXa(PERL_GET_SIG_CONTEXT);
4681 Perl_warn(aTHX_ "Got signal %d",sig);
4687 Perl_sys_intern_init(pTHX)
4690 w32_perlshell_tokens = Nullch;
4691 w32_perlshell_vec = (char**)NULL;
4692 w32_perlshell_items = 0;
4693 w32_fdpid = newAV();
4694 New(1313, w32_children, 1, child_tab);
4695 w32_num_children = 0;
4696 # ifdef USE_ITHREADS
4698 New(1313, w32_pseudo_children, 1, child_tab);
4699 w32_num_pseudo_children = 0;
4701 w32_init_socktype = 0;
4704 for (i=0; i < SIG_SIZE; i++) {
4705 w32_sighandler[i] = SIG_DFL;
4708 if (my_perl == PL_curinterp) {
4712 /* Force C runtime signal stuff to set its console handler */
4713 signal(SIGINT,&win32_csighandler);
4714 signal(SIGBREAK,&win32_csighandler);
4715 /* Push our handler on top */
4716 SetConsoleCtrlHandler(win32_ctrlhandler,TRUE);
4721 Perl_sys_intern_clear(pTHX)
4723 Safefree(w32_perlshell_tokens);
4724 Safefree(w32_perlshell_vec);
4725 /* NOTE: w32_fdpid is freed by sv_clean_all() */
4726 Safefree(w32_children);
4728 KillTimer(NULL,w32_timerid);
4731 # ifdef MULTIPLICITY
4732 if (my_perl == PL_curinterp) {
4736 SetConsoleCtrlHandler(win32_ctrlhandler,FALSE);
4738 # ifdef USE_ITHREADS
4739 Safefree(w32_pseudo_children);
4743 # ifdef USE_ITHREADS
4746 Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
4748 dst->perlshell_tokens = Nullch;
4749 dst->perlshell_vec = (char**)NULL;
4750 dst->perlshell_items = 0;
4751 dst->fdpid = newAV();
4752 Newz(1313, dst->children, 1, child_tab);
4754 Newz(1313, dst->pseudo_children, 1, child_tab);
4755 dst->thr_intern.Winit_socktype = 0;
4757 dst->poll_count = 0;
4758 Copy(src->sigtable,dst->sigtable,SIG_SIZE,Sighandler_t);
4760 # endif /* USE_ITHREADS */
4761 #endif /* HAVE_INTERP_INTERN */
4764 win32_free_argvw(pTHX_ void *ptr)
4766 char** argv = (char**)ptr;
4774 win32_argv2utf8(int argc, char** argv)
4779 LPWSTR* lpwStr = CommandLineToArgvW(GetCommandLineW(), &wargc);
4780 if (lpwStr && argc) {
4782 length = WideCharToMultiByte(CP_UTF8, 0, lpwStr[--wargc], -1, NULL, 0, NULL, NULL);
4783 Newz(0, psz, length, char);
4784 WideCharToMultiByte(CP_UTF8, 0, lpwStr[wargc], -1, psz, length, NULL, NULL);
4787 call_atexit(win32_free_argvw, argv);
4789 GlobalFree((HGLOBAL)lpwStr);