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 clock_t process_time_so_far = clock();
1507 if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy,
1509 timebuf->tms_utime = filetime_to_clock(&user);
1510 timebuf->tms_stime = filetime_to_clock(&kernel);
1511 timebuf->tms_cutime = 0;
1512 timebuf->tms_cstime = 0;
1514 /* That failed - e.g. Win95 fallback to clock() */
1515 timebuf->tms_utime = process_time_so_far;
1516 timebuf->tms_stime = 0;
1517 timebuf->tms_cutime = 0;
1518 timebuf->tms_cstime = 0;
1520 return process_time_so_far;
1523 /* fix utime() so it works on directories in NT */
1525 filetime_from_time(PFILETIME pFileTime, time_t Time)
1527 struct tm *pTM = localtime(&Time);
1528 SYSTEMTIME SystemTime;
1534 SystemTime.wYear = pTM->tm_year + 1900;
1535 SystemTime.wMonth = pTM->tm_mon + 1;
1536 SystemTime.wDay = pTM->tm_mday;
1537 SystemTime.wHour = pTM->tm_hour;
1538 SystemTime.wMinute = pTM->tm_min;
1539 SystemTime.wSecond = pTM->tm_sec;
1540 SystemTime.wMilliseconds = 0;
1542 return SystemTimeToFileTime(&SystemTime, &LocalTime) &&
1543 LocalFileTimeToFileTime(&LocalTime, pFileTime);
1547 win32_unlink(const char *filename)
1554 WCHAR wBuffer[MAX_PATH+1];
1557 A2WHELPER(filename, wBuffer, sizeof(wBuffer));
1558 pwBuffer = PerlDir_mapW(wBuffer);
1559 attrs = GetFileAttributesW(pwBuffer);
1560 if (attrs == 0xFFFFFFFF)
1562 if (attrs & FILE_ATTRIBUTE_READONLY) {
1563 (void)SetFileAttributesW(pwBuffer, attrs & ~FILE_ATTRIBUTE_READONLY);
1564 ret = _wunlink(pwBuffer);
1566 (void)SetFileAttributesW(pwBuffer, attrs);
1569 ret = _wunlink(pwBuffer);
1572 filename = PerlDir_mapA(filename);
1573 attrs = GetFileAttributesA(filename);
1574 if (attrs == 0xFFFFFFFF)
1576 if (attrs & FILE_ATTRIBUTE_READONLY) {
1577 (void)SetFileAttributesA(filename, attrs & ~FILE_ATTRIBUTE_READONLY);
1578 ret = unlink(filename);
1580 (void)SetFileAttributesA(filename, attrs);
1583 ret = unlink(filename);
1592 win32_utime(const char *filename, struct utimbuf *times)
1599 struct utimbuf TimeBuffer;
1600 WCHAR wbuffer[MAX_PATH+1];
1605 A2WHELPER(filename, wbuffer, sizeof(wbuffer));
1606 pwbuffer = PerlDir_mapW(wbuffer);
1607 rc = _wutime(pwbuffer, (struct _utimbuf*)times);
1610 filename = PerlDir_mapA(filename);
1611 rc = utime(filename, times);
1613 /* EACCES: path specifies directory or readonly file */
1614 if (rc == 0 || errno != EACCES /* || !IsWinNT() */)
1617 if (times == NULL) {
1618 times = &TimeBuffer;
1619 time(×->actime);
1620 times->modtime = times->actime;
1623 /* This will (and should) still fail on readonly files */
1625 handle = CreateFileW(pwbuffer, GENERIC_READ | GENERIC_WRITE,
1626 FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
1627 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1630 handle = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE,
1631 FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
1632 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1634 if (handle == INVALID_HANDLE_VALUE)
1637 if (GetFileTime(handle, &ftCreate, &ftAccess, &ftWrite) &&
1638 filetime_from_time(&ftAccess, times->actime) &&
1639 filetime_from_time(&ftWrite, times->modtime) &&
1640 SetFileTime(handle, &ftCreate, &ftAccess, &ftWrite))
1645 CloseHandle(handle);
1650 win32_uname(struct utsname *name)
1652 struct hostent *hep;
1653 STRLEN nodemax = sizeof(name->nodename)-1;
1654 OSVERSIONINFO osver;
1656 memset(&osver, 0, sizeof(OSVERSIONINFO));
1657 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1658 if (GetVersionEx(&osver)) {
1660 switch (osver.dwPlatformId) {
1661 case VER_PLATFORM_WIN32_WINDOWS:
1662 strcpy(name->sysname, "Windows");
1664 case VER_PLATFORM_WIN32_NT:
1665 strcpy(name->sysname, "Windows NT");
1667 case VER_PLATFORM_WIN32s:
1668 strcpy(name->sysname, "Win32s");
1671 strcpy(name->sysname, "Win32 Unknown");
1676 sprintf(name->release, "%d.%d",
1677 osver.dwMajorVersion, osver.dwMinorVersion);
1680 sprintf(name->version, "Build %d",
1681 osver.dwPlatformId == VER_PLATFORM_WIN32_NT
1682 ? osver.dwBuildNumber : (osver.dwBuildNumber & 0xffff));
1683 if (osver.szCSDVersion[0]) {
1684 char *buf = name->version + strlen(name->version);
1685 sprintf(buf, " (%s)", osver.szCSDVersion);
1689 *name->sysname = '\0';
1690 *name->version = '\0';
1691 *name->release = '\0';
1695 hep = win32_gethostbyname("localhost");
1697 STRLEN len = strlen(hep->h_name);
1698 if (len <= nodemax) {
1699 strcpy(name->nodename, hep->h_name);
1702 strncpy(name->nodename, hep->h_name, nodemax);
1703 name->nodename[nodemax] = '\0';
1708 if (!GetComputerName(name->nodename, &sz))
1709 *name->nodename = '\0';
1712 /* machine (architecture) */
1716 GetSystemInfo(&info);
1718 #if (defined(__BORLANDC__)&&(__BORLANDC__<=0x520)) \
1719 || (defined(__MINGW32__) && !defined(_ANONYMOUS_UNION))
1720 switch (info.u.s.wProcessorArchitecture) {
1722 switch (info.wProcessorArchitecture) {
1724 case PROCESSOR_ARCHITECTURE_INTEL:
1725 arch = "x86"; break;
1726 case PROCESSOR_ARCHITECTURE_MIPS:
1727 arch = "mips"; break;
1728 case PROCESSOR_ARCHITECTURE_ALPHA:
1729 arch = "alpha"; break;
1730 case PROCESSOR_ARCHITECTURE_PPC:
1731 arch = "ppc"; break;
1733 arch = "unknown"; break;
1735 strcpy(name->machine, arch);
1740 /* Timing related stuff */
1743 do_raise(pTHX_ int sig)
1745 if (sig < SIG_SIZE) {
1746 Sighandler_t handler = w32_sighandler[sig];
1747 if (handler == SIG_IGN) {
1750 else if (handler != SIG_DFL) {
1755 /* Choose correct default behaviour */
1771 /* Tell caller to exit thread/process as approriate */
1776 sig_terminate(pTHX_ int sig)
1778 Perl_warn(aTHX_ "Terminating on signal SIG%s(%d)\n",PL_sig_name[sig], sig);
1779 /* exit() seems to be safe, my_exit() or die() is a problem in ^C
1786 win32_async_check(pTHX)
1790 /* Passing PeekMessage -1 as HWND (2nd arg) only get PostThreadMessage() messages
1791 * and ignores window messages - should co-exist better with windows apps e.g. Tk
1793 while (PeekMessage(&msg, (HWND)-1, 0, 0, PM_REMOVE|PM_NOYIELD)) {
1795 switch(msg.message) {
1798 /* Perhaps some other messages could map to signals ? ... */
1801 /* Treat WM_QUIT like SIGHUP? */
1807 /* We use WM_USER to fake kill() with other signals */
1811 if (do_raise(aTHX_ sig)) {
1812 sig_terminate(aTHX_ sig);
1818 /* alarm() is a one-shot but SetTimer() repeats so kill it */
1820 KillTimer(NULL,w32_timerid);
1823 /* Now fake a call to signal handler */
1824 if (do_raise(aTHX_ 14)) {
1825 sig_terminate(aTHX_ 14);
1830 /* Otherwise do normal Win32 thing - in case it is useful */
1832 TranslateMessage(&msg);
1833 DispatchMessage(&msg);
1840 /* Above or other stuff may have set a signal flag */
1841 if (PL_sig_pending) {
1848 win32_msgwait(pTHX_ DWORD count, LPHANDLE handles, DWORD timeout, LPDWORD resultp)
1850 /* We may need several goes at this - so compute when we stop */
1852 if (timeout != INFINITE) {
1853 ticks = GetTickCount();
1857 DWORD result = MsgWaitForMultipleObjects(count,handles,FALSE,timeout-ticks, QS_ALLEVENTS);
1860 if (result == WAIT_TIMEOUT) {
1861 /* Ran out of time - explicit return of zero to avoid -ve if we
1862 have scheduling issues
1866 if (timeout != INFINITE) {
1867 ticks = GetTickCount();
1869 if (result == WAIT_OBJECT_0 + count) {
1870 /* Message has arrived - check it */
1871 if (win32_async_check(aTHX)) {
1872 /* was one of ours */
1877 /* Not timeout or message - one of handles is ready */
1881 /* compute time left to wait */
1882 ticks = timeout - ticks;
1883 /* If we are past the end say zero */
1884 return (ticks > 0) ? ticks : 0;
1888 win32_internal_wait(int *status, DWORD timeout)
1890 /* XXX this wait emulation only knows about processes
1891 * spawned via win32_spawnvp(P_NOWAIT, ...).
1895 DWORD exitcode, waitcode;
1898 if (w32_num_pseudo_children) {
1899 win32_msgwait(aTHX_ w32_num_pseudo_children, w32_pseudo_child_handles,
1900 timeout, &waitcode);
1901 /* Time out here if there are no other children to wait for. */
1902 if (waitcode == WAIT_TIMEOUT) {
1903 if (!w32_num_children) {
1907 else if (waitcode != WAIT_FAILED) {
1908 if (waitcode >= WAIT_ABANDONED_0
1909 && waitcode < WAIT_ABANDONED_0 + w32_num_pseudo_children)
1910 i = waitcode - WAIT_ABANDONED_0;
1912 i = waitcode - WAIT_OBJECT_0;
1913 if (GetExitCodeThread(w32_pseudo_child_handles[i], &exitcode)) {
1914 *status = (int)((exitcode & 0xff) << 8);
1915 retval = (int)w32_pseudo_child_pids[i];
1916 remove_dead_pseudo_process(i);
1923 if (!w32_num_children) {
1928 /* if a child exists, wait for it to die */
1929 win32_msgwait(aTHX_ w32_num_children, w32_child_handles, timeout, &waitcode);
1930 if (waitcode == WAIT_TIMEOUT) {
1933 if (waitcode != WAIT_FAILED) {
1934 if (waitcode >= WAIT_ABANDONED_0
1935 && waitcode < WAIT_ABANDONED_0 + w32_num_children)
1936 i = waitcode - WAIT_ABANDONED_0;
1938 i = waitcode - WAIT_OBJECT_0;
1939 if (GetExitCodeProcess(w32_child_handles[i], &exitcode) ) {
1940 *status = (int)((exitcode & 0xff) << 8);
1941 retval = (int)w32_child_pids[i];
1942 remove_dead_process(i);
1948 errno = GetLastError();
1953 win32_waitpid(int pid, int *status, int flags)
1956 DWORD timeout = (flags & WNOHANG) ? 0 : INFINITE;
1959 if (pid == -1) /* XXX threadid == 1 ? */
1960 return win32_internal_wait(status, timeout);
1963 child = find_pseudo_pid(-pid);
1965 HANDLE hThread = w32_pseudo_child_handles[child];
1967 win32_msgwait(aTHX_ 1, &hThread, timeout, &waitcode);
1968 if (waitcode == WAIT_TIMEOUT) {
1971 else if (waitcode == WAIT_OBJECT_0) {
1972 if (GetExitCodeThread(hThread, &waitcode)) {
1973 *status = (int)((waitcode & 0xff) << 8);
1974 retval = (int)w32_pseudo_child_pids[child];
1975 remove_dead_pseudo_process(child);
1982 else if (IsWin95()) {
1991 child = find_pid(pid);
1993 hProcess = w32_child_handles[child];
1994 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
1995 if (waitcode == WAIT_TIMEOUT) {
1998 else if (waitcode == WAIT_OBJECT_0) {
1999 if (GetExitCodeProcess(hProcess, &waitcode)) {
2000 *status = (int)((waitcode & 0xff) << 8);
2001 retval = (int)w32_child_pids[child];
2002 remove_dead_process(child);
2011 hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE,
2012 (IsWin95() ? -pid : pid));
2014 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
2015 if (waitcode == WAIT_TIMEOUT) {
2018 else if (waitcode == WAIT_OBJECT_0) {
2019 if (GetExitCodeProcess(hProcess, &waitcode)) {
2020 *status = (int)((waitcode & 0xff) << 8);
2021 CloseHandle(hProcess);
2025 CloseHandle(hProcess);
2031 return retval >= 0 ? pid : retval;
2035 win32_wait(int *status)
2037 return win32_internal_wait(status, INFINITE);
2040 DllExport unsigned int
2041 win32_sleep(unsigned int t)
2044 /* Win32 times are in ms so *1000 in and /1000 out */
2045 return win32_msgwait(aTHX_ 0, NULL, t*1000, NULL)/1000;
2048 DllExport unsigned int
2049 win32_alarm(unsigned int sec)
2052 * the 'obvious' implentation is SetTimer() with a callback
2053 * which does whatever receiving SIGALRM would do
2054 * we cannot use SIGALRM even via raise() as it is not
2055 * one of the supported codes in <signal.h>
2059 w32_timerid = SetTimer(NULL,w32_timerid,sec*1000,NULL);
2063 KillTimer(NULL,w32_timerid);
2070 #ifdef HAVE_DES_FCRYPT
2071 extern char * des_fcrypt(const char *txt, const char *salt, char *cbuf);
2075 win32_crypt(const char *txt, const char *salt)
2078 #ifdef HAVE_DES_FCRYPT
2079 return des_fcrypt(txt, salt, w32_crypt_buffer);
2081 Perl_croak(aTHX_ "The crypt() function is unimplemented due to excessive paranoia.");
2086 #ifdef USE_FIXED_OSFHANDLE
2088 #define FOPEN 0x01 /* file handle open */
2089 #define FNOINHERIT 0x10 /* file handle opened O_NOINHERIT */
2090 #define FAPPEND 0x20 /* file handle opened O_APPEND */
2091 #define FDEV 0x40 /* file handle refers to device */
2092 #define FTEXT 0x80 /* file handle is in text mode */
2095 *int my_open_osfhandle(long osfhandle, int flags) - open C Runtime file handle
2098 * This function allocates a free C Runtime file handle and associates
2099 * it with the Win32 HANDLE specified by the first parameter. This is a
2100 * temperary fix for WIN95's brain damage GetFileType() error on socket
2101 * we just bypass that call for socket
2103 * This works with MSVC++ 4.0+ or GCC/Mingw32
2106 * long osfhandle - Win32 HANDLE to associate with C Runtime file handle.
2107 * int flags - flags to associate with C Runtime file handle.
2110 * returns index of entry in fh, if successful
2111 * return -1, if no free entry is found
2115 *******************************************************************************/
2118 * we fake up some parts of the CRT that aren't exported by MSVCRT.dll
2119 * this lets sockets work on Win9X with GCC and should fix the problems
2124 /* create an ioinfo entry, kill its handle, and steal the entry */
2129 HANDLE hF = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
2130 int fh = _open_osfhandle((long)hF, 0);
2134 EnterCriticalSection(&(_pioinfo(fh)->lock));
2139 my_open_osfhandle(long osfhandle, int flags)
2142 char fileflags; /* _osfile flags */
2144 /* copy relevant flags from second parameter */
2147 if (flags & O_APPEND)
2148 fileflags |= FAPPEND;
2153 if (flags & O_NOINHERIT)
2154 fileflags |= FNOINHERIT;
2156 /* attempt to allocate a C Runtime file handle */
2157 if ((fh = _alloc_osfhnd()) == -1) {
2158 errno = EMFILE; /* too many open files */
2159 _doserrno = 0L; /* not an OS error */
2160 return -1; /* return error to caller */
2163 /* the file is open. now, set the info in _osfhnd array */
2164 _set_osfhnd(fh, osfhandle);
2166 fileflags |= FOPEN; /* mark as open */
2168 _osfile(fh) = fileflags; /* set osfile entry */
2169 LeaveCriticalSection(&_pioinfo(fh)->lock);
2171 return fh; /* return handle */
2174 #endif /* USE_FIXED_OSFHANDLE */
2176 /* simulate flock by locking a range on the file */
2178 #define LK_ERR(f,i) ((f) ? (i = 0) : (errno = GetLastError()))
2179 #define LK_LEN 0xffff0000
2182 win32_flock(int fd, int oper)
2190 Perl_croak_nocontext("flock() unimplemented on this platform");
2193 fh = (HANDLE)_get_osfhandle(fd);
2194 memset(&o, 0, sizeof(o));
2197 case LOCK_SH: /* shared lock */
2198 LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, 0, &o),i);
2200 case LOCK_EX: /* exclusive lock */
2201 LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o),i);
2203 case LOCK_SH|LOCK_NB: /* non-blocking shared lock */
2204 LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o),i);
2206 case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */
2207 LK_ERR(LockFileEx(fh,
2208 LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
2209 0, LK_LEN, 0, &o),i);
2211 case LOCK_UN: /* unlock lock */
2212 LK_ERR(UnlockFileEx(fh, 0, LK_LEN, 0, &o),i);
2214 default: /* unknown */
2225 * redirected io subsystem for all XS modules
2238 return (&(_environ));
2241 /* the rest are the remapped stdio routines */
2261 win32_ferror(FILE *fp)
2263 return (ferror(fp));
2268 win32_feof(FILE *fp)
2274 * Since the errors returned by the socket error function
2275 * WSAGetLastError() are not known by the library routine strerror
2276 * we have to roll our own.
2280 win32_strerror(int e)
2282 #if !defined __BORLANDC__ && !defined __MINGW32__ /* compiler intolerance */
2283 extern int sys_nerr;
2287 if (e < 0 || e > sys_nerr) {
2292 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0,
2293 w32_strerror_buffer,
2294 sizeof(w32_strerror_buffer), NULL) == 0)
2295 strcpy(w32_strerror_buffer, "Unknown Error");
2297 return w32_strerror_buffer;
2303 win32_str_os_error(void *sv, DWORD dwErr)
2307 dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
2308 |FORMAT_MESSAGE_IGNORE_INSERTS
2309 |FORMAT_MESSAGE_FROM_SYSTEM, NULL,
2310 dwErr, 0, (char *)&sMsg, 1, NULL);
2311 /* strip trailing whitespace and period */
2314 --dwLen; /* dwLen doesn't include trailing null */
2315 } while (0 < dwLen && isSPACE(sMsg[dwLen]));
2316 if ('.' != sMsg[dwLen])
2321 sMsg = (char*)LocalAlloc(0, 64/**sizeof(TCHAR)*/);
2323 dwLen = sprintf(sMsg,
2324 "Unknown error #0x%lX (lookup 0x%lX)",
2325 dwErr, GetLastError());
2329 sv_setpvn((SV*)sv, sMsg, dwLen);
2335 win32_fprintf(FILE *fp, const char *format, ...)
2338 va_start(marker, format); /* Initialize variable arguments. */
2340 return (vfprintf(fp, format, marker));
2344 win32_printf(const char *format, ...)
2347 va_start(marker, format); /* Initialize variable arguments. */
2349 return (vprintf(format, marker));
2353 win32_vfprintf(FILE *fp, const char *format, va_list args)
2355 return (vfprintf(fp, format, args));
2359 win32_vprintf(const char *format, va_list args)
2361 return (vprintf(format, args));
2365 win32_fread(void *buf, size_t size, size_t count, FILE *fp)
2367 return fread(buf, size, count, fp);
2371 win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
2373 return fwrite(buf, size, count, fp);
2376 #define MODE_SIZE 10
2379 win32_fopen(const char *filename, const char *mode)
2382 WCHAR wMode[MODE_SIZE], wBuffer[MAX_PATH+1];
2388 if (stricmp(filename, "/dev/null")==0)
2392 A2WHELPER(mode, wMode, sizeof(wMode));
2393 A2WHELPER(filename, wBuffer, sizeof(wBuffer));
2394 f = _wfopen(PerlDir_mapW(wBuffer), wMode);
2397 f = fopen(PerlDir_mapA(filename), mode);
2398 /* avoid buffering headaches for child processes */
2399 if (f && *mode == 'a')
2400 win32_fseek(f, 0, SEEK_END);
2404 #ifndef USE_SOCKETS_AS_HANDLES
2406 #define fdopen my_fdopen
2410 win32_fdopen(int handle, const char *mode)
2413 WCHAR wMode[MODE_SIZE];
2416 A2WHELPER(mode, wMode, sizeof(wMode));
2417 f = _wfdopen(handle, wMode);
2420 f = fdopen(handle, (char *) mode);
2421 /* avoid buffering headaches for child processes */
2422 if (f && *mode == 'a')
2423 win32_fseek(f, 0, SEEK_END);
2428 win32_freopen(const char *path, const char *mode, FILE *stream)
2431 WCHAR wMode[MODE_SIZE], wBuffer[MAX_PATH+1];
2432 if (stricmp(path, "/dev/null")==0)
2436 A2WHELPER(mode, wMode, sizeof(wMode));
2437 A2WHELPER(path, wBuffer, sizeof(wBuffer));
2438 return _wfreopen(PerlDir_mapW(wBuffer), wMode, stream);
2440 return freopen(PerlDir_mapA(path), mode, stream);
2444 win32_fclose(FILE *pf)
2446 return my_fclose(pf); /* defined in win32sck.c */
2450 win32_fputs(const char *s,FILE *pf)
2452 return fputs(s, pf);
2456 win32_fputc(int c,FILE *pf)
2462 win32_ungetc(int c,FILE *pf)
2464 return ungetc(c,pf);
2468 win32_getc(FILE *pf)
2474 win32_fileno(FILE *pf)
2480 win32_clearerr(FILE *pf)
2487 win32_fflush(FILE *pf)
2493 win32_ftell(FILE *pf)
2499 win32_fseek(FILE *pf,long offset,int origin)
2501 return fseek(pf, offset, origin);
2505 win32_fgetpos(FILE *pf,fpos_t *p)
2507 return fgetpos(pf, p);
2511 win32_fsetpos(FILE *pf,const fpos_t *p)
2513 return fsetpos(pf, p);
2517 win32_rewind(FILE *pf)
2527 char prefix[MAX_PATH+1];
2528 char filename[MAX_PATH+1];
2529 DWORD len = GetTempPath(MAX_PATH, prefix);
2530 if (len && len < MAX_PATH) {
2531 if (GetTempFileName(prefix, "plx", 0, filename)) {
2532 HANDLE fh = CreateFile(filename,
2533 DELETE | GENERIC_READ | GENERIC_WRITE,
2537 FILE_ATTRIBUTE_NORMAL
2538 | FILE_FLAG_DELETE_ON_CLOSE,
2540 if (fh != INVALID_HANDLE_VALUE) {
2541 int fd = win32_open_osfhandle((long)fh, 0);
2543 #if defined(__BORLANDC__)
2544 setmode(fd,O_BINARY);
2546 DEBUG_p(PerlIO_printf(Perl_debug_log,
2547 "Created tmpfile=%s\n",filename));
2548 return fdopen(fd, "w+b");
2564 win32_fstat(int fd,struct stat *sbufptr)
2567 /* A file designated by filehandle is not shown as accessible
2568 * for write operations, probably because it is opened for reading.
2571 int rc = fstat(fd,sbufptr);
2572 BY_HANDLE_FILE_INFORMATION bhfi;
2573 if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &bhfi)) {
2574 sbufptr->st_mode &= 0xFE00;
2575 if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
2576 sbufptr->st_mode |= (S_IREAD + (S_IREAD >> 3) + (S_IREAD >> 6));
2578 sbufptr->st_mode |= ((S_IREAD|S_IWRITE) + ((S_IREAD|S_IWRITE) >> 3)
2579 + ((S_IREAD|S_IWRITE) >> 6));
2583 return my_fstat(fd,sbufptr);
2588 win32_pipe(int *pfd, unsigned int size, int mode)
2590 return _pipe(pfd, size, mode);
2594 win32_popenlist(const char *mode, IV narg, SV **args)
2597 Perl_croak(aTHX_ "List form of pipe open not implemented");
2602 * a popen() clone that respects PERL5SHELL
2604 * changed to return PerlIO* rather than FILE * by BKS, 11-11-2000
2608 win32_popen(const char *command, const char *mode)
2610 #ifdef USE_RTL_POPEN
2611 return _popen(command, mode);
2619 /* establish which ends read and write */
2620 if (strchr(mode,'w')) {
2621 stdfd = 0; /* stdin */
2625 else if (strchr(mode,'r')) {
2626 stdfd = 1; /* stdout */
2633 /* set the correct mode */
2634 if (strchr(mode,'b'))
2636 else if (strchr(mode,'t'))
2639 ourmode = _fmode & (O_TEXT | O_BINARY);
2641 /* the child doesn't inherit handles */
2642 ourmode |= O_NOINHERIT;
2644 if (win32_pipe( p, 512, ourmode) == -1)
2647 /* save current stdfd */
2648 if ((oldfd = win32_dup(stdfd)) == -1)
2651 /* make stdfd go to child end of pipe (implicitly closes stdfd) */
2652 /* stdfd will be inherited by the child */
2653 if (win32_dup2(p[child], stdfd) == -1)
2656 /* close the child end in parent */
2657 win32_close(p[child]);
2659 /* start the child */
2662 if ((childpid = do_spawn_nowait((char*)command)) == -1)
2665 /* revert stdfd to whatever it was before */
2666 if (win32_dup2(oldfd, stdfd) == -1)
2669 /* close saved handle */
2673 sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid);
2676 /* set process id so that it can be returned by perl's open() */
2677 PL_forkprocess = childpid;
2680 /* we have an fd, return a file stream */
2681 return (PerlIO_fdopen(p[parent], (char *)mode));
2684 /* we don't need to check for errors here */
2688 win32_dup2(oldfd, stdfd);
2693 #endif /* USE_RTL_POPEN */
2701 win32_pclose(PerlIO *pf)
2703 #ifdef USE_RTL_POPEN
2707 int childpid, status;
2711 sv = *av_fetch(w32_fdpid, PerlIO_fileno(pf), TRUE);
2714 childpid = SvIVX(sv);
2731 if (win32_waitpid(childpid, &status, 0) == -1)
2736 #endif /* USE_RTL_POPEN */
2742 LPCWSTR lpExistingFileName,
2743 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
2746 WCHAR wFullName[MAX_PATH+1];
2747 LPVOID lpContext = NULL;
2748 WIN32_STREAM_ID StreamId;
2749 DWORD dwSize = (char*)&StreamId.cStreamName - (char*)&StreamId;
2754 BOOL (__stdcall *pfnBackupWrite)(HANDLE, LPBYTE, DWORD, LPDWORD,
2755 BOOL, BOOL, LPVOID*) =
2756 (BOOL (__stdcall *)(HANDLE, LPBYTE, DWORD, LPDWORD,
2757 BOOL, BOOL, LPVOID*))
2758 GetProcAddress(GetModuleHandle("kernel32.dll"), "BackupWrite");
2759 if (pfnBackupWrite == NULL)
2762 dwLen = GetFullPathNameW(lpFileName, MAX_PATH, wFullName, NULL);
2765 dwLen = (dwLen+1)*sizeof(WCHAR);
2767 handle = CreateFileW(lpExistingFileName, FILE_WRITE_ATTRIBUTES,
2768 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2769 NULL, OPEN_EXISTING, 0, NULL);
2770 if (handle == INVALID_HANDLE_VALUE)
2773 StreamId.dwStreamId = BACKUP_LINK;
2774 StreamId.dwStreamAttributes = 0;
2775 StreamId.dwStreamNameSize = 0;
2776 #if defined(__BORLANDC__) \
2777 ||(defined(__MINGW32__) && !defined(_ANONYMOUS_UNION))
2778 StreamId.Size.u.HighPart = 0;
2779 StreamId.Size.u.LowPart = dwLen;
2781 StreamId.Size.HighPart = 0;
2782 StreamId.Size.LowPart = dwLen;
2785 bSuccess = pfnBackupWrite(handle, (LPBYTE)&StreamId, dwSize, &dwWritten,
2786 FALSE, FALSE, &lpContext);
2788 bSuccess = pfnBackupWrite(handle, (LPBYTE)wFullName, dwLen, &dwWritten,
2789 FALSE, FALSE, &lpContext);
2790 pfnBackupWrite(handle, NULL, 0, &dwWritten, TRUE, FALSE, &lpContext);
2793 CloseHandle(handle);
2798 win32_link(const char *oldname, const char *newname)
2801 BOOL (__stdcall *pfnCreateHardLinkW)(LPCWSTR,LPCWSTR,LPSECURITY_ATTRIBUTES);
2802 WCHAR wOldName[MAX_PATH+1];
2803 WCHAR wNewName[MAX_PATH+1];
2806 Perl_croak(aTHX_ PL_no_func, "link");
2808 pfnCreateHardLinkW =
2809 (BOOL (__stdcall *)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES))
2810 GetProcAddress(GetModuleHandle("kernel32.dll"), "CreateHardLinkW");
2811 if (pfnCreateHardLinkW == NULL)
2812 pfnCreateHardLinkW = Nt4CreateHardLinkW;
2814 if ((A2WHELPER(oldname, wOldName, sizeof(wOldName))) &&
2815 (A2WHELPER(newname, wNewName, sizeof(wNewName))) &&
2816 (wcscpy(wOldName, PerlDir_mapW(wOldName)),
2817 pfnCreateHardLinkW(PerlDir_mapW(wNewName), wOldName, NULL)))
2821 errno = (GetLastError() == ERROR_FILE_NOT_FOUND) ? ENOENT : EINVAL;
2826 win32_rename(const char *oname, const char *newname)
2828 WCHAR wOldName[MAX_PATH+1];
2829 WCHAR wNewName[MAX_PATH+1];
2830 char szOldName[MAX_PATH+1];
2831 char szNewName[MAX_PATH+1];
2835 /* XXX despite what the documentation says about MoveFileEx(),
2836 * it doesn't work under Windows95!
2839 DWORD dwFlags = MOVEFILE_COPY_ALLOWED;
2841 A2WHELPER(oname, wOldName, sizeof(wOldName));
2842 A2WHELPER(newname, wNewName, sizeof(wNewName));
2843 if (wcsicmp(wNewName, wOldName))
2844 dwFlags |= MOVEFILE_REPLACE_EXISTING;
2845 wcscpy(wOldName, PerlDir_mapW(wOldName));
2846 bResult = MoveFileExW(wOldName,PerlDir_mapW(wNewName), dwFlags);
2849 if (stricmp(newname, oname))
2850 dwFlags |= MOVEFILE_REPLACE_EXISTING;
2851 strcpy(szOldName, PerlDir_mapA(oname));
2852 bResult = MoveFileExA(szOldName,PerlDir_mapA(newname), dwFlags);
2855 DWORD err = GetLastError();
2857 case ERROR_BAD_NET_NAME:
2858 case ERROR_BAD_NETPATH:
2859 case ERROR_BAD_PATHNAME:
2860 case ERROR_FILE_NOT_FOUND:
2861 case ERROR_FILENAME_EXCED_RANGE:
2862 case ERROR_INVALID_DRIVE:
2863 case ERROR_NO_MORE_FILES:
2864 case ERROR_PATH_NOT_FOUND:
2877 char szTmpName[MAX_PATH+1];
2878 char dname[MAX_PATH+1];
2879 char *endname = Nullch;
2881 DWORD from_attr, to_attr;
2883 strcpy(szOldName, PerlDir_mapA(oname));
2884 strcpy(szNewName, PerlDir_mapA(newname));
2886 /* if oname doesn't exist, do nothing */
2887 from_attr = GetFileAttributes(szOldName);
2888 if (from_attr == 0xFFFFFFFF) {
2893 /* if newname exists, rename it to a temporary name so that we
2894 * don't delete it in case oname happens to be the same file
2895 * (but perhaps accessed via a different path)
2897 to_attr = GetFileAttributes(szNewName);
2898 if (to_attr != 0xFFFFFFFF) {
2899 /* if newname is a directory, we fail
2900 * XXX could overcome this with yet more convoluted logic */
2901 if (to_attr & FILE_ATTRIBUTE_DIRECTORY) {
2905 tmplen = strlen(szNewName);
2906 strcpy(szTmpName,szNewName);
2907 endname = szTmpName+tmplen;
2908 for (; endname > szTmpName ; --endname) {
2909 if (*endname == '/' || *endname == '\\') {
2914 if (endname > szTmpName)
2915 endname = strcpy(dname,szTmpName);
2919 /* get a temporary filename in same directory
2920 * XXX is this really the best we can do? */
2921 if (!GetTempFileName((LPCTSTR)endname, "plr", 0, szTmpName)) {
2925 DeleteFile(szTmpName);
2927 retval = rename(szNewName, szTmpName);
2934 /* rename oname to newname */
2935 retval = rename(szOldName, szNewName);
2937 /* if we created a temporary file before ... */
2938 if (endname != Nullch) {
2939 /* ...and rename succeeded, delete temporary file/directory */
2941 DeleteFile(szTmpName);
2942 /* else restore it to what it was */
2944 (void)rename(szTmpName, szNewName);
2951 win32_setmode(int fd, int mode)
2953 return setmode(fd, mode);
2957 win32_lseek(int fd, long offset, int origin)
2959 return lseek(fd, offset, origin);
2969 win32_open(const char *path, int flag, ...)
2974 WCHAR wBuffer[MAX_PATH+1];
2977 pmode = va_arg(ap, int);
2980 if (stricmp(path, "/dev/null")==0)
2984 A2WHELPER(path, wBuffer, sizeof(wBuffer));
2985 return _wopen(PerlDir_mapW(wBuffer), flag, pmode);
2987 return open(PerlDir_mapA(path), flag, pmode);
2990 /* close() that understands socket */
2991 extern int my_close(int); /* in win32sck.c */
2996 return my_close(fd);
3012 win32_dup2(int fd1,int fd2)
3014 return dup2(fd1,fd2);
3017 #ifdef PERL_MSVCRT_READFIX
3019 #define LF 10 /* line feed */
3020 #define CR 13 /* carriage return */
3021 #define CTRLZ 26 /* ctrl-z means eof for text */
3022 #define FOPEN 0x01 /* file handle open */
3023 #define FEOFLAG 0x02 /* end of file has been encountered */
3024 #define FCRLF 0x04 /* CR-LF across read buffer (in text mode) */
3025 #define FPIPE 0x08 /* file handle refers to a pipe */
3026 #define FAPPEND 0x20 /* file handle opened O_APPEND */
3027 #define FDEV 0x40 /* file handle refers to device */
3028 #define FTEXT 0x80 /* file handle is in text mode */
3029 #define MAX_DESCRIPTOR_COUNT (64*32) /* this is the maximun that MSVCRT can handle */
3032 _fixed_read(int fh, void *buf, unsigned cnt)
3034 int bytes_read; /* number of bytes read */
3035 char *buffer; /* buffer to read to */
3036 int os_read; /* bytes read on OS call */
3037 char *p, *q; /* pointers into buffer */
3038 char peekchr; /* peek-ahead character */
3039 ULONG filepos; /* file position after seek */
3040 ULONG dosretval; /* o.s. return value */
3042 /* validate handle */
3043 if (((unsigned)fh >= (unsigned)MAX_DESCRIPTOR_COUNT) ||
3044 !(_osfile(fh) & FOPEN))
3046 /* out of range -- return error */
3048 _doserrno = 0; /* not o.s. error */
3053 * If lockinitflag is FALSE, assume fd is device
3054 * lockinitflag is set to TRUE by open.
3056 if (_pioinfo(fh)->lockinitflag)
3057 EnterCriticalSection(&(_pioinfo(fh)->lock)); /* lock file */
3059 bytes_read = 0; /* nothing read yet */
3060 buffer = (char*)buf;
3062 if (cnt == 0 || (_osfile(fh) & FEOFLAG)) {
3063 /* nothing to read or at EOF, so return 0 read */
3067 if ((_osfile(fh) & (FPIPE|FDEV)) && _pipech(fh) != LF) {
3068 /* a pipe/device and pipe lookahead non-empty: read the lookahead
3070 *buffer++ = _pipech(fh);
3073 _pipech(fh) = LF; /* mark as empty */
3078 if (!ReadFile((HANDLE)_osfhnd(fh), buffer, cnt, (LPDWORD)&os_read, NULL))
3080 /* ReadFile has reported an error. recognize two special cases.
3082 * 1. map ERROR_ACCESS_DENIED to EBADF
3084 * 2. just return 0 if ERROR_BROKEN_PIPE has occurred. it
3085 * means the handle is a read-handle on a pipe for which
3086 * all write-handles have been closed and all data has been
3089 if ((dosretval = GetLastError()) == ERROR_ACCESS_DENIED) {
3090 /* wrong read/write mode should return EBADF, not EACCES */
3092 _doserrno = dosretval;
3096 else if (dosretval == ERROR_BROKEN_PIPE) {
3106 bytes_read += os_read; /* update bytes read */
3108 if (_osfile(fh) & FTEXT) {
3109 /* now must translate CR-LFs to LFs in the buffer */
3111 /* set CRLF flag to indicate LF at beginning of buffer */
3112 /* if ((os_read != 0) && (*(char *)buf == LF)) */
3113 /* _osfile(fh) |= FCRLF; */
3115 /* _osfile(fh) &= ~FCRLF; */
3117 _osfile(fh) &= ~FCRLF;
3119 /* convert chars in the buffer: p is src, q is dest */
3121 while (p < (char *)buf + bytes_read) {
3123 /* if fh is not a device, set ctrl-z flag */
3124 if (!(_osfile(fh) & FDEV))
3125 _osfile(fh) |= FEOFLAG;
3126 break; /* stop translating */
3131 /* *p is CR, so must check next char for LF */
3132 if (p < (char *)buf + bytes_read - 1) {
3135 *q++ = LF; /* convert CR-LF to LF */
3138 *q++ = *p++; /* store char normally */
3141 /* This is the hard part. We found a CR at end of
3142 buffer. We must peek ahead to see if next char
3147 if (!ReadFile((HANDLE)_osfhnd(fh), &peekchr, 1,
3148 (LPDWORD)&os_read, NULL))
3149 dosretval = GetLastError();
3151 if (dosretval != 0 || os_read == 0) {
3152 /* couldn't read ahead, store CR */
3156 /* peekchr now has the extra character -- we now
3157 have several possibilities:
3158 1. disk file and char is not LF; just seek back
3160 2. disk file and char is LF; store LF, don't seek back
3161 3. pipe/device and char is LF; store LF.
3162 4. pipe/device and char isn't LF, store CR and
3163 put char in pipe lookahead buffer. */
3164 if (_osfile(fh) & (FDEV|FPIPE)) {
3165 /* non-seekable device */
3170 _pipech(fh) = peekchr;
3175 if (peekchr == LF) {
3176 /* nothing read yet; must make some
3179 /* turn on this flag for tell routine */
3180 _osfile(fh) |= FCRLF;
3183 HANDLE osHandle; /* o.s. handle value */
3185 if ((osHandle = (HANDLE)_get_osfhandle(fh)) != (HANDLE)-1)
3187 if ((filepos = SetFilePointer(osHandle, -1, NULL, FILE_CURRENT)) == -1)
3188 dosretval = GetLastError();
3199 /* we now change bytes_read to reflect the true number of chars
3201 bytes_read = q - (char *)buf;
3205 if (_pioinfo(fh)->lockinitflag)
3206 LeaveCriticalSection(&(_pioinfo(fh)->lock)); /* unlock file */
3211 #endif /* PERL_MSVCRT_READFIX */
3214 win32_read(int fd, void *buf, unsigned int cnt)
3216 #ifdef PERL_MSVCRT_READFIX
3217 return _fixed_read(fd, buf, cnt);
3219 return read(fd, buf, cnt);
3224 win32_write(int fd, const void *buf, unsigned int cnt)
3226 return write(fd, buf, cnt);
3230 win32_mkdir(const char *dir, int mode)
3234 WCHAR wBuffer[MAX_PATH+1];
3235 A2WHELPER(dir, wBuffer, sizeof(wBuffer));
3236 return _wmkdir(PerlDir_mapW(wBuffer));
3238 return mkdir(PerlDir_mapA(dir)); /* just ignore mode */
3242 win32_rmdir(const char *dir)
3246 WCHAR wBuffer[MAX_PATH+1];
3247 A2WHELPER(dir, wBuffer, sizeof(wBuffer));
3248 return _wrmdir(PerlDir_mapW(wBuffer));
3250 return rmdir(PerlDir_mapA(dir));
3254 win32_chdir(const char *dir)
3262 WCHAR wBuffer[MAX_PATH+1];
3263 A2WHELPER(dir, wBuffer, sizeof(wBuffer));
3264 return _wchdir(wBuffer);
3270 win32_access(const char *path, int mode)
3274 WCHAR wBuffer[MAX_PATH+1];
3275 A2WHELPER(path, wBuffer, sizeof(wBuffer));
3276 return _waccess(PerlDir_mapW(wBuffer), mode);
3278 return access(PerlDir_mapA(path), mode);
3282 win32_chmod(const char *path, int mode)
3286 WCHAR wBuffer[MAX_PATH+1];
3287 A2WHELPER(path, wBuffer, sizeof(wBuffer));
3288 return _wchmod(PerlDir_mapW(wBuffer), mode);
3290 return chmod(PerlDir_mapA(path), mode);
3295 create_command_line(char *cname, STRLEN clen, const char * const *args)
3302 bool bat_file = FALSE;
3303 bool cmd_shell = FALSE;
3304 bool dumb_shell = FALSE;
3305 bool extra_quotes = FALSE;
3306 bool quote_next = FALSE;
3309 cname = (char*)args[0];
3311 /* The NT cmd.exe shell has the following peculiarity that needs to be
3312 * worked around. It strips a leading and trailing dquote when any
3313 * of the following is true:
3314 * 1. the /S switch was used
3315 * 2. there are more than two dquotes
3316 * 3. there is a special character from this set: &<>()@^|
3317 * 4. no whitespace characters within the two dquotes
3318 * 5. string between two dquotes isn't an executable file
3319 * To work around this, we always add a leading and trailing dquote
3320 * to the string, if the first argument is either "cmd.exe" or "cmd",
3321 * and there were at least two or more arguments passed to cmd.exe
3322 * (not including switches).
3323 * XXX the above rules (from "cmd /?") don't seem to be applied
3324 * always, making for the convolutions below :-(
3328 clen = strlen(cname);
3331 && (stricmp(&cname[clen-4], ".bat") == 0
3332 || (IsWinNT() && stricmp(&cname[clen-4], ".cmd") == 0)))
3338 char *exe = strrchr(cname, '/');
3339 char *exe2 = strrchr(cname, '\\');
3346 if (stricmp(exe, "cmd.exe") == 0 || stricmp(exe, "cmd") == 0) {
3350 else if (stricmp(exe, "command.com") == 0
3351 || stricmp(exe, "command") == 0)
3358 DEBUG_p(PerlIO_printf(Perl_debug_log, "Args "));
3359 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3360 STRLEN curlen = strlen(arg);
3361 if (!(arg[0] == '"' && arg[curlen-1] == '"'))
3362 len += 2; /* assume quoting needed (worst case) */
3364 DEBUG_p(PerlIO_printf(Perl_debug_log, "[%s]",arg));
3366 DEBUG_p(PerlIO_printf(Perl_debug_log, "\n"));
3369 New(1310, cmd, len, char);
3374 extra_quotes = TRUE;
3377 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3379 STRLEN curlen = strlen(arg);
3381 /* we want to protect empty arguments and ones with spaces with
3382 * dquotes, but only if they aren't already there */
3387 else if (quote_next) {
3388 /* see if it really is multiple arguments pretending to
3389 * be one and force a set of quotes around it */
3390 if (*find_next_space(arg))
3393 else if (!(arg[0] == '"' && curlen > 1 && arg[curlen-1] == '"')) {
3395 while (i < curlen) {
3396 if (isSPACE(arg[i])) {
3399 else if (arg[i] == '"') {
3422 && (stricmp(arg, "/x/c") == 0 || stricmp(arg, "/c") == 0))
3424 /* is there a next argument? */
3425 if (args[index+1]) {
3426 /* are there two or more next arguments? */
3427 if (args[index+2]) {
3429 extra_quotes = TRUE;
3432 /* single argument, force quoting if it has spaces */
3448 qualified_path(const char *cmd)
3452 char *fullcmd, *curfullcmd;
3458 fullcmd = (char*)cmd;
3460 if (*fullcmd == '/' || *fullcmd == '\\')
3467 pathstr = PerlEnv_getenv("PATH");
3468 New(0, fullcmd, MAX_PATH+1, char);
3469 curfullcmd = fullcmd;
3474 /* start by appending the name to the current prefix */
3475 strcpy(curfullcmd, cmd);
3476 curfullcmd += cmdlen;
3478 /* if it doesn't end with '.', or has no extension, try adding
3479 * a trailing .exe first */
3480 if (cmd[cmdlen-1] != '.'
3481 && (cmdlen < 4 || cmd[cmdlen-4] != '.'))
3483 strcpy(curfullcmd, ".exe");
3484 res = GetFileAttributes(fullcmd);
3485 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3490 /* that failed, try the bare name */
3491 res = GetFileAttributes(fullcmd);
3492 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3495 /* quit if no other path exists, or if cmd already has path */
3496 if (!pathstr || !*pathstr || has_slash)
3499 /* skip leading semis */
3500 while (*pathstr == ';')
3503 /* build a new prefix from scratch */
3504 curfullcmd = fullcmd;
3505 while (*pathstr && *pathstr != ';') {
3506 if (*pathstr == '"') { /* foo;"baz;etc";bar */
3507 pathstr++; /* skip initial '"' */
3508 while (*pathstr && *pathstr != '"') {
3509 if (curfullcmd-fullcmd < MAX_PATH-cmdlen-5)
3510 *curfullcmd++ = *pathstr;
3514 pathstr++; /* skip trailing '"' */
3517 if (curfullcmd-fullcmd < MAX_PATH-cmdlen-5)
3518 *curfullcmd++ = *pathstr;
3523 pathstr++; /* skip trailing semi */
3524 if (curfullcmd > fullcmd /* append a dir separator */
3525 && curfullcmd[-1] != '/' && curfullcmd[-1] != '\\')
3527 *curfullcmd++ = '\\';
3535 /* The following are just place holders.
3536 * Some hosts may provide and environment that the OS is
3537 * not tracking, therefore, these host must provide that
3538 * environment and the current directory to CreateProcess
3542 win32_get_childenv(void)
3548 win32_free_childenv(void* d)
3553 win32_clearenv(void)
3555 char *envv = GetEnvironmentStrings();
3559 char *end = strchr(cur,'=');
3560 if (end && end != cur) {
3562 SetEnvironmentVariable(cur, NULL);
3564 cur = end + strlen(end+1)+2;
3566 else if ((len = strlen(cur)))
3569 FreeEnvironmentStrings(envv);
3573 win32_get_childdir(void)
3577 char szfilename[(MAX_PATH+1)*2];
3579 WCHAR wfilename[MAX_PATH+1];
3580 GetCurrentDirectoryW(MAX_PATH+1, wfilename);
3581 W2AHELPER(wfilename, szfilename, sizeof(szfilename));
3584 GetCurrentDirectoryA(MAX_PATH+1, szfilename);
3587 New(0, ptr, strlen(szfilename)+1, char);
3588 strcpy(ptr, szfilename);
3593 win32_free_childdir(char* d)
3600 /* XXX this needs to be made more compatible with the spawnvp()
3601 * provided by the various RTLs. In particular, searching for
3602 * *.{com,bat,cmd} files (as done by the RTLs) is unimplemented.
3603 * This doesn't significantly affect perl itself, because we
3604 * always invoke things using PERL5SHELL if a direct attempt to
3605 * spawn the executable fails.
3607 * XXX splitting and rejoining the commandline between do_aspawn()
3608 * and win32_spawnvp() could also be avoided.
3612 win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
3614 #ifdef USE_RTL_SPAWNVP
3615 return spawnvp(mode, cmdname, (char * const *)argv);
3622 STARTUPINFO StartupInfo;
3623 PROCESS_INFORMATION ProcessInformation;
3626 char *fullcmd = Nullch;
3627 char *cname = (char *)cmdname;
3631 clen = strlen(cname);
3632 /* if command name contains dquotes, must remove them */
3633 if (strchr(cname, '"')) {
3635 New(0,cname,clen+1,char);
3648 cmd = create_command_line(cname, clen, argv);
3650 env = PerlEnv_get_childenv();
3651 dir = PerlEnv_get_childdir();
3654 case P_NOWAIT: /* asynch + remember result */
3655 if (w32_num_children >= MAXIMUM_WAIT_OBJECTS) {
3660 /* Create a new process group so we can use GenerateConsoleCtrlEvent()
3663 create |= CREATE_NEW_PROCESS_GROUP;
3666 case P_WAIT: /* synchronous execution */
3668 default: /* invalid mode */
3673 memset(&StartupInfo,0,sizeof(StartupInfo));
3674 StartupInfo.cb = sizeof(StartupInfo);
3675 memset(&tbl,0,sizeof(tbl));
3676 PerlEnv_get_child_IO(&tbl);
3677 StartupInfo.dwFlags = tbl.dwFlags;
3678 StartupInfo.dwX = tbl.dwX;
3679 StartupInfo.dwY = tbl.dwY;
3680 StartupInfo.dwXSize = tbl.dwXSize;
3681 StartupInfo.dwYSize = tbl.dwYSize;
3682 StartupInfo.dwXCountChars = tbl.dwXCountChars;
3683 StartupInfo.dwYCountChars = tbl.dwYCountChars;
3684 StartupInfo.dwFillAttribute = tbl.dwFillAttribute;
3685 StartupInfo.wShowWindow = tbl.wShowWindow;
3686 StartupInfo.hStdInput = tbl.childStdIn;
3687 StartupInfo.hStdOutput = tbl.childStdOut;
3688 StartupInfo.hStdError = tbl.childStdErr;
3689 if (StartupInfo.hStdInput != INVALID_HANDLE_VALUE &&
3690 StartupInfo.hStdOutput != INVALID_HANDLE_VALUE &&
3691 StartupInfo.hStdError != INVALID_HANDLE_VALUE)
3693 StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
3696 create |= CREATE_NEW_CONSOLE;
3698 if (w32_use_showwindow) {
3699 StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
3700 StartupInfo.wShowWindow = w32_showwindow;
3703 DEBUG_p(PerlIO_printf(Perl_debug_log, "Spawning [%s] with [%s]\n",
3706 if (!CreateProcess(cname, /* search PATH to find executable */
3707 cmd, /* executable, and its arguments */
3708 NULL, /* process attributes */
3709 NULL, /* thread attributes */
3710 TRUE, /* inherit handles */
3711 create, /* creation flags */
3712 (LPVOID)env, /* inherit environment */
3713 dir, /* inherit cwd */
3715 &ProcessInformation))
3717 /* initial NULL argument to CreateProcess() does a PATH
3718 * search, but it always first looks in the directory
3719 * where the current process was started, which behavior
3720 * is undesirable for backward compatibility. So we
3721 * jump through our own hoops by picking out the path
3722 * we really want it to use. */
3724 fullcmd = qualified_path(cname);
3726 if (cname != cmdname)
3729 DEBUG_p(PerlIO_printf(Perl_debug_log,
3730 "Retrying [%s] with same args\n",
3740 if (mode == P_NOWAIT) {
3741 /* asynchronous spawn -- store handle, return PID */
3742 ret = (int)ProcessInformation.dwProcessId;
3743 if (IsWin95() && ret < 0)
3746 w32_child_handles[w32_num_children] = ProcessInformation.hProcess;
3747 w32_child_pids[w32_num_children] = (DWORD)ret;
3752 win32_msgwait(aTHX_ 1, &ProcessInformation.hProcess, INFINITE, NULL);
3753 /* FIXME: if msgwait returned due to message perhaps forward the
3754 "signal" to the process
3756 GetExitCodeProcess(ProcessInformation.hProcess, &status);
3758 CloseHandle(ProcessInformation.hProcess);
3761 CloseHandle(ProcessInformation.hThread);
3764 PerlEnv_free_childenv(env);
3765 PerlEnv_free_childdir(dir);
3767 if (cname != cmdname)
3774 win32_execv(const char *cmdname, const char *const *argv)
3778 /* if this is a pseudo-forked child, we just want to spawn
3779 * the new program, and return */
3781 return spawnv(P_WAIT, cmdname, (char *const *)argv);
3783 return execv(cmdname, (char *const *)argv);
3787 win32_execvp(const char *cmdname, const char *const *argv)
3791 /* if this is a pseudo-forked child, we just want to spawn
3792 * the new program, and return */
3793 if (w32_pseudo_id) {
3794 int status = win32_spawnvp(P_WAIT, cmdname, (char *const *)argv);
3803 return execvp(cmdname, (char *const *)argv);
3807 win32_perror(const char *str)
3813 win32_setbuf(FILE *pf, char *buf)
3819 win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
3821 return setvbuf(pf, buf, type, size);
3825 win32_flushall(void)
3831 win32_fcloseall(void)
3837 win32_fgets(char *s, int n, FILE *pf)
3839 return fgets(s, n, pf);
3849 win32_fgetc(FILE *pf)
3855 win32_putc(int c, FILE *pf)
3861 win32_puts(const char *s)
3873 win32_putchar(int c)
3880 #ifndef USE_PERL_SBRK
3882 static char *committed = NULL; /* XXX threadead */
3883 static char *base = NULL; /* XXX threadead */
3884 static char *reserved = NULL; /* XXX threadead */
3885 static char *brk = NULL; /* XXX threadead */
3886 static DWORD pagesize = 0; /* XXX threadead */
3887 static DWORD allocsize = 0; /* XXX threadead */
3895 GetSystemInfo(&info);
3896 /* Pretend page size is larger so we don't perpetually
3897 * call the OS to commit just one page ...
3899 pagesize = info.dwPageSize << 3;
3900 allocsize = info.dwAllocationGranularity;
3902 /* This scheme fails eventually if request for contiguous
3903 * block is denied so reserve big blocks - this is only
3904 * address space not memory ...
3906 if (brk+need >= reserved)
3908 DWORD size = 64*1024*1024;
3910 if (committed && reserved && committed < reserved)
3912 /* Commit last of previous chunk cannot span allocations */
3913 addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
3915 committed = reserved;
3917 /* Reserve some (more) space
3918 * Note this is a little sneaky, 1st call passes NULL as reserved
3919 * so lets system choose where we start, subsequent calls pass
3920 * the old end address so ask for a contiguous block
3922 addr = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
3925 reserved = addr+size;
3940 if (brk > committed)
3942 DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
3943 char *addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
3958 win32_malloc(size_t size)
3960 return malloc(size);
3964 win32_calloc(size_t numitems, size_t size)
3966 return calloc(numitems,size);
3970 win32_realloc(void *block, size_t size)
3972 return realloc(block,size);
3976 win32_free(void *block)
3983 win32_open_osfhandle(long handle, int flags)
3985 #ifdef USE_FIXED_OSFHANDLE
3987 return my_open_osfhandle(handle, flags);
3989 return _open_osfhandle(handle, flags);
3993 win32_get_osfhandle(int fd)
3995 return _get_osfhandle(fd);
3999 win32_dynaload(const char* filename)
4003 char buf[MAX_PATH+1];
4006 /* LoadLibrary() doesn't recognize forward slashes correctly,
4007 * so turn 'em back. */
4008 first = strchr(filename, '/');
4010 STRLEN len = strlen(filename);
4011 if (len <= MAX_PATH) {
4012 strcpy(buf, filename);
4013 filename = &buf[first - filename];
4015 if (*filename == '/')
4016 *(char*)filename = '\\';
4023 WCHAR wfilename[MAX_PATH+1];
4024 A2WHELPER(filename, wfilename, sizeof(wfilename));
4025 hModule = LoadLibraryExW(PerlDir_mapW(wfilename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
4028 hModule = LoadLibraryExA(PerlDir_mapA(filename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
4038 XS(w32_SetChildShowWindow)
4041 BOOL use_showwindow = w32_use_showwindow;
4042 /* use "unsigned short" because Perl has redefined "WORD" */
4043 unsigned short showwindow = w32_showwindow;
4046 Perl_croak(aTHX_ "usage: Win32::SetChildShowWindow($showwindow)");
4048 if (items == 0 || !SvOK(ST(0)))
4049 w32_use_showwindow = FALSE;
4051 w32_use_showwindow = TRUE;
4052 w32_showwindow = (unsigned short)SvIV(ST(0));
4057 ST(0) = sv_2mortal(newSViv(showwindow));
4059 ST(0) = &PL_sv_undef;
4067 /* Make the host for current directory */
4068 char* ptr = PerlEnv_get_childdir();
4071 * then it worked, set PV valid,
4072 * else return 'undef'
4075 SV *sv = sv_newmortal();
4077 PerlEnv_free_childdir(ptr);
4079 #ifndef INCOMPLETE_TAINTS
4096 Perl_croak(aTHX_ "usage: Win32::SetCurrentDirectory($cwd)");
4097 if (!PerlDir_chdir(SvPV_nolen(ST(0))))
4104 XS(w32_GetNextAvailDrive)
4108 char root[] = "_:\\";
4113 if (GetDriveType(root) == 1) {
4122 XS(w32_GetLastError)
4126 XSRETURN_IV(GetLastError());
4130 XS(w32_SetLastError)
4134 Perl_croak(aTHX_ "usage: Win32::SetLastError($error)");
4135 SetLastError(SvIV(ST(0)));
4143 char *name = w32_getlogin_buffer;
4144 DWORD size = sizeof(w32_getlogin_buffer);
4146 if (GetUserName(name,&size)) {
4147 /* size includes NULL */
4148 ST(0) = sv_2mortal(newSVpvn(name,size-1));
4158 char name[MAX_COMPUTERNAME_LENGTH+1];
4159 DWORD size = sizeof(name);
4161 if (GetComputerName(name,&size)) {
4162 /* size does NOT include NULL :-( */
4163 ST(0) = sv_2mortal(newSVpvn(name,size));
4174 HINSTANCE hNetApi32 = LoadLibrary("netapi32.dll");
4175 DWORD (__stdcall *pfnNetApiBufferFree)(LPVOID Buffer);
4176 DWORD (__stdcall *pfnNetWkstaGetInfo)(LPWSTR servername, DWORD level,
4180 pfnNetApiBufferFree = (DWORD (__stdcall *)(void *))
4181 GetProcAddress(hNetApi32, "NetApiBufferFree");
4182 pfnNetWkstaGetInfo = (DWORD (__stdcall *)(LPWSTR, DWORD, void *))
4183 GetProcAddress(hNetApi32, "NetWkstaGetInfo");
4186 if (hNetApi32 && pfnNetWkstaGetInfo && pfnNetApiBufferFree) {
4187 /* this way is more reliable, in case user has a local account. */
4189 DWORD dnamelen = sizeof(dname);
4191 DWORD wki100_platform_id;
4192 LPWSTR wki100_computername;
4193 LPWSTR wki100_langroup;
4194 DWORD wki100_ver_major;
4195 DWORD wki100_ver_minor;
4197 /* NERR_Success *is* 0*/
4198 if (0 == pfnNetWkstaGetInfo(NULL, 100, &pwi)) {
4199 if (pwi->wki100_langroup && *(pwi->wki100_langroup)) {
4200 WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_langroup,
4201 -1, (LPSTR)dname, dnamelen, NULL, NULL);
4204 WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_computername,
4205 -1, (LPSTR)dname, dnamelen, NULL, NULL);
4207 pfnNetApiBufferFree(pwi);
4208 FreeLibrary(hNetApi32);
4211 FreeLibrary(hNetApi32);
4214 /* Win95 doesn't have NetWksta*(), so do it the old way */
4216 DWORD size = sizeof(name);
4218 FreeLibrary(hNetApi32);
4219 if (GetUserName(name,&size)) {
4220 char sid[ONE_K_BUFSIZE];
4221 DWORD sidlen = sizeof(sid);
4223 DWORD dnamelen = sizeof(dname);
4225 if (LookupAccountName(NULL, name, (PSID)&sid, &sidlen,
4226 dname, &dnamelen, &snu)) {
4227 XSRETURN_PV(dname); /* all that for this */
4239 DWORD flags, filecomplen;
4240 if (GetVolumeInformation(NULL, NULL, 0, NULL, &filecomplen,
4241 &flags, fsname, sizeof(fsname))) {
4242 if (GIMME_V == G_ARRAY) {
4243 XPUSHs(sv_2mortal(newSVpvn(fsname,strlen(fsname))));
4244 XPUSHs(sv_2mortal(newSViv(flags)));
4245 XPUSHs(sv_2mortal(newSViv(filecomplen)));
4250 XSRETURN_PV(fsname);
4256 XS(w32_GetOSVersion)
4259 OSVERSIONINFOA osver;
4262 OSVERSIONINFOW osverw;
4263 char szCSDVersion[sizeof(osverw.szCSDVersion)];
4264 osverw.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
4265 if (!GetVersionExW(&osverw)) {
4268 W2AHELPER(osverw.szCSDVersion, szCSDVersion, sizeof(szCSDVersion));
4269 XPUSHs(newSVpvn(szCSDVersion, strlen(szCSDVersion)));
4270 osver.dwMajorVersion = osverw.dwMajorVersion;
4271 osver.dwMinorVersion = osverw.dwMinorVersion;
4272 osver.dwBuildNumber = osverw.dwBuildNumber;
4273 osver.dwPlatformId = osverw.dwPlatformId;
4276 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
4277 if (!GetVersionExA(&osver)) {
4280 XPUSHs(newSVpvn(osver.szCSDVersion, strlen(osver.szCSDVersion)));
4282 XPUSHs(newSViv(osver.dwMajorVersion));
4283 XPUSHs(newSViv(osver.dwMinorVersion));
4284 XPUSHs(newSViv(osver.dwBuildNumber));
4285 XPUSHs(newSViv(osver.dwPlatformId));
4294 XSRETURN_IV(IsWinNT());
4302 XSRETURN_IV(IsWin95());
4306 XS(w32_FormatMessage)
4310 char msgbuf[ONE_K_BUFSIZE];
4313 Perl_croak(aTHX_ "usage: Win32::FormatMessage($errno)");
4316 WCHAR wmsgbuf[ONE_K_BUFSIZE];
4317 if (FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
4318 &source, SvIV(ST(0)), 0,
4319 wmsgbuf, ONE_K_BUFSIZE-1, NULL))
4321 W2AHELPER(wmsgbuf, msgbuf, sizeof(msgbuf));
4322 XSRETURN_PV(msgbuf);
4326 if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,
4327 &source, SvIV(ST(0)), 0,
4328 msgbuf, sizeof(msgbuf)-1, NULL))
4329 XSRETURN_PV(msgbuf);
4342 PROCESS_INFORMATION stProcInfo;
4343 STARTUPINFO stStartInfo;
4344 BOOL bSuccess = FALSE;
4347 Perl_croak(aTHX_ "usage: Win32::Spawn($cmdName, $args, $PID)");
4349 cmd = SvPV_nolen(ST(0));
4350 args = SvPV_nolen(ST(1));
4352 env = PerlEnv_get_childenv();
4353 dir = PerlEnv_get_childdir();
4355 memset(&stStartInfo, 0, sizeof(stStartInfo)); /* Clear the block */
4356 stStartInfo.cb = sizeof(stStartInfo); /* Set the structure size */
4357 stStartInfo.dwFlags = STARTF_USESHOWWINDOW; /* Enable wShowWindow control */
4358 stStartInfo.wShowWindow = SW_SHOWMINNOACTIVE; /* Start min (normal) */
4361 cmd, /* Image path */
4362 args, /* Arguments for command line */
4363 NULL, /* Default process security */
4364 NULL, /* Default thread security */
4365 FALSE, /* Must be TRUE to use std handles */
4366 NORMAL_PRIORITY_CLASS, /* No special scheduling */
4367 env, /* Inherit our environment block */
4368 dir, /* Inherit our currrent directory */
4369 &stStartInfo, /* -> Startup info */
4370 &stProcInfo)) /* <- Process info (if OK) */
4372 int pid = (int)stProcInfo.dwProcessId;
4373 if (IsWin95() && pid < 0)
4375 sv_setiv(ST(2), pid);
4376 CloseHandle(stProcInfo.hThread);/* library source code does this. */
4379 PerlEnv_free_childenv(env);
4380 PerlEnv_free_childdir(dir);
4381 XSRETURN_IV(bSuccess);
4385 XS(w32_GetTickCount)
4388 DWORD msec = GetTickCount();
4396 XS(w32_GetShortPathName)
4403 Perl_croak(aTHX_ "usage: Win32::GetShortPathName($longPathName)");
4405 shortpath = sv_mortalcopy(ST(0));
4406 SvUPGRADE(shortpath, SVt_PV);
4407 if (!SvPVX(shortpath) || !SvLEN(shortpath))
4410 /* src == target is allowed */
4412 len = GetShortPathName(SvPVX(shortpath),
4415 } while (len >= SvLEN(shortpath) && sv_grow(shortpath,len+1));
4417 SvCUR_set(shortpath,len);
4425 XS(w32_GetFullPathName)
4434 Perl_croak(aTHX_ "usage: Win32::GetFullPathName($filename)");
4437 fullpath = sv_mortalcopy(filename);
4438 SvUPGRADE(fullpath, SVt_PV);
4439 if (!SvPVX(fullpath) || !SvLEN(fullpath))
4443 len = GetFullPathName(SvPVX(filename),
4447 } while (len >= SvLEN(fullpath) && sv_grow(fullpath,len+1));
4449 if (GIMME_V == G_ARRAY) {
4451 XST_mPV(1,filepart);
4452 len = filepart - SvPVX(fullpath);
4455 SvCUR_set(fullpath,len);
4463 XS(w32_GetLongPathName)
4467 char tmpbuf[MAX_PATH+1];
4472 Perl_croak(aTHX_ "usage: Win32::GetLongPathName($pathname)");
4475 pathstr = SvPV(path,len);
4476 strcpy(tmpbuf, pathstr);
4477 pathstr = win32_longpath(tmpbuf);
4479 ST(0) = sv_2mortal(newSVpvn(pathstr, strlen(pathstr)));
4490 Perl_croak(aTHX_ "usage: Win32::Sleep($milliseconds)");
4501 Perl_croak(aTHX_ "usage: Win32::CopyFile($from, $to, $overwrite)");
4503 WCHAR wSourceFile[MAX_PATH+1];
4504 WCHAR wDestFile[MAX_PATH+1];
4505 A2WHELPER(SvPV_nolen(ST(0)), wSourceFile, sizeof(wSourceFile));
4506 wcscpy(wSourceFile, PerlDir_mapW(wSourceFile));
4507 A2WHELPER(SvPV_nolen(ST(1)), wDestFile, sizeof(wDestFile));
4508 bResult = CopyFileW(wSourceFile, PerlDir_mapW(wDestFile), !SvTRUE(ST(2)));
4511 char szSourceFile[MAX_PATH+1];
4512 strcpy(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(0))));
4513 bResult = CopyFileA(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(1))), !SvTRUE(ST(2)));
4522 Perl_init_os_extras(void)
4525 char *file = __FILE__;
4528 /* these names are Activeware compatible */
4529 newXS("Win32::GetCwd", w32_GetCwd, file);
4530 newXS("Win32::SetCwd", w32_SetCwd, file);
4531 newXS("Win32::GetNextAvailDrive", w32_GetNextAvailDrive, file);
4532 newXS("Win32::GetLastError", w32_GetLastError, file);
4533 newXS("Win32::SetLastError", w32_SetLastError, file);
4534 newXS("Win32::LoginName", w32_LoginName, file);
4535 newXS("Win32::NodeName", w32_NodeName, file);
4536 newXS("Win32::DomainName", w32_DomainName, file);
4537 newXS("Win32::FsType", w32_FsType, file);
4538 newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
4539 newXS("Win32::IsWinNT", w32_IsWinNT, file);
4540 newXS("Win32::IsWin95", w32_IsWin95, file);
4541 newXS("Win32::FormatMessage", w32_FormatMessage, file);
4542 newXS("Win32::Spawn", w32_Spawn, file);
4543 newXS("Win32::GetTickCount", w32_GetTickCount, file);
4544 newXS("Win32::GetShortPathName", w32_GetShortPathName, file);
4545 newXS("Win32::GetFullPathName", w32_GetFullPathName, file);
4546 newXS("Win32::GetLongPathName", w32_GetLongPathName, file);
4547 newXS("Win32::CopyFile", w32_CopyFile, file);
4548 newXS("Win32::Sleep", w32_Sleep, file);
4549 newXS("Win32::SetChildShowWindow", w32_SetChildShowWindow, file);
4551 /* XXX Bloat Alert! The following Activeware preloads really
4552 * ought to be part of Win32::Sys::*, so they're not included
4555 /* LookupAccountName
4557 * InitiateSystemShutdown
4558 * AbortSystemShutdown
4559 * ExpandEnvrironmentStrings
4566 win32_signal_context(void)
4570 my_perl = PL_curinterp;
4571 PERL_SET_THX(my_perl);
4579 win32_ctrlhandler(DWORD dwCtrlType)
4582 dTHXa(PERL_GET_SIG_CONTEXT);
4588 switch(dwCtrlType) {
4589 case CTRL_CLOSE_EVENT:
4590 /* A signal that the system sends to all processes attached to a console when
4591 the user closes the console (either by choosing the Close command from the
4592 console window's System menu, or by choosing the End Task command from the
4595 if (do_raise(aTHX_ 1)) /* SIGHUP */
4596 sig_terminate(aTHX_ 1);
4600 /* A CTRL+c signal was received */
4601 if (do_raise(aTHX_ SIGINT))
4602 sig_terminate(aTHX_ SIGINT);
4605 case CTRL_BREAK_EVENT:
4606 /* A CTRL+BREAK signal was received */
4607 if (do_raise(aTHX_ SIGBREAK))
4608 sig_terminate(aTHX_ SIGBREAK);
4611 case CTRL_LOGOFF_EVENT:
4612 /* A signal that the system sends to all console processes when a user is logging
4613 off. This signal does not indicate which user is logging off, so no
4614 assumptions can be made.
4617 case CTRL_SHUTDOWN_EVENT:
4618 /* A signal that the system sends to all console processes when the system is
4621 if (do_raise(aTHX_ SIGTERM))
4622 sig_terminate(aTHX_ SIGTERM);
4632 Perl_win32_init(int *argcp, char ***argvp)
4634 /* Disable floating point errors, Perl will trap the ones we
4635 * care about. VC++ RTL defaults to switching these off
4636 * already, but the Borland RTL doesn't. Since we don't
4637 * want to be at the vendor's whim on the default, we set
4638 * it explicitly here.
4640 #if !defined(_ALPHA_) && !defined(__GNUC__)
4641 _control87(MCW_EM, MCW_EM);
4647 win32_get_child_IO(child_IO_table* ptbl)
4649 ptbl->childStdIn = GetStdHandle(STD_INPUT_HANDLE);
4650 ptbl->childStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
4651 ptbl->childStdErr = GetStdHandle(STD_ERROR_HANDLE);
4655 win32_signal(int sig, Sighandler_t subcode)
4658 if (sig < SIG_SIZE) {
4659 int save_errno = errno;
4660 Sighandler_t result = signal(sig, subcode);
4661 if (result == SIG_ERR) {
4662 result = w32_sighandler[sig];
4665 w32_sighandler[sig] = subcode;
4675 #ifdef HAVE_INTERP_INTERN
4679 win32_csighandler(int sig)
4682 dTHXa(PERL_GET_SIG_CONTEXT);
4683 Perl_warn(aTHX_ "Got signal %d",sig);
4689 Perl_sys_intern_init(pTHX)
4692 w32_perlshell_tokens = Nullch;
4693 w32_perlshell_vec = (char**)NULL;
4694 w32_perlshell_items = 0;
4695 w32_fdpid = newAV();
4696 New(1313, w32_children, 1, child_tab);
4697 w32_num_children = 0;
4698 # ifdef USE_ITHREADS
4700 New(1313, w32_pseudo_children, 1, child_tab);
4701 w32_num_pseudo_children = 0;
4703 w32_init_socktype = 0;
4706 for (i=0; i < SIG_SIZE; i++) {
4707 w32_sighandler[i] = SIG_DFL;
4710 if (my_perl == PL_curinterp) {
4714 /* Force C runtime signal stuff to set its console handler */
4715 signal(SIGINT,&win32_csighandler);
4716 signal(SIGBREAK,&win32_csighandler);
4717 /* Push our handler on top */
4718 SetConsoleCtrlHandler(win32_ctrlhandler,TRUE);
4723 Perl_sys_intern_clear(pTHX)
4725 Safefree(w32_perlshell_tokens);
4726 Safefree(w32_perlshell_vec);
4727 /* NOTE: w32_fdpid is freed by sv_clean_all() */
4728 Safefree(w32_children);
4730 KillTimer(NULL,w32_timerid);
4733 # ifdef MULTIPLICITY
4734 if (my_perl == PL_curinterp) {
4738 SetConsoleCtrlHandler(win32_ctrlhandler,FALSE);
4740 # ifdef USE_ITHREADS
4741 Safefree(w32_pseudo_children);
4745 # ifdef USE_ITHREADS
4748 Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
4750 dst->perlshell_tokens = Nullch;
4751 dst->perlshell_vec = (char**)NULL;
4752 dst->perlshell_items = 0;
4753 dst->fdpid = newAV();
4754 Newz(1313, dst->children, 1, child_tab);
4756 Newz(1313, dst->pseudo_children, 1, child_tab);
4757 dst->thr_intern.Winit_socktype = 0;
4759 dst->poll_count = 0;
4760 Copy(src->sigtable,dst->sigtable,SIG_SIZE,Sighandler_t);
4762 # endif /* USE_ITHREADS */
4763 #endif /* HAVE_INTERP_INTERN */
4766 win32_free_argvw(pTHX_ void *ptr)
4768 char** argv = (char**)ptr;
4776 win32_argv2utf8(int argc, char** argv)
4781 LPWSTR* lpwStr = CommandLineToArgvW(GetCommandLineW(), &wargc);
4782 if (lpwStr && argc) {
4784 length = WideCharToMultiByte(CP_UTF8, 0, lpwStr[--wargc], -1, NULL, 0, NULL, NULL);
4785 Newz(0, psz, length, char);
4786 WideCharToMultiByte(CP_UTF8, 0, lpwStr[wargc], -1, psz, length, NULL, NULL);
4789 call_atexit(win32_free_argvw, argv);
4791 GlobalFree((HGLOBAL)lpwStr);