3 * (c) 1995 Microsoft Corporation. All rights reserved.
4 * Developed by hip communications inc., http://info.hip.com/info/
5 * Portions (c) 1993 Intergraph Corporation. All rights reserved.
7 * You may distribute under the terms of either the GNU General Public
8 * License or the Artistic License, as specified in the README file.
10 #define PERLIO_NOT_STDIO 0
11 #define WIN32_LEAN_AND_MEAN
12 #define WIN32IO_IS_STDIO
19 # define HWND_MESSAGE ((HWND)-3)
21 /* GCC-2.95.2/Mingw32-1.1 forgot the WINAPI on CommandLineToArgvW() */
22 #if defined(__MINGW32__) && (__MINGW32_MAJOR_VERSION==1)
23 # include <shellapi.h>
25 LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCommandLine, int * pNumArgs);
31 /* #include "config.h" */
33 #if !defined(PERLIO_IS_STDIO) && !defined(USE_SFIO)
42 #define PERL_NO_GET_CONTEXT
48 /* assert.h conflicts with #define of assert in perl.h */
55 #if defined(_MSC_VER) || defined(__MINGW32__)
56 #include <sys/utime.h>
61 /* Mingw32 defaults to globing command line
62 * So we turn it off like this:
67 #if defined(__MINGW32__) && (__MINGW32_MAJOR_VERSION==1)
68 /* Mingw32-1.1 is missing some prototypes */
69 FILE * _wfopen(LPCWSTR wszFileName, LPCWSTR wszMode);
70 FILE * _wfdopen(int nFd, LPCWSTR wszMode);
71 FILE * _freopen(LPCWSTR wszFileName, LPCWSTR wszMode, FILE * pOldStream);
76 #if defined(__BORLANDC__)
78 # define _utimbuf utimbuf
83 #define EXECF_SPAWN_NOWAIT 3
85 #if defined(PERL_IMPLICIT_SYS)
86 # undef win32_get_privlib
87 # define win32_get_privlib g_win32_get_privlib
88 # undef win32_get_sitelib
89 # define win32_get_sitelib g_win32_get_sitelib
90 # undef win32_get_vendorlib
91 # define win32_get_vendorlib g_win32_get_vendorlib
93 # define getlogin g_getlogin
96 static void get_shell(void);
97 static long tokenize(const char *str, char **dest, char ***destv);
98 static int do_spawn2(pTHX_ const char *cmd, int exectype);
99 static BOOL has_shell_metachars(const char *ptr);
100 static long filetime_to_clock(PFILETIME ft);
101 static BOOL filetime_from_time(PFILETIME ft, time_t t);
102 static char * get_emd_part(SV **leading, char *trailing, ...);
103 static void remove_dead_process(long deceased);
104 static long find_pid(int pid);
105 static char * qualified_path(const char *cmd);
106 static char * win32_get_xlib(const char *pl, const char *xlib,
107 const char *libname);
110 static void remove_dead_pseudo_process(long child);
111 static long find_pseudo_pid(int pid);
115 HANDLE w32_perldll_handle = INVALID_HANDLE_VALUE;
116 char w32_module_name[MAX_PATH+1];
119 static OSVERSIONINFO g_osver = {0, 0, 0, 0, 0, ""};
121 #define ONE_K_BUFSIZE 1024
124 /* Silence STDERR grumblings from Borland's math library. */
126 _matherr(struct _exception *a)
136 return (g_osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
142 return (g_osver.dwPlatformId == VER_PLATFORM_WIN32_NT);
146 set_w32_module_name(void)
149 GetModuleFileName((HMODULE)((w32_perldll_handle == INVALID_HANDLE_VALUE)
150 ? GetModuleHandle(NULL)
151 : w32_perldll_handle),
152 w32_module_name, sizeof(w32_module_name));
154 /* remove \\?\ prefix */
155 if (memcmp(w32_module_name, "\\\\?\\", 4) == 0)
156 memmove(w32_module_name, w32_module_name+4, strlen(w32_module_name+4)+1);
158 /* try to get full path to binary (which may be mangled when perl is
159 * run from a 16-bit app) */
160 /*PerlIO_printf(Perl_debug_log, "Before %s\n", w32_module_name);*/
161 (void)win32_longpath(w32_module_name);
162 /*PerlIO_printf(Perl_debug_log, "After %s\n", w32_module_name);*/
164 /* normalize to forward slashes */
165 ptr = w32_module_name;
173 /* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
175 get_regstr_from(HKEY hkey, const char *valuename, SV **svp)
177 /* Retrieve a REG_SZ or REG_EXPAND_SZ from the registry */
180 const char *subkey = "Software\\Perl";
184 retval = RegOpenKeyEx(hkey, subkey, 0, KEY_READ, &handle);
185 if (retval == ERROR_SUCCESS) {
187 retval = RegQueryValueEx(handle, valuename, 0, &type, NULL, &datalen);
188 if (retval == ERROR_SUCCESS
189 && (type == REG_SZ || type == REG_EXPAND_SZ))
193 *svp = sv_2mortal(newSVpvn("",0));
194 SvGROW(*svp, datalen);
195 retval = RegQueryValueEx(handle, valuename, 0, NULL,
196 (PBYTE)SvPVX(*svp), &datalen);
197 if (retval == ERROR_SUCCESS) {
199 SvCUR_set(*svp,datalen-1);
207 /* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
209 get_regstr(const char *valuename, SV **svp)
211 char *str = get_regstr_from(HKEY_CURRENT_USER, valuename, svp);
213 str = get_regstr_from(HKEY_LOCAL_MACHINE, valuename, svp);
217 /* *prev_pathp (if non-NULL) is expected to be POK (valid allocated SvPVX(sv)) */
219 get_emd_part(SV **prev_pathp, char *trailing_path, ...)
223 char mod_name[MAX_PATH+1];
229 va_start(ap, trailing_path);
230 strip = va_arg(ap, char *);
232 sprintf(base, "%d.%d", (int)PERL_REVISION, (int)PERL_VERSION);
233 baselen = strlen(base);
235 if (!*w32_module_name) {
236 set_w32_module_name();
238 strcpy(mod_name, w32_module_name);
239 ptr = strrchr(mod_name, '/');
240 while (ptr && strip) {
241 /* look for directories to skip back */
244 ptr = strrchr(mod_name, '/');
245 /* avoid stripping component if there is no slash,
246 * or it doesn't match ... */
247 if (!ptr || stricmp(ptr+1, strip) != 0) {
248 /* ... but not if component matches m|5\.$patchlevel.*| */
249 if (!ptr || !(*strip == '5' && *(ptr+1) == '5'
250 && strncmp(strip, base, baselen) == 0
251 && strncmp(ptr+1, base, baselen) == 0))
257 strip = va_arg(ap, char *);
265 strcpy(++ptr, trailing_path);
267 /* only add directory if it exists */
268 if (GetFileAttributes(mod_name) != (DWORD) -1) {
269 /* directory exists */
272 *prev_pathp = sv_2mortal(newSVpvn("",0));
273 else if (SvPVX(*prev_pathp))
274 sv_catpvn(*prev_pathp, ";", 1);
275 sv_catpv(*prev_pathp, mod_name);
276 return SvPVX(*prev_pathp);
283 win32_get_privlib(const char *pl)
286 char *stdlib = "lib";
287 char buffer[MAX_PATH+1];
290 /* $stdlib = $HKCU{"lib-$]"} || $HKLM{"lib-$]"} || $HKCU{"lib"} || $HKLM{"lib"} || ""; */
291 sprintf(buffer, "%s-%s", stdlib, pl);
292 if (!get_regstr(buffer, &sv))
293 (void)get_regstr(stdlib, &sv);
295 /* $stdlib .= ";$EMD/../../lib" */
296 return get_emd_part(&sv, stdlib, ARCHNAME, "bin", Nullch);
300 win32_get_xlib(const char *pl, const char *xlib, const char *libname)
304 char pathstr[MAX_PATH+1];
308 /* $HKCU{"$xlib-$]"} || $HKLM{"$xlib-$]"} . ---; */
309 sprintf(regstr, "%s-%s", xlib, pl);
310 (void)get_regstr(regstr, &sv1);
313 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/$]/lib"; */
314 sprintf(pathstr, "%s/%s/lib", libname, pl);
315 (void)get_emd_part(&sv1, pathstr, ARCHNAME, "bin", pl, Nullch);
317 /* $HKCU{$xlib} || $HKLM{$xlib} . ---; */
318 (void)get_regstr(xlib, &sv2);
321 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/lib"; */
322 sprintf(pathstr, "%s/lib", libname);
323 (void)get_emd_part(&sv2, pathstr, ARCHNAME, "bin", pl, Nullch);
332 sv_catpvn(sv1, ";", 1);
339 win32_get_sitelib(const char *pl)
341 return win32_get_xlib(pl, "sitelib", "site");
344 #ifndef PERL_VENDORLIB_NAME
345 # define PERL_VENDORLIB_NAME "vendor"
349 win32_get_vendorlib(const char *pl)
351 return win32_get_xlib(pl, "vendorlib", PERL_VENDORLIB_NAME);
355 has_shell_metachars(const char *ptr)
361 * Scan string looking for redirection (< or >) or pipe
362 * characters (|) that are not in a quoted string.
363 * Shell variable interpolation (%VAR%) can also happen inside strings.
395 #if !defined(PERL_IMPLICIT_SYS)
396 /* since the current process environment is being updated in util.c
397 * the library functions will get the correct environment
400 Perl_my_popen(pTHX_ const char *cmd, const char *mode)
403 #define fixcmd(x) { \
404 char *pspace = strchr((x),' '); \
407 while (p < pspace) { \
418 PERL_FLUSHALL_FOR_CHILD;
419 return win32_popen(cmd, mode);
423 Perl_my_pclose(pTHX_ PerlIO *fp)
425 return win32_pclose(fp);
429 DllExport unsigned long
432 return (unsigned long)g_osver.dwPlatformId;
442 return -((int)w32_pseudo_id);
445 /* Windows 9x appears to always reports a pid for threads and processes
446 * that has the high bit set. So we treat the lower 31 bits as the
447 * "real" PID for Perl's purposes. */
448 if (IsWin95() && pid < 0)
453 /* Tokenize a string. Words are null-separated, and the list
454 * ends with a doubled null. Any character (except null and
455 * including backslash) may be escaped by preceding it with a
456 * backslash (the backslash will be stripped).
457 * Returns number of words in result buffer.
460 tokenize(const char *str, char **dest, char ***destv)
462 char *retstart = Nullch;
463 char **retvstart = 0;
467 int slen = strlen(str);
469 register char **retv;
470 Newx(ret, slen+2, char);
471 Newx(retv, (slen+3)/2, char*);
479 if (*ret == '\\' && *str)
481 else if (*ret == ' ') {
497 retvstart[items] = Nullch;
510 if (!w32_perlshell_tokens) {
511 /* we don't use COMSPEC here for two reasons:
512 * 1. the same reason perl on UNIX doesn't use SHELL--rampant and
513 * uncontrolled unportability of the ensuing scripts.
514 * 2. PERL5SHELL could be set to a shell that may not be fit for
515 * interactive use (which is what most programs look in COMSPEC
518 const char* defaultshell = (IsWinNT()
519 ? "cmd.exe /x/d/c" : "command.com /c");
520 const char *usershell = PerlEnv_getenv("PERL5SHELL");
521 w32_perlshell_items = tokenize(usershell ? usershell : defaultshell,
522 &w32_perlshell_tokens,
528 Perl_do_aspawn(pTHX_ SV *really, SV **mark, SV **sp)
540 Newx(argv, (sp - mark) + w32_perlshell_items + 2, char*);
542 if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
547 while (++mark <= sp) {
548 if (*mark && (str = SvPV_nolen(*mark)))
555 status = win32_spawnvp(flag,
556 (const char*)(really ? SvPV_nolen(really) : argv[0]),
557 (const char* const*)argv);
559 if (status < 0 && (errno == ENOEXEC || errno == ENOENT)) {
560 /* possible shell-builtin, invoke with shell */
562 sh_items = w32_perlshell_items;
564 argv[index+sh_items] = argv[index];
565 while (--sh_items >= 0)
566 argv[sh_items] = w32_perlshell_vec[sh_items];
568 status = win32_spawnvp(flag,
569 (const char*)(really ? SvPV_nolen(really) : argv[0]),
570 (const char* const*)argv);
573 if (flag == P_NOWAIT) {
575 PL_statusvalue = -1; /* >16bits hint for pp_system() */
579 if (ckWARN(WARN_EXEC))
580 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't spawn \"%s\": %s", argv[0], strerror(errno));
585 PL_statusvalue = status;
591 /* returns pointer to the next unquoted space or the end of the string */
593 find_next_space(const char *s)
595 bool in_quotes = FALSE;
597 /* ignore doubled backslashes, or backslash+quote */
598 if (*s == '\\' && (s[1] == '\\' || s[1] == '"')) {
601 /* keep track of when we're within quotes */
602 else if (*s == '"') {
604 in_quotes = !in_quotes;
606 /* break it up only at spaces that aren't in quotes */
607 else if (!in_quotes && isSPACE(*s))
616 do_spawn2(pTHX_ const char *cmd, int exectype)
622 BOOL needToTry = TRUE;
625 /* Save an extra exec if possible. See if there are shell
626 * metacharacters in it */
627 if (!has_shell_metachars(cmd)) {
628 Newx(argv, strlen(cmd) / 2 + 2, char*);
629 Newx(cmd2, strlen(cmd) + 1, char);
632 for (s = cmd2; *s;) {
633 while (*s && isSPACE(*s))
637 s = find_next_space(s);
645 status = win32_spawnvp(P_WAIT, argv[0],
646 (const char* const*)argv);
648 case EXECF_SPAWN_NOWAIT:
649 status = win32_spawnvp(P_NOWAIT, argv[0],
650 (const char* const*)argv);
653 status = win32_execvp(argv[0], (const char* const*)argv);
656 if (status != -1 || errno == 0)
666 Newx(argv, w32_perlshell_items + 2, char*);
667 while (++i < w32_perlshell_items)
668 argv[i] = w32_perlshell_vec[i];
669 argv[i++] = (char *)cmd;
673 status = win32_spawnvp(P_WAIT, argv[0],
674 (const char* const*)argv);
676 case EXECF_SPAWN_NOWAIT:
677 status = win32_spawnvp(P_NOWAIT, argv[0],
678 (const char* const*)argv);
681 status = win32_execvp(argv[0], (const char* const*)argv);
687 if (exectype == EXECF_SPAWN_NOWAIT) {
689 PL_statusvalue = -1; /* >16bits hint for pp_system() */
693 if (ckWARN(WARN_EXEC))
694 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s \"%s\": %s",
695 (exectype == EXECF_EXEC ? "exec" : "spawn"),
696 cmd, strerror(errno));
701 PL_statusvalue = status;
707 Perl_do_spawn(pTHX_ char *cmd)
709 return do_spawn2(aTHX_ cmd, EXECF_SPAWN);
713 Perl_do_spawn_nowait(pTHX_ char *cmd)
715 return do_spawn2(aTHX_ cmd, EXECF_SPAWN_NOWAIT);
719 Perl_do_exec(pTHX_ const char *cmd)
721 do_spawn2(aTHX_ cmd, EXECF_EXEC);
725 /* The idea here is to read all the directory names into a string table
726 * (separated by nulls) and when one of the other dir functions is called
727 * return the pointer to the current file name.
730 win32_opendir(const char *filename)
736 char scanname[MAX_PATH+3];
738 WIN32_FIND_DATAA aFindData;
740 len = strlen(filename);
744 /* check to see if filename is a directory */
745 if (win32_stat(filename, &sbuf) < 0 || !S_ISDIR(sbuf.st_mode))
748 /* Get us a DIR structure */
751 /* Create the search pattern */
752 strcpy(scanname, filename);
754 /* bare drive name means look in cwd for drive */
755 if (len == 2 && isALPHA(scanname[0]) && scanname[1] == ':') {
756 scanname[len++] = '.';
757 scanname[len++] = '/';
759 else if (scanname[len-1] != '/' && scanname[len-1] != '\\') {
760 scanname[len++] = '/';
762 scanname[len++] = '*';
763 scanname[len] = '\0';
765 /* do the FindFirstFile call */
766 dirp->handle = FindFirstFileA(PerlDir_mapA(scanname), &aFindData);
767 if (dirp->handle == INVALID_HANDLE_VALUE) {
768 DWORD err = GetLastError();
769 /* FindFirstFile() fails on empty drives! */
771 case ERROR_FILE_NOT_FOUND:
773 case ERROR_NO_MORE_FILES:
774 case ERROR_PATH_NOT_FOUND:
777 case ERROR_NOT_ENOUGH_MEMORY:
788 /* now allocate the first part of the string table for
789 * the filenames that we find.
791 idx = strlen(aFindData.cFileName)+1;
796 Newx(dirp->start, dirp->size, char);
797 strcpy(dirp->start, aFindData.cFileName);
799 dirp->end = dirp->curr = dirp->start;
805 /* Readdir just returns the current string pointer and bumps the
806 * string pointer to the nDllExport entry.
808 DllExport struct direct *
809 win32_readdir(DIR *dirp)
814 /* first set up the structure to return */
815 len = strlen(dirp->curr);
816 strcpy(dirp->dirstr.d_name, dirp->curr);
817 dirp->dirstr.d_namlen = len;
820 dirp->dirstr.d_ino = dirp->curr - dirp->start;
822 /* Now set up for the next call to readdir */
823 dirp->curr += len + 1;
824 if (dirp->curr >= dirp->end) {
827 WIN32_FIND_DATAA aFindData;
829 /* finding the next file that matches the wildcard
830 * (which should be all of them in this directory!).
832 res = FindNextFileA(dirp->handle, &aFindData);
834 long endpos = dirp->end - dirp->start;
835 long newsize = endpos + strlen(aFindData.cFileName) + 1;
836 /* bump the string table size by enough for the
837 * new name and its null terminator */
838 while (newsize > dirp->size) {
839 long curpos = dirp->curr - dirp->start;
841 Renew(dirp->start, dirp->size, char);
842 dirp->curr = dirp->start + curpos;
844 strcpy(dirp->start + endpos, aFindData.cFileName);
845 dirp->end = dirp->start + newsize;
851 return &(dirp->dirstr);
857 /* Telldir returns the current string pointer position */
859 win32_telldir(DIR *dirp)
861 return (dirp->curr - dirp->start);
865 /* Seekdir moves the string pointer to a previously saved position
866 * (returned by telldir).
869 win32_seekdir(DIR *dirp, long loc)
871 dirp->curr = dirp->start + loc;
874 /* Rewinddir resets the string pointer to the start */
876 win32_rewinddir(DIR *dirp)
878 dirp->curr = dirp->start;
881 /* free the memory allocated by opendir */
883 win32_closedir(DIR *dirp)
886 if (dirp->handle != INVALID_HANDLE_VALUE)
887 FindClose(dirp->handle);
888 Safefree(dirp->start);
901 * Just pretend that everyone is a superuser. NT will let us know if
902 * we don\'t really have permission to do something.
905 #define ROOT_UID ((uid_t)0)
906 #define ROOT_GID ((gid_t)0)
935 return (auid == ROOT_UID ? 0 : -1);
941 return (agid == ROOT_GID ? 0 : -1);
948 char *buf = w32_getlogin_buffer;
949 DWORD size = sizeof(w32_getlogin_buffer);
950 if (GetUserName(buf,&size))
956 chown(const char *path, uid_t owner, gid_t group)
963 * XXX this needs strengthening (for PerlIO)
966 int mkstemp(const char *path)
969 char buf[MAX_PATH+1];
973 if (i++ > 10) { /* give up */
977 if (!GetTempFileNameA((LPCSTR)path, "plr", 1, buf)) {
981 fd = PerlLIO_open3(buf, O_CREAT|O_RDWR|O_EXCL, 0600);
991 long child = w32_num_children;
992 while (--child >= 0) {
993 if ((int)w32_child_pids[child] == pid)
1000 remove_dead_process(long child)
1004 CloseHandle(w32_child_handles[child]);
1005 Move(&w32_child_handles[child+1], &w32_child_handles[child],
1006 (w32_num_children-child-1), HANDLE);
1007 Move(&w32_child_pids[child+1], &w32_child_pids[child],
1008 (w32_num_children-child-1), DWORD);
1015 find_pseudo_pid(int pid)
1018 long child = w32_num_pseudo_children;
1019 while (--child >= 0) {
1020 if ((int)w32_pseudo_child_pids[child] == pid)
1027 remove_dead_pseudo_process(long child)
1031 CloseHandle(w32_pseudo_child_handles[child]);
1032 Move(&w32_pseudo_child_handles[child+1], &w32_pseudo_child_handles[child],
1033 (w32_num_pseudo_children-child-1), HANDLE);
1034 Move(&w32_pseudo_child_pids[child+1], &w32_pseudo_child_pids[child],
1035 (w32_num_pseudo_children-child-1), DWORD);
1036 Move(&w32_pseudo_child_message_hwnds[child+1], &w32_pseudo_child_message_hwnds[child],
1037 (w32_num_pseudo_children-child-1), HWND);
1038 w32_num_pseudo_children--;
1044 win32_kill(int pid, int sig)
1052 /* it is a pseudo-forked child */
1053 child = find_pseudo_pid(-pid);
1055 HWND hwnd = w32_pseudo_child_message_hwnds[child];
1056 hProcess = w32_pseudo_child_handles[child];
1059 /* "Does process exist?" use of kill */
1063 /* kill -9 style un-graceful exit */
1064 if (TerminateThread(hProcess, sig)) {
1065 remove_dead_pseudo_process(child);
1072 /* pseudo-process has not yet properly initialized if hwnd isn't set */
1073 while (hwnd == INVALID_HANDLE_VALUE && count < 5) {
1074 /* Yield and wait for the other thread to send us its message_hwnd */
1076 win32_async_check(aTHX);
1079 if (hwnd != INVALID_HANDLE_VALUE) {
1080 /* We fake signals to pseudo-processes using Win32
1081 * message queue. In Win9X the pids are negative already. */
1082 if ((hwnd != NULL && PostMessage(hwnd, WM_USER_KILL, sig, 0)) ||
1083 PostThreadMessage(IsWin95() ? pid : -pid, WM_USER_KILL, sig, 0))
1085 /* It might be us ... */
1094 else if (IsWin95()) {
1102 child = find_pid(pid);
1104 hProcess = w32_child_handles[child];
1107 /* "Does process exist?" use of kill */
1110 if (GenerateConsoleCtrlEvent(CTRL_C_EVENT,pid))
1115 if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,pid))
1118 default: /* For now be backwards compatible with perl5.6 */
1120 if (TerminateProcess(hProcess, sig)) {
1121 remove_dead_process(child);
1130 hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE,
1131 (IsWin95() ? -pid : pid));
1135 /* "Does process exist?" use of kill */
1139 if (GenerateConsoleCtrlEvent(CTRL_C_EVENT,pid))
1144 if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,pid))
1147 default: /* For now be backwards compatible with perl5.6 */
1149 if (TerminateProcess(hProcess, sig))
1154 CloseHandle(hProcess);
1164 win32_stat(const char *path, Stat_t *sbuf)
1167 char buffer[MAX_PATH+1];
1168 int l = strlen(path);
1172 BOOL expect_dir = FALSE;
1175 switch(path[l - 1]) {
1176 /* FindFirstFile() and stat() are buggy with a trailing
1177 * slashes, except for the root directory of a drive */
1180 if (l > sizeof(buffer)) {
1181 errno = ENAMETOOLONG;
1185 strncpy(buffer, path, l);
1186 /* remove additional trailing slashes */
1187 while (l > 1 && (buffer[l-1] == '/' || buffer[l-1] == '\\'))
1189 /* add back slash if we otherwise end up with just a drive letter */
1190 if (l == 2 && isALPHA(buffer[0]) && buffer[1] == ':')
1197 /* FindFirstFile() is buggy with "x:", so add a dot :-( */
1199 if (l == 2 && isALPHA(path[0])) {
1200 buffer[0] = path[0];
1211 /* We *must* open & close the file once; otherwise file attribute changes */
1212 /* might not yet have propagated to "other" hard links of the same file. */
1213 /* This also gives us an opportunity to determine the number of links. */
1214 path = PerlDir_mapA(path);
1216 handle = CreateFileA(path, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
1217 if (handle != INVALID_HANDLE_VALUE) {
1218 BY_HANDLE_FILE_INFORMATION bhi;
1219 if (GetFileInformationByHandle(handle, &bhi))
1220 nlink = bhi.nNumberOfLinks;
1221 CloseHandle(handle);
1224 /* path will be mapped correctly above */
1225 #if defined(WIN64) || defined(USE_LARGE_FILES)
1226 res = _stati64(path, sbuf);
1228 res = stat(path, sbuf);
1230 sbuf->st_nlink = nlink;
1233 /* CRT is buggy on sharenames, so make sure it really isn't.
1234 * XXX using GetFileAttributesEx() will enable us to set
1235 * sbuf->st_*time (but note that's not available on the
1236 * Windows of 1995) */
1237 DWORD r = GetFileAttributesA(path);
1238 if (r != 0xffffffff && (r & FILE_ATTRIBUTE_DIRECTORY)) {
1239 /* sbuf may still contain old garbage since stat() failed */
1240 Zero(sbuf, 1, Stat_t);
1241 sbuf->st_mode = S_IFDIR | S_IREAD;
1243 if (!(r & FILE_ATTRIBUTE_READONLY))
1244 sbuf->st_mode |= S_IWRITE | S_IEXEC;
1249 if (l == 3 && isALPHA(path[0]) && path[1] == ':'
1250 && (path[2] == '\\' || path[2] == '/'))
1252 /* The drive can be inaccessible, some _stat()s are buggy */
1253 if (!GetVolumeInformationA(path,NULL,0,NULL,NULL,NULL,NULL,0)) {
1258 if (expect_dir && !S_ISDIR(sbuf->st_mode)) {
1263 if (S_ISDIR(sbuf->st_mode))
1264 sbuf->st_mode |= S_IWRITE | S_IEXEC;
1265 else if (S_ISREG(sbuf->st_mode)) {
1267 if (l >= 4 && path[l-4] == '.') {
1268 const char *e = path + l - 3;
1269 if (strnicmp(e,"exe",3)
1270 && strnicmp(e,"bat",3)
1271 && strnicmp(e,"com",3)
1272 && (IsWin95() || strnicmp(e,"cmd",3)))
1273 sbuf->st_mode &= ~S_IEXEC;
1275 sbuf->st_mode |= S_IEXEC;
1278 sbuf->st_mode &= ~S_IEXEC;
1279 /* Propagate permissions to _group_ and _others_ */
1280 perms = sbuf->st_mode & (S_IREAD|S_IWRITE|S_IEXEC);
1281 sbuf->st_mode |= (perms>>3) | (perms>>6);
1288 #define isSLASH(c) ((c) == '/' || (c) == '\\')
1289 #define SKIP_SLASHES(s) \
1291 while (*(s) && isSLASH(*(s))) \
1294 #define COPY_NONSLASHES(d,s) \
1296 while (*(s) && !isSLASH(*(s))) \
1300 /* Find the longname of a given path. path is destructively modified.
1301 * It should have space for at least MAX_PATH characters. */
1303 win32_longpath(char *path)
1305 WIN32_FIND_DATA fdata;
1307 char tmpbuf[MAX_PATH+1];
1308 char *tmpstart = tmpbuf;
1315 if (isALPHA(path[0]) && path[1] == ':') {
1317 *tmpstart++ = path[0];
1321 else if (isSLASH(path[0]) && isSLASH(path[1])) {
1323 *tmpstart++ = path[0];
1324 *tmpstart++ = path[1];
1325 SKIP_SLASHES(start);
1326 COPY_NONSLASHES(tmpstart,start); /* copy machine name */
1328 *tmpstart++ = *start++;
1329 SKIP_SLASHES(start);
1330 COPY_NONSLASHES(tmpstart,start); /* copy share name */
1335 /* copy initial slash, if any */
1336 if (isSLASH(*start)) {
1337 *tmpstart++ = *start++;
1339 SKIP_SLASHES(start);
1342 /* FindFirstFile() expands "." and "..", so we need to pass
1343 * those through unmolested */
1345 && (!start[1] || isSLASH(start[1])
1346 || (start[1] == '.' && (!start[2] || isSLASH(start[2])))))
1348 COPY_NONSLASHES(tmpstart,start); /* copy "." or ".." */
1353 /* if this is the end, bust outta here */
1357 /* now we're at a non-slash; walk up to next slash */
1358 while (*start && !isSLASH(*start))
1361 /* stop and find full name of component */
1364 fhand = FindFirstFile(path,&fdata);
1366 if (fhand != INVALID_HANDLE_VALUE) {
1367 STRLEN len = strlen(fdata.cFileName);
1368 if ((STRLEN)(tmpbuf + sizeof(tmpbuf) - tmpstart) > len) {
1369 strcpy(tmpstart, fdata.cFileName);
1380 /* failed a step, just return without side effects */
1381 /*PerlIO_printf(Perl_debug_log, "Failed to find %s\n", path);*/
1386 strcpy(path,tmpbuf);
1391 win32_getenv(const char *name)
1395 SV *curitem = Nullsv;
1397 needlen = GetEnvironmentVariableA(name,NULL,0);
1399 curitem = sv_2mortal(newSVpvn("", 0));
1401 SvGROW(curitem, needlen+1);
1402 needlen = GetEnvironmentVariableA(name,SvPVX(curitem),
1404 } while (needlen >= SvLEN(curitem));
1405 SvCUR_set(curitem, needlen);
1408 /* allow any environment variables that begin with 'PERL'
1409 to be stored in the registry */
1410 if (strncmp(name, "PERL", 4) == 0)
1411 (void)get_regstr(name, &curitem);
1413 if (curitem && SvCUR(curitem))
1414 return SvPVX(curitem);
1420 win32_putenv(const char *name)
1428 Newx(curitem,strlen(name)+1,char);
1429 strcpy(curitem, name);
1430 val = strchr(curitem, '=');
1432 /* The sane way to deal with the environment.
1433 * Has these advantages over putenv() & co.:
1434 * * enables us to store a truly empty value in the
1435 * environment (like in UNIX).
1436 * * we don't have to deal with RTL globals, bugs and leaks.
1438 * Why you may want to enable USE_WIN32_RTL_ENV:
1439 * * environ[] and RTL functions will not reflect changes,
1440 * which might be an issue if extensions want to access
1441 * the env. via RTL. This cuts both ways, since RTL will
1442 * not see changes made by extensions that call the Win32
1443 * functions directly, either.
1447 if (SetEnvironmentVariableA(curitem, *val ? val : NULL))
1456 filetime_to_clock(PFILETIME ft)
1458 __int64 qw = ft->dwHighDateTime;
1460 qw |= ft->dwLowDateTime;
1461 qw /= 10000; /* File time ticks at 0.1uS, clock at 1mS */
1466 win32_times(struct tms *timebuf)
1471 clock_t process_time_so_far = clock();
1472 if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy,
1474 timebuf->tms_utime = filetime_to_clock(&user);
1475 timebuf->tms_stime = filetime_to_clock(&kernel);
1476 timebuf->tms_cutime = 0;
1477 timebuf->tms_cstime = 0;
1479 /* That failed - e.g. Win95 fallback to clock() */
1480 timebuf->tms_utime = process_time_so_far;
1481 timebuf->tms_stime = 0;
1482 timebuf->tms_cutime = 0;
1483 timebuf->tms_cstime = 0;
1485 return process_time_so_far;
1488 /* fix utime() so it works on directories in NT */
1490 filetime_from_time(PFILETIME pFileTime, time_t Time)
1492 struct tm *pTM = localtime(&Time);
1493 SYSTEMTIME SystemTime;
1499 SystemTime.wYear = pTM->tm_year + 1900;
1500 SystemTime.wMonth = pTM->tm_mon + 1;
1501 SystemTime.wDay = pTM->tm_mday;
1502 SystemTime.wHour = pTM->tm_hour;
1503 SystemTime.wMinute = pTM->tm_min;
1504 SystemTime.wSecond = pTM->tm_sec;
1505 SystemTime.wMilliseconds = 0;
1507 return SystemTimeToFileTime(&SystemTime, &LocalTime) &&
1508 LocalFileTimeToFileTime(&LocalTime, pFileTime);
1512 win32_unlink(const char *filename)
1518 filename = PerlDir_mapA(filename);
1519 attrs = GetFileAttributesA(filename);
1520 if (attrs == 0xFFFFFFFF) {
1524 if (attrs & FILE_ATTRIBUTE_READONLY) {
1525 (void)SetFileAttributesA(filename, attrs & ~FILE_ATTRIBUTE_READONLY);
1526 ret = unlink(filename);
1528 (void)SetFileAttributesA(filename, attrs);
1531 ret = unlink(filename);
1536 win32_utime(const char *filename, struct utimbuf *times)
1543 struct utimbuf TimeBuffer;
1546 filename = PerlDir_mapA(filename);
1547 rc = utime(filename, times);
1549 /* EACCES: path specifies directory or readonly file */
1550 if (rc == 0 || errno != EACCES /* || !IsWinNT() */)
1553 if (times == NULL) {
1554 times = &TimeBuffer;
1555 time(×->actime);
1556 times->modtime = times->actime;
1559 /* This will (and should) still fail on readonly files */
1560 handle = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE,
1561 FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
1562 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1563 if (handle == INVALID_HANDLE_VALUE)
1566 if (GetFileTime(handle, &ftCreate, &ftAccess, &ftWrite) &&
1567 filetime_from_time(&ftAccess, times->actime) &&
1568 filetime_from_time(&ftWrite, times->modtime) &&
1569 SetFileTime(handle, &ftCreate, &ftAccess, &ftWrite))
1574 CloseHandle(handle);
1579 unsigned __int64 ft_i64;
1584 #define Const64(x) x##LL
1586 #define Const64(x) x##i64
1588 /* Number of 100 nanosecond units from 1/1/1601 to 1/1/1970 */
1589 #define EPOCH_BIAS Const64(116444736000000000)
1591 /* NOTE: This does not compute the timezone info (doing so can be expensive,
1592 * and appears to be unsupported even by glibc) */
1594 win32_gettimeofday(struct timeval *tp, void *not_used)
1598 /* this returns time in 100-nanosecond units (i.e. tens of usecs) */
1599 GetSystemTimeAsFileTime(&ft.ft_val);
1601 /* seconds since epoch */
1602 tp->tv_sec = (long)((ft.ft_i64 - EPOCH_BIAS) / Const64(10000000));
1604 /* microseconds remaining */
1605 tp->tv_usec = (long)((ft.ft_i64 / Const64(10)) % Const64(1000000));
1611 win32_uname(struct utsname *name)
1613 struct hostent *hep;
1614 STRLEN nodemax = sizeof(name->nodename)-1;
1617 switch (g_osver.dwPlatformId) {
1618 case VER_PLATFORM_WIN32_WINDOWS:
1619 strcpy(name->sysname, "Windows");
1621 case VER_PLATFORM_WIN32_NT:
1622 strcpy(name->sysname, "Windows NT");
1624 case VER_PLATFORM_WIN32s:
1625 strcpy(name->sysname, "Win32s");
1628 strcpy(name->sysname, "Win32 Unknown");
1633 sprintf(name->release, "%d.%d",
1634 g_osver.dwMajorVersion, g_osver.dwMinorVersion);
1637 sprintf(name->version, "Build %d",
1638 g_osver.dwPlatformId == VER_PLATFORM_WIN32_NT
1639 ? g_osver.dwBuildNumber : (g_osver.dwBuildNumber & 0xffff));
1640 if (g_osver.szCSDVersion[0]) {
1641 char *buf = name->version + strlen(name->version);
1642 sprintf(buf, " (%s)", g_osver.szCSDVersion);
1646 hep = win32_gethostbyname("localhost");
1648 STRLEN len = strlen(hep->h_name);
1649 if (len <= nodemax) {
1650 strcpy(name->nodename, hep->h_name);
1653 strncpy(name->nodename, hep->h_name, nodemax);
1654 name->nodename[nodemax] = '\0';
1659 if (!GetComputerName(name->nodename, &sz))
1660 *name->nodename = '\0';
1663 /* machine (architecture) */
1668 GetSystemInfo(&info);
1670 #if (defined(__BORLANDC__)&&(__BORLANDC__<=0x520)) \
1671 || (defined(__MINGW32__) && !defined(_ANONYMOUS_UNION))
1672 procarch = info.u.s.wProcessorArchitecture;
1674 procarch = info.wProcessorArchitecture;
1677 case PROCESSOR_ARCHITECTURE_INTEL:
1678 arch = "x86"; break;
1679 case PROCESSOR_ARCHITECTURE_MIPS:
1680 arch = "mips"; break;
1681 case PROCESSOR_ARCHITECTURE_ALPHA:
1682 arch = "alpha"; break;
1683 case PROCESSOR_ARCHITECTURE_PPC:
1684 arch = "ppc"; break;
1685 #ifdef PROCESSOR_ARCHITECTURE_SHX
1686 case PROCESSOR_ARCHITECTURE_SHX:
1687 arch = "shx"; break;
1689 #ifdef PROCESSOR_ARCHITECTURE_ARM
1690 case PROCESSOR_ARCHITECTURE_ARM:
1691 arch = "arm"; break;
1693 #ifdef PROCESSOR_ARCHITECTURE_IA64
1694 case PROCESSOR_ARCHITECTURE_IA64:
1695 arch = "ia64"; break;
1697 #ifdef PROCESSOR_ARCHITECTURE_ALPHA64
1698 case PROCESSOR_ARCHITECTURE_ALPHA64:
1699 arch = "alpha64"; break;
1701 #ifdef PROCESSOR_ARCHITECTURE_MSIL
1702 case PROCESSOR_ARCHITECTURE_MSIL:
1703 arch = "msil"; break;
1705 #ifdef PROCESSOR_ARCHITECTURE_AMD64
1706 case PROCESSOR_ARCHITECTURE_AMD64:
1707 arch = "amd64"; break;
1709 #ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
1710 case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
1711 arch = "ia32-64"; break;
1713 #ifdef PROCESSOR_ARCHITECTURE_UNKNOWN
1714 case PROCESSOR_ARCHITECTURE_UNKNOWN:
1715 arch = "unknown"; break;
1718 sprintf(name->machine, "unknown(0x%x)", procarch);
1719 arch = name->machine;
1722 if (name->machine != arch)
1723 strcpy(name->machine, arch);
1728 /* Timing related stuff */
1731 do_raise(pTHX_ int sig)
1733 if (sig < SIG_SIZE) {
1734 Sighandler_t handler = w32_sighandler[sig];
1735 if (handler == SIG_IGN) {
1738 else if (handler != SIG_DFL) {
1743 /* Choose correct default behaviour */
1759 /* Tell caller to exit thread/process as approriate */
1764 sig_terminate(pTHX_ int sig)
1766 Perl_warn(aTHX_ "Terminating on signal SIG%s(%d)\n",PL_sig_name[sig], sig);
1767 /* exit() seems to be safe, my_exit() or die() is a problem in ^C
1774 win32_async_check(pTHX)
1777 HWND hwnd = w32_message_hwnd;
1781 if (hwnd == INVALID_HANDLE_VALUE)
1784 /* Passing PeekMessage -1 as HWND (2nd arg) only get PostThreadMessage() messages
1785 * and ignores window messages - should co-exist better with windows apps e.g. Tk
1790 while (PeekMessage(&msg, hwnd, WM_TIMER, WM_TIMER, PM_REMOVE|PM_NOYIELD) ||
1791 PeekMessage(&msg, hwnd, WM_USER_MIN, WM_USER_MAX, PM_REMOVE|PM_NOYIELD))
1793 switch (msg.message) {
1795 case WM_USER_MESSAGE: {
1796 int child = find_pseudo_pid(msg.wParam);
1798 w32_pseudo_child_message_hwnds[child] = (HWND)msg.lParam;
1803 case WM_USER_KILL: {
1804 /* We use WM_USER to fake kill() with other signals */
1805 int sig = msg.wParam;
1806 if (do_raise(aTHX_ sig))
1807 sig_terminate(aTHX_ sig);
1812 /* alarm() is a one-shot but SetTimer() repeats so kill it */
1813 if (w32_timerid && w32_timerid==msg.wParam) {
1814 KillTimer(w32_message_hwnd, w32_timerid);
1817 /* Now fake a call to signal handler */
1818 if (do_raise(aTHX_ 14))
1819 sig_terminate(aTHX_ 14);
1826 /* Above or other stuff may have set a signal flag */
1827 if (PL_sig_pending) {
1833 /* This function will not return until the timeout has elapsed, or until
1834 * one of the handles is ready. */
1836 win32_msgwait(pTHX_ DWORD count, LPHANDLE handles, DWORD timeout, LPDWORD resultp)
1838 /* We may need several goes at this - so compute when we stop */
1840 if (timeout != INFINITE) {
1841 ticks = GetTickCount();
1845 DWORD result = MsgWaitForMultipleObjects(count,handles,FALSE,timeout-ticks, QS_ALLEVENTS);
1848 if (result == WAIT_TIMEOUT) {
1849 /* Ran out of time - explicit return of zero to avoid -ve if we
1850 have scheduling issues
1854 if (timeout != INFINITE) {
1855 ticks = GetTickCount();
1857 if (result == WAIT_OBJECT_0 + count) {
1858 /* Message has arrived - check it */
1859 (void)win32_async_check(aTHX);
1862 /* Not timeout or message - one of handles is ready */
1866 /* compute time left to wait */
1867 ticks = timeout - ticks;
1868 /* If we are past the end say zero */
1869 return (ticks > 0) ? ticks : 0;
1873 win32_internal_wait(int *status, DWORD timeout)
1875 /* XXX this wait emulation only knows about processes
1876 * spawned via win32_spawnvp(P_NOWAIT, ...).
1880 DWORD exitcode, waitcode;
1883 if (w32_num_pseudo_children) {
1884 win32_msgwait(aTHX_ w32_num_pseudo_children, w32_pseudo_child_handles,
1885 timeout, &waitcode);
1886 /* Time out here if there are no other children to wait for. */
1887 if (waitcode == WAIT_TIMEOUT) {
1888 if (!w32_num_children) {
1892 else if (waitcode != WAIT_FAILED) {
1893 if (waitcode >= WAIT_ABANDONED_0
1894 && waitcode < WAIT_ABANDONED_0 + w32_num_pseudo_children)
1895 i = waitcode - WAIT_ABANDONED_0;
1897 i = waitcode - WAIT_OBJECT_0;
1898 if (GetExitCodeThread(w32_pseudo_child_handles[i], &exitcode)) {
1899 *status = (int)((exitcode & 0xff) << 8);
1900 retval = (int)w32_pseudo_child_pids[i];
1901 remove_dead_pseudo_process(i);
1908 if (!w32_num_children) {
1913 /* if a child exists, wait for it to die */
1914 win32_msgwait(aTHX_ w32_num_children, w32_child_handles, timeout, &waitcode);
1915 if (waitcode == WAIT_TIMEOUT) {
1918 if (waitcode != WAIT_FAILED) {
1919 if (waitcode >= WAIT_ABANDONED_0
1920 && waitcode < WAIT_ABANDONED_0 + w32_num_children)
1921 i = waitcode - WAIT_ABANDONED_0;
1923 i = waitcode - WAIT_OBJECT_0;
1924 if (GetExitCodeProcess(w32_child_handles[i], &exitcode) ) {
1925 *status = (int)((exitcode & 0xff) << 8);
1926 retval = (int)w32_child_pids[i];
1927 remove_dead_process(i);
1932 errno = GetLastError();
1937 win32_waitpid(int pid, int *status, int flags)
1940 DWORD timeout = (flags & WNOHANG) ? 0 : INFINITE;
1943 if (pid == -1) /* XXX threadid == 1 ? */
1944 return win32_internal_wait(status, timeout);
1947 child = find_pseudo_pid(-pid);
1949 HANDLE hThread = w32_pseudo_child_handles[child];
1951 win32_msgwait(aTHX_ 1, &hThread, timeout, &waitcode);
1952 if (waitcode == WAIT_TIMEOUT) {
1955 else if (waitcode == WAIT_OBJECT_0) {
1956 if (GetExitCodeThread(hThread, &waitcode)) {
1957 *status = (int)((waitcode & 0xff) << 8);
1958 retval = (int)w32_pseudo_child_pids[child];
1959 remove_dead_pseudo_process(child);
1966 else if (IsWin95()) {
1975 child = find_pid(pid);
1977 hProcess = w32_child_handles[child];
1978 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
1979 if (waitcode == WAIT_TIMEOUT) {
1982 else if (waitcode == WAIT_OBJECT_0) {
1983 if (GetExitCodeProcess(hProcess, &waitcode)) {
1984 *status = (int)((waitcode & 0xff) << 8);
1985 retval = (int)w32_child_pids[child];
1986 remove_dead_process(child);
1995 hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE,
1996 (IsWin95() ? -pid : pid));
1998 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
1999 if (waitcode == WAIT_TIMEOUT) {
2000 CloseHandle(hProcess);
2003 else if (waitcode == WAIT_OBJECT_0) {
2004 if (GetExitCodeProcess(hProcess, &waitcode)) {
2005 *status = (int)((waitcode & 0xff) << 8);
2006 CloseHandle(hProcess);
2010 CloseHandle(hProcess);
2016 return retval >= 0 ? pid : retval;
2020 win32_wait(int *status)
2022 return win32_internal_wait(status, INFINITE);
2025 DllExport unsigned int
2026 win32_sleep(unsigned int t)
2029 /* Win32 times are in ms so *1000 in and /1000 out */
2030 return win32_msgwait(aTHX_ 0, NULL, t*1000, NULL)/1000;
2033 DllExport unsigned int
2034 win32_alarm(unsigned int sec)
2037 * the 'obvious' implentation is SetTimer() with a callback
2038 * which does whatever receiving SIGALRM would do
2039 * we cannot use SIGALRM even via raise() as it is not
2040 * one of the supported codes in <signal.h>
2044 if (w32_message_hwnd == INVALID_HANDLE_VALUE)
2045 w32_message_hwnd = win32_create_message_window();
2048 if (w32_message_hwnd == NULL)
2049 w32_timerid = SetTimer(NULL, w32_timerid, sec*1000, NULL);
2052 SetTimer(w32_message_hwnd, w32_timerid, sec*1000, NULL);
2057 KillTimer(w32_message_hwnd, w32_timerid);
2064 #ifdef HAVE_DES_FCRYPT
2065 extern char * des_fcrypt(const char *txt, const char *salt, char *cbuf);
2069 win32_crypt(const char *txt, const char *salt)
2072 #ifdef HAVE_DES_FCRYPT
2073 return des_fcrypt(txt, salt, w32_crypt_buffer);
2075 Perl_croak(aTHX_ "The crypt() function is unimplemented due to excessive paranoia.");
2080 #ifdef USE_FIXED_OSFHANDLE
2082 #define FOPEN 0x01 /* file handle open */
2083 #define FNOINHERIT 0x10 /* file handle opened O_NOINHERIT */
2084 #define FAPPEND 0x20 /* file handle opened O_APPEND */
2085 #define FDEV 0x40 /* file handle refers to device */
2086 #define FTEXT 0x80 /* file handle is in text mode */
2089 *int my_open_osfhandle(intptr_t osfhandle, int flags) - open C Runtime file handle
2092 * This function allocates a free C Runtime file handle and associates
2093 * it with the Win32 HANDLE specified by the first parameter. This is a
2094 * temperary fix for WIN95's brain damage GetFileType() error on socket
2095 * we just bypass that call for socket
2097 * This works with MSVC++ 4.0+ or GCC/Mingw32
2100 * intptr_t osfhandle - Win32 HANDLE to associate with C Runtime file handle.
2101 * int flags - flags to associate with C Runtime file handle.
2104 * returns index of entry in fh, if successful
2105 * return -1, if no free entry is found
2109 *******************************************************************************/
2112 * we fake up some parts of the CRT that aren't exported by MSVCRT.dll
2113 * this lets sockets work on Win9X with GCC and should fix the problems
2118 /* create an ioinfo entry, kill its handle, and steal the entry */
2123 HANDLE hF = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
2124 int fh = _open_osfhandle((intptr_t)hF, 0);
2128 EnterCriticalSection(&(_pioinfo(fh)->lock));
2133 my_open_osfhandle(intptr_t osfhandle, int flags)
2136 char fileflags; /* _osfile flags */
2138 /* copy relevant flags from second parameter */
2141 if (flags & O_APPEND)
2142 fileflags |= FAPPEND;
2147 if (flags & O_NOINHERIT)
2148 fileflags |= FNOINHERIT;
2150 /* attempt to allocate a C Runtime file handle */
2151 if ((fh = _alloc_osfhnd()) == -1) {
2152 errno = EMFILE; /* too many open files */
2153 _doserrno = 0L; /* not an OS error */
2154 return -1; /* return error to caller */
2157 /* the file is open. now, set the info in _osfhnd array */
2158 _set_osfhnd(fh, osfhandle);
2160 fileflags |= FOPEN; /* mark as open */
2162 _osfile(fh) = fileflags; /* set osfile entry */
2163 LeaveCriticalSection(&_pioinfo(fh)->lock);
2165 return fh; /* return handle */
2168 #endif /* USE_FIXED_OSFHANDLE */
2170 /* simulate flock by locking a range on the file */
2172 #define LK_ERR(f,i) ((f) ? (i = 0) : (errno = GetLastError()))
2173 #define LK_LEN 0xffff0000
2176 win32_flock(int fd, int oper)
2184 Perl_croak_nocontext("flock() unimplemented on this platform");
2187 fh = (HANDLE)_get_osfhandle(fd);
2188 memset(&o, 0, sizeof(o));
2191 case LOCK_SH: /* shared lock */
2192 LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, 0, &o),i);
2194 case LOCK_EX: /* exclusive lock */
2195 LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o),i);
2197 case LOCK_SH|LOCK_NB: /* non-blocking shared lock */
2198 LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o),i);
2200 case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */
2201 LK_ERR(LockFileEx(fh,
2202 LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
2203 0, LK_LEN, 0, &o),i);
2205 case LOCK_UN: /* unlock lock */
2206 LK_ERR(UnlockFileEx(fh, 0, LK_LEN, 0, &o),i);
2208 default: /* unknown */
2219 * redirected io subsystem for all XS modules
2232 return (&(_environ));
2235 /* the rest are the remapped stdio routines */
2255 win32_ferror(FILE *fp)
2257 return (ferror(fp));
2262 win32_feof(FILE *fp)
2268 * Since the errors returned by the socket error function
2269 * WSAGetLastError() are not known by the library routine strerror
2270 * we have to roll our own.
2274 win32_strerror(int e)
2276 #if !defined __BORLANDC__ && !defined __MINGW32__ /* compiler intolerance */
2277 extern int sys_nerr;
2281 if (e < 0 || e > sys_nerr) {
2286 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0,
2287 w32_strerror_buffer,
2288 sizeof(w32_strerror_buffer), NULL) == 0)
2289 strcpy(w32_strerror_buffer, "Unknown Error");
2291 return w32_strerror_buffer;
2297 win32_str_os_error(void *sv, DWORD dwErr)
2301 dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
2302 |FORMAT_MESSAGE_IGNORE_INSERTS
2303 |FORMAT_MESSAGE_FROM_SYSTEM, NULL,
2304 dwErr, 0, (char *)&sMsg, 1, NULL);
2305 /* strip trailing whitespace and period */
2308 --dwLen; /* dwLen doesn't include trailing null */
2309 } while (0 < dwLen && isSPACE(sMsg[dwLen]));
2310 if ('.' != sMsg[dwLen])
2315 sMsg = (char*)LocalAlloc(0, 64/**sizeof(TCHAR)*/);
2317 dwLen = sprintf(sMsg,
2318 "Unknown error #0x%lX (lookup 0x%lX)",
2319 dwErr, GetLastError());
2323 sv_setpvn((SV*)sv, sMsg, dwLen);
2329 win32_fprintf(FILE *fp, const char *format, ...)
2332 va_start(marker, format); /* Initialize variable arguments. */
2334 return (vfprintf(fp, format, marker));
2338 win32_printf(const char *format, ...)
2341 va_start(marker, format); /* Initialize variable arguments. */
2343 return (vprintf(format, marker));
2347 win32_vfprintf(FILE *fp, const char *format, va_list args)
2349 return (vfprintf(fp, format, args));
2353 win32_vprintf(const char *format, va_list args)
2355 return (vprintf(format, args));
2359 win32_fread(void *buf, size_t size, size_t count, FILE *fp)
2361 return fread(buf, size, count, fp);
2365 win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
2367 return fwrite(buf, size, count, fp);
2370 #define MODE_SIZE 10
2373 win32_fopen(const char *filename, const char *mode)
2381 if (stricmp(filename, "/dev/null")==0)
2384 f = fopen(PerlDir_mapA(filename), mode);
2385 /* avoid buffering headaches for child processes */
2386 if (f && *mode == 'a')
2387 win32_fseek(f, 0, SEEK_END);
2391 #ifndef USE_SOCKETS_AS_HANDLES
2393 #define fdopen my_fdopen
2397 win32_fdopen(int handle, const char *mode)
2401 f = fdopen(handle, (char *) mode);
2402 /* avoid buffering headaches for child processes */
2403 if (f && *mode == 'a')
2404 win32_fseek(f, 0, SEEK_END);
2409 win32_freopen(const char *path, const char *mode, FILE *stream)
2412 if (stricmp(path, "/dev/null")==0)
2415 return freopen(PerlDir_mapA(path), mode, stream);
2419 win32_fclose(FILE *pf)
2421 return my_fclose(pf); /* defined in win32sck.c */
2425 win32_fputs(const char *s,FILE *pf)
2427 return fputs(s, pf);
2431 win32_fputc(int c,FILE *pf)
2437 win32_ungetc(int c,FILE *pf)
2439 return ungetc(c,pf);
2443 win32_getc(FILE *pf)
2449 win32_fileno(FILE *pf)
2455 win32_clearerr(FILE *pf)
2462 win32_fflush(FILE *pf)
2468 win32_ftell(FILE *pf)
2470 #if defined(WIN64) || defined(USE_LARGE_FILES)
2471 #if defined(__BORLANDC__) /* buk */
2472 return win32_tell( fileno( pf ) );
2475 if (fgetpos(pf, &pos))
2485 win32_fseek(FILE *pf, Off_t offset,int origin)
2487 #if defined(WIN64) || defined(USE_LARGE_FILES)
2488 #if defined(__BORLANDC__) /* buk */
2498 if (fgetpos(pf, &pos))
2503 fseek(pf, 0, SEEK_END);
2504 pos = _telli64(fileno(pf));
2513 return fsetpos(pf, &offset);
2516 return fseek(pf, (long)offset, origin);
2521 win32_fgetpos(FILE *pf,fpos_t *p)
2523 #if defined(__BORLANDC__) && defined(USE_LARGE_FILES) /* buk */
2524 if( win32_tell(fileno(pf)) == -1L ) {
2530 return fgetpos(pf, p);
2535 win32_fsetpos(FILE *pf,const fpos_t *p)
2537 #if defined(__BORLANDC__) && defined(USE_LARGE_FILES) /* buk */
2538 return win32_lseek(fileno(pf), *p, SEEK_CUR);
2540 return fsetpos(pf, p);
2545 win32_rewind(FILE *pf)
2555 char prefix[MAX_PATH+1];
2556 char filename[MAX_PATH+1];
2557 DWORD len = GetTempPath(MAX_PATH, prefix);
2558 if (len && len < MAX_PATH) {
2559 if (GetTempFileName(prefix, "plx", 0, filename)) {
2560 HANDLE fh = CreateFile(filename,
2561 DELETE | GENERIC_READ | GENERIC_WRITE,
2565 FILE_ATTRIBUTE_NORMAL
2566 | FILE_FLAG_DELETE_ON_CLOSE,
2568 if (fh != INVALID_HANDLE_VALUE) {
2569 int fd = win32_open_osfhandle((intptr_t)fh, 0);
2571 #if defined(__BORLANDC__)
2572 setmode(fd,O_BINARY);
2574 DEBUG_p(PerlIO_printf(Perl_debug_log,
2575 "Created tmpfile=%s\n",filename));
2587 int fd = win32_tmpfd();
2589 return win32_fdopen(fd, "w+b");
2601 win32_fstat(int fd, Stat_t *sbufptr)
2604 /* A file designated by filehandle is not shown as accessible
2605 * for write operations, probably because it is opened for reading.
2608 BY_HANDLE_FILE_INFORMATION bhfi;
2609 #if defined(WIN64) || defined(USE_LARGE_FILES)
2610 /* Borland 5.5.1 has a 64-bit stat, but only a 32-bit fstat */
2612 int rc = fstat(fd,&tmp);
2614 sbufptr->st_dev = tmp.st_dev;
2615 sbufptr->st_ino = tmp.st_ino;
2616 sbufptr->st_mode = tmp.st_mode;
2617 sbufptr->st_nlink = tmp.st_nlink;
2618 sbufptr->st_uid = tmp.st_uid;
2619 sbufptr->st_gid = tmp.st_gid;
2620 sbufptr->st_rdev = tmp.st_rdev;
2621 sbufptr->st_size = tmp.st_size;
2622 sbufptr->st_atime = tmp.st_atime;
2623 sbufptr->st_mtime = tmp.st_mtime;
2624 sbufptr->st_ctime = tmp.st_ctime;
2626 int rc = fstat(fd,sbufptr);
2629 if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &bhfi)) {
2630 #if defined(WIN64) || defined(USE_LARGE_FILES)
2631 sbufptr->st_size = (bhfi.nFileSizeHigh << 32) + bhfi.nFileSizeLow ;
2633 sbufptr->st_mode &= 0xFE00;
2634 if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
2635 sbufptr->st_mode |= (S_IREAD + (S_IREAD >> 3) + (S_IREAD >> 6));
2637 sbufptr->st_mode |= ((S_IREAD|S_IWRITE) + ((S_IREAD|S_IWRITE) >> 3)
2638 + ((S_IREAD|S_IWRITE) >> 6));
2642 return my_fstat(fd,sbufptr);
2647 win32_pipe(int *pfd, unsigned int size, int mode)
2649 return _pipe(pfd, size, mode);
2653 win32_popenlist(const char *mode, IV narg, SV **args)
2656 Perl_croak(aTHX_ "List form of pipe open not implemented");
2661 * a popen() clone that respects PERL5SHELL
2663 * changed to return PerlIO* rather than FILE * by BKS, 11-11-2000
2667 win32_popen(const char *command, const char *mode)
2669 #ifdef USE_RTL_POPEN
2670 return _popen(command, mode);
2682 /* establish which ends read and write */
2683 if (strchr(mode,'w')) {
2684 stdfd = 0; /* stdin */
2687 nhandle = STD_INPUT_HANDLE;
2689 else if (strchr(mode,'r')) {
2690 stdfd = 1; /* stdout */
2693 nhandle = STD_OUTPUT_HANDLE;
2698 /* set the correct mode */
2699 if (strchr(mode,'b'))
2701 else if (strchr(mode,'t'))
2704 ourmode = _fmode & (O_TEXT | O_BINARY);
2706 /* the child doesn't inherit handles */
2707 ourmode |= O_NOINHERIT;
2709 if (win32_pipe(p, 512, ourmode) == -1)
2712 /* save current stdfd */
2713 if ((oldfd = win32_dup(stdfd)) == -1)
2716 /* save the old std handle (this needs to happen before the
2717 * dup2(), since that might call SetStdHandle() too) */
2720 old_h = GetStdHandle(nhandle);
2722 /* make stdfd go to child end of pipe (implicitly closes stdfd) */
2723 /* stdfd will be inherited by the child */
2724 if (win32_dup2(p[child], stdfd) == -1)
2727 /* close the child end in parent */
2728 win32_close(p[child]);
2730 /* set the new std handle (in case dup2() above didn't) */
2731 SetStdHandle(nhandle, (HANDLE)_get_osfhandle(stdfd));
2733 /* start the child */
2736 if ((childpid = do_spawn_nowait((char*)command)) == -1)
2739 /* revert stdfd to whatever it was before */
2740 if (win32_dup2(oldfd, stdfd) == -1)
2743 /* restore the old std handle (this needs to happen after the
2744 * dup2(), since that might call SetStdHandle() too */
2746 SetStdHandle(nhandle, old_h);
2751 /* close saved handle */
2755 sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid);
2758 /* set process id so that it can be returned by perl's open() */
2759 PL_forkprocess = childpid;
2762 /* we have an fd, return a file stream */
2763 return (PerlIO_fdopen(p[parent], (char *)mode));
2766 /* we don't need to check for errors here */
2770 SetStdHandle(nhandle, old_h);
2775 win32_dup2(oldfd, stdfd);
2780 #endif /* USE_RTL_POPEN */
2788 win32_pclose(PerlIO *pf)
2790 #ifdef USE_RTL_POPEN
2794 int childpid, status;
2798 sv = *av_fetch(w32_fdpid, PerlIO_fileno(pf), TRUE);
2801 childpid = SvIVX(sv);
2818 if (win32_waitpid(childpid, &status, 0) == -1)
2823 #endif /* USE_RTL_POPEN */
2829 LPCWSTR lpExistingFileName,
2830 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
2833 WCHAR wFullName[MAX_PATH+1];
2834 LPVOID lpContext = NULL;
2835 WIN32_STREAM_ID StreamId;
2836 DWORD dwSize = (char*)&StreamId.cStreamName - (char*)&StreamId;
2841 BOOL (__stdcall *pfnBackupWrite)(HANDLE, LPBYTE, DWORD, LPDWORD,
2842 BOOL, BOOL, LPVOID*) =
2843 (BOOL (__stdcall *)(HANDLE, LPBYTE, DWORD, LPDWORD,
2844 BOOL, BOOL, LPVOID*))
2845 GetProcAddress(GetModuleHandle("kernel32.dll"), "BackupWrite");
2846 if (pfnBackupWrite == NULL)
2849 dwLen = GetFullPathNameW(lpFileName, MAX_PATH, wFullName, NULL);
2852 dwLen = (dwLen+1)*sizeof(WCHAR);
2854 handle = CreateFileW(lpExistingFileName, FILE_WRITE_ATTRIBUTES,
2855 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2856 NULL, OPEN_EXISTING, 0, NULL);
2857 if (handle == INVALID_HANDLE_VALUE)
2860 StreamId.dwStreamId = BACKUP_LINK;
2861 StreamId.dwStreamAttributes = 0;
2862 StreamId.dwStreamNameSize = 0;
2863 #if defined(__BORLANDC__) \
2864 ||(defined(__MINGW32__) && !defined(_ANONYMOUS_UNION))
2865 StreamId.Size.u.HighPart = 0;
2866 StreamId.Size.u.LowPart = dwLen;
2868 StreamId.Size.HighPart = 0;
2869 StreamId.Size.LowPart = dwLen;
2872 bSuccess = pfnBackupWrite(handle, (LPBYTE)&StreamId, dwSize, &dwWritten,
2873 FALSE, FALSE, &lpContext);
2875 bSuccess = pfnBackupWrite(handle, (LPBYTE)wFullName, dwLen, &dwWritten,
2876 FALSE, FALSE, &lpContext);
2877 pfnBackupWrite(handle, NULL, 0, &dwWritten, TRUE, FALSE, &lpContext);
2880 CloseHandle(handle);
2885 win32_link(const char *oldname, const char *newname)
2888 BOOL (__stdcall *pfnCreateHardLinkW)(LPCWSTR,LPCWSTR,LPSECURITY_ATTRIBUTES);
2889 WCHAR wOldName[MAX_PATH+1];
2890 WCHAR wNewName[MAX_PATH+1];
2893 Perl_croak(aTHX_ PL_no_func, "link");
2895 pfnCreateHardLinkW =
2896 (BOOL (__stdcall *)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES))
2897 GetProcAddress(GetModuleHandle("kernel32.dll"), "CreateHardLinkW");
2898 if (pfnCreateHardLinkW == NULL)
2899 pfnCreateHardLinkW = Nt4CreateHardLinkW;
2901 if (MultiByteToWideChar(CP_ACP, 0, oldname, -1, wOldName, MAX_PATH+1) &&
2902 MultiByteToWideChar(CP_ACP, 0, newname, -1, wNewName, MAX_PATH+1) &&
2903 (wcscpy(wOldName, PerlDir_mapW(wOldName)),
2904 pfnCreateHardLinkW(PerlDir_mapW(wNewName), wOldName, NULL)))
2908 errno = (GetLastError() == ERROR_FILE_NOT_FOUND) ? ENOENT : EINVAL;
2913 win32_rename(const char *oname, const char *newname)
2915 char szOldName[MAX_PATH+1];
2916 char szNewName[MAX_PATH+1];
2920 /* XXX despite what the documentation says about MoveFileEx(),
2921 * it doesn't work under Windows95!
2924 DWORD dwFlags = MOVEFILE_COPY_ALLOWED;
2925 if (stricmp(newname, oname))
2926 dwFlags |= MOVEFILE_REPLACE_EXISTING;
2927 strcpy(szOldName, PerlDir_mapA(oname));
2928 bResult = MoveFileExA(szOldName,PerlDir_mapA(newname), dwFlags);
2930 DWORD err = GetLastError();
2932 case ERROR_BAD_NET_NAME:
2933 case ERROR_BAD_NETPATH:
2934 case ERROR_BAD_PATHNAME:
2935 case ERROR_FILE_NOT_FOUND:
2936 case ERROR_FILENAME_EXCED_RANGE:
2937 case ERROR_INVALID_DRIVE:
2938 case ERROR_NO_MORE_FILES:
2939 case ERROR_PATH_NOT_FOUND:
2952 char szTmpName[MAX_PATH+1];
2953 char dname[MAX_PATH+1];
2954 char *endname = Nullch;
2956 DWORD from_attr, to_attr;
2958 strcpy(szOldName, PerlDir_mapA(oname));
2959 strcpy(szNewName, PerlDir_mapA(newname));
2961 /* if oname doesn't exist, do nothing */
2962 from_attr = GetFileAttributes(szOldName);
2963 if (from_attr == 0xFFFFFFFF) {
2968 /* if newname exists, rename it to a temporary name so that we
2969 * don't delete it in case oname happens to be the same file
2970 * (but perhaps accessed via a different path)
2972 to_attr = GetFileAttributes(szNewName);
2973 if (to_attr != 0xFFFFFFFF) {
2974 /* if newname is a directory, we fail
2975 * XXX could overcome this with yet more convoluted logic */
2976 if (to_attr & FILE_ATTRIBUTE_DIRECTORY) {
2980 tmplen = strlen(szNewName);
2981 strcpy(szTmpName,szNewName);
2982 endname = szTmpName+tmplen;
2983 for (; endname > szTmpName ; --endname) {
2984 if (*endname == '/' || *endname == '\\') {
2989 if (endname > szTmpName)
2990 endname = strcpy(dname,szTmpName);
2994 /* get a temporary filename in same directory
2995 * XXX is this really the best we can do? */
2996 if (!GetTempFileName((LPCTSTR)endname, "plr", 0, szTmpName)) {
3000 DeleteFile(szTmpName);
3002 retval = rename(szNewName, szTmpName);
3009 /* rename oname to newname */
3010 retval = rename(szOldName, szNewName);
3012 /* if we created a temporary file before ... */
3013 if (endname != Nullch) {
3014 /* ...and rename succeeded, delete temporary file/directory */
3016 DeleteFile(szTmpName);
3017 /* else restore it to what it was */
3019 (void)rename(szTmpName, szNewName);
3026 win32_setmode(int fd, int mode)
3028 return setmode(fd, mode);
3032 win32_chsize(int fd, Off_t size)
3034 #if defined(WIN64) || defined(USE_LARGE_FILES)
3036 Off_t cur, end, extend;
3038 cur = win32_tell(fd);
3041 end = win32_lseek(fd, 0, SEEK_END);
3044 extend = size - end;
3048 else if (extend > 0) {
3049 /* must grow the file, padding with nulls */
3051 int oldmode = win32_setmode(fd, O_BINARY);
3053 memset(b, '\0', sizeof(b));
3055 count = extend >= sizeof(b) ? sizeof(b) : (size_t)extend;
3056 count = win32_write(fd, b, count);
3057 if ((int)count < 0) {
3061 } while ((extend -= count) > 0);
3062 win32_setmode(fd, oldmode);
3065 /* shrink the file */
3066 win32_lseek(fd, size, SEEK_SET);
3067 if (!SetEndOfFile((HANDLE)_get_osfhandle(fd))) {
3073 win32_lseek(fd, cur, SEEK_SET);
3076 return chsize(fd, (long)size);
3081 win32_lseek(int fd, Off_t offset, int origin)
3083 #if defined(WIN64) || defined(USE_LARGE_FILES)
3084 #if defined(__BORLANDC__) /* buk */
3086 pos.QuadPart = offset;
3087 pos.LowPart = SetFilePointer(
3088 (HANDLE)_get_osfhandle(fd),
3093 if (pos.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
3097 return pos.QuadPart;
3099 return _lseeki64(fd, offset, origin);
3102 return lseek(fd, (long)offset, origin);
3109 #if defined(WIN64) || defined(USE_LARGE_FILES)
3110 #if defined(__BORLANDC__) /* buk */
3113 pos.LowPart = SetFilePointer(
3114 (HANDLE)_get_osfhandle(fd),
3119 if (pos.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
3123 return pos.QuadPart;
3124 /* return tell(fd); */
3126 return _telli64(fd);
3134 win32_open(const char *path, int flag, ...)
3141 pmode = va_arg(ap, int);
3144 if (stricmp(path, "/dev/null")==0)
3147 return open(PerlDir_mapA(path), flag, pmode);
3150 /* close() that understands socket */
3151 extern int my_close(int); /* in win32sck.c */
3156 return my_close(fd);
3172 win32_dup2(int fd1,int fd2)
3174 return dup2(fd1,fd2);
3177 #ifdef PERL_MSVCRT_READFIX
3179 #define LF 10 /* line feed */
3180 #define CR 13 /* carriage return */
3181 #define CTRLZ 26 /* ctrl-z means eof for text */
3182 #define FOPEN 0x01 /* file handle open */
3183 #define FEOFLAG 0x02 /* end of file has been encountered */
3184 #define FCRLF 0x04 /* CR-LF across read buffer (in text mode) */
3185 #define FPIPE 0x08 /* file handle refers to a pipe */
3186 #define FAPPEND 0x20 /* file handle opened O_APPEND */
3187 #define FDEV 0x40 /* file handle refers to device */
3188 #define FTEXT 0x80 /* file handle is in text mode */
3189 #define MAX_DESCRIPTOR_COUNT (64*32) /* this is the maximun that MSVCRT can handle */
3192 _fixed_read(int fh, void *buf, unsigned cnt)
3194 int bytes_read; /* number of bytes read */
3195 char *buffer; /* buffer to read to */
3196 int os_read; /* bytes read on OS call */
3197 char *p, *q; /* pointers into buffer */
3198 char peekchr; /* peek-ahead character */
3199 ULONG filepos; /* file position after seek */
3200 ULONG dosretval; /* o.s. return value */
3202 /* validate handle */
3203 if (((unsigned)fh >= (unsigned)MAX_DESCRIPTOR_COUNT) ||
3204 !(_osfile(fh) & FOPEN))
3206 /* out of range -- return error */
3208 _doserrno = 0; /* not o.s. error */
3213 * If lockinitflag is FALSE, assume fd is device
3214 * lockinitflag is set to TRUE by open.
3216 if (_pioinfo(fh)->lockinitflag)
3217 EnterCriticalSection(&(_pioinfo(fh)->lock)); /* lock file */
3219 bytes_read = 0; /* nothing read yet */
3220 buffer = (char*)buf;
3222 if (cnt == 0 || (_osfile(fh) & FEOFLAG)) {
3223 /* nothing to read or at EOF, so return 0 read */
3227 if ((_osfile(fh) & (FPIPE|FDEV)) && _pipech(fh) != LF) {
3228 /* a pipe/device and pipe lookahead non-empty: read the lookahead
3230 *buffer++ = _pipech(fh);
3233 _pipech(fh) = LF; /* mark as empty */
3238 if (!ReadFile((HANDLE)_osfhnd(fh), buffer, cnt, (LPDWORD)&os_read, NULL))
3240 /* ReadFile has reported an error. recognize two special cases.
3242 * 1. map ERROR_ACCESS_DENIED to EBADF
3244 * 2. just return 0 if ERROR_BROKEN_PIPE has occurred. it
3245 * means the handle is a read-handle on a pipe for which
3246 * all write-handles have been closed and all data has been
3249 if ((dosretval = GetLastError()) == ERROR_ACCESS_DENIED) {
3250 /* wrong read/write mode should return EBADF, not EACCES */
3252 _doserrno = dosretval;
3256 else if (dosretval == ERROR_BROKEN_PIPE) {
3266 bytes_read += os_read; /* update bytes read */
3268 if (_osfile(fh) & FTEXT) {
3269 /* now must translate CR-LFs to LFs in the buffer */
3271 /* set CRLF flag to indicate LF at beginning of buffer */
3272 /* if ((os_read != 0) && (*(char *)buf == LF)) */
3273 /* _osfile(fh) |= FCRLF; */
3275 /* _osfile(fh) &= ~FCRLF; */
3277 _osfile(fh) &= ~FCRLF;
3279 /* convert chars in the buffer: p is src, q is dest */
3281 while (p < (char *)buf + bytes_read) {
3283 /* if fh is not a device, set ctrl-z flag */
3284 if (!(_osfile(fh) & FDEV))
3285 _osfile(fh) |= FEOFLAG;
3286 break; /* stop translating */
3291 /* *p is CR, so must check next char for LF */
3292 if (p < (char *)buf + bytes_read - 1) {
3295 *q++ = LF; /* convert CR-LF to LF */
3298 *q++ = *p++; /* store char normally */
3301 /* This is the hard part. We found a CR at end of
3302 buffer. We must peek ahead to see if next char
3307 if (!ReadFile((HANDLE)_osfhnd(fh), &peekchr, 1,
3308 (LPDWORD)&os_read, NULL))
3309 dosretval = GetLastError();
3311 if (dosretval != 0 || os_read == 0) {
3312 /* couldn't read ahead, store CR */
3316 /* peekchr now has the extra character -- we now
3317 have several possibilities:
3318 1. disk file and char is not LF; just seek back
3320 2. disk file and char is LF; store LF, don't seek back
3321 3. pipe/device and char is LF; store LF.
3322 4. pipe/device and char isn't LF, store CR and
3323 put char in pipe lookahead buffer. */
3324 if (_osfile(fh) & (FDEV|FPIPE)) {
3325 /* non-seekable device */
3330 _pipech(fh) = peekchr;
3335 if (peekchr == LF) {
3336 /* nothing read yet; must make some
3339 /* turn on this flag for tell routine */
3340 _osfile(fh) |= FCRLF;
3343 HANDLE osHandle; /* o.s. handle value */
3345 if ((osHandle = (HANDLE)_get_osfhandle(fh)) != (HANDLE)-1)
3347 if ((filepos = SetFilePointer(osHandle, -1, NULL, FILE_CURRENT)) == -1)
3348 dosretval = GetLastError();
3359 /* we now change bytes_read to reflect the true number of chars
3361 bytes_read = q - (char *)buf;
3365 if (_pioinfo(fh)->lockinitflag)
3366 LeaveCriticalSection(&(_pioinfo(fh)->lock)); /* unlock file */
3371 #endif /* PERL_MSVCRT_READFIX */
3374 win32_read(int fd, void *buf, unsigned int cnt)
3376 #ifdef PERL_MSVCRT_READFIX
3377 return _fixed_read(fd, buf, cnt);
3379 return read(fd, buf, cnt);
3384 win32_write(int fd, const void *buf, unsigned int cnt)
3386 return write(fd, buf, cnt);
3390 win32_mkdir(const char *dir, int mode)
3393 return mkdir(PerlDir_mapA(dir)); /* just ignore mode */
3397 win32_rmdir(const char *dir)
3400 return rmdir(PerlDir_mapA(dir));
3404 win32_chdir(const char *dir)
3415 win32_access(const char *path, int mode)
3418 return access(PerlDir_mapA(path), mode);
3422 win32_chmod(const char *path, int mode)
3425 return chmod(PerlDir_mapA(path), mode);
3430 create_command_line(char *cname, STRLEN clen, const char * const *args)
3437 bool bat_file = FALSE;
3438 bool cmd_shell = FALSE;
3439 bool dumb_shell = FALSE;
3440 bool extra_quotes = FALSE;
3441 bool quote_next = FALSE;
3444 cname = (char*)args[0];
3446 /* The NT cmd.exe shell has the following peculiarity that needs to be
3447 * worked around. It strips a leading and trailing dquote when any
3448 * of the following is true:
3449 * 1. the /S switch was used
3450 * 2. there are more than two dquotes
3451 * 3. there is a special character from this set: &<>()@^|
3452 * 4. no whitespace characters within the two dquotes
3453 * 5. string between two dquotes isn't an executable file
3454 * To work around this, we always add a leading and trailing dquote
3455 * to the string, if the first argument is either "cmd.exe" or "cmd",
3456 * and there were at least two or more arguments passed to cmd.exe
3457 * (not including switches).
3458 * XXX the above rules (from "cmd /?") don't seem to be applied
3459 * always, making for the convolutions below :-(
3463 clen = strlen(cname);
3466 && (stricmp(&cname[clen-4], ".bat") == 0
3467 || (IsWinNT() && stricmp(&cname[clen-4], ".cmd") == 0)))
3474 char *exe = strrchr(cname, '/');
3475 char *exe2 = strrchr(cname, '\\');
3482 if (stricmp(exe, "cmd.exe") == 0 || stricmp(exe, "cmd") == 0) {
3486 else if (stricmp(exe, "command.com") == 0
3487 || stricmp(exe, "command") == 0)
3494 DEBUG_p(PerlIO_printf(Perl_debug_log, "Args "));
3495 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3496 STRLEN curlen = strlen(arg);
3497 if (!(arg[0] == '"' && arg[curlen-1] == '"'))
3498 len += 2; /* assume quoting needed (worst case) */
3500 DEBUG_p(PerlIO_printf(Perl_debug_log, "[%s]",arg));
3502 DEBUG_p(PerlIO_printf(Perl_debug_log, "\n"));
3505 Newx(cmd, len, char);
3508 if (bat_file && !IsWin95()) {
3510 extra_quotes = TRUE;
3513 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3515 STRLEN curlen = strlen(arg);
3517 /* we want to protect empty arguments and ones with spaces with
3518 * dquotes, but only if they aren't already there */
3523 else if (quote_next) {
3524 /* see if it really is multiple arguments pretending to
3525 * be one and force a set of quotes around it */
3526 if (*find_next_space(arg))
3529 else if (!(arg[0] == '"' && curlen > 1 && arg[curlen-1] == '"')) {
3531 while (i < curlen) {
3532 if (isSPACE(arg[i])) {
3535 else if (arg[i] == '"') {
3559 && *arg == '/' /* see if arg is "/c", "/x/c", "/x/d/c" etc. */
3560 && stricmp(arg+curlen-2, "/c") == 0)
3562 /* is there a next argument? */
3563 if (args[index+1]) {
3564 /* are there two or more next arguments? */
3565 if (args[index+2]) {
3567 extra_quotes = TRUE;
3570 /* single argument, force quoting if it has spaces */
3586 qualified_path(const char *cmd)
3590 char *fullcmd, *curfullcmd;
3596 fullcmd = (char*)cmd;
3598 if (*fullcmd == '/' || *fullcmd == '\\')
3605 pathstr = PerlEnv_getenv("PATH");
3607 /* worst case: PATH is a single directory; we need additional space
3608 * to append "/", ".exe" and trailing "\0" */
3609 Newx(fullcmd, (pathstr ? strlen(pathstr) : 0) + cmdlen + 6, char);
3610 curfullcmd = fullcmd;
3615 /* start by appending the name to the current prefix */
3616 strcpy(curfullcmd, cmd);
3617 curfullcmd += cmdlen;
3619 /* if it doesn't end with '.', or has no extension, try adding
3620 * a trailing .exe first */
3621 if (cmd[cmdlen-1] != '.'
3622 && (cmdlen < 4 || cmd[cmdlen-4] != '.'))
3624 strcpy(curfullcmd, ".exe");
3625 res = GetFileAttributes(fullcmd);
3626 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3631 /* that failed, try the bare name */
3632 res = GetFileAttributes(fullcmd);
3633 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3636 /* quit if no other path exists, or if cmd already has path */
3637 if (!pathstr || !*pathstr || has_slash)
3640 /* skip leading semis */
3641 while (*pathstr == ';')
3644 /* build a new prefix from scratch */
3645 curfullcmd = fullcmd;
3646 while (*pathstr && *pathstr != ';') {
3647 if (*pathstr == '"') { /* foo;"baz;etc";bar */
3648 pathstr++; /* skip initial '"' */
3649 while (*pathstr && *pathstr != '"') {
3650 *curfullcmd++ = *pathstr++;
3653 pathstr++; /* skip trailing '"' */
3656 *curfullcmd++ = *pathstr++;
3660 pathstr++; /* skip trailing semi */
3661 if (curfullcmd > fullcmd /* append a dir separator */
3662 && curfullcmd[-1] != '/' && curfullcmd[-1] != '\\')
3664 *curfullcmd++ = '\\';
3672 /* The following are just place holders.
3673 * Some hosts may provide and environment that the OS is
3674 * not tracking, therefore, these host must provide that
3675 * environment and the current directory to CreateProcess
3679 win32_get_childenv(void)
3685 win32_free_childenv(void* d)
3690 win32_clearenv(void)
3692 char *envv = GetEnvironmentStrings();
3696 char *end = strchr(cur,'=');
3697 if (end && end != cur) {
3699 SetEnvironmentVariable(cur, NULL);
3701 cur = end + strlen(end+1)+2;
3703 else if ((len = strlen(cur)))
3706 FreeEnvironmentStrings(envv);
3710 win32_get_childdir(void)
3714 char szfilename[MAX_PATH+1];
3716 GetCurrentDirectoryA(MAX_PATH+1, szfilename);
3717 Newx(ptr, strlen(szfilename)+1, char);
3718 strcpy(ptr, szfilename);
3723 win32_free_childdir(char* d)
3730 /* XXX this needs to be made more compatible with the spawnvp()
3731 * provided by the various RTLs. In particular, searching for
3732 * *.{com,bat,cmd} files (as done by the RTLs) is unimplemented.
3733 * This doesn't significantly affect perl itself, because we
3734 * always invoke things using PERL5SHELL if a direct attempt to
3735 * spawn the executable fails.
3737 * XXX splitting and rejoining the commandline between do_aspawn()
3738 * and win32_spawnvp() could also be avoided.
3742 win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
3744 #ifdef USE_RTL_SPAWNVP
3745 return spawnvp(mode, cmdname, (char * const *)argv);
3752 STARTUPINFO StartupInfo;
3753 PROCESS_INFORMATION ProcessInformation;
3756 char *fullcmd = Nullch;
3757 char *cname = (char *)cmdname;
3761 clen = strlen(cname);
3762 /* if command name contains dquotes, must remove them */
3763 if (strchr(cname, '"')) {
3765 Newx(cname,clen+1,char);
3778 cmd = create_command_line(cname, clen, argv);
3780 env = PerlEnv_get_childenv();
3781 dir = PerlEnv_get_childdir();
3784 case P_NOWAIT: /* asynch + remember result */
3785 if (w32_num_children >= MAXIMUM_WAIT_OBJECTS) {
3790 /* Create a new process group so we can use GenerateConsoleCtrlEvent()
3793 create |= CREATE_NEW_PROCESS_GROUP;
3796 case P_WAIT: /* synchronous execution */
3798 default: /* invalid mode */
3803 memset(&StartupInfo,0,sizeof(StartupInfo));
3804 StartupInfo.cb = sizeof(StartupInfo);
3805 memset(&tbl,0,sizeof(tbl));
3806 PerlEnv_get_child_IO(&tbl);
3807 StartupInfo.dwFlags = tbl.dwFlags;
3808 StartupInfo.dwX = tbl.dwX;
3809 StartupInfo.dwY = tbl.dwY;
3810 StartupInfo.dwXSize = tbl.dwXSize;
3811 StartupInfo.dwYSize = tbl.dwYSize;
3812 StartupInfo.dwXCountChars = tbl.dwXCountChars;
3813 StartupInfo.dwYCountChars = tbl.dwYCountChars;
3814 StartupInfo.dwFillAttribute = tbl.dwFillAttribute;
3815 StartupInfo.wShowWindow = tbl.wShowWindow;
3816 StartupInfo.hStdInput = tbl.childStdIn;
3817 StartupInfo.hStdOutput = tbl.childStdOut;
3818 StartupInfo.hStdError = tbl.childStdErr;
3819 if (StartupInfo.hStdInput == INVALID_HANDLE_VALUE &&
3820 StartupInfo.hStdOutput == INVALID_HANDLE_VALUE &&
3821 StartupInfo.hStdError == INVALID_HANDLE_VALUE)
3823 create |= CREATE_NEW_CONSOLE;
3826 StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
3828 if (w32_use_showwindow) {
3829 StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
3830 StartupInfo.wShowWindow = w32_showwindow;
3833 DEBUG_p(PerlIO_printf(Perl_debug_log, "Spawning [%s] with [%s]\n",
3836 if (!CreateProcess(cname, /* search PATH to find executable */
3837 cmd, /* executable, and its arguments */
3838 NULL, /* process attributes */
3839 NULL, /* thread attributes */
3840 TRUE, /* inherit handles */
3841 create, /* creation flags */
3842 (LPVOID)env, /* inherit environment */
3843 dir, /* inherit cwd */
3845 &ProcessInformation))
3847 /* initial NULL argument to CreateProcess() does a PATH
3848 * search, but it always first looks in the directory
3849 * where the current process was started, which behavior
3850 * is undesirable for backward compatibility. So we
3851 * jump through our own hoops by picking out the path
3852 * we really want it to use. */
3854 fullcmd = qualified_path(cname);
3856 if (cname != cmdname)
3859 DEBUG_p(PerlIO_printf(Perl_debug_log,
3860 "Retrying [%s] with same args\n",
3870 if (mode == P_NOWAIT) {
3871 /* asynchronous spawn -- store handle, return PID */
3872 ret = (int)ProcessInformation.dwProcessId;
3873 if (IsWin95() && ret < 0)
3876 w32_child_handles[w32_num_children] = ProcessInformation.hProcess;
3877 w32_child_pids[w32_num_children] = (DWORD)ret;
3882 win32_msgwait(aTHX_ 1, &ProcessInformation.hProcess, INFINITE, NULL);
3883 /* FIXME: if msgwait returned due to message perhaps forward the
3884 "signal" to the process
3886 GetExitCodeProcess(ProcessInformation.hProcess, &status);
3888 CloseHandle(ProcessInformation.hProcess);
3891 CloseHandle(ProcessInformation.hThread);
3894 PerlEnv_free_childenv(env);
3895 PerlEnv_free_childdir(dir);
3897 if (cname != cmdname)
3904 win32_execv(const char *cmdname, const char *const *argv)
3908 /* if this is a pseudo-forked child, we just want to spawn
3909 * the new program, and return */
3911 # ifdef __BORLANDC__
3912 return spawnv(P_WAIT, cmdname, (char *const *)argv);
3914 return spawnv(P_WAIT, cmdname, argv);
3918 return execv(cmdname, (char *const *)argv);
3920 return execv(cmdname, argv);
3925 win32_execvp(const char *cmdname, const char *const *argv)
3929 /* if this is a pseudo-forked child, we just want to spawn
3930 * the new program, and return */
3931 if (w32_pseudo_id) {
3932 int status = win32_spawnvp(P_WAIT, cmdname, (const char *const *)argv);
3942 return execvp(cmdname, (char *const *)argv);
3944 return execvp(cmdname, argv);
3949 win32_perror(const char *str)
3955 win32_setbuf(FILE *pf, char *buf)
3961 win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
3963 return setvbuf(pf, buf, type, size);
3967 win32_flushall(void)
3973 win32_fcloseall(void)
3979 win32_fgets(char *s, int n, FILE *pf)
3981 return fgets(s, n, pf);
3991 win32_fgetc(FILE *pf)
3997 win32_putc(int c, FILE *pf)
4003 win32_puts(const char *s)
4015 win32_putchar(int c)
4022 #ifndef USE_PERL_SBRK
4024 static char *committed = NULL; /* XXX threadead */
4025 static char *base = NULL; /* XXX threadead */
4026 static char *reserved = NULL; /* XXX threadead */
4027 static char *brk = NULL; /* XXX threadead */
4028 static DWORD pagesize = 0; /* XXX threadead */
4031 sbrk(ptrdiff_t need)
4036 GetSystemInfo(&info);
4037 /* Pretend page size is larger so we don't perpetually
4038 * call the OS to commit just one page ...
4040 pagesize = info.dwPageSize << 3;
4042 if (brk+need >= reserved)
4044 DWORD size = brk+need-reserved;
4046 char *prev_committed = NULL;
4047 if (committed && reserved && committed < reserved)
4049 /* Commit last of previous chunk cannot span allocations */
4050 addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
4053 /* Remember where we committed from in case we want to decommit later */
4054 prev_committed = committed;
4055 committed = reserved;
4058 /* Reserve some (more) space
4059 * Contiguous blocks give us greater efficiency, so reserve big blocks -
4060 * this is only address space not memory...
4061 * Note this is a little sneaky, 1st call passes NULL as reserved
4062 * so lets system choose where we start, subsequent calls pass
4063 * the old end address so ask for a contiguous block
4066 if (size < 64*1024*1024)
4067 size = 64*1024*1024;
4068 size = ((size + pagesize - 1) / pagesize) * pagesize;
4069 addr = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
4072 reserved = addr+size;
4082 /* The existing block could not be extended far enough, so decommit
4083 * anything that was just committed above and start anew */
4086 if (!VirtualFree(prev_committed,reserved-prev_committed,MEM_DECOMMIT))
4089 reserved = base = committed = brk = NULL;
4100 if (brk > committed)
4102 DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
4104 if (committed+size > reserved)
4105 size = reserved-committed;
4106 addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
4119 win32_malloc(size_t size)
4121 return malloc(size);
4125 win32_calloc(size_t numitems, size_t size)
4127 return calloc(numitems,size);
4131 win32_realloc(void *block, size_t size)
4133 return realloc(block,size);
4137 win32_free(void *block)
4144 win32_open_osfhandle(intptr_t handle, int flags)
4146 #ifdef USE_FIXED_OSFHANDLE
4148 return my_open_osfhandle(handle, flags);
4150 return _open_osfhandle(handle, flags);
4154 win32_get_osfhandle(int fd)
4156 return (intptr_t)_get_osfhandle(fd);
4160 win32_fdupopen(FILE *pf)
4165 int fileno = win32_dup(win32_fileno(pf));
4167 /* open the file in the same mode */
4169 if((pf)->flags & _F_READ) {
4173 else if((pf)->flags & _F_WRIT) {
4177 else if((pf)->flags & _F_RDWR) {
4183 if((pf)->_flag & _IOREAD) {
4187 else if((pf)->_flag & _IOWRT) {
4191 else if((pf)->_flag & _IORW) {
4198 /* it appears that the binmode is attached to the
4199 * file descriptor so binmode files will be handled
4202 pfdup = win32_fdopen(fileno, mode);
4204 /* move the file pointer to the same position */
4205 if (!fgetpos(pf, &pos)) {
4206 fsetpos(pfdup, &pos);
4212 win32_dynaload(const char* filename)
4215 char buf[MAX_PATH+1];
4218 /* LoadLibrary() doesn't recognize forward slashes correctly,
4219 * so turn 'em back. */
4220 first = strchr(filename, '/');
4222 STRLEN len = strlen(filename);
4223 if (len <= MAX_PATH) {
4224 strcpy(buf, filename);
4225 filename = &buf[first - filename];
4227 if (*filename == '/')
4228 *(char*)filename = '\\';
4234 return LoadLibraryExA(PerlDir_mapA(filename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
4242 XS(w32_SetChildShowWindow)
4245 BOOL use_showwindow = w32_use_showwindow;
4246 /* use "unsigned short" because Perl has redefined "WORD" */
4247 unsigned short showwindow = w32_showwindow;
4250 Perl_croak(aTHX_ "usage: Win32::SetChildShowWindow($showwindow)");
4252 if (items == 0 || !SvOK(ST(0)))
4253 w32_use_showwindow = FALSE;
4255 w32_use_showwindow = TRUE;
4256 w32_showwindow = (unsigned short)SvIV(ST(0));
4261 ST(0) = sv_2mortal(newSViv(showwindow));
4263 ST(0) = &PL_sv_undef;
4271 /* Make the host for current directory */
4272 char* ptr = PerlEnv_get_childdir();
4275 * then it worked, set PV valid,
4276 * else return 'undef'
4279 SV *sv = sv_newmortal();
4281 PerlEnv_free_childdir(ptr);
4283 #ifndef INCOMPLETE_TAINTS
4300 Perl_croak(aTHX_ "usage: Win32::SetCurrentDirectory($cwd)");
4301 if (!PerlDir_chdir(SvPV_nolen(ST(0))))
4308 XS(w32_GetNextAvailDrive)
4312 char root[] = "_:\\";
4317 if (GetDriveType(root) == 1) {
4326 XS(w32_GetLastError)
4330 XSRETURN_IV(GetLastError());
4334 XS(w32_SetLastError)
4338 Perl_croak(aTHX_ "usage: Win32::SetLastError($error)");
4339 SetLastError(SvIV(ST(0)));
4347 char *name = w32_getlogin_buffer;
4348 DWORD size = sizeof(w32_getlogin_buffer);
4350 if (GetUserName(name,&size)) {
4351 /* size includes NULL */
4352 ST(0) = sv_2mortal(newSVpvn(name,size-1));
4362 char name[MAX_COMPUTERNAME_LENGTH+1];
4363 DWORD size = sizeof(name);
4365 if (GetComputerName(name,&size)) {
4366 /* size does NOT include NULL :-( */
4367 ST(0) = sv_2mortal(newSVpvn(name,size));
4378 HINSTANCE hNetApi32 = LoadLibrary("netapi32.dll");
4379 DWORD (__stdcall *pfnNetApiBufferFree)(LPVOID Buffer);
4380 DWORD (__stdcall *pfnNetWkstaGetInfo)(LPWSTR servername, DWORD level,
4384 pfnNetApiBufferFree = (DWORD (__stdcall *)(void *))
4385 GetProcAddress(hNetApi32, "NetApiBufferFree");
4386 pfnNetWkstaGetInfo = (DWORD (__stdcall *)(LPWSTR, DWORD, void *))
4387 GetProcAddress(hNetApi32, "NetWkstaGetInfo");
4390 if (hNetApi32 && pfnNetWkstaGetInfo && pfnNetApiBufferFree) {
4391 /* this way is more reliable, in case user has a local account. */
4393 DWORD dnamelen = sizeof(dname);
4395 DWORD wki100_platform_id;
4396 LPWSTR wki100_computername;
4397 LPWSTR wki100_langroup;
4398 DWORD wki100_ver_major;
4399 DWORD wki100_ver_minor;
4401 /* NERR_Success *is* 0*/
4402 if (0 == pfnNetWkstaGetInfo(NULL, 100, &pwi)) {
4403 if (pwi->wki100_langroup && *(pwi->wki100_langroup)) {
4404 WideCharToMultiByte(CP_ACP, 0, pwi->wki100_langroup,
4405 -1, (LPSTR)dname, dnamelen, NULL, NULL);
4408 WideCharToMultiByte(CP_ACP, 0, pwi->wki100_computername,
4409 -1, (LPSTR)dname, dnamelen, NULL, NULL);
4411 pfnNetApiBufferFree(pwi);
4412 FreeLibrary(hNetApi32);
4415 FreeLibrary(hNetApi32);
4418 /* Win95 doesn't have NetWksta*(), so do it the old way */
4420 DWORD size = sizeof(name);
4422 FreeLibrary(hNetApi32);
4423 if (GetUserName(name,&size)) {
4424 char sid[ONE_K_BUFSIZE];
4425 DWORD sidlen = sizeof(sid);
4427 DWORD dnamelen = sizeof(dname);
4429 if (LookupAccountName(NULL, name, (PSID)&sid, &sidlen,
4430 dname, &dnamelen, &snu)) {
4431 XSRETURN_PV(dname); /* all that for this */
4443 DWORD flags, filecomplen;
4444 if (GetVolumeInformation(NULL, NULL, 0, NULL, &filecomplen,
4445 &flags, fsname, sizeof(fsname))) {
4446 if (GIMME_V == G_ARRAY) {
4447 XPUSHs(sv_2mortal(newSVpvn(fsname,strlen(fsname))));
4448 XPUSHs(sv_2mortal(newSViv(flags)));
4449 XPUSHs(sv_2mortal(newSViv(filecomplen)));
4454 XSRETURN_PV(fsname);
4460 XS(w32_GetOSVersion)
4463 /* Use explicit struct definition because wSuiteMask and
4464 * wProductType are not defined in the VC++ 6.0 headers.
4465 * WORD type has been replaced by unsigned short because
4466 * WORD is already used by Perl itself.
4469 DWORD dwOSVersionInfoSize;
4470 DWORD dwMajorVersion;
4471 DWORD dwMinorVersion;
4472 DWORD dwBuildNumber;
4474 CHAR szCSDVersion[128];
4475 unsigned short wServicePackMajor;
4476 unsigned short wServicePackMinor;
4477 unsigned short wSuiteMask;
4483 osver.dwOSVersionInfoSize = sizeof(osver);
4484 if (!GetVersionExA((OSVERSIONINFOA*)&osver)) {
4486 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
4487 if (!GetVersionExA((OSVERSIONINFOA*)&osver)) {
4491 if (GIMME_V == G_SCALAR) {
4492 XSRETURN_IV(osver.dwPlatformId);
4494 XPUSHs(newSVpvn(osver.szCSDVersion, strlen(osver.szCSDVersion)));
4496 XPUSHs(newSViv(osver.dwMajorVersion));
4497 XPUSHs(newSViv(osver.dwMinorVersion));
4498 XPUSHs(newSViv(osver.dwBuildNumber));
4499 XPUSHs(newSViv(osver.dwPlatformId));
4501 XPUSHs(newSViv(osver.wServicePackMajor));
4502 XPUSHs(newSViv(osver.wServicePackMinor));
4503 XPUSHs(newSViv(osver.wSuiteMask));
4504 XPUSHs(newSViv(osver.wProductType));
4514 XSRETURN_IV(IsWinNT());
4522 XSRETURN_IV(IsWin95());
4526 XS(w32_FormatMessage)
4530 char msgbuf[ONE_K_BUFSIZE];
4533 Perl_croak(aTHX_ "usage: Win32::FormatMessage($errno)");
4535 if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,
4536 &source, SvIV(ST(0)), 0,
4537 msgbuf, sizeof(msgbuf)-1, NULL))
4539 XSRETURN_PV(msgbuf);
4552 PROCESS_INFORMATION stProcInfo;
4553 STARTUPINFO stStartInfo;
4554 BOOL bSuccess = FALSE;
4557 Perl_croak(aTHX_ "usage: Win32::Spawn($cmdName, $args, $PID)");
4559 cmd = SvPV_nolen(ST(0));
4560 args = SvPV_nolen(ST(1));
4562 env = PerlEnv_get_childenv();
4563 dir = PerlEnv_get_childdir();
4565 memset(&stStartInfo, 0, sizeof(stStartInfo)); /* Clear the block */
4566 stStartInfo.cb = sizeof(stStartInfo); /* Set the structure size */
4567 stStartInfo.dwFlags = STARTF_USESHOWWINDOW; /* Enable wShowWindow control */
4568 stStartInfo.wShowWindow = SW_SHOWMINNOACTIVE; /* Start min (normal) */
4571 cmd, /* Image path */
4572 args, /* Arguments for command line */
4573 NULL, /* Default process security */
4574 NULL, /* Default thread security */
4575 FALSE, /* Must be TRUE to use std handles */
4576 NORMAL_PRIORITY_CLASS, /* No special scheduling */
4577 env, /* Inherit our environment block */
4578 dir, /* Inherit our currrent directory */
4579 &stStartInfo, /* -> Startup info */
4580 &stProcInfo)) /* <- Process info (if OK) */
4582 int pid = (int)stProcInfo.dwProcessId;
4583 if (IsWin95() && pid < 0)
4585 sv_setiv(ST(2), pid);
4586 CloseHandle(stProcInfo.hThread);/* library source code does this. */
4589 PerlEnv_free_childenv(env);
4590 PerlEnv_free_childdir(dir);
4591 XSRETURN_IV(bSuccess);
4595 XS(w32_GetTickCount)
4598 DWORD msec = GetTickCount();
4606 XS(w32_GetShortPathName)
4613 Perl_croak(aTHX_ "usage: Win32::GetShortPathName($longPathName)");
4615 shortpath = sv_mortalcopy(ST(0));
4616 SvUPGRADE(shortpath, SVt_PV);
4617 if (!SvPVX(shortpath) || !SvLEN(shortpath))
4620 /* src == target is allowed */
4622 len = GetShortPathName(SvPVX(shortpath),
4625 } while (len >= SvLEN(shortpath) && sv_grow(shortpath,len+1));
4627 SvCUR_set(shortpath,len);
4628 *SvEND(shortpath) = '\0';
4636 XS(w32_GetFullPathName)
4643 STRLEN filename_len;
4647 Perl_croak(aTHX_ "usage: Win32::GetFullPathName($filename)");
4650 filename_p = SvPV(filename, filename_len);
4651 fullpath = sv_2mortal(newSVpvn(filename_p, filename_len));
4652 if (!SvPVX(fullpath) || !SvLEN(fullpath))
4656 len = GetFullPathName(SvPVX(filename),
4660 } while (len >= SvLEN(fullpath) && sv_grow(fullpath,len+1));
4662 if (GIMME_V == G_ARRAY) {
4665 XST_mPV(1,filepart);
4666 len = filepart - SvPVX(fullpath);
4673 SvCUR_set(fullpath,len);
4674 *SvEND(fullpath) = '\0';
4682 XS(w32_GetLongPathName)
4686 char tmpbuf[MAX_PATH+1];
4691 Perl_croak(aTHX_ "usage: Win32::GetLongPathName($pathname)");
4694 pathstr = SvPV(path,len);
4695 strcpy(tmpbuf, pathstr);
4696 pathstr = win32_longpath(tmpbuf);
4698 ST(0) = sv_2mortal(newSVpvn(pathstr, strlen(pathstr)));
4709 Perl_croak(aTHX_ "usage: Win32::Sleep($milliseconds)");
4719 char szSourceFile[MAX_PATH+1];
4722 Perl_croak(aTHX_ "usage: Win32::CopyFile($from, $to, $overwrite)");
4723 strcpy(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(0))));
4724 bResult = CopyFileA(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(1))), !SvTRUE(ST(2)));
4731 Perl_init_os_extras(void)
4734 char *file = __FILE__;
4737 /* these names are Activeware compatible */
4738 newXS("Win32::GetCwd", w32_GetCwd, file);
4739 newXS("Win32::SetCwd", w32_SetCwd, file);
4740 newXS("Win32::GetNextAvailDrive", w32_GetNextAvailDrive, file);
4741 newXS("Win32::GetLastError", w32_GetLastError, file);
4742 newXS("Win32::SetLastError", w32_SetLastError, file);
4743 newXS("Win32::LoginName", w32_LoginName, file);
4744 newXS("Win32::NodeName", w32_NodeName, file);
4745 newXS("Win32::DomainName", w32_DomainName, file);
4746 newXS("Win32::FsType", w32_FsType, file);
4747 newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
4748 newXS("Win32::IsWinNT", w32_IsWinNT, file);
4749 newXS("Win32::IsWin95", w32_IsWin95, file);
4750 newXS("Win32::FormatMessage", w32_FormatMessage, file);
4751 newXS("Win32::Spawn", w32_Spawn, file);
4752 newXS("Win32::GetTickCount", w32_GetTickCount, file);
4753 newXS("Win32::GetShortPathName", w32_GetShortPathName, file);
4754 newXS("Win32::GetFullPathName", w32_GetFullPathName, file);
4755 newXS("Win32::GetLongPathName", w32_GetLongPathName, file);
4756 newXS("Win32::CopyFile", w32_CopyFile, file);
4757 newXS("Win32::Sleep", w32_Sleep, file);
4758 newXS("Win32::SetChildShowWindow", w32_SetChildShowWindow, file);
4760 /* XXX Bloat Alert! The following Activeware preloads really
4761 * ought to be part of Win32::Sys::*, so they're not included
4764 /* LookupAccountName
4766 * InitiateSystemShutdown
4767 * AbortSystemShutdown
4768 * ExpandEnvrironmentStrings
4773 win32_signal_context(void)
4778 my_perl = PL_curinterp;
4779 PERL_SET_THX(my_perl);
4783 return PL_curinterp;
4789 win32_ctrlhandler(DWORD dwCtrlType)
4792 dTHXa(PERL_GET_SIG_CONTEXT);
4798 switch(dwCtrlType) {
4799 case CTRL_CLOSE_EVENT:
4800 /* A signal that the system sends to all processes attached to a console when
4801 the user closes the console (either by choosing the Close command from the
4802 console window's System menu, or by choosing the End Task command from the
4805 if (do_raise(aTHX_ 1)) /* SIGHUP */
4806 sig_terminate(aTHX_ 1);
4810 /* A CTRL+c signal was received */
4811 if (do_raise(aTHX_ SIGINT))
4812 sig_terminate(aTHX_ SIGINT);
4815 case CTRL_BREAK_EVENT:
4816 /* A CTRL+BREAK signal was received */
4817 if (do_raise(aTHX_ SIGBREAK))
4818 sig_terminate(aTHX_ SIGBREAK);
4821 case CTRL_LOGOFF_EVENT:
4822 /* A signal that the system sends to all console processes when a user is logging
4823 off. This signal does not indicate which user is logging off, so no
4824 assumptions can be made.
4827 case CTRL_SHUTDOWN_EVENT:
4828 /* A signal that the system sends to all console processes when the system is
4831 if (do_raise(aTHX_ SIGTERM))
4832 sig_terminate(aTHX_ SIGTERM);
4842 Perl_win32_init(int *argcp, char ***argvp)
4844 /* Disable floating point errors, Perl will trap the ones we
4845 * care about. VC++ RTL defaults to switching these off
4846 * already, but the Borland RTL doesn't. Since we don't
4847 * want to be at the vendor's whim on the default, we set
4848 * it explicitly here.
4850 #if !defined(_ALPHA_) && !defined(__GNUC__)
4851 _control87(MCW_EM, MCW_EM);
4857 Perl_win32_term(void)
4864 win32_get_child_IO(child_IO_table* ptbl)
4866 ptbl->childStdIn = GetStdHandle(STD_INPUT_HANDLE);
4867 ptbl->childStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
4868 ptbl->childStdErr = GetStdHandle(STD_ERROR_HANDLE);
4872 win32_signal(int sig, Sighandler_t subcode)
4875 if (sig < SIG_SIZE) {
4876 int save_errno = errno;
4877 Sighandler_t result = signal(sig, subcode);
4878 if (result == SIG_ERR) {
4879 result = w32_sighandler[sig];
4882 w32_sighandler[sig] = subcode;
4892 #ifdef HAVE_INTERP_INTERN
4896 win32_csighandler(int sig)
4899 dTHXa(PERL_GET_SIG_CONTEXT);
4900 Perl_warn(aTHX_ "Got signal %d",sig);
4906 win32_create_message_window()
4908 /* "message-only" windows have been implemented in Windows 2000 and later.
4909 * On earlier versions we'll continue to post messages to a specific
4910 * thread and use hwnd==NULL. This is brittle when either an embedding
4911 * application or an XS module is also posting messages to hwnd=NULL
4912 * because once removed from the queue they cannot be delivered to the
4913 * "right" place with DispatchMessage() anymore, as there is no WindowProc
4914 * if there is no window handle.
4916 if (g_osver.dwMajorVersion < 5)
4919 return CreateWindow("Static", "", 0, 0, 0, 0, 0, HWND_MESSAGE, 0, 0, NULL);
4923 Perl_sys_intern_init(pTHX)
4927 if (g_osver.dwOSVersionInfoSize == 0) {
4928 g_osver.dwOSVersionInfoSize = sizeof(g_osver);
4929 GetVersionEx(&g_osver);
4932 w32_perlshell_tokens = Nullch;
4933 w32_perlshell_vec = (char**)NULL;
4934 w32_perlshell_items = 0;
4935 w32_fdpid = newAV();
4936 Newx(w32_children, 1, child_tab);
4937 w32_num_children = 0;
4938 # ifdef USE_ITHREADS
4940 Newx(w32_pseudo_children, 1, pseudo_child_tab);
4941 w32_num_pseudo_children = 0;
4944 w32_message_hwnd = INVALID_HANDLE_VALUE;
4946 for (i=0; i < SIG_SIZE; i++) {
4947 w32_sighandler[i] = SIG_DFL;
4950 if (my_perl == PL_curinterp) {
4954 /* Force C runtime signal stuff to set its console handler */
4955 signal(SIGINT,win32_csighandler);
4956 signal(SIGBREAK,win32_csighandler);
4957 /* Push our handler on top */
4958 SetConsoleCtrlHandler(win32_ctrlhandler,TRUE);
4963 Perl_sys_intern_clear(pTHX)
4965 Safefree(w32_perlshell_tokens);
4966 Safefree(w32_perlshell_vec);
4967 /* NOTE: w32_fdpid is freed by sv_clean_all() */
4968 Safefree(w32_children);
4970 KillTimer(w32_message_hwnd, w32_timerid);
4973 if (w32_message_hwnd != NULL && w32_message_hwnd != INVALID_HANDLE_VALUE)
4974 DestroyWindow(w32_message_hwnd);
4975 # ifdef MULTIPLICITY
4976 if (my_perl == PL_curinterp) {
4980 SetConsoleCtrlHandler(win32_ctrlhandler,FALSE);
4982 # ifdef USE_ITHREADS
4983 Safefree(w32_pseudo_children);
4987 # ifdef USE_ITHREADS
4990 Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
4992 dst->perlshell_tokens = Nullch;
4993 dst->perlshell_vec = (char**)NULL;
4994 dst->perlshell_items = 0;
4995 dst->fdpid = newAV();
4996 Newxz(dst->children, 1, child_tab);
4998 Newxz(dst->pseudo_children, 1, pseudo_child_tab);
5000 dst->message_hwnd = INVALID_HANDLE_VALUE;
5001 dst->poll_count = 0;
5002 Copy(src->sigtable,dst->sigtable,SIG_SIZE,Sighandler_t);
5004 # endif /* USE_ITHREADS */
5005 #endif /* HAVE_INTERP_INTERN */
5008 win32_free_argvw(pTHX_ void *ptr)
5010 char** argv = (char**)ptr;
5018 win32_argv2utf8(int argc, char** argv)
5023 LPWSTR* lpwStr = CommandLineToArgvW(GetCommandLineW(), &wargc);
5024 if (lpwStr && argc) {
5026 length = WideCharToMultiByte(CP_UTF8, 0, lpwStr[--wargc], -1, NULL, 0, NULL, NULL);
5027 Newxz(psz, length, char);
5028 WideCharToMultiByte(CP_UTF8, 0, lpwStr[wargc], -1, psz, length, NULL, NULL);
5031 call_atexit(win32_free_argvw, argv);
5033 GlobalFree((HGLOBAL)lpwStr);