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 /* GCC-2.95.2/Mingw32-1.1 forgot the WINAPI on CommandLineToArgvW() */
19 #if defined(__MINGW32__) && (__MINGW32_MAJOR_VERSION==1)
20 # include <shellapi.h>
22 LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCommandLine, int * pNumArgs);
28 /* #include "config.h" */
30 #if !defined(PERLIO_IS_STDIO) && !defined(USE_SFIO)
39 #define PERL_NO_GET_CONTEXT
45 /* assert.h conflicts with #define of assert in perl.h */
52 #if defined(_MSC_VER) || defined(__MINGW32__)
53 #include <sys/utime.h>
58 /* Mingw32 defaults to globing command line
59 * So we turn it off like this:
64 #if defined(__MINGW32__) && (__MINGW32_MAJOR_VERSION==1)
65 /* Mingw32-1.1 is missing some prototypes */
66 FILE * _wfopen(LPCWSTR wszFileName, LPCWSTR wszMode);
67 FILE * _wfdopen(int nFd, LPCWSTR wszMode);
68 FILE * _freopen(LPCWSTR wszFileName, LPCWSTR wszMode, FILE * pOldStream);
73 #if defined(__BORLANDC__)
75 # define _utimbuf utimbuf
80 #define EXECF_SPAWN_NOWAIT 3
82 #if defined(PERL_IMPLICIT_SYS)
83 # undef win32_get_privlib
84 # define win32_get_privlib g_win32_get_privlib
85 # undef win32_get_sitelib
86 # define win32_get_sitelib g_win32_get_sitelib
87 # undef win32_get_vendorlib
88 # define win32_get_vendorlib g_win32_get_vendorlib
90 # define getlogin g_getlogin
93 static void get_shell(void);
94 static long tokenize(const char *str, char **dest, char ***destv);
95 static int do_spawn2(pTHX_ char *cmd, int exectype);
96 static BOOL has_shell_metachars(char *ptr);
97 static long filetime_to_clock(PFILETIME ft);
98 static BOOL filetime_from_time(PFILETIME ft, time_t t);
99 static char * get_emd_part(SV **leading, char *trailing, ...);
100 static void remove_dead_process(long deceased);
101 static long find_pid(int pid);
102 static char * qualified_path(const char *cmd);
103 static char * win32_get_xlib(const char *pl, const char *xlib,
104 const char *libname);
107 static void remove_dead_pseudo_process(long child);
108 static long find_pseudo_pid(int pid);
112 HANDLE w32_perldll_handle = INVALID_HANDLE_VALUE;
113 char w32_module_name[MAX_PATH+1];
116 static DWORD w32_platform = (DWORD)-1;
118 #define ONE_K_BUFSIZE 1024
123 return (win32_os_id() == VER_PLATFORM_WIN32_WINDOWS);
129 return (win32_os_id() == VER_PLATFORM_WIN32_NT);
133 set_w32_module_name(void)
136 GetModuleFileName((HMODULE)((w32_perldll_handle == INVALID_HANDLE_VALUE)
137 ? GetModuleHandle(NULL)
138 : w32_perldll_handle),
139 w32_module_name, sizeof(w32_module_name));
141 /* try to get full path to binary (which may be mangled when perl is
142 * run from a 16-bit app) */
143 /*PerlIO_printf(Perl_debug_log, "Before %s\n", w32_module_name);*/
144 (void)win32_longpath(w32_module_name);
145 /*PerlIO_printf(Perl_debug_log, "After %s\n", w32_module_name);*/
147 /* normalize to forward slashes */
148 ptr = w32_module_name;
156 /* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
158 get_regstr_from(HKEY hkey, const char *valuename, SV **svp)
160 /* Retrieve a REG_SZ or REG_EXPAND_SZ from the registry */
163 const char *subkey = "Software\\Perl";
167 retval = RegOpenKeyEx(hkey, subkey, 0, KEY_READ, &handle);
168 if (retval == ERROR_SUCCESS) {
170 retval = RegQueryValueEx(handle, valuename, 0, &type, NULL, &datalen);
171 if (retval == ERROR_SUCCESS
172 && (type == REG_SZ || type == REG_EXPAND_SZ))
176 *svp = sv_2mortal(newSVpvn("",0));
177 SvGROW(*svp, datalen);
178 retval = RegQueryValueEx(handle, valuename, 0, NULL,
179 (PBYTE)SvPVX(*svp), &datalen);
180 if (retval == ERROR_SUCCESS) {
182 SvCUR_set(*svp,datalen-1);
190 /* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
192 get_regstr(const char *valuename, SV **svp)
194 char *str = get_regstr_from(HKEY_CURRENT_USER, valuename, svp);
196 str = get_regstr_from(HKEY_LOCAL_MACHINE, valuename, svp);
200 /* *prev_pathp (if non-NULL) is expected to be POK (valid allocated SvPVX(sv)) */
202 get_emd_part(SV **prev_pathp, char *trailing_path, ...)
206 char mod_name[MAX_PATH+1];
212 va_start(ap, trailing_path);
213 strip = va_arg(ap, char *);
215 sprintf(base, "%d.%d", (int)PERL_REVISION, (int)PERL_VERSION);
216 baselen = strlen(base);
218 if (!*w32_module_name) {
219 set_w32_module_name();
221 strcpy(mod_name, w32_module_name);
222 ptr = strrchr(mod_name, '/');
223 while (ptr && strip) {
224 /* look for directories to skip back */
227 ptr = strrchr(mod_name, '/');
228 /* avoid stripping component if there is no slash,
229 * or it doesn't match ... */
230 if (!ptr || stricmp(ptr+1, strip) != 0) {
231 /* ... but not if component matches m|5\.$patchlevel.*| */
232 if (!ptr || !(*strip == '5' && *(ptr+1) == '5'
233 && strncmp(strip, base, baselen) == 0
234 && strncmp(ptr+1, base, baselen) == 0))
240 strip = va_arg(ap, char *);
248 strcpy(++ptr, trailing_path);
250 /* only add directory if it exists */
251 if (GetFileAttributes(mod_name) != (DWORD) -1) {
252 /* directory exists */
255 *prev_pathp = sv_2mortal(newSVpvn("",0));
256 sv_catpvn(*prev_pathp, ";", 1);
257 sv_catpv(*prev_pathp, mod_name);
258 return SvPVX(*prev_pathp);
265 win32_get_privlib(const char *pl)
268 char *stdlib = "lib";
269 char buffer[MAX_PATH+1];
272 /* $stdlib = $HKCU{"lib-$]"} || $HKLM{"lib-$]"} || $HKCU{"lib"} || $HKLM{"lib"} || ""; */
273 sprintf(buffer, "%s-%s", stdlib, pl);
274 if (!get_regstr(buffer, &sv))
275 (void)get_regstr(stdlib, &sv);
277 /* $stdlib .= ";$EMD/../../lib" */
278 return get_emd_part(&sv, stdlib, ARCHNAME, "bin", Nullch);
282 win32_get_xlib(const char *pl, const char *xlib, const char *libname)
286 char pathstr[MAX_PATH+1];
290 /* $HKCU{"$xlib-$]"} || $HKLM{"$xlib-$]"} . ---; */
291 sprintf(regstr, "%s-%s", xlib, pl);
292 (void)get_regstr(regstr, &sv1);
295 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/$]/lib"; */
296 sprintf(pathstr, "%s/%s/lib", libname, pl);
297 (void)get_emd_part(&sv1, pathstr, ARCHNAME, "bin", pl, Nullch);
299 /* $HKCU{$xlib} || $HKLM{$xlib} . ---; */
300 (void)get_regstr(xlib, &sv2);
303 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/lib"; */
304 sprintf(pathstr, "%s/lib", libname);
305 (void)get_emd_part(&sv2, pathstr, ARCHNAME, "bin", pl, Nullch);
314 sv_catpvn(sv1, ";", 1);
321 win32_get_sitelib(const char *pl)
323 return win32_get_xlib(pl, "sitelib", "site");
326 #ifndef PERL_VENDORLIB_NAME
327 # define PERL_VENDORLIB_NAME "vendor"
331 win32_get_vendorlib(const char *pl)
333 return win32_get_xlib(pl, "vendorlib", PERL_VENDORLIB_NAME);
337 has_shell_metachars(char *ptr)
343 * Scan string looking for redirection (< or >) or pipe
344 * characters (|) that are not in a quoted string.
345 * Shell variable interpolation (%VAR%) can also happen inside strings.
377 #if !defined(PERL_IMPLICIT_SYS)
378 /* since the current process environment is being updated in util.c
379 * the library functions will get the correct environment
382 Perl_my_popen(pTHX_ char *cmd, char *mode)
385 #define fixcmd(x) { \
386 char *pspace = strchr((x),' '); \
389 while (p < pspace) { \
400 PERL_FLUSHALL_FOR_CHILD;
401 return win32_popen(cmd, mode);
405 Perl_my_pclose(pTHX_ PerlIO *fp)
407 return win32_pclose(fp);
411 DllExport unsigned long
414 static OSVERSIONINFO osver;
416 if (osver.dwPlatformId != w32_platform) {
417 memset(&osver, 0, sizeof(OSVERSIONINFO));
418 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
419 GetVersionEx(&osver);
420 w32_platform = osver.dwPlatformId;
422 return (unsigned long)w32_platform;
432 return -((int)w32_pseudo_id);
435 /* Windows 9x appears to always reports a pid for threads and processes
436 * that has the high bit set. So we treat the lower 31 bits as the
437 * "real" PID for Perl's purposes. */
438 if (IsWin95() && pid < 0)
443 /* Tokenize a string. Words are null-separated, and the list
444 * ends with a doubled null. Any character (except null and
445 * including backslash) may be escaped by preceding it with a
446 * backslash (the backslash will be stripped).
447 * Returns number of words in result buffer.
450 tokenize(const char *str, char **dest, char ***destv)
452 char *retstart = Nullch;
453 char **retvstart = 0;
457 int slen = strlen(str);
459 register char **retv;
460 New(1307, ret, slen+2, char);
461 New(1308, retv, (slen+3)/2, char*);
469 if (*ret == '\\' && *str)
471 else if (*ret == ' ') {
487 retvstart[items] = Nullch;
500 if (!w32_perlshell_tokens) {
501 /* we don't use COMSPEC here for two reasons:
502 * 1. the same reason perl on UNIX doesn't use SHELL--rampant and
503 * uncontrolled unportability of the ensuing scripts.
504 * 2. PERL5SHELL could be set to a shell that may not be fit for
505 * interactive use (which is what most programs look in COMSPEC
508 const char* defaultshell = (IsWinNT()
509 ? "cmd.exe /x/d/c" : "command.com /c");
510 const char *usershell = PerlEnv_getenv("PERL5SHELL");
511 w32_perlshell_items = tokenize(usershell ? usershell : defaultshell,
512 &w32_perlshell_tokens,
518 Perl_do_aspawn(pTHX_ SV *really, SV **mark, SV **sp)
530 New(1306, argv, (sp - mark) + w32_perlshell_items + 2, char*);
532 if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
537 while (++mark <= sp) {
538 if (*mark && (str = SvPV_nolen(*mark)))
545 status = win32_spawnvp(flag,
546 (const char*)(really ? SvPV_nolen(really) : argv[0]),
547 (const char* const*)argv);
549 if (status < 0 && (errno == ENOEXEC || errno == ENOENT)) {
550 /* possible shell-builtin, invoke with shell */
552 sh_items = w32_perlshell_items;
554 argv[index+sh_items] = argv[index];
555 while (--sh_items >= 0)
556 argv[sh_items] = w32_perlshell_vec[sh_items];
558 status = win32_spawnvp(flag,
559 (const char*)(really ? SvPV_nolen(really) : argv[0]),
560 (const char* const*)argv);
563 if (flag == P_NOWAIT) {
565 PL_statusvalue = -1; /* >16bits hint for pp_system() */
569 if (ckWARN(WARN_EXEC))
570 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't spawn \"%s\": %s", argv[0], strerror(errno));
575 PL_statusvalue = status;
581 /* returns pointer to the next unquoted space or the end of the string */
583 find_next_space(const char *s)
585 bool in_quotes = FALSE;
587 /* ignore doubled backslashes, or backslash+quote */
588 if (*s == '\\' && (s[1] == '\\' || s[1] == '"')) {
591 /* keep track of when we're within quotes */
592 else if (*s == '"') {
594 in_quotes = !in_quotes;
596 /* break it up only at spaces that aren't in quotes */
597 else if (!in_quotes && isSPACE(*s))
606 do_spawn2(pTHX_ char *cmd, int exectype)
612 BOOL needToTry = TRUE;
615 /* Save an extra exec if possible. See if there are shell
616 * metacharacters in it */
617 if (!has_shell_metachars(cmd)) {
618 New(1301,argv, strlen(cmd) / 2 + 2, char*);
619 New(1302,cmd2, strlen(cmd) + 1, char);
622 for (s = cmd2; *s;) {
623 while (*s && isSPACE(*s))
627 s = find_next_space(s);
635 status = win32_spawnvp(P_WAIT, argv[0],
636 (const char* const*)argv);
638 case EXECF_SPAWN_NOWAIT:
639 status = win32_spawnvp(P_NOWAIT, argv[0],
640 (const char* const*)argv);
643 status = win32_execvp(argv[0], (const char* const*)argv);
646 if (status != -1 || errno == 0)
656 New(1306, argv, w32_perlshell_items + 2, char*);
657 while (++i < w32_perlshell_items)
658 argv[i] = w32_perlshell_vec[i];
663 status = win32_spawnvp(P_WAIT, argv[0],
664 (const char* const*)argv);
666 case EXECF_SPAWN_NOWAIT:
667 status = win32_spawnvp(P_NOWAIT, argv[0],
668 (const char* const*)argv);
671 status = win32_execvp(argv[0], (const char* const*)argv);
677 if (exectype == EXECF_SPAWN_NOWAIT) {
679 PL_statusvalue = -1; /* >16bits hint for pp_system() */
683 if (ckWARN(WARN_EXEC))
684 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s \"%s\": %s",
685 (exectype == EXECF_EXEC ? "exec" : "spawn"),
686 cmd, strerror(errno));
691 PL_statusvalue = status;
697 Perl_do_spawn(pTHX_ char *cmd)
699 return do_spawn2(aTHX_ cmd, EXECF_SPAWN);
703 Perl_do_spawn_nowait(pTHX_ char *cmd)
705 return do_spawn2(aTHX_ cmd, EXECF_SPAWN_NOWAIT);
709 Perl_do_exec(pTHX_ char *cmd)
711 do_spawn2(aTHX_ cmd, EXECF_EXEC);
715 /* The idea here is to read all the directory names into a string table
716 * (separated by nulls) and when one of the other dir functions is called
717 * return the pointer to the current file name.
720 win32_opendir(char *filename)
726 char scanname[MAX_PATH+3];
728 WIN32_FIND_DATAA aFindData;
729 WIN32_FIND_DATAW wFindData;
731 char buffer[MAX_PATH*2];
732 WCHAR wbuffer[MAX_PATH+1];
735 len = strlen(filename);
739 /* check to see if filename is a directory */
740 if (win32_stat(filename, &sbuf) < 0 || !S_ISDIR(sbuf.st_mode))
743 /* Get us a DIR structure */
744 Newz(1303, dirp, 1, DIR);
746 /* Create the search pattern */
747 strcpy(scanname, filename);
749 /* bare drive name means look in cwd for drive */
750 if (len == 2 && isALPHA(scanname[0]) && scanname[1] == ':') {
751 scanname[len++] = '.';
752 scanname[len++] = '/';
754 else if (scanname[len-1] != '/' && scanname[len-1] != '\\') {
755 scanname[len++] = '/';
757 scanname[len++] = '*';
758 scanname[len] = '\0';
760 /* do the FindFirstFile call */
762 A2WHELPER(scanname, wbuffer, sizeof(wbuffer));
763 fh = FindFirstFileW(PerlDir_mapW(wbuffer), &wFindData);
766 fh = FindFirstFileA(PerlDir_mapA(scanname), &aFindData);
769 if (fh == INVALID_HANDLE_VALUE) {
770 DWORD err = GetLastError();
771 /* FindFirstFile() fails on empty drives! */
773 case ERROR_FILE_NOT_FOUND:
775 case ERROR_NO_MORE_FILES:
776 case ERROR_PATH_NOT_FOUND:
779 case ERROR_NOT_ENOUGH_MEMORY:
790 /* now allocate the first part of the string table for
791 * the filenames that we find.
794 W2AHELPER(wFindData.cFileName, buffer, sizeof(buffer));
798 ptr = aFindData.cFileName;
805 New(1304, dirp->start, dirp->size, char);
806 strcpy(dirp->start, ptr);
808 dirp->end = dirp->curr = dirp->start;
814 /* Readdir just returns the current string pointer and bumps the
815 * string pointer to the nDllExport entry.
817 DllExport struct direct *
818 win32_readdir(DIR *dirp)
823 /* first set up the structure to return */
824 len = strlen(dirp->curr);
825 strcpy(dirp->dirstr.d_name, dirp->curr);
826 dirp->dirstr.d_namlen = len;
829 dirp->dirstr.d_ino = dirp->curr - dirp->start;
831 /* Now set up for the next call to readdir */
832 dirp->curr += len + 1;
833 if (dirp->curr >= dirp->end) {
837 WIN32_FIND_DATAW wFindData;
838 WIN32_FIND_DATAA aFindData;
839 char buffer[MAX_PATH*2];
841 /* finding the next file that matches the wildcard
842 * (which should be all of them in this directory!).
845 res = FindNextFileW(dirp->handle, &wFindData);
847 W2AHELPER(wFindData.cFileName, buffer, sizeof(buffer));
852 res = FindNextFileA(dirp->handle, &aFindData);
854 ptr = aFindData.cFileName;
857 long endpos = dirp->end - dirp->start;
858 long newsize = endpos + strlen(ptr) + 1;
859 /* bump the string table size by enough for the
860 * new name and its null terminator */
861 while (newsize > dirp->size) {
862 long curpos = dirp->curr - dirp->start;
864 Renew(dirp->start, dirp->size, char);
865 dirp->curr = dirp->start + curpos;
867 strcpy(dirp->start + endpos, ptr);
868 dirp->end = dirp->start + newsize;
874 return &(dirp->dirstr);
880 /* Telldir returns the current string pointer position */
882 win32_telldir(DIR *dirp)
884 return (dirp->curr - dirp->start);
888 /* Seekdir moves the string pointer to a previously saved position
889 * (returned by telldir).
892 win32_seekdir(DIR *dirp, long loc)
894 dirp->curr = dirp->start + loc;
897 /* Rewinddir resets the string pointer to the start */
899 win32_rewinddir(DIR *dirp)
901 dirp->curr = dirp->start;
904 /* free the memory allocated by opendir */
906 win32_closedir(DIR *dirp)
909 if (dirp->handle != INVALID_HANDLE_VALUE)
910 FindClose(dirp->handle);
911 Safefree(dirp->start);
924 * Just pretend that everyone is a superuser. NT will let us know if
925 * we don\'t really have permission to do something.
928 #define ROOT_UID ((uid_t)0)
929 #define ROOT_GID ((gid_t)0)
958 return (auid == ROOT_UID ? 0 : -1);
964 return (agid == ROOT_GID ? 0 : -1);
971 char *buf = w32_getlogin_buffer;
972 DWORD size = sizeof(w32_getlogin_buffer);
973 if (GetUserName(buf,&size))
979 chown(const char *path, uid_t owner, gid_t group)
986 * XXX this needs strengthening (for PerlIO)
989 int mkstemp(const char *path)
992 char buf[MAX_PATH+1];
996 if (i++ > 10) { /* give up */
1000 if (!GetTempFileNameA((LPCSTR)path, "plr", 1, buf)) {
1004 fd = PerlLIO_open3(buf, O_CREAT|O_RDWR|O_EXCL, 0600);
1014 long child = w32_num_children;
1015 while (--child >= 0) {
1016 if ((int)w32_child_pids[child] == pid)
1023 remove_dead_process(long child)
1027 CloseHandle(w32_child_handles[child]);
1028 Move(&w32_child_handles[child+1], &w32_child_handles[child],
1029 (w32_num_children-child-1), HANDLE);
1030 Move(&w32_child_pids[child+1], &w32_child_pids[child],
1031 (w32_num_children-child-1), DWORD);
1038 find_pseudo_pid(int pid)
1041 long child = w32_num_pseudo_children;
1042 while (--child >= 0) {
1043 if ((int)w32_pseudo_child_pids[child] == pid)
1050 remove_dead_pseudo_process(long child)
1054 CloseHandle(w32_pseudo_child_handles[child]);
1055 Move(&w32_pseudo_child_handles[child+1], &w32_pseudo_child_handles[child],
1056 (w32_num_pseudo_children-child-1), HANDLE);
1057 Move(&w32_pseudo_child_pids[child+1], &w32_pseudo_child_pids[child],
1058 (w32_num_pseudo_children-child-1), DWORD);
1059 w32_num_pseudo_children--;
1065 win32_kill(int pid, int sig)
1073 /* it is a pseudo-forked child */
1074 child = find_pseudo_pid(-pid);
1076 hProcess = w32_pseudo_child_handles[child];
1079 /* "Does process exist?" use of kill */
1082 /* kill -9 style un-graceful exit */
1083 if (TerminateThread(hProcess, sig)) {
1084 remove_dead_pseudo_process(child);
1089 /* We fake signals to pseudo-processes using Win32
1090 * message queue. In Win9X the pids are negative already. */
1091 if (PostThreadMessage(IsWin95() ? pid : -pid,WM_USER,sig,0)) {
1092 /* It might be us ... */
1099 else if (IsWin95()) {
1107 child = find_pid(pid);
1109 hProcess = w32_child_handles[child];
1112 /* "Does process exist?" use of kill */
1115 if (GenerateConsoleCtrlEvent(CTRL_C_EVENT,pid))
1120 if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,pid))
1123 default: /* For now be backwards compatible with perl5.6 */
1125 if (TerminateProcess(hProcess, sig)) {
1126 remove_dead_process(child);
1135 hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE,
1136 (IsWin95() ? -pid : pid));
1140 /* "Does process exist?" use of kill */
1144 if (GenerateConsoleCtrlEvent(CTRL_C_EVENT,pid))
1149 if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,pid))
1152 default: /* For now be backwards compatible with perl5.6 */
1154 if (TerminateProcess(hProcess, sig))
1159 CloseHandle(hProcess);
1169 win32_stat(const char *path, Stat_t *sbuf)
1172 char buffer[MAX_PATH+1];
1173 int l = strlen(path);
1175 WCHAR wbuffer[MAX_PATH+1];
1181 switch(path[l - 1]) {
1182 /* FindFirstFile() and stat() are buggy with a trailing
1183 * backslash, so change it to a forward slash :-( */
1185 if (l >= sizeof(buffer)) {
1186 errno = ENAMETOOLONG;
1189 strncpy(buffer, path, l-1);
1190 buffer[l - 1] = '/';
1194 /* FindFirstFile() is buggy with "x:", so add a dot :-( */
1196 if (l == 2 && isALPHA(path[0])) {
1197 buffer[0] = path[0];
1208 /* We *must* open & close the file once; otherwise file attribute changes */
1209 /* might not yet have propagated to "other" hard links of the same file. */
1210 /* This also gives us an opportunity to determine the number of links. */
1212 A2WHELPER(path, wbuffer, sizeof(wbuffer));
1213 pwbuffer = PerlDir_mapW(wbuffer);
1214 handle = CreateFileW(pwbuffer, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
1217 path = PerlDir_mapA(path);
1219 handle = CreateFileA(path, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
1221 if (handle != INVALID_HANDLE_VALUE) {
1222 BY_HANDLE_FILE_INFORMATION bhi;
1223 if (GetFileInformationByHandle(handle, &bhi))
1224 nlink = bhi.nNumberOfLinks;
1225 CloseHandle(handle);
1228 /* pwbuffer or path will be mapped correctly above */
1230 #if defined(WIN64) || defined(USE_LARGE_FILES)
1231 res = _wstati64(pwbuffer, sbuf);
1233 res = _wstat(pwbuffer, (struct _stat*)sbuf);
1237 #if defined(WIN64) || defined(USE_LARGE_FILES)
1238 res = _stati64(path, sbuf);
1240 res = stat(path, sbuf);
1243 sbuf->st_nlink = nlink;
1246 /* CRT is buggy on sharenames, so make sure it really isn't.
1247 * XXX using GetFileAttributesEx() will enable us to set
1248 * sbuf->st_*time (but note that's not available on the
1249 * Windows of 1995) */
1252 r = GetFileAttributesW(pwbuffer);
1255 r = GetFileAttributesA(path);
1257 if (r != 0xffffffff && (r & FILE_ATTRIBUTE_DIRECTORY)) {
1258 /* sbuf may still contain old garbage since stat() failed */
1259 Zero(sbuf, 1, Stat_t);
1260 sbuf->st_mode = S_IFDIR | S_IREAD;
1262 if (!(r & FILE_ATTRIBUTE_READONLY))
1263 sbuf->st_mode |= S_IWRITE | S_IEXEC;
1268 if (l == 3 && isALPHA(path[0]) && path[1] == ':'
1269 && (path[2] == '\\' || path[2] == '/'))
1271 /* The drive can be inaccessible, some _stat()s are buggy */
1273 ? !GetVolumeInformationW(pwbuffer,NULL,0,NULL,NULL,NULL,NULL,0)
1274 : !GetVolumeInformationA(path,NULL,0,NULL,NULL,NULL,NULL,0)) {
1280 if (S_ISDIR(sbuf->st_mode))
1281 sbuf->st_mode |= S_IWRITE | S_IEXEC;
1282 else if (S_ISREG(sbuf->st_mode)) {
1284 if (l >= 4 && path[l-4] == '.') {
1285 const char *e = path + l - 3;
1286 if (strnicmp(e,"exe",3)
1287 && strnicmp(e,"bat",3)
1288 && strnicmp(e,"com",3)
1289 && (IsWin95() || strnicmp(e,"cmd",3)))
1290 sbuf->st_mode &= ~S_IEXEC;
1292 sbuf->st_mode |= S_IEXEC;
1295 sbuf->st_mode &= ~S_IEXEC;
1296 /* Propagate permissions to _group_ and _others_ */
1297 perms = sbuf->st_mode & (S_IREAD|S_IWRITE|S_IEXEC);
1298 sbuf->st_mode |= (perms>>3) | (perms>>6);
1305 #define isSLASH(c) ((c) == '/' || (c) == '\\')
1306 #define SKIP_SLASHES(s) \
1308 while (*(s) && isSLASH(*(s))) \
1311 #define COPY_NONSLASHES(d,s) \
1313 while (*(s) && !isSLASH(*(s))) \
1317 /* Find the longname of a given path. path is destructively modified.
1318 * It should have space for at least MAX_PATH characters. */
1320 win32_longpath(char *path)
1322 WIN32_FIND_DATA fdata;
1324 char tmpbuf[MAX_PATH+1];
1325 char *tmpstart = tmpbuf;
1332 if (isALPHA(path[0]) && path[1] == ':') {
1334 *tmpstart++ = path[0];
1338 else if (isSLASH(path[0]) && isSLASH(path[1])) {
1340 *tmpstart++ = path[0];
1341 *tmpstart++ = path[1];
1342 SKIP_SLASHES(start);
1343 COPY_NONSLASHES(tmpstart,start); /* copy machine name */
1345 *tmpstart++ = *start++;
1346 SKIP_SLASHES(start);
1347 COPY_NONSLASHES(tmpstart,start); /* copy share name */
1352 /* copy initial slash, if any */
1353 if (isSLASH(*start)) {
1354 *tmpstart++ = *start++;
1356 SKIP_SLASHES(start);
1359 /* FindFirstFile() expands "." and "..", so we need to pass
1360 * those through unmolested */
1362 && (!start[1] || isSLASH(start[1])
1363 || (start[1] == '.' && (!start[2] || isSLASH(start[2])))))
1365 COPY_NONSLASHES(tmpstart,start); /* copy "." or ".." */
1370 /* if this is the end, bust outta here */
1374 /* now we're at a non-slash; walk up to next slash */
1375 while (*start && !isSLASH(*start))
1378 /* stop and find full name of component */
1381 fhand = FindFirstFile(path,&fdata);
1383 if (fhand != INVALID_HANDLE_VALUE) {
1384 STRLEN len = strlen(fdata.cFileName);
1385 if ((STRLEN)(tmpbuf + sizeof(tmpbuf) - tmpstart) > len) {
1386 strcpy(tmpstart, fdata.cFileName);
1397 /* failed a step, just return without side effects */
1398 /*PerlIO_printf(Perl_debug_log, "Failed to find %s\n", path);*/
1403 strcpy(path,tmpbuf);
1408 win32_getenv(const char *name)
1411 WCHAR wBuffer[MAX_PATH+1];
1413 SV *curitem = Nullsv;
1416 A2WHELPER(name, wBuffer, sizeof(wBuffer));
1417 needlen = GetEnvironmentVariableW(wBuffer, NULL, 0);
1420 needlen = GetEnvironmentVariableA(name,NULL,0);
1422 curitem = sv_2mortal(newSVpvn("", 0));
1426 SvGROW(curitem, (needlen+1)*sizeof(WCHAR));
1427 needlen = GetEnvironmentVariableW(wBuffer,
1428 (WCHAR*)SvPVX(curitem),
1430 } while (needlen >= SvLEN(curitem)/sizeof(WCHAR));
1431 SvCUR_set(curitem, (needlen*sizeof(WCHAR))+1);
1432 acuritem = sv_2mortal(newSVsv(curitem));
1433 W2AHELPER((WCHAR*)SvPVX(acuritem), SvPVX(curitem), SvCUR(curitem));
1437 SvGROW(curitem, needlen+1);
1438 needlen = GetEnvironmentVariableA(name,SvPVX(curitem),
1440 } while (needlen >= SvLEN(curitem));
1441 SvCUR_set(curitem, needlen);
1445 /* allow any environment variables that begin with 'PERL'
1446 to be stored in the registry */
1447 if (strncmp(name, "PERL", 4) == 0)
1448 (void)get_regstr(name, &curitem);
1450 if (curitem && SvCUR(curitem))
1451 return SvPVX(curitem);
1457 win32_putenv(const char *name)
1464 int length, relval = -1;
1468 length = strlen(name)+1;
1469 New(1309,wCuritem,length,WCHAR);
1470 A2WHELPER(name, wCuritem, length*sizeof(WCHAR));
1471 wVal = wcschr(wCuritem, '=');
1474 if (SetEnvironmentVariableW(wCuritem, *wVal ? wVal : NULL))
1480 New(1309,curitem,strlen(name)+1,char);
1481 strcpy(curitem, name);
1482 val = strchr(curitem, '=');
1484 /* The sane way to deal with the environment.
1485 * Has these advantages over putenv() & co.:
1486 * * enables us to store a truly empty value in the
1487 * environment (like in UNIX).
1488 * * we don't have to deal with RTL globals, bugs and leaks.
1490 * Why you may want to enable USE_WIN32_RTL_ENV:
1491 * * environ[] and RTL functions will not reflect changes,
1492 * which might be an issue if extensions want to access
1493 * the env. via RTL. This cuts both ways, since RTL will
1494 * not see changes made by extensions that call the Win32
1495 * functions directly, either.
1499 if (SetEnvironmentVariableA(curitem, *val ? val : NULL))
1509 filetime_to_clock(PFILETIME ft)
1511 __int64 qw = ft->dwHighDateTime;
1513 qw |= ft->dwLowDateTime;
1514 qw /= 10000; /* File time ticks at 0.1uS, clock at 1mS */
1519 win32_times(struct tms *timebuf)
1524 clock_t process_time_so_far = clock();
1525 if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy,
1527 timebuf->tms_utime = filetime_to_clock(&user);
1528 timebuf->tms_stime = filetime_to_clock(&kernel);
1529 timebuf->tms_cutime = 0;
1530 timebuf->tms_cstime = 0;
1532 /* That failed - e.g. Win95 fallback to clock() */
1533 timebuf->tms_utime = process_time_so_far;
1534 timebuf->tms_stime = 0;
1535 timebuf->tms_cutime = 0;
1536 timebuf->tms_cstime = 0;
1538 return process_time_so_far;
1541 /* fix utime() so it works on directories in NT */
1543 filetime_from_time(PFILETIME pFileTime, time_t Time)
1545 struct tm *pTM = localtime(&Time);
1546 SYSTEMTIME SystemTime;
1552 SystemTime.wYear = pTM->tm_year + 1900;
1553 SystemTime.wMonth = pTM->tm_mon + 1;
1554 SystemTime.wDay = pTM->tm_mday;
1555 SystemTime.wHour = pTM->tm_hour;
1556 SystemTime.wMinute = pTM->tm_min;
1557 SystemTime.wSecond = pTM->tm_sec;
1558 SystemTime.wMilliseconds = 0;
1560 return SystemTimeToFileTime(&SystemTime, &LocalTime) &&
1561 LocalFileTimeToFileTime(&LocalTime, pFileTime);
1565 win32_unlink(const char *filename)
1572 WCHAR wBuffer[MAX_PATH+1];
1575 A2WHELPER(filename, wBuffer, sizeof(wBuffer));
1576 pwBuffer = PerlDir_mapW(wBuffer);
1577 attrs = GetFileAttributesW(pwBuffer);
1578 if (attrs == 0xFFFFFFFF)
1580 if (attrs & FILE_ATTRIBUTE_READONLY) {
1581 (void)SetFileAttributesW(pwBuffer, attrs & ~FILE_ATTRIBUTE_READONLY);
1582 ret = _wunlink(pwBuffer);
1584 (void)SetFileAttributesW(pwBuffer, attrs);
1587 ret = _wunlink(pwBuffer);
1590 filename = PerlDir_mapA(filename);
1591 attrs = GetFileAttributesA(filename);
1592 if (attrs == 0xFFFFFFFF)
1594 if (attrs & FILE_ATTRIBUTE_READONLY) {
1595 (void)SetFileAttributesA(filename, attrs & ~FILE_ATTRIBUTE_READONLY);
1596 ret = unlink(filename);
1598 (void)SetFileAttributesA(filename, attrs);
1601 ret = unlink(filename);
1610 win32_utime(const char *filename, struct utimbuf *times)
1617 struct utimbuf TimeBuffer;
1618 WCHAR wbuffer[MAX_PATH+1];
1623 A2WHELPER(filename, wbuffer, sizeof(wbuffer));
1624 pwbuffer = PerlDir_mapW(wbuffer);
1625 rc = _wutime(pwbuffer, (struct _utimbuf*)times);
1628 filename = PerlDir_mapA(filename);
1629 rc = utime(filename, times);
1631 /* EACCES: path specifies directory or readonly file */
1632 if (rc == 0 || errno != EACCES /* || !IsWinNT() */)
1635 if (times == NULL) {
1636 times = &TimeBuffer;
1637 time(×->actime);
1638 times->modtime = times->actime;
1641 /* This will (and should) still fail on readonly files */
1643 handle = CreateFileW(pwbuffer, GENERIC_READ | GENERIC_WRITE,
1644 FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
1645 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1648 handle = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE,
1649 FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
1650 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1652 if (handle == INVALID_HANDLE_VALUE)
1655 if (GetFileTime(handle, &ftCreate, &ftAccess, &ftWrite) &&
1656 filetime_from_time(&ftAccess, times->actime) &&
1657 filetime_from_time(&ftWrite, times->modtime) &&
1658 SetFileTime(handle, &ftCreate, &ftAccess, &ftWrite))
1663 CloseHandle(handle);
1668 unsigned __int64 ft_i64;
1673 #define Const64(x) x##LL
1675 #define Const64(x) x##i64
1677 /* Number of 100 nanosecond units from 1/1/1601 to 1/1/1970 */
1678 #define EPOCH_BIAS Const64(116444736000000000)
1680 /* NOTE: This does not compute the timezone info (doing so can be expensive,
1681 * and appears to be unsupported even by glibc) */
1683 win32_gettimeofday(struct timeval *tp, void *not_used)
1687 /* this returns time in 100-nanosecond units (i.e. tens of usecs) */
1688 GetSystemTimeAsFileTime(&ft.ft_val);
1690 /* seconds since epoch */
1691 tp->tv_sec = (long)((ft.ft_i64 - EPOCH_BIAS) / Const64(10000000));
1693 /* microseconds remaining */
1694 tp->tv_usec = (long)((ft.ft_i64 / Const64(10)) % Const64(1000000));
1700 win32_uname(struct utsname *name)
1702 struct hostent *hep;
1703 STRLEN nodemax = sizeof(name->nodename)-1;
1704 OSVERSIONINFO osver;
1706 memset(&osver, 0, sizeof(OSVERSIONINFO));
1707 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1708 if (GetVersionEx(&osver)) {
1710 switch (osver.dwPlatformId) {
1711 case VER_PLATFORM_WIN32_WINDOWS:
1712 strcpy(name->sysname, "Windows");
1714 case VER_PLATFORM_WIN32_NT:
1715 strcpy(name->sysname, "Windows NT");
1717 case VER_PLATFORM_WIN32s:
1718 strcpy(name->sysname, "Win32s");
1721 strcpy(name->sysname, "Win32 Unknown");
1726 sprintf(name->release, "%d.%d",
1727 osver.dwMajorVersion, osver.dwMinorVersion);
1730 sprintf(name->version, "Build %d",
1731 osver.dwPlatformId == VER_PLATFORM_WIN32_NT
1732 ? osver.dwBuildNumber : (osver.dwBuildNumber & 0xffff));
1733 if (osver.szCSDVersion[0]) {
1734 char *buf = name->version + strlen(name->version);
1735 sprintf(buf, " (%s)", osver.szCSDVersion);
1739 *name->sysname = '\0';
1740 *name->version = '\0';
1741 *name->release = '\0';
1745 hep = win32_gethostbyname("localhost");
1747 STRLEN len = strlen(hep->h_name);
1748 if (len <= nodemax) {
1749 strcpy(name->nodename, hep->h_name);
1752 strncpy(name->nodename, hep->h_name, nodemax);
1753 name->nodename[nodemax] = '\0';
1758 if (!GetComputerName(name->nodename, &sz))
1759 *name->nodename = '\0';
1762 /* machine (architecture) */
1767 GetSystemInfo(&info);
1769 #if (defined(__BORLANDC__)&&(__BORLANDC__<=0x520)) \
1770 || (defined(__MINGW32__) && !defined(_ANONYMOUS_UNION))
1771 procarch = info.u.s.wProcessorArchitecture;
1773 procarch = info.wProcessorArchitecture;
1776 case PROCESSOR_ARCHITECTURE_INTEL:
1777 arch = "x86"; break;
1778 case PROCESSOR_ARCHITECTURE_MIPS:
1779 arch = "mips"; break;
1780 case PROCESSOR_ARCHITECTURE_ALPHA:
1781 arch = "alpha"; break;
1782 case PROCESSOR_ARCHITECTURE_PPC:
1783 arch = "ppc"; break;
1784 #ifdef PROCESSOR_ARCHITECTURE_SHX
1785 case PROCESSOR_ARCHITECTURE_SHX:
1786 arch = "shx"; break;
1788 #ifdef PROCESSOR_ARCHITECTURE_ARM
1789 case PROCESSOR_ARCHITECTURE_ARM:
1790 arch = "arm"; break;
1792 #ifdef PROCESSOR_ARCHITECTURE_IA64
1793 case PROCESSOR_ARCHITECTURE_IA64:
1794 arch = "ia64"; break;
1796 #ifdef PROCESSOR_ARCHITECTURE_ALPHA64
1797 case PROCESSOR_ARCHITECTURE_ALPHA64:
1798 arch = "alpha64"; break;
1800 #ifdef PROCESSOR_ARCHITECTURE_MSIL
1801 case PROCESSOR_ARCHITECTURE_MSIL:
1802 arch = "msil"; break;
1804 #ifdef PROCESSOR_ARCHITECTURE_AMD64
1805 case PROCESSOR_ARCHITECTURE_AMD64:
1806 arch = "amd64"; break;
1808 #ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
1809 case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
1810 arch = "ia32-64"; break;
1812 #ifdef PROCESSOR_ARCHITECTURE_UNKNOWN
1813 case PROCESSOR_ARCHITECTURE_UNKNOWN:
1814 arch = "unknown"; break;
1817 sprintf(name->machine, "unknown(0x%x)", procarch);
1818 arch = name->machine;
1821 if (name->machine != arch)
1822 strcpy(name->machine, arch);
1827 /* Timing related stuff */
1830 do_raise(pTHX_ int sig)
1832 if (sig < SIG_SIZE) {
1833 Sighandler_t handler = w32_sighandler[sig];
1834 if (handler == SIG_IGN) {
1837 else if (handler != SIG_DFL) {
1842 /* Choose correct default behaviour */
1858 /* Tell caller to exit thread/process as approriate */
1863 sig_terminate(pTHX_ int sig)
1865 Perl_warn(aTHX_ "Terminating on signal SIG%s(%d)\n",PL_sig_name[sig], sig);
1866 /* exit() seems to be safe, my_exit() or die() is a problem in ^C
1873 win32_async_check(pTHX)
1877 /* Passing PeekMessage -1 as HWND (2nd arg) only get PostThreadMessage() messages
1878 * and ignores window messages - should co-exist better with windows apps e.g. Tk
1880 while (PeekMessage(&msg, (HWND)-1, 0, 0, PM_REMOVE|PM_NOYIELD)) {
1882 switch(msg.message) {
1885 /* Perhaps some other messages could map to signals ? ... */
1888 /* Treat WM_QUIT like SIGHUP? */
1894 /* We use WM_USER to fake kill() with other signals */
1898 if (do_raise(aTHX_ sig)) {
1899 sig_terminate(aTHX_ sig);
1905 /* alarm() is a one-shot but SetTimer() repeats so kill it */
1906 if (w32_timerid && w32_timerid==msg.wParam) {
1907 KillTimer(NULL,w32_timerid);
1912 /* Now fake a call to signal handler */
1913 if (do_raise(aTHX_ 14)) {
1914 sig_terminate(aTHX_ 14);
1919 /* Otherwise do normal Win32 thing - in case it is useful */
1922 TranslateMessage(&msg);
1923 DispatchMessage(&msg);
1930 /* Above or other stuff may have set a signal flag */
1931 if (PL_sig_pending) {
1937 /* This function will not return until the timeout has elapsed, or until
1938 * one of the handles is ready. */
1940 win32_msgwait(pTHX_ DWORD count, LPHANDLE handles, DWORD timeout, LPDWORD resultp)
1942 /* We may need several goes at this - so compute when we stop */
1944 if (timeout != INFINITE) {
1945 ticks = GetTickCount();
1949 DWORD result = MsgWaitForMultipleObjects(count,handles,FALSE,timeout-ticks, QS_ALLEVENTS);
1952 if (result == WAIT_TIMEOUT) {
1953 /* Ran out of time - explicit return of zero to avoid -ve if we
1954 have scheduling issues
1958 if (timeout != INFINITE) {
1959 ticks = GetTickCount();
1961 if (result == WAIT_OBJECT_0 + count) {
1962 /* Message has arrived - check it */
1963 (void)win32_async_check(aTHX);
1966 /* Not timeout or message - one of handles is ready */
1970 /* compute time left to wait */
1971 ticks = timeout - ticks;
1972 /* If we are past the end say zero */
1973 return (ticks > 0) ? ticks : 0;
1977 win32_internal_wait(int *status, DWORD timeout)
1979 /* XXX this wait emulation only knows about processes
1980 * spawned via win32_spawnvp(P_NOWAIT, ...).
1984 DWORD exitcode, waitcode;
1987 if (w32_num_pseudo_children) {
1988 win32_msgwait(aTHX_ w32_num_pseudo_children, w32_pseudo_child_handles,
1989 timeout, &waitcode);
1990 /* Time out here if there are no other children to wait for. */
1991 if (waitcode == WAIT_TIMEOUT) {
1992 if (!w32_num_children) {
1996 else if (waitcode != WAIT_FAILED) {
1997 if (waitcode >= WAIT_ABANDONED_0
1998 && waitcode < WAIT_ABANDONED_0 + w32_num_pseudo_children)
1999 i = waitcode - WAIT_ABANDONED_0;
2001 i = waitcode - WAIT_OBJECT_0;
2002 if (GetExitCodeThread(w32_pseudo_child_handles[i], &exitcode)) {
2003 *status = (int)((exitcode & 0xff) << 8);
2004 retval = (int)w32_pseudo_child_pids[i];
2005 remove_dead_pseudo_process(i);
2012 if (!w32_num_children) {
2017 /* if a child exists, wait for it to die */
2018 win32_msgwait(aTHX_ w32_num_children, w32_child_handles, timeout, &waitcode);
2019 if (waitcode == WAIT_TIMEOUT) {
2022 if (waitcode != WAIT_FAILED) {
2023 if (waitcode >= WAIT_ABANDONED_0
2024 && waitcode < WAIT_ABANDONED_0 + w32_num_children)
2025 i = waitcode - WAIT_ABANDONED_0;
2027 i = waitcode - WAIT_OBJECT_0;
2028 if (GetExitCodeProcess(w32_child_handles[i], &exitcode) ) {
2029 *status = (int)((exitcode & 0xff) << 8);
2030 retval = (int)w32_child_pids[i];
2031 remove_dead_process(i);
2036 errno = GetLastError();
2041 win32_waitpid(int pid, int *status, int flags)
2044 DWORD timeout = (flags & WNOHANG) ? 0 : INFINITE;
2047 if (pid == -1) /* XXX threadid == 1 ? */
2048 return win32_internal_wait(status, timeout);
2051 child = find_pseudo_pid(-pid);
2053 HANDLE hThread = w32_pseudo_child_handles[child];
2055 win32_msgwait(aTHX_ 1, &hThread, timeout, &waitcode);
2056 if (waitcode == WAIT_TIMEOUT) {
2059 else if (waitcode == WAIT_OBJECT_0) {
2060 if (GetExitCodeThread(hThread, &waitcode)) {
2061 *status = (int)((waitcode & 0xff) << 8);
2062 retval = (int)w32_pseudo_child_pids[child];
2063 remove_dead_pseudo_process(child);
2070 else if (IsWin95()) {
2079 child = find_pid(pid);
2081 hProcess = w32_child_handles[child];
2082 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
2083 if (waitcode == WAIT_TIMEOUT) {
2086 else if (waitcode == WAIT_OBJECT_0) {
2087 if (GetExitCodeProcess(hProcess, &waitcode)) {
2088 *status = (int)((waitcode & 0xff) << 8);
2089 retval = (int)w32_child_pids[child];
2090 remove_dead_process(child);
2099 hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE,
2100 (IsWin95() ? -pid : pid));
2102 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
2103 if (waitcode == WAIT_TIMEOUT) {
2104 CloseHandle(hProcess);
2107 else if (waitcode == WAIT_OBJECT_0) {
2108 if (GetExitCodeProcess(hProcess, &waitcode)) {
2109 *status = (int)((waitcode & 0xff) << 8);
2110 CloseHandle(hProcess);
2114 CloseHandle(hProcess);
2120 return retval >= 0 ? pid : retval;
2124 win32_wait(int *status)
2126 return win32_internal_wait(status, INFINITE);
2129 DllExport unsigned int
2130 win32_sleep(unsigned int t)
2133 /* Win32 times are in ms so *1000 in and /1000 out */
2134 return win32_msgwait(aTHX_ 0, NULL, t*1000, NULL)/1000;
2137 DllExport unsigned int
2138 win32_alarm(unsigned int sec)
2141 * the 'obvious' implentation is SetTimer() with a callback
2142 * which does whatever receiving SIGALRM would do
2143 * we cannot use SIGALRM even via raise() as it is not
2144 * one of the supported codes in <signal.h>
2148 w32_timerid = SetTimer(NULL,w32_timerid,sec*1000,NULL);
2152 KillTimer(NULL,w32_timerid);
2159 #ifdef HAVE_DES_FCRYPT
2160 extern char * des_fcrypt(const char *txt, const char *salt, char *cbuf);
2164 win32_crypt(const char *txt, const char *salt)
2167 #ifdef HAVE_DES_FCRYPT
2168 return des_fcrypt(txt, salt, w32_crypt_buffer);
2170 Perl_croak(aTHX_ "The crypt() function is unimplemented due to excessive paranoia.");
2175 #ifdef USE_FIXED_OSFHANDLE
2177 #define FOPEN 0x01 /* file handle open */
2178 #define FNOINHERIT 0x10 /* file handle opened O_NOINHERIT */
2179 #define FAPPEND 0x20 /* file handle opened O_APPEND */
2180 #define FDEV 0x40 /* file handle refers to device */
2181 #define FTEXT 0x80 /* file handle is in text mode */
2184 *int my_open_osfhandle(intptr_t osfhandle, int flags) - open C Runtime file handle
2187 * This function allocates a free C Runtime file handle and associates
2188 * it with the Win32 HANDLE specified by the first parameter. This is a
2189 * temperary fix for WIN95's brain damage GetFileType() error on socket
2190 * we just bypass that call for socket
2192 * This works with MSVC++ 4.0+ or GCC/Mingw32
2195 * intptr_t osfhandle - Win32 HANDLE to associate with C Runtime file handle.
2196 * int flags - flags to associate with C Runtime file handle.
2199 * returns index of entry in fh, if successful
2200 * return -1, if no free entry is found
2204 *******************************************************************************/
2207 * we fake up some parts of the CRT that aren't exported by MSVCRT.dll
2208 * this lets sockets work on Win9X with GCC and should fix the problems
2213 /* create an ioinfo entry, kill its handle, and steal the entry */
2218 HANDLE hF = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
2219 int fh = _open_osfhandle((intptr_t)hF, 0);
2223 EnterCriticalSection(&(_pioinfo(fh)->lock));
2228 my_open_osfhandle(intptr_t osfhandle, int flags)
2231 char fileflags; /* _osfile flags */
2233 /* copy relevant flags from second parameter */
2236 if (flags & O_APPEND)
2237 fileflags |= FAPPEND;
2242 if (flags & O_NOINHERIT)
2243 fileflags |= FNOINHERIT;
2245 /* attempt to allocate a C Runtime file handle */
2246 if ((fh = _alloc_osfhnd()) == -1) {
2247 errno = EMFILE; /* too many open files */
2248 _doserrno = 0L; /* not an OS error */
2249 return -1; /* return error to caller */
2252 /* the file is open. now, set the info in _osfhnd array */
2253 _set_osfhnd(fh, osfhandle);
2255 fileflags |= FOPEN; /* mark as open */
2257 _osfile(fh) = fileflags; /* set osfile entry */
2258 LeaveCriticalSection(&_pioinfo(fh)->lock);
2260 return fh; /* return handle */
2263 #endif /* USE_FIXED_OSFHANDLE */
2265 /* simulate flock by locking a range on the file */
2267 #define LK_ERR(f,i) ((f) ? (i = 0) : (errno = GetLastError()))
2268 #define LK_LEN 0xffff0000
2271 win32_flock(int fd, int oper)
2279 Perl_croak_nocontext("flock() unimplemented on this platform");
2282 fh = (HANDLE)_get_osfhandle(fd);
2283 memset(&o, 0, sizeof(o));
2286 case LOCK_SH: /* shared lock */
2287 LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, 0, &o),i);
2289 case LOCK_EX: /* exclusive lock */
2290 LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o),i);
2292 case LOCK_SH|LOCK_NB: /* non-blocking shared lock */
2293 LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o),i);
2295 case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */
2296 LK_ERR(LockFileEx(fh,
2297 LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
2298 0, LK_LEN, 0, &o),i);
2300 case LOCK_UN: /* unlock lock */
2301 LK_ERR(UnlockFileEx(fh, 0, LK_LEN, 0, &o),i);
2303 default: /* unknown */
2314 * redirected io subsystem for all XS modules
2327 return (&(_environ));
2330 /* the rest are the remapped stdio routines */
2350 win32_ferror(FILE *fp)
2352 return (ferror(fp));
2357 win32_feof(FILE *fp)
2363 * Since the errors returned by the socket error function
2364 * WSAGetLastError() are not known by the library routine strerror
2365 * we have to roll our own.
2369 win32_strerror(int e)
2371 #if !defined __BORLANDC__ && !defined __MINGW32__ /* compiler intolerance */
2372 extern int sys_nerr;
2376 if (e < 0 || e > sys_nerr) {
2381 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0,
2382 w32_strerror_buffer,
2383 sizeof(w32_strerror_buffer), NULL) == 0)
2384 strcpy(w32_strerror_buffer, "Unknown Error");
2386 return w32_strerror_buffer;
2392 win32_str_os_error(void *sv, DWORD dwErr)
2396 dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
2397 |FORMAT_MESSAGE_IGNORE_INSERTS
2398 |FORMAT_MESSAGE_FROM_SYSTEM, NULL,
2399 dwErr, 0, (char *)&sMsg, 1, NULL);
2400 /* strip trailing whitespace and period */
2403 --dwLen; /* dwLen doesn't include trailing null */
2404 } while (0 < dwLen && isSPACE(sMsg[dwLen]));
2405 if ('.' != sMsg[dwLen])
2410 sMsg = (char*)LocalAlloc(0, 64/**sizeof(TCHAR)*/);
2412 dwLen = sprintf(sMsg,
2413 "Unknown error #0x%lX (lookup 0x%lX)",
2414 dwErr, GetLastError());
2418 sv_setpvn((SV*)sv, sMsg, dwLen);
2424 win32_fprintf(FILE *fp, const char *format, ...)
2427 va_start(marker, format); /* Initialize variable arguments. */
2429 return (vfprintf(fp, format, marker));
2433 win32_printf(const char *format, ...)
2436 va_start(marker, format); /* Initialize variable arguments. */
2438 return (vprintf(format, marker));
2442 win32_vfprintf(FILE *fp, const char *format, va_list args)
2444 return (vfprintf(fp, format, args));
2448 win32_vprintf(const char *format, va_list args)
2450 return (vprintf(format, args));
2454 win32_fread(void *buf, size_t size, size_t count, FILE *fp)
2456 return fread(buf, size, count, fp);
2460 win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
2462 return fwrite(buf, size, count, fp);
2465 #define MODE_SIZE 10
2468 win32_fopen(const char *filename, const char *mode)
2471 WCHAR wMode[MODE_SIZE], wBuffer[MAX_PATH+1];
2477 if (stricmp(filename, "/dev/null")==0)
2481 A2WHELPER(mode, wMode, sizeof(wMode));
2482 A2WHELPER(filename, wBuffer, sizeof(wBuffer));
2483 f = _wfopen(PerlDir_mapW(wBuffer), wMode);
2486 f = fopen(PerlDir_mapA(filename), mode);
2487 /* avoid buffering headaches for child processes */
2488 if (f && *mode == 'a')
2489 win32_fseek(f, 0, SEEK_END);
2493 #ifndef USE_SOCKETS_AS_HANDLES
2495 #define fdopen my_fdopen
2499 win32_fdopen(int handle, const char *mode)
2502 WCHAR wMode[MODE_SIZE];
2505 A2WHELPER(mode, wMode, sizeof(wMode));
2506 f = _wfdopen(handle, wMode);
2509 f = fdopen(handle, (char *) mode);
2510 /* avoid buffering headaches for child processes */
2511 if (f && *mode == 'a')
2512 win32_fseek(f, 0, SEEK_END);
2517 win32_freopen(const char *path, const char *mode, FILE *stream)
2520 WCHAR wMode[MODE_SIZE], wBuffer[MAX_PATH+1];
2521 if (stricmp(path, "/dev/null")==0)
2525 A2WHELPER(mode, wMode, sizeof(wMode));
2526 A2WHELPER(path, wBuffer, sizeof(wBuffer));
2527 return _wfreopen(PerlDir_mapW(wBuffer), wMode, stream);
2529 return freopen(PerlDir_mapA(path), mode, stream);
2533 win32_fclose(FILE *pf)
2535 return my_fclose(pf); /* defined in win32sck.c */
2539 win32_fputs(const char *s,FILE *pf)
2541 return fputs(s, pf);
2545 win32_fputc(int c,FILE *pf)
2551 win32_ungetc(int c,FILE *pf)
2553 return ungetc(c,pf);
2557 win32_getc(FILE *pf)
2563 win32_fileno(FILE *pf)
2569 win32_clearerr(FILE *pf)
2576 win32_fflush(FILE *pf)
2582 win32_ftell(FILE *pf)
2584 #if defined(WIN64) || defined(USE_LARGE_FILES)
2585 #if defined(__BORLAND__) /* buk */
2586 return win32_tell( fileno( pf ) );
2589 if (fgetpos(pf, &pos))
2599 win32_fseek(FILE *pf, Off_t offset,int origin)
2601 #if defined(WIN64) || defined(USE_LARGE_FILES)
2602 #if defined(__BORLANDC__) /* buk */
2612 if (fgetpos(pf, &pos))
2617 fseek(pf, 0, SEEK_END);
2618 pos = _telli64(fileno(pf));
2627 return fsetpos(pf, &offset);
2630 return fseek(pf, offset, origin);
2635 win32_fgetpos(FILE *pf,fpos_t *p)
2637 #if defined(__BORLANDC__) && defined(USE_LARGE_FILES) /* buk */
2638 if( win32_tell(fileno(pf)) == -1L ) {
2644 return fgetpos(pf, p);
2649 win32_fsetpos(FILE *pf,const fpos_t *p)
2651 #if defined(__BORLANDC__) && defined(USE_LARGE_FILES) /* buk */
2652 return win32_lseek(fileno(pf), *p, SEEK_CUR);
2654 return fsetpos(pf, p);
2659 win32_rewind(FILE *pf)
2669 char prefix[MAX_PATH+1];
2670 char filename[MAX_PATH+1];
2671 DWORD len = GetTempPath(MAX_PATH, prefix);
2672 if (len && len < MAX_PATH) {
2673 if (GetTempFileName(prefix, "plx", 0, filename)) {
2674 HANDLE fh = CreateFile(filename,
2675 DELETE | GENERIC_READ | GENERIC_WRITE,
2679 FILE_ATTRIBUTE_NORMAL
2680 | FILE_FLAG_DELETE_ON_CLOSE,
2682 if (fh != INVALID_HANDLE_VALUE) {
2683 int fd = win32_open_osfhandle((intptr_t)fh, 0);
2685 #if defined(__BORLANDC__)
2686 setmode(fd,O_BINARY);
2688 DEBUG_p(PerlIO_printf(Perl_debug_log,
2689 "Created tmpfile=%s\n",filename));
2701 int fd = win32_tmpfd();
2703 return win32_fdopen(fd, "w+b");
2715 win32_fstat(int fd, Stat_t *sbufptr)
2718 /* A file designated by filehandle is not shown as accessible
2719 * for write operations, probably because it is opened for reading.
2722 int rc = fstat(fd,sbufptr);
2723 BY_HANDLE_FILE_INFORMATION bhfi;
2724 if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &bhfi)) {
2725 sbufptr->st_mode &= 0xFE00;
2726 if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
2727 sbufptr->st_mode |= (S_IREAD + (S_IREAD >> 3) + (S_IREAD >> 6));
2729 sbufptr->st_mode |= ((S_IREAD|S_IWRITE) + ((S_IREAD|S_IWRITE) >> 3)
2730 + ((S_IREAD|S_IWRITE) >> 6));
2734 return my_fstat(fd,sbufptr);
2739 win32_pipe(int *pfd, unsigned int size, int mode)
2741 return _pipe(pfd, size, mode);
2745 win32_popenlist(const char *mode, IV narg, SV **args)
2748 Perl_croak(aTHX_ "List form of pipe open not implemented");
2753 * a popen() clone that respects PERL5SHELL
2755 * changed to return PerlIO* rather than FILE * by BKS, 11-11-2000
2759 win32_popen(const char *command, const char *mode)
2761 #ifdef USE_RTL_POPEN
2762 return _popen(command, mode);
2774 /* establish which ends read and write */
2775 if (strchr(mode,'w')) {
2776 stdfd = 0; /* stdin */
2779 nhandle = STD_INPUT_HANDLE;
2781 else if (strchr(mode,'r')) {
2782 stdfd = 1; /* stdout */
2785 nhandle = STD_OUTPUT_HANDLE;
2790 /* set the correct mode */
2791 if (strchr(mode,'b'))
2793 else if (strchr(mode,'t'))
2796 ourmode = _fmode & (O_TEXT | O_BINARY);
2798 /* the child doesn't inherit handles */
2799 ourmode |= O_NOINHERIT;
2801 if (win32_pipe(p, 512, ourmode) == -1)
2804 /* save current stdfd */
2805 if ((oldfd = win32_dup(stdfd)) == -1)
2808 /* save the old std handle (this needs to happen before the
2809 * dup2(), since that might call SetStdHandle() too) */
2812 old_h = GetStdHandle(nhandle);
2814 /* make stdfd go to child end of pipe (implicitly closes stdfd) */
2815 /* stdfd will be inherited by the child */
2816 if (win32_dup2(p[child], stdfd) == -1)
2819 /* close the child end in parent */
2820 win32_close(p[child]);
2822 /* set the new std handle (in case dup2() above didn't) */
2823 SetStdHandle(nhandle, (HANDLE)_get_osfhandle(stdfd));
2825 /* start the child */
2828 if ((childpid = do_spawn_nowait((char*)command)) == -1)
2831 /* revert stdfd to whatever it was before */
2832 if (win32_dup2(oldfd, stdfd) == -1)
2835 /* restore the old std handle (this needs to happen after the
2836 * dup2(), since that might call SetStdHandle() too */
2838 SetStdHandle(nhandle, old_h);
2843 /* close saved handle */
2847 sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid);
2850 /* set process id so that it can be returned by perl's open() */
2851 PL_forkprocess = childpid;
2854 /* we have an fd, return a file stream */
2855 return (PerlIO_fdopen(p[parent], (char *)mode));
2858 /* we don't need to check for errors here */
2862 SetStdHandle(nhandle, old_h);
2867 win32_dup2(oldfd, stdfd);
2872 #endif /* USE_RTL_POPEN */
2880 win32_pclose(PerlIO *pf)
2882 #ifdef USE_RTL_POPEN
2886 int childpid, status;
2890 sv = *av_fetch(w32_fdpid, PerlIO_fileno(pf), TRUE);
2893 childpid = SvIVX(sv);
2910 if (win32_waitpid(childpid, &status, 0) == -1)
2915 #endif /* USE_RTL_POPEN */
2921 LPCWSTR lpExistingFileName,
2922 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
2925 WCHAR wFullName[MAX_PATH+1];
2926 LPVOID lpContext = NULL;
2927 WIN32_STREAM_ID StreamId;
2928 DWORD dwSize = (char*)&StreamId.cStreamName - (char*)&StreamId;
2933 BOOL (__stdcall *pfnBackupWrite)(HANDLE, LPBYTE, DWORD, LPDWORD,
2934 BOOL, BOOL, LPVOID*) =
2935 (BOOL (__stdcall *)(HANDLE, LPBYTE, DWORD, LPDWORD,
2936 BOOL, BOOL, LPVOID*))
2937 GetProcAddress(GetModuleHandle("kernel32.dll"), "BackupWrite");
2938 if (pfnBackupWrite == NULL)
2941 dwLen = GetFullPathNameW(lpFileName, MAX_PATH, wFullName, NULL);
2944 dwLen = (dwLen+1)*sizeof(WCHAR);
2946 handle = CreateFileW(lpExistingFileName, FILE_WRITE_ATTRIBUTES,
2947 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2948 NULL, OPEN_EXISTING, 0, NULL);
2949 if (handle == INVALID_HANDLE_VALUE)
2952 StreamId.dwStreamId = BACKUP_LINK;
2953 StreamId.dwStreamAttributes = 0;
2954 StreamId.dwStreamNameSize = 0;
2955 #if defined(__BORLANDC__) \
2956 ||(defined(__MINGW32__) && !defined(_ANONYMOUS_UNION))
2957 StreamId.Size.u.HighPart = 0;
2958 StreamId.Size.u.LowPart = dwLen;
2960 StreamId.Size.HighPart = 0;
2961 StreamId.Size.LowPart = dwLen;
2964 bSuccess = pfnBackupWrite(handle, (LPBYTE)&StreamId, dwSize, &dwWritten,
2965 FALSE, FALSE, &lpContext);
2967 bSuccess = pfnBackupWrite(handle, (LPBYTE)wFullName, dwLen, &dwWritten,
2968 FALSE, FALSE, &lpContext);
2969 pfnBackupWrite(handle, NULL, 0, &dwWritten, TRUE, FALSE, &lpContext);
2972 CloseHandle(handle);
2977 win32_link(const char *oldname, const char *newname)
2980 BOOL (__stdcall *pfnCreateHardLinkW)(LPCWSTR,LPCWSTR,LPSECURITY_ATTRIBUTES);
2981 WCHAR wOldName[MAX_PATH+1];
2982 WCHAR wNewName[MAX_PATH+1];
2985 Perl_croak(aTHX_ PL_no_func, "link");
2987 pfnCreateHardLinkW =
2988 (BOOL (__stdcall *)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES))
2989 GetProcAddress(GetModuleHandle("kernel32.dll"), "CreateHardLinkW");
2990 if (pfnCreateHardLinkW == NULL)
2991 pfnCreateHardLinkW = Nt4CreateHardLinkW;
2993 if ((A2WHELPER(oldname, wOldName, sizeof(wOldName))) &&
2994 (A2WHELPER(newname, wNewName, sizeof(wNewName))) &&
2995 (wcscpy(wOldName, PerlDir_mapW(wOldName)),
2996 pfnCreateHardLinkW(PerlDir_mapW(wNewName), wOldName, NULL)))
3000 errno = (GetLastError() == ERROR_FILE_NOT_FOUND) ? ENOENT : EINVAL;
3005 win32_rename(const char *oname, const char *newname)
3007 WCHAR wOldName[MAX_PATH+1];
3008 WCHAR wNewName[MAX_PATH+1];
3009 char szOldName[MAX_PATH+1];
3010 char szNewName[MAX_PATH+1];
3014 /* XXX despite what the documentation says about MoveFileEx(),
3015 * it doesn't work under Windows95!
3018 DWORD dwFlags = MOVEFILE_COPY_ALLOWED;
3020 A2WHELPER(oname, wOldName, sizeof(wOldName));
3021 A2WHELPER(newname, wNewName, sizeof(wNewName));
3022 if (wcsicmp(wNewName, wOldName))
3023 dwFlags |= MOVEFILE_REPLACE_EXISTING;
3024 wcscpy(wOldName, PerlDir_mapW(wOldName));
3025 bResult = MoveFileExW(wOldName,PerlDir_mapW(wNewName), dwFlags);
3028 if (stricmp(newname, oname))
3029 dwFlags |= MOVEFILE_REPLACE_EXISTING;
3030 strcpy(szOldName, PerlDir_mapA(oname));
3031 bResult = MoveFileExA(szOldName,PerlDir_mapA(newname), dwFlags);
3034 DWORD err = GetLastError();
3036 case ERROR_BAD_NET_NAME:
3037 case ERROR_BAD_NETPATH:
3038 case ERROR_BAD_PATHNAME:
3039 case ERROR_FILE_NOT_FOUND:
3040 case ERROR_FILENAME_EXCED_RANGE:
3041 case ERROR_INVALID_DRIVE:
3042 case ERROR_NO_MORE_FILES:
3043 case ERROR_PATH_NOT_FOUND:
3056 char szTmpName[MAX_PATH+1];
3057 char dname[MAX_PATH+1];
3058 char *endname = Nullch;
3060 DWORD from_attr, to_attr;
3062 strcpy(szOldName, PerlDir_mapA(oname));
3063 strcpy(szNewName, PerlDir_mapA(newname));
3065 /* if oname doesn't exist, do nothing */
3066 from_attr = GetFileAttributes(szOldName);
3067 if (from_attr == 0xFFFFFFFF) {
3072 /* if newname exists, rename it to a temporary name so that we
3073 * don't delete it in case oname happens to be the same file
3074 * (but perhaps accessed via a different path)
3076 to_attr = GetFileAttributes(szNewName);
3077 if (to_attr != 0xFFFFFFFF) {
3078 /* if newname is a directory, we fail
3079 * XXX could overcome this with yet more convoluted logic */
3080 if (to_attr & FILE_ATTRIBUTE_DIRECTORY) {
3084 tmplen = strlen(szNewName);
3085 strcpy(szTmpName,szNewName);
3086 endname = szTmpName+tmplen;
3087 for (; endname > szTmpName ; --endname) {
3088 if (*endname == '/' || *endname == '\\') {
3093 if (endname > szTmpName)
3094 endname = strcpy(dname,szTmpName);
3098 /* get a temporary filename in same directory
3099 * XXX is this really the best we can do? */
3100 if (!GetTempFileName((LPCTSTR)endname, "plr", 0, szTmpName)) {
3104 DeleteFile(szTmpName);
3106 retval = rename(szNewName, szTmpName);
3113 /* rename oname to newname */
3114 retval = rename(szOldName, szNewName);
3116 /* if we created a temporary file before ... */
3117 if (endname != Nullch) {
3118 /* ...and rename succeeded, delete temporary file/directory */
3120 DeleteFile(szTmpName);
3121 /* else restore it to what it was */
3123 (void)rename(szTmpName, szNewName);
3130 win32_setmode(int fd, int mode)
3132 return setmode(fd, mode);
3136 win32_chsize(int fd, Off_t size)
3138 #if defined(WIN64) || defined(USE_LARGE_FILES)
3140 Off_t cur, end, extend;
3142 cur = win32_tell(fd);
3145 end = win32_lseek(fd, 0, SEEK_END);
3148 extend = size - end;
3152 else if (extend > 0) {
3153 /* must grow the file, padding with nulls */
3155 int oldmode = win32_setmode(fd, O_BINARY);
3157 memset(b, '\0', sizeof(b));
3159 count = extend >= sizeof(b) ? sizeof(b) : (size_t)extend;
3160 count = win32_write(fd, b, count);
3161 if ((int)count < 0) {
3165 } while ((extend -= count) > 0);
3166 win32_setmode(fd, oldmode);
3169 /* shrink the file */
3170 win32_lseek(fd, size, SEEK_SET);
3171 if (!SetEndOfFile((HANDLE)_get_osfhandle(fd))) {
3177 win32_lseek(fd, cur, SEEK_SET);
3180 return chsize(fd, size);
3185 win32_lseek(int fd, Off_t offset, int origin)
3187 #if defined(WIN64) || defined(USE_LARGE_FILES)
3188 #if defined(__BORLANDC__) /* buk */
3190 pos.QuadPart = offset;
3191 pos.LowPart = SetFilePointer(
3192 (HANDLE)_get_osfhandle(fd),
3197 if (pos.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
3201 return pos.QuadPart;
3203 return _lseeki64(fd, offset, origin);
3206 return lseek(fd, offset, origin);
3213 #if defined(WIN64) || defined(USE_LARGE_FILES)
3214 #if defined(__BORLANDC__) /* buk */
3217 pos.LowPart = SetFilePointer(
3218 (HANDLE)_get_osfhandle(fd),
3223 if (pos.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
3227 return pos.QuadPart;
3228 /* return tell(fd); */
3230 return _telli64(fd);
3238 win32_open(const char *path, int flag, ...)
3243 WCHAR wBuffer[MAX_PATH+1];
3246 pmode = va_arg(ap, int);
3249 if (stricmp(path, "/dev/null")==0)
3253 A2WHELPER(path, wBuffer, sizeof(wBuffer));
3254 return _wopen(PerlDir_mapW(wBuffer), flag, pmode);
3256 return open(PerlDir_mapA(path), flag, pmode);
3259 /* close() that understands socket */
3260 extern int my_close(int); /* in win32sck.c */
3265 return my_close(fd);
3281 win32_dup2(int fd1,int fd2)
3283 return dup2(fd1,fd2);
3286 #ifdef PERL_MSVCRT_READFIX
3288 #define LF 10 /* line feed */
3289 #define CR 13 /* carriage return */
3290 #define CTRLZ 26 /* ctrl-z means eof for text */
3291 #define FOPEN 0x01 /* file handle open */
3292 #define FEOFLAG 0x02 /* end of file has been encountered */
3293 #define FCRLF 0x04 /* CR-LF across read buffer (in text mode) */
3294 #define FPIPE 0x08 /* file handle refers to a pipe */
3295 #define FAPPEND 0x20 /* file handle opened O_APPEND */
3296 #define FDEV 0x40 /* file handle refers to device */
3297 #define FTEXT 0x80 /* file handle is in text mode */
3298 #define MAX_DESCRIPTOR_COUNT (64*32) /* this is the maximun that MSVCRT can handle */
3301 _fixed_read(int fh, void *buf, unsigned cnt)
3303 int bytes_read; /* number of bytes read */
3304 char *buffer; /* buffer to read to */
3305 int os_read; /* bytes read on OS call */
3306 char *p, *q; /* pointers into buffer */
3307 char peekchr; /* peek-ahead character */
3308 ULONG filepos; /* file position after seek */
3309 ULONG dosretval; /* o.s. return value */
3311 /* validate handle */
3312 if (((unsigned)fh >= (unsigned)MAX_DESCRIPTOR_COUNT) ||
3313 !(_osfile(fh) & FOPEN))
3315 /* out of range -- return error */
3317 _doserrno = 0; /* not o.s. error */
3322 * If lockinitflag is FALSE, assume fd is device
3323 * lockinitflag is set to TRUE by open.
3325 if (_pioinfo(fh)->lockinitflag)
3326 EnterCriticalSection(&(_pioinfo(fh)->lock)); /* lock file */
3328 bytes_read = 0; /* nothing read yet */
3329 buffer = (char*)buf;
3331 if (cnt == 0 || (_osfile(fh) & FEOFLAG)) {
3332 /* nothing to read or at EOF, so return 0 read */
3336 if ((_osfile(fh) & (FPIPE|FDEV)) && _pipech(fh) != LF) {
3337 /* a pipe/device and pipe lookahead non-empty: read the lookahead
3339 *buffer++ = _pipech(fh);
3342 _pipech(fh) = LF; /* mark as empty */
3347 if (!ReadFile((HANDLE)_osfhnd(fh), buffer, cnt, (LPDWORD)&os_read, NULL))
3349 /* ReadFile has reported an error. recognize two special cases.
3351 * 1. map ERROR_ACCESS_DENIED to EBADF
3353 * 2. just return 0 if ERROR_BROKEN_PIPE has occurred. it
3354 * means the handle is a read-handle on a pipe for which
3355 * all write-handles have been closed and all data has been
3358 if ((dosretval = GetLastError()) == ERROR_ACCESS_DENIED) {
3359 /* wrong read/write mode should return EBADF, not EACCES */
3361 _doserrno = dosretval;
3365 else if (dosretval == ERROR_BROKEN_PIPE) {
3375 bytes_read += os_read; /* update bytes read */
3377 if (_osfile(fh) & FTEXT) {
3378 /* now must translate CR-LFs to LFs in the buffer */
3380 /* set CRLF flag to indicate LF at beginning of buffer */
3381 /* if ((os_read != 0) && (*(char *)buf == LF)) */
3382 /* _osfile(fh) |= FCRLF; */
3384 /* _osfile(fh) &= ~FCRLF; */
3386 _osfile(fh) &= ~FCRLF;
3388 /* convert chars in the buffer: p is src, q is dest */
3390 while (p < (char *)buf + bytes_read) {
3392 /* if fh is not a device, set ctrl-z flag */
3393 if (!(_osfile(fh) & FDEV))
3394 _osfile(fh) |= FEOFLAG;
3395 break; /* stop translating */
3400 /* *p is CR, so must check next char for LF */
3401 if (p < (char *)buf + bytes_read - 1) {
3404 *q++ = LF; /* convert CR-LF to LF */
3407 *q++ = *p++; /* store char normally */
3410 /* This is the hard part. We found a CR at end of
3411 buffer. We must peek ahead to see if next char
3416 if (!ReadFile((HANDLE)_osfhnd(fh), &peekchr, 1,
3417 (LPDWORD)&os_read, NULL))
3418 dosretval = GetLastError();
3420 if (dosretval != 0 || os_read == 0) {
3421 /* couldn't read ahead, store CR */
3425 /* peekchr now has the extra character -- we now
3426 have several possibilities:
3427 1. disk file and char is not LF; just seek back
3429 2. disk file and char is LF; store LF, don't seek back
3430 3. pipe/device and char is LF; store LF.
3431 4. pipe/device and char isn't LF, store CR and
3432 put char in pipe lookahead buffer. */
3433 if (_osfile(fh) & (FDEV|FPIPE)) {
3434 /* non-seekable device */
3439 _pipech(fh) = peekchr;
3444 if (peekchr == LF) {
3445 /* nothing read yet; must make some
3448 /* turn on this flag for tell routine */
3449 _osfile(fh) |= FCRLF;
3452 HANDLE osHandle; /* o.s. handle value */
3454 if ((osHandle = (HANDLE)_get_osfhandle(fh)) != (HANDLE)-1)
3456 if ((filepos = SetFilePointer(osHandle, -1, NULL, FILE_CURRENT)) == -1)
3457 dosretval = GetLastError();
3468 /* we now change bytes_read to reflect the true number of chars
3470 bytes_read = q - (char *)buf;
3474 if (_pioinfo(fh)->lockinitflag)
3475 LeaveCriticalSection(&(_pioinfo(fh)->lock)); /* unlock file */
3480 #endif /* PERL_MSVCRT_READFIX */
3483 win32_read(int fd, void *buf, unsigned int cnt)
3485 #ifdef PERL_MSVCRT_READFIX
3486 return _fixed_read(fd, buf, cnt);
3488 return read(fd, buf, cnt);
3493 win32_write(int fd, const void *buf, unsigned int cnt)
3495 return write(fd, buf, cnt);
3499 win32_mkdir(const char *dir, int mode)
3503 WCHAR wBuffer[MAX_PATH+1];
3504 A2WHELPER(dir, wBuffer, sizeof(wBuffer));
3505 return _wmkdir(PerlDir_mapW(wBuffer));
3507 return mkdir(PerlDir_mapA(dir)); /* just ignore mode */
3511 win32_rmdir(const char *dir)
3515 WCHAR wBuffer[MAX_PATH+1];
3516 A2WHELPER(dir, wBuffer, sizeof(wBuffer));
3517 return _wrmdir(PerlDir_mapW(wBuffer));
3519 return rmdir(PerlDir_mapA(dir));
3523 win32_chdir(const char *dir)
3531 WCHAR wBuffer[MAX_PATH+1];
3532 A2WHELPER(dir, wBuffer, sizeof(wBuffer));
3533 return _wchdir(wBuffer);
3539 win32_access(const char *path, int mode)
3543 WCHAR wBuffer[MAX_PATH+1];
3544 A2WHELPER(path, wBuffer, sizeof(wBuffer));
3545 return _waccess(PerlDir_mapW(wBuffer), mode);
3547 return access(PerlDir_mapA(path), mode);
3551 win32_chmod(const char *path, int mode)
3555 WCHAR wBuffer[MAX_PATH+1];
3556 A2WHELPER(path, wBuffer, sizeof(wBuffer));
3557 return _wchmod(PerlDir_mapW(wBuffer), mode);
3559 return chmod(PerlDir_mapA(path), mode);
3564 create_command_line(char *cname, STRLEN clen, const char * const *args)
3571 bool bat_file = FALSE;
3572 bool cmd_shell = FALSE;
3573 bool dumb_shell = FALSE;
3574 bool extra_quotes = FALSE;
3575 bool quote_next = FALSE;
3578 cname = (char*)args[0];
3580 /* The NT cmd.exe shell has the following peculiarity that needs to be
3581 * worked around. It strips a leading and trailing dquote when any
3582 * of the following is true:
3583 * 1. the /S switch was used
3584 * 2. there are more than two dquotes
3585 * 3. there is a special character from this set: &<>()@^|
3586 * 4. no whitespace characters within the two dquotes
3587 * 5. string between two dquotes isn't an executable file
3588 * To work around this, we always add a leading and trailing dquote
3589 * to the string, if the first argument is either "cmd.exe" or "cmd",
3590 * and there were at least two or more arguments passed to cmd.exe
3591 * (not including switches).
3592 * XXX the above rules (from "cmd /?") don't seem to be applied
3593 * always, making for the convolutions below :-(
3597 clen = strlen(cname);
3600 && (stricmp(&cname[clen-4], ".bat") == 0
3601 || (IsWinNT() && stricmp(&cname[clen-4], ".cmd") == 0)))
3608 char *exe = strrchr(cname, '/');
3609 char *exe2 = strrchr(cname, '\\');
3616 if (stricmp(exe, "cmd.exe") == 0 || stricmp(exe, "cmd") == 0) {
3620 else if (stricmp(exe, "command.com") == 0
3621 || stricmp(exe, "command") == 0)
3628 DEBUG_p(PerlIO_printf(Perl_debug_log, "Args "));
3629 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3630 STRLEN curlen = strlen(arg);
3631 if (!(arg[0] == '"' && arg[curlen-1] == '"'))
3632 len += 2; /* assume quoting needed (worst case) */
3634 DEBUG_p(PerlIO_printf(Perl_debug_log, "[%s]",arg));
3636 DEBUG_p(PerlIO_printf(Perl_debug_log, "\n"));
3639 New(1310, cmd, len, char);
3642 if (bat_file && !IsWin95()) {
3644 extra_quotes = TRUE;
3647 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3649 STRLEN curlen = strlen(arg);
3651 /* we want to protect empty arguments and ones with spaces with
3652 * dquotes, but only if they aren't already there */
3657 else if (quote_next) {
3658 /* see if it really is multiple arguments pretending to
3659 * be one and force a set of quotes around it */
3660 if (*find_next_space(arg))
3663 else if (!(arg[0] == '"' && curlen > 1 && arg[curlen-1] == '"')) {
3665 while (i < curlen) {
3666 if (isSPACE(arg[i])) {
3669 else if (arg[i] == '"') {
3693 && *arg == '/' /* see if arg is "/c", "/x/c", "/x/d/c" etc. */
3694 && stricmp(arg+curlen-2, "/c") == 0)
3696 /* is there a next argument? */
3697 if (args[index+1]) {
3698 /* are there two or more next arguments? */
3699 if (args[index+2]) {
3701 extra_quotes = TRUE;
3704 /* single argument, force quoting if it has spaces */
3720 qualified_path(const char *cmd)
3724 char *fullcmd, *curfullcmd;
3730 fullcmd = (char*)cmd;
3732 if (*fullcmd == '/' || *fullcmd == '\\')
3739 pathstr = PerlEnv_getenv("PATH");
3741 /* worst case: PATH is a single directory; we need additional space
3742 * to append "/", ".exe" and trailing "\0" */
3743 New(0, fullcmd, (pathstr ? strlen(pathstr) : 0) + cmdlen + 6, char);
3744 curfullcmd = fullcmd;
3749 /* start by appending the name to the current prefix */
3750 strcpy(curfullcmd, cmd);
3751 curfullcmd += cmdlen;
3753 /* if it doesn't end with '.', or has no extension, try adding
3754 * a trailing .exe first */
3755 if (cmd[cmdlen-1] != '.'
3756 && (cmdlen < 4 || cmd[cmdlen-4] != '.'))
3758 strcpy(curfullcmd, ".exe");
3759 res = GetFileAttributes(fullcmd);
3760 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3765 /* that failed, try the bare name */
3766 res = GetFileAttributes(fullcmd);
3767 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3770 /* quit if no other path exists, or if cmd already has path */
3771 if (!pathstr || !*pathstr || has_slash)
3774 /* skip leading semis */
3775 while (*pathstr == ';')
3778 /* build a new prefix from scratch */
3779 curfullcmd = fullcmd;
3780 while (*pathstr && *pathstr != ';') {
3781 if (*pathstr == '"') { /* foo;"baz;etc";bar */
3782 pathstr++; /* skip initial '"' */
3783 while (*pathstr && *pathstr != '"') {
3784 *curfullcmd++ = *pathstr++;
3787 pathstr++; /* skip trailing '"' */
3790 *curfullcmd++ = *pathstr++;
3794 pathstr++; /* skip trailing semi */
3795 if (curfullcmd > fullcmd /* append a dir separator */
3796 && curfullcmd[-1] != '/' && curfullcmd[-1] != '\\')
3798 *curfullcmd++ = '\\';
3806 /* The following are just place holders.
3807 * Some hosts may provide and environment that the OS is
3808 * not tracking, therefore, these host must provide that
3809 * environment and the current directory to CreateProcess
3813 win32_get_childenv(void)
3819 win32_free_childenv(void* d)
3824 win32_clearenv(void)
3826 char *envv = GetEnvironmentStrings();
3830 char *end = strchr(cur,'=');
3831 if (end && end != cur) {
3833 SetEnvironmentVariable(cur, NULL);
3835 cur = end + strlen(end+1)+2;
3837 else if ((len = strlen(cur)))
3840 FreeEnvironmentStrings(envv);
3844 win32_get_childdir(void)
3848 char szfilename[(MAX_PATH+1)*2];
3850 WCHAR wfilename[MAX_PATH+1];
3851 GetCurrentDirectoryW(MAX_PATH+1, wfilename);
3852 W2AHELPER(wfilename, szfilename, sizeof(szfilename));
3855 GetCurrentDirectoryA(MAX_PATH+1, szfilename);
3858 New(0, ptr, strlen(szfilename)+1, char);
3859 strcpy(ptr, szfilename);
3864 win32_free_childdir(char* d)
3871 /* XXX this needs to be made more compatible with the spawnvp()
3872 * provided by the various RTLs. In particular, searching for
3873 * *.{com,bat,cmd} files (as done by the RTLs) is unimplemented.
3874 * This doesn't significantly affect perl itself, because we
3875 * always invoke things using PERL5SHELL if a direct attempt to
3876 * spawn the executable fails.
3878 * XXX splitting and rejoining the commandline between do_aspawn()
3879 * and win32_spawnvp() could also be avoided.
3883 win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
3885 #ifdef USE_RTL_SPAWNVP
3886 return spawnvp(mode, cmdname, (char * const *)argv);
3893 STARTUPINFO StartupInfo;
3894 PROCESS_INFORMATION ProcessInformation;
3897 char *fullcmd = Nullch;
3898 char *cname = (char *)cmdname;
3902 clen = strlen(cname);
3903 /* if command name contains dquotes, must remove them */
3904 if (strchr(cname, '"')) {
3906 New(0,cname,clen+1,char);
3919 cmd = create_command_line(cname, clen, argv);
3921 env = PerlEnv_get_childenv();
3922 dir = PerlEnv_get_childdir();
3925 case P_NOWAIT: /* asynch + remember result */
3926 if (w32_num_children >= MAXIMUM_WAIT_OBJECTS) {
3931 /* Create a new process group so we can use GenerateConsoleCtrlEvent()
3934 create |= CREATE_NEW_PROCESS_GROUP;
3937 case P_WAIT: /* synchronous execution */
3939 default: /* invalid mode */
3944 memset(&StartupInfo,0,sizeof(StartupInfo));
3945 StartupInfo.cb = sizeof(StartupInfo);
3946 memset(&tbl,0,sizeof(tbl));
3947 PerlEnv_get_child_IO(&tbl);
3948 StartupInfo.dwFlags = tbl.dwFlags;
3949 StartupInfo.dwX = tbl.dwX;
3950 StartupInfo.dwY = tbl.dwY;
3951 StartupInfo.dwXSize = tbl.dwXSize;
3952 StartupInfo.dwYSize = tbl.dwYSize;
3953 StartupInfo.dwXCountChars = tbl.dwXCountChars;
3954 StartupInfo.dwYCountChars = tbl.dwYCountChars;
3955 StartupInfo.dwFillAttribute = tbl.dwFillAttribute;
3956 StartupInfo.wShowWindow = tbl.wShowWindow;
3957 StartupInfo.hStdInput = tbl.childStdIn;
3958 StartupInfo.hStdOutput = tbl.childStdOut;
3959 StartupInfo.hStdError = tbl.childStdErr;
3960 if (StartupInfo.hStdInput == INVALID_HANDLE_VALUE &&
3961 StartupInfo.hStdOutput == INVALID_HANDLE_VALUE &&
3962 StartupInfo.hStdError == INVALID_HANDLE_VALUE)
3964 create |= CREATE_NEW_CONSOLE;
3967 StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
3969 if (w32_use_showwindow) {
3970 StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
3971 StartupInfo.wShowWindow = w32_showwindow;
3974 DEBUG_p(PerlIO_printf(Perl_debug_log, "Spawning [%s] with [%s]\n",
3977 if (!CreateProcess(cname, /* search PATH to find executable */
3978 cmd, /* executable, and its arguments */
3979 NULL, /* process attributes */
3980 NULL, /* thread attributes */
3981 TRUE, /* inherit handles */
3982 create, /* creation flags */
3983 (LPVOID)env, /* inherit environment */
3984 dir, /* inherit cwd */
3986 &ProcessInformation))
3988 /* initial NULL argument to CreateProcess() does a PATH
3989 * search, but it always first looks in the directory
3990 * where the current process was started, which behavior
3991 * is undesirable for backward compatibility. So we
3992 * jump through our own hoops by picking out the path
3993 * we really want it to use. */
3995 fullcmd = qualified_path(cname);
3997 if (cname != cmdname)
4000 DEBUG_p(PerlIO_printf(Perl_debug_log,
4001 "Retrying [%s] with same args\n",
4011 if (mode == P_NOWAIT) {
4012 /* asynchronous spawn -- store handle, return PID */
4013 ret = (int)ProcessInformation.dwProcessId;
4014 if (IsWin95() && ret < 0)
4017 w32_child_handles[w32_num_children] = ProcessInformation.hProcess;
4018 w32_child_pids[w32_num_children] = (DWORD)ret;
4023 win32_msgwait(aTHX_ 1, &ProcessInformation.hProcess, INFINITE, NULL);
4024 /* FIXME: if msgwait returned due to message perhaps forward the
4025 "signal" to the process
4027 GetExitCodeProcess(ProcessInformation.hProcess, &status);
4029 CloseHandle(ProcessInformation.hProcess);
4032 CloseHandle(ProcessInformation.hThread);
4035 PerlEnv_free_childenv(env);
4036 PerlEnv_free_childdir(dir);
4038 if (cname != cmdname)
4045 win32_execv(const char *cmdname, const char *const *argv)
4049 /* if this is a pseudo-forked child, we just want to spawn
4050 * the new program, and return */
4052 return spawnv(P_WAIT, cmdname, (char *const *)argv);
4054 return execv(cmdname, (char *const *)argv);
4058 win32_execvp(const char *cmdname, const char *const *argv)
4062 /* if this is a pseudo-forked child, we just want to spawn
4063 * the new program, and return */
4064 if (w32_pseudo_id) {
4065 int status = win32_spawnvp(P_WAIT, cmdname, (const char *const *)argv);
4074 return execvp(cmdname, (char *const *)argv);
4078 win32_perror(const char *str)
4084 win32_setbuf(FILE *pf, char *buf)
4090 win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
4092 return setvbuf(pf, buf, type, size);
4096 win32_flushall(void)
4102 win32_fcloseall(void)
4108 win32_fgets(char *s, int n, FILE *pf)
4110 return fgets(s, n, pf);
4120 win32_fgetc(FILE *pf)
4126 win32_putc(int c, FILE *pf)
4132 win32_puts(const char *s)
4144 win32_putchar(int c)
4151 #ifndef USE_PERL_SBRK
4153 static char *committed = NULL; /* XXX threadead */
4154 static char *base = NULL; /* XXX threadead */
4155 static char *reserved = NULL; /* XXX threadead */
4156 static char *brk = NULL; /* XXX threadead */
4157 static DWORD pagesize = 0; /* XXX threadead */
4160 sbrk(ptrdiff_t need)
4165 GetSystemInfo(&info);
4166 /* Pretend page size is larger so we don't perpetually
4167 * call the OS to commit just one page ...
4169 pagesize = info.dwPageSize << 3;
4171 if (brk+need >= reserved)
4173 DWORD size = brk+need-reserved;
4175 char *prev_committed = NULL;
4176 if (committed && reserved && committed < reserved)
4178 /* Commit last of previous chunk cannot span allocations */
4179 addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
4182 /* Remember where we committed from in case we want to decommit later */
4183 prev_committed = committed;
4184 committed = reserved;
4187 /* Reserve some (more) space
4188 * Contiguous blocks give us greater efficiency, so reserve big blocks -
4189 * this is only address space not memory...
4190 * Note this is a little sneaky, 1st call passes NULL as reserved
4191 * so lets system choose where we start, subsequent calls pass
4192 * the old end address so ask for a contiguous block
4195 if (size < 64*1024*1024)
4196 size = 64*1024*1024;
4197 size = ((size + pagesize - 1) / pagesize) * pagesize;
4198 addr = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
4201 reserved = addr+size;
4211 /* The existing block could not be extended far enough, so decommit
4212 * anything that was just committed above and start anew */
4215 if (!VirtualFree(prev_committed,reserved-prev_committed,MEM_DECOMMIT))
4218 reserved = base = committed = brk = NULL;
4229 if (brk > committed)
4231 DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
4233 if (committed+size > reserved)
4234 size = reserved-committed;
4235 addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
4248 win32_malloc(size_t size)
4250 return malloc(size);
4254 win32_calloc(size_t numitems, size_t size)
4256 return calloc(numitems,size);
4260 win32_realloc(void *block, size_t size)
4262 return realloc(block,size);
4266 win32_free(void *block)
4273 win32_open_osfhandle(intptr_t handle, int flags)
4275 #ifdef USE_FIXED_OSFHANDLE
4277 return my_open_osfhandle(handle, flags);
4279 return _open_osfhandle(handle, flags);
4283 win32_get_osfhandle(int fd)
4285 return (intptr_t)_get_osfhandle(fd);
4289 win32_fdupopen(FILE *pf)
4294 int fileno = win32_dup(win32_fileno(pf));
4296 /* open the file in the same mode */
4298 if((pf)->flags & _F_READ) {
4302 else if((pf)->flags & _F_WRIT) {
4306 else if((pf)->flags & _F_RDWR) {
4312 if((pf)->_flag & _IOREAD) {
4316 else if((pf)->_flag & _IOWRT) {
4320 else if((pf)->_flag & _IORW) {
4327 /* it appears that the binmode is attached to the
4328 * file descriptor so binmode files will be handled
4331 pfdup = win32_fdopen(fileno, mode);
4333 /* move the file pointer to the same position */
4334 if (!fgetpos(pf, &pos)) {
4335 fsetpos(pfdup, &pos);
4341 win32_dynaload(const char* filename)
4345 char buf[MAX_PATH+1];
4348 /* LoadLibrary() doesn't recognize forward slashes correctly,
4349 * so turn 'em back. */
4350 first = strchr(filename, '/');
4352 STRLEN len = strlen(filename);
4353 if (len <= MAX_PATH) {
4354 strcpy(buf, filename);
4355 filename = &buf[first - filename];
4357 if (*filename == '/')
4358 *(char*)filename = '\\';
4365 WCHAR wfilename[MAX_PATH+1];
4366 A2WHELPER(filename, wfilename, sizeof(wfilename));
4367 hModule = LoadLibraryExW(PerlDir_mapW(wfilename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
4370 hModule = LoadLibraryExA(PerlDir_mapA(filename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
4380 XS(w32_SetChildShowWindow)
4383 BOOL use_showwindow = w32_use_showwindow;
4384 /* use "unsigned short" because Perl has redefined "WORD" */
4385 unsigned short showwindow = w32_showwindow;
4388 Perl_croak(aTHX_ "usage: Win32::SetChildShowWindow($showwindow)");
4390 if (items == 0 || !SvOK(ST(0)))
4391 w32_use_showwindow = FALSE;
4393 w32_use_showwindow = TRUE;
4394 w32_showwindow = (unsigned short)SvIV(ST(0));
4399 ST(0) = sv_2mortal(newSViv(showwindow));
4401 ST(0) = &PL_sv_undef;
4409 /* Make the host for current directory */
4410 char* ptr = PerlEnv_get_childdir();
4413 * then it worked, set PV valid,
4414 * else return 'undef'
4417 SV *sv = sv_newmortal();
4419 PerlEnv_free_childdir(ptr);
4421 #ifndef INCOMPLETE_TAINTS
4438 Perl_croak(aTHX_ "usage: Win32::SetCurrentDirectory($cwd)");
4439 if (!PerlDir_chdir(SvPV_nolen(ST(0))))
4446 XS(w32_GetNextAvailDrive)
4450 char root[] = "_:\\";
4455 if (GetDriveType(root) == 1) {
4464 XS(w32_GetLastError)
4468 XSRETURN_IV(GetLastError());
4472 XS(w32_SetLastError)
4476 Perl_croak(aTHX_ "usage: Win32::SetLastError($error)");
4477 SetLastError(SvIV(ST(0)));
4485 char *name = w32_getlogin_buffer;
4486 DWORD size = sizeof(w32_getlogin_buffer);
4488 if (GetUserName(name,&size)) {
4489 /* size includes NULL */
4490 ST(0) = sv_2mortal(newSVpvn(name,size-1));
4500 char name[MAX_COMPUTERNAME_LENGTH+1];
4501 DWORD size = sizeof(name);
4503 if (GetComputerName(name,&size)) {
4504 /* size does NOT include NULL :-( */
4505 ST(0) = sv_2mortal(newSVpvn(name,size));
4516 HINSTANCE hNetApi32 = LoadLibrary("netapi32.dll");
4517 DWORD (__stdcall *pfnNetApiBufferFree)(LPVOID Buffer);
4518 DWORD (__stdcall *pfnNetWkstaGetInfo)(LPWSTR servername, DWORD level,
4522 pfnNetApiBufferFree = (DWORD (__stdcall *)(void *))
4523 GetProcAddress(hNetApi32, "NetApiBufferFree");
4524 pfnNetWkstaGetInfo = (DWORD (__stdcall *)(LPWSTR, DWORD, void *))
4525 GetProcAddress(hNetApi32, "NetWkstaGetInfo");
4528 if (hNetApi32 && pfnNetWkstaGetInfo && pfnNetApiBufferFree) {
4529 /* this way is more reliable, in case user has a local account. */
4531 DWORD dnamelen = sizeof(dname);
4533 DWORD wki100_platform_id;
4534 LPWSTR wki100_computername;
4535 LPWSTR wki100_langroup;
4536 DWORD wki100_ver_major;
4537 DWORD wki100_ver_minor;
4539 /* NERR_Success *is* 0*/
4540 if (0 == pfnNetWkstaGetInfo(NULL, 100, &pwi)) {
4541 if (pwi->wki100_langroup && *(pwi->wki100_langroup)) {
4542 WideCharToMultiByte(CP_ACP, 0, pwi->wki100_langroup,
4543 -1, (LPSTR)dname, dnamelen, NULL, NULL);
4546 WideCharToMultiByte(CP_ACP, 0, pwi->wki100_computername,
4547 -1, (LPSTR)dname, dnamelen, NULL, NULL);
4549 pfnNetApiBufferFree(pwi);
4550 FreeLibrary(hNetApi32);
4553 FreeLibrary(hNetApi32);
4556 /* Win95 doesn't have NetWksta*(), so do it the old way */
4558 DWORD size = sizeof(name);
4560 FreeLibrary(hNetApi32);
4561 if (GetUserName(name,&size)) {
4562 char sid[ONE_K_BUFSIZE];
4563 DWORD sidlen = sizeof(sid);
4565 DWORD dnamelen = sizeof(dname);
4567 if (LookupAccountName(NULL, name, (PSID)&sid, &sidlen,
4568 dname, &dnamelen, &snu)) {
4569 XSRETURN_PV(dname); /* all that for this */
4581 DWORD flags, filecomplen;
4582 if (GetVolumeInformation(NULL, NULL, 0, NULL, &filecomplen,
4583 &flags, fsname, sizeof(fsname))) {
4584 if (GIMME_V == G_ARRAY) {
4585 XPUSHs(sv_2mortal(newSVpvn(fsname,strlen(fsname))));
4586 XPUSHs(sv_2mortal(newSViv(flags)));
4587 XPUSHs(sv_2mortal(newSViv(filecomplen)));
4592 XSRETURN_PV(fsname);
4598 XS(w32_GetOSVersion)
4601 /* Use explicit struct definition because wSuiteMask and
4602 * wProductType are not defined in the VC++ 6.0 headers.
4603 * WORD type has been replaced by unsigned short because
4604 * WORD is already used by Perl itself.
4607 DWORD dwOSVersionInfoSize;
4608 DWORD dwMajorVersion;
4609 DWORD dwMinorVersion;
4610 DWORD dwBuildNumber;
4612 CHAR szCSDVersion[128];
4613 unsigned short wServicePackMajor;
4614 unsigned short wServicePackMinor;
4615 unsigned short wSuiteMask;
4623 DWORD dwOSVersionInfoSize;
4624 DWORD dwMajorVersion;
4625 DWORD dwMinorVersion;
4626 DWORD dwBuildNumber;
4628 WCHAR szCSDVersion[128];
4629 unsigned short wServicePackMajor;
4630 unsigned short wServicePackMinor;
4631 unsigned short wSuiteMask;
4635 char szCSDVersion[sizeof(osverw.szCSDVersion)];
4636 osverw.dwOSVersionInfoSize = sizeof(osverw);
4637 if (!GetVersionExW((OSVERSIONINFOW*)&osverw)) {
4639 osverw.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
4640 if (!GetVersionExW((OSVERSIONINFOW*)&osverw)) {
4644 if (GIMME_V == G_SCALAR) {
4645 XSRETURN_IV(osverw.dwPlatformId);
4647 W2AHELPER(osverw.szCSDVersion, szCSDVersion, sizeof(szCSDVersion));
4648 XPUSHs(newSVpvn(szCSDVersion, strlen(szCSDVersion)));
4649 osver.dwMajorVersion = osverw.dwMajorVersion;
4650 osver.dwMinorVersion = osverw.dwMinorVersion;
4651 osver.dwBuildNumber = osverw.dwBuildNumber;
4652 osver.dwPlatformId = osverw.dwPlatformId;
4653 osver.wServicePackMajor = osverw.wServicePackMajor;
4654 osver.wServicePackMinor = osverw.wServicePackMinor;
4655 osver.wSuiteMask = osverw.wSuiteMask;
4656 osver.wProductType = osverw.wProductType;
4659 osver.dwOSVersionInfoSize = sizeof(osver);
4660 if (!GetVersionExA((OSVERSIONINFOA*)&osver)) {
4662 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
4663 if (!GetVersionExA((OSVERSIONINFOA*)&osver)) {
4667 if (GIMME_V == G_SCALAR) {
4668 XSRETURN_IV(osver.dwPlatformId);
4670 XPUSHs(newSVpvn(osver.szCSDVersion, strlen(osver.szCSDVersion)));
4672 XPUSHs(newSViv(osver.dwMajorVersion));
4673 XPUSHs(newSViv(osver.dwMinorVersion));
4674 XPUSHs(newSViv(osver.dwBuildNumber));
4675 XPUSHs(newSViv(osver.dwPlatformId));
4677 XPUSHs(newSViv(osver.wServicePackMajor));
4678 XPUSHs(newSViv(osver.wServicePackMinor));
4679 XPUSHs(newSViv(osver.wSuiteMask));
4680 XPUSHs(newSViv(osver.wProductType));
4690 XSRETURN_IV(IsWinNT());
4698 XSRETURN_IV(IsWin95());
4702 XS(w32_FormatMessage)
4706 char msgbuf[ONE_K_BUFSIZE];
4709 Perl_croak(aTHX_ "usage: Win32::FormatMessage($errno)");
4712 WCHAR wmsgbuf[ONE_K_BUFSIZE];
4713 if (FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
4714 &source, SvIV(ST(0)), 0,
4715 wmsgbuf, ONE_K_BUFSIZE-1, NULL))
4717 W2AHELPER(wmsgbuf, msgbuf, sizeof(msgbuf));
4718 XSRETURN_PV(msgbuf);
4722 if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,
4723 &source, SvIV(ST(0)), 0,
4724 msgbuf, sizeof(msgbuf)-1, NULL))
4725 XSRETURN_PV(msgbuf);
4738 PROCESS_INFORMATION stProcInfo;
4739 STARTUPINFO stStartInfo;
4740 BOOL bSuccess = FALSE;
4743 Perl_croak(aTHX_ "usage: Win32::Spawn($cmdName, $args, $PID)");
4745 cmd = SvPV_nolen(ST(0));
4746 args = SvPV_nolen(ST(1));
4748 env = PerlEnv_get_childenv();
4749 dir = PerlEnv_get_childdir();
4751 memset(&stStartInfo, 0, sizeof(stStartInfo)); /* Clear the block */
4752 stStartInfo.cb = sizeof(stStartInfo); /* Set the structure size */
4753 stStartInfo.dwFlags = STARTF_USESHOWWINDOW; /* Enable wShowWindow control */
4754 stStartInfo.wShowWindow = SW_SHOWMINNOACTIVE; /* Start min (normal) */
4757 cmd, /* Image path */
4758 args, /* Arguments for command line */
4759 NULL, /* Default process security */
4760 NULL, /* Default thread security */
4761 FALSE, /* Must be TRUE to use std handles */
4762 NORMAL_PRIORITY_CLASS, /* No special scheduling */
4763 env, /* Inherit our environment block */
4764 dir, /* Inherit our currrent directory */
4765 &stStartInfo, /* -> Startup info */
4766 &stProcInfo)) /* <- Process info (if OK) */
4768 int pid = (int)stProcInfo.dwProcessId;
4769 if (IsWin95() && pid < 0)
4771 sv_setiv(ST(2), pid);
4772 CloseHandle(stProcInfo.hThread);/* library source code does this. */
4775 PerlEnv_free_childenv(env);
4776 PerlEnv_free_childdir(dir);
4777 XSRETURN_IV(bSuccess);
4781 XS(w32_GetTickCount)
4784 DWORD msec = GetTickCount();
4792 XS(w32_GetShortPathName)
4799 Perl_croak(aTHX_ "usage: Win32::GetShortPathName($longPathName)");
4801 shortpath = sv_mortalcopy(ST(0));
4802 SvUPGRADE(shortpath, SVt_PV);
4803 if (!SvPVX(shortpath) || !SvLEN(shortpath))
4806 /* src == target is allowed */
4808 len = GetShortPathName(SvPVX(shortpath),
4811 } while (len >= SvLEN(shortpath) && sv_grow(shortpath,len+1));
4813 SvCUR_set(shortpath,len);
4814 *SvEND(shortpath) = '\0';
4822 XS(w32_GetFullPathName)
4829 STRLEN filename_len;
4833 Perl_croak(aTHX_ "usage: Win32::GetFullPathName($filename)");
4836 filename_p = SvPV(filename, filename_len);
4837 fullpath = sv_2mortal(newSVpvn(filename_p, filename_len));
4838 if (!SvPVX(fullpath) || !SvLEN(fullpath))
4842 len = GetFullPathName(SvPVX(filename),
4846 } while (len >= SvLEN(fullpath) && sv_grow(fullpath,len+1));
4848 if (GIMME_V == G_ARRAY) {
4851 XST_mPV(1,filepart);
4852 len = filepart - SvPVX(fullpath);
4859 SvCUR_set(fullpath,len);
4860 *SvEND(fullpath) = '\0';
4868 XS(w32_GetLongPathName)
4872 char tmpbuf[MAX_PATH+1];
4877 Perl_croak(aTHX_ "usage: Win32::GetLongPathName($pathname)");
4880 pathstr = SvPV(path,len);
4881 strcpy(tmpbuf, pathstr);
4882 pathstr = win32_longpath(tmpbuf);
4884 ST(0) = sv_2mortal(newSVpvn(pathstr, strlen(pathstr)));
4895 Perl_croak(aTHX_ "usage: Win32::Sleep($milliseconds)");
4906 Perl_croak(aTHX_ "usage: Win32::CopyFile($from, $to, $overwrite)");
4908 WCHAR wSourceFile[MAX_PATH+1];
4909 WCHAR wDestFile[MAX_PATH+1];
4910 A2WHELPER(SvPV_nolen(ST(0)), wSourceFile, sizeof(wSourceFile));
4911 wcscpy(wSourceFile, PerlDir_mapW(wSourceFile));
4912 A2WHELPER(SvPV_nolen(ST(1)), wDestFile, sizeof(wDestFile));
4913 bResult = CopyFileW(wSourceFile, PerlDir_mapW(wDestFile), !SvTRUE(ST(2)));
4916 char szSourceFile[MAX_PATH+1];
4917 strcpy(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(0))));
4918 bResult = CopyFileA(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(1))), !SvTRUE(ST(2)));
4927 Perl_init_os_extras(void)
4930 char *file = __FILE__;
4933 /* these names are Activeware compatible */
4934 newXS("Win32::GetCwd", w32_GetCwd, file);
4935 newXS("Win32::SetCwd", w32_SetCwd, file);
4936 newXS("Win32::GetNextAvailDrive", w32_GetNextAvailDrive, file);
4937 newXS("Win32::GetLastError", w32_GetLastError, file);
4938 newXS("Win32::SetLastError", w32_SetLastError, file);
4939 newXS("Win32::LoginName", w32_LoginName, file);
4940 newXS("Win32::NodeName", w32_NodeName, file);
4941 newXS("Win32::DomainName", w32_DomainName, file);
4942 newXS("Win32::FsType", w32_FsType, file);
4943 newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
4944 newXS("Win32::IsWinNT", w32_IsWinNT, file);
4945 newXS("Win32::IsWin95", w32_IsWin95, file);
4946 newXS("Win32::FormatMessage", w32_FormatMessage, file);
4947 newXS("Win32::Spawn", w32_Spawn, file);
4948 newXS("Win32::GetTickCount", w32_GetTickCount, file);
4949 newXS("Win32::GetShortPathName", w32_GetShortPathName, file);
4950 newXS("Win32::GetFullPathName", w32_GetFullPathName, file);
4951 newXS("Win32::GetLongPathName", w32_GetLongPathName, file);
4952 newXS("Win32::CopyFile", w32_CopyFile, file);
4953 newXS("Win32::Sleep", w32_Sleep, file);
4954 newXS("Win32::SetChildShowWindow", w32_SetChildShowWindow, file);
4956 /* XXX Bloat Alert! The following Activeware preloads really
4957 * ought to be part of Win32::Sys::*, so they're not included
4960 /* LookupAccountName
4962 * InitiateSystemShutdown
4963 * AbortSystemShutdown
4964 * ExpandEnvrironmentStrings
4969 win32_signal_context(void)
4974 my_perl = PL_curinterp;
4975 PERL_SET_THX(my_perl);
4979 return PL_curinterp;
4985 win32_ctrlhandler(DWORD dwCtrlType)
4988 dTHXa(PERL_GET_SIG_CONTEXT);
4994 switch(dwCtrlType) {
4995 case CTRL_CLOSE_EVENT:
4996 /* A signal that the system sends to all processes attached to a console when
4997 the user closes the console (either by choosing the Close command from the
4998 console window's System menu, or by choosing the End Task command from the
5001 if (do_raise(aTHX_ 1)) /* SIGHUP */
5002 sig_terminate(aTHX_ 1);
5006 /* A CTRL+c signal was received */
5007 if (do_raise(aTHX_ SIGINT))
5008 sig_terminate(aTHX_ SIGINT);
5011 case CTRL_BREAK_EVENT:
5012 /* A CTRL+BREAK signal was received */
5013 if (do_raise(aTHX_ SIGBREAK))
5014 sig_terminate(aTHX_ SIGBREAK);
5017 case CTRL_LOGOFF_EVENT:
5018 /* A signal that the system sends to all console processes when a user is logging
5019 off. This signal does not indicate which user is logging off, so no
5020 assumptions can be made.
5023 case CTRL_SHUTDOWN_EVENT:
5024 /* A signal that the system sends to all console processes when the system is
5027 if (do_raise(aTHX_ SIGTERM))
5028 sig_terminate(aTHX_ SIGTERM);
5038 Perl_win32_init(int *argcp, char ***argvp)
5040 /* Disable floating point errors, Perl will trap the ones we
5041 * care about. VC++ RTL defaults to switching these off
5042 * already, but the Borland RTL doesn't. Since we don't
5043 * want to be at the vendor's whim on the default, we set
5044 * it explicitly here.
5046 #if !defined(_ALPHA_) && !defined(__GNUC__)
5047 _control87(MCW_EM, MCW_EM);
5053 Perl_win32_term(void)
5060 win32_get_child_IO(child_IO_table* ptbl)
5062 ptbl->childStdIn = GetStdHandle(STD_INPUT_HANDLE);
5063 ptbl->childStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
5064 ptbl->childStdErr = GetStdHandle(STD_ERROR_HANDLE);
5068 win32_signal(int sig, Sighandler_t subcode)
5071 if (sig < SIG_SIZE) {
5072 int save_errno = errno;
5073 Sighandler_t result = signal(sig, subcode);
5074 if (result == SIG_ERR) {
5075 result = w32_sighandler[sig];
5078 w32_sighandler[sig] = subcode;
5088 #ifdef HAVE_INTERP_INTERN
5092 win32_csighandler(int sig)
5095 dTHXa(PERL_GET_SIG_CONTEXT);
5096 Perl_warn(aTHX_ "Got signal %d",sig);
5102 Perl_sys_intern_init(pTHX)
5105 w32_perlshell_tokens = Nullch;
5106 w32_perlshell_vec = (char**)NULL;
5107 w32_perlshell_items = 0;
5108 w32_fdpid = newAV();
5109 New(1313, w32_children, 1, child_tab);
5110 w32_num_children = 0;
5111 # ifdef USE_ITHREADS
5113 New(1313, w32_pseudo_children, 1, child_tab);
5114 w32_num_pseudo_children = 0;
5118 for (i=0; i < SIG_SIZE; i++) {
5119 w32_sighandler[i] = SIG_DFL;
5122 if (my_perl == PL_curinterp) {
5126 /* Force C runtime signal stuff to set its console handler */
5127 signal(SIGINT,&win32_csighandler);
5128 signal(SIGBREAK,&win32_csighandler);
5129 /* Push our handler on top */
5130 SetConsoleCtrlHandler(win32_ctrlhandler,TRUE);
5135 Perl_sys_intern_clear(pTHX)
5137 Safefree(w32_perlshell_tokens);
5138 Safefree(w32_perlshell_vec);
5139 /* NOTE: w32_fdpid is freed by sv_clean_all() */
5140 Safefree(w32_children);
5142 KillTimer(NULL,w32_timerid);
5145 # ifdef MULTIPLICITY
5146 if (my_perl == PL_curinterp) {
5150 SetConsoleCtrlHandler(win32_ctrlhandler,FALSE);
5152 # ifdef USE_ITHREADS
5153 Safefree(w32_pseudo_children);
5157 # ifdef USE_ITHREADS
5160 Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
5162 dst->perlshell_tokens = Nullch;
5163 dst->perlshell_vec = (char**)NULL;
5164 dst->perlshell_items = 0;
5165 dst->fdpid = newAV();
5166 Newz(1313, dst->children, 1, child_tab);
5168 Newz(1313, dst->pseudo_children, 1, child_tab);
5170 dst->poll_count = 0;
5171 Copy(src->sigtable,dst->sigtable,SIG_SIZE,Sighandler_t);
5173 # endif /* USE_ITHREADS */
5174 #endif /* HAVE_INTERP_INTERN */
5177 win32_free_argvw(pTHX_ void *ptr)
5179 char** argv = (char**)ptr;
5187 win32_argv2utf8(int argc, char** argv)
5192 LPWSTR* lpwStr = CommandLineToArgvW(GetCommandLineW(), &wargc);
5193 if (lpwStr && argc) {
5195 length = WideCharToMultiByte(CP_UTF8, 0, lpwStr[--wargc], -1, NULL, 0, NULL, NULL);
5196 Newz(0, psz, length, char);
5197 WideCharToMultiByte(CP_UTF8, 0, lpwStr[wargc], -1, psz, length, NULL, NULL);
5200 call_atexit(win32_free_argvw, argv);
5202 GlobalFree((HGLOBAL)lpwStr);