3 * (c) 1995 Microsoft Corporation. All rights reserved.
4 * Developed by hip communications inc., http://info.hip.com/info/
5 * Portions (c) 1993 Intergraph Corporation. All rights reserved.
7 * You may distribute under the terms of either the GNU General Public
8 * License or the Artistic License, as specified in the README file.
10 #define PERLIO_NOT_STDIO 0
11 #define WIN32_LEAN_AND_MEAN
12 #define WIN32IO_IS_STDIO
19 # define HWND_MESSAGE ((HWND)-3)
21 /* GCC-2.95.2/Mingw32-1.1 forgot the WINAPI on CommandLineToArgvW() */
22 #if defined(__MINGW32__) && (__MINGW32_MAJOR_VERSION==1)
23 # include <shellapi.h>
25 LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCommandLine, int * pNumArgs);
31 /* #include "config.h" */
33 #if !defined(PERLIO_IS_STDIO) && !defined(USE_SFIO)
42 #define PERL_NO_GET_CONTEXT
48 /* assert.h conflicts with #define of assert in perl.h */
55 #if defined(_MSC_VER) || defined(__MINGW32__)
56 #include <sys/utime.h>
61 /* Mingw32 defaults to globing command line
62 * So we turn it off like this:
67 #if defined(__MINGW32__) && (__MINGW32_MAJOR_VERSION==1)
68 /* Mingw32-1.1 is missing some prototypes */
69 FILE * _wfopen(LPCWSTR wszFileName, LPCWSTR wszMode);
70 FILE * _wfdopen(int nFd, LPCWSTR wszMode);
71 FILE * _freopen(LPCWSTR wszFileName, LPCWSTR wszMode, FILE * pOldStream);
76 #if defined(__BORLANDC__)
78 # define _utimbuf utimbuf
83 #define EXECF_SPAWN_NOWAIT 3
85 #if defined(PERL_IMPLICIT_SYS)
86 # undef win32_get_privlib
87 # define win32_get_privlib g_win32_get_privlib
88 # undef win32_get_sitelib
89 # define win32_get_sitelib g_win32_get_sitelib
90 # undef win32_get_vendorlib
91 # define win32_get_vendorlib g_win32_get_vendorlib
93 # define getlogin g_getlogin
96 static void get_shell(void);
97 static long tokenize(const char *str, char **dest, char ***destv);
98 static int do_spawn2(pTHX_ const char *cmd, int exectype);
99 static BOOL has_shell_metachars(const char *ptr);
100 static long filetime_to_clock(PFILETIME ft);
101 static BOOL filetime_from_time(PFILETIME ft, time_t t);
102 static char * get_emd_part(SV **leading, char *trailing, ...);
103 static void remove_dead_process(long deceased);
104 static long find_pid(int pid);
105 static char * qualified_path(const char *cmd);
106 static char * win32_get_xlib(const char *pl, const char *xlib,
107 const char *libname);
110 static void remove_dead_pseudo_process(long child);
111 static long find_pseudo_pid(int pid);
115 HANDLE w32_perldll_handle = INVALID_HANDLE_VALUE;
116 char w32_module_name[MAX_PATH+1];
119 static OSVERSIONINFO g_osver = {0, 0, 0, 0, 0, ""};
121 #define ONE_K_BUFSIZE 1024
124 /* Silence STDERR grumblings from Borland's math library. */
126 _matherr(struct _exception *a)
136 return (g_osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
142 return (g_osver.dwPlatformId == VER_PLATFORM_WIN32_NT);
146 set_w32_module_name(void)
149 GetModuleFileName((HMODULE)((w32_perldll_handle == INVALID_HANDLE_VALUE)
150 ? GetModuleHandle(NULL)
151 : w32_perldll_handle),
152 w32_module_name, sizeof(w32_module_name));
154 /* remove \\?\ prefix */
155 if (memcmp(w32_module_name, "\\\\?\\", 4) == 0)
156 memmove(w32_module_name, w32_module_name+4, strlen(w32_module_name+4)+1);
158 /* try to get full path to binary (which may be mangled when perl is
159 * run from a 16-bit app) */
160 /*PerlIO_printf(Perl_debug_log, "Before %s\n", w32_module_name);*/
161 (void)win32_longpath(w32_module_name);
162 /*PerlIO_printf(Perl_debug_log, "After %s\n", w32_module_name);*/
164 /* normalize to forward slashes */
165 ptr = w32_module_name;
173 /* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
175 get_regstr_from(HKEY hkey, const char *valuename, SV **svp)
177 /* Retrieve a REG_SZ or REG_EXPAND_SZ from the registry */
180 const char *subkey = "Software\\Perl";
184 retval = RegOpenKeyEx(hkey, subkey, 0, KEY_READ, &handle);
185 if (retval == ERROR_SUCCESS) {
187 retval = RegQueryValueEx(handle, valuename, 0, &type, NULL, &datalen);
188 if (retval == ERROR_SUCCESS
189 && (type == REG_SZ || type == REG_EXPAND_SZ))
193 *svp = sv_2mortal(newSVpvn("",0));
194 SvGROW(*svp, datalen);
195 retval = RegQueryValueEx(handle, valuename, 0, NULL,
196 (PBYTE)SvPVX(*svp), &datalen);
197 if (retval == ERROR_SUCCESS) {
199 SvCUR_set(*svp,datalen-1);
207 /* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
209 get_regstr(const char *valuename, SV **svp)
211 char *str = get_regstr_from(HKEY_CURRENT_USER, valuename, svp);
213 str = get_regstr_from(HKEY_LOCAL_MACHINE, valuename, svp);
217 /* *prev_pathp (if non-NULL) is expected to be POK (valid allocated SvPVX(sv)) */
219 get_emd_part(SV **prev_pathp, char *trailing_path, ...)
223 char mod_name[MAX_PATH+1];
229 va_start(ap, trailing_path);
230 strip = va_arg(ap, char *);
232 sprintf(base, "%d.%d", (int)PERL_REVISION, (int)PERL_VERSION);
233 baselen = strlen(base);
235 if (!*w32_module_name) {
236 set_w32_module_name();
238 strcpy(mod_name, w32_module_name);
239 ptr = strrchr(mod_name, '/');
240 while (ptr && strip) {
241 /* look for directories to skip back */
244 ptr = strrchr(mod_name, '/');
245 /* avoid stripping component if there is no slash,
246 * or it doesn't match ... */
247 if (!ptr || stricmp(ptr+1, strip) != 0) {
248 /* ... but not if component matches m|5\.$patchlevel.*| */
249 if (!ptr || !(*strip == '5' && *(ptr+1) == '5'
250 && strncmp(strip, base, baselen) == 0
251 && strncmp(ptr+1, base, baselen) == 0))
257 strip = va_arg(ap, char *);
265 strcpy(++ptr, trailing_path);
267 /* only add directory if it exists */
268 if (GetFileAttributes(mod_name) != (DWORD) -1) {
269 /* directory exists */
272 *prev_pathp = sv_2mortal(newSVpvn("",0));
273 else if (SvPVX(*prev_pathp))
274 sv_catpvn(*prev_pathp, ";", 1);
275 sv_catpv(*prev_pathp, mod_name);
276 return SvPVX(*prev_pathp);
283 win32_get_privlib(const char *pl)
286 char *stdlib = "lib";
287 char buffer[MAX_PATH+1];
290 /* $stdlib = $HKCU{"lib-$]"} || $HKLM{"lib-$]"} || $HKCU{"lib"} || $HKLM{"lib"} || ""; */
291 sprintf(buffer, "%s-%s", stdlib, pl);
292 if (!get_regstr(buffer, &sv))
293 (void)get_regstr(stdlib, &sv);
295 /* $stdlib .= ";$EMD/../../lib" */
296 return get_emd_part(&sv, stdlib, ARCHNAME, "bin", Nullch);
300 win32_get_xlib(const char *pl, const char *xlib, const char *libname)
304 char pathstr[MAX_PATH+1];
308 /* $HKCU{"$xlib-$]"} || $HKLM{"$xlib-$]"} . ---; */
309 sprintf(regstr, "%s-%s", xlib, pl);
310 (void)get_regstr(regstr, &sv1);
313 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/$]/lib"; */
314 sprintf(pathstr, "%s/%s/lib", libname, pl);
315 (void)get_emd_part(&sv1, pathstr, ARCHNAME, "bin", pl, Nullch);
317 /* $HKCU{$xlib} || $HKLM{$xlib} . ---; */
318 (void)get_regstr(xlib, &sv2);
321 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/lib"; */
322 sprintf(pathstr, "%s/lib", libname);
323 (void)get_emd_part(&sv2, pathstr, ARCHNAME, "bin", pl, Nullch);
332 sv_catpvn(sv1, ";", 1);
339 win32_get_sitelib(const char *pl)
341 return win32_get_xlib(pl, "sitelib", "site");
344 #ifndef PERL_VENDORLIB_NAME
345 # define PERL_VENDORLIB_NAME "vendor"
349 win32_get_vendorlib(const char *pl)
351 return win32_get_xlib(pl, "vendorlib", PERL_VENDORLIB_NAME);
355 has_shell_metachars(const char *ptr)
361 * Scan string looking for redirection (< or >) or pipe
362 * characters (|) that are not in a quoted string.
363 * Shell variable interpolation (%VAR%) can also happen inside strings.
395 #if !defined(PERL_IMPLICIT_SYS)
396 /* since the current process environment is being updated in util.c
397 * the library functions will get the correct environment
400 Perl_my_popen(pTHX_ const char *cmd, const char *mode)
403 #define fixcmd(x) { \
404 char *pspace = strchr((x),' '); \
407 while (p < pspace) { \
418 PERL_FLUSHALL_FOR_CHILD;
419 return win32_popen(cmd, mode);
423 Perl_my_pclose(pTHX_ PerlIO *fp)
425 return win32_pclose(fp);
429 DllExport unsigned long
432 return (unsigned long)g_osver.dwPlatformId;
442 return -((int)w32_pseudo_id);
445 /* Windows 9x appears to always reports a pid for threads and processes
446 * that has the high bit set. So we treat the lower 31 bits as the
447 * "real" PID for Perl's purposes. */
448 if (IsWin95() && pid < 0)
453 /* Tokenize a string. Words are null-separated, and the list
454 * ends with a doubled null. Any character (except null and
455 * including backslash) may be escaped by preceding it with a
456 * backslash (the backslash will be stripped).
457 * Returns number of words in result buffer.
460 tokenize(const char *str, char **dest, char ***destv)
462 char *retstart = Nullch;
463 char **retvstart = 0;
467 int slen = strlen(str);
469 register char **retv;
470 Newx(ret, slen+2, char);
471 Newx(retv, (slen+3)/2, char*);
479 if (*ret == '\\' && *str)
481 else if (*ret == ' ') {
497 retvstart[items] = Nullch;
510 if (!w32_perlshell_tokens) {
511 /* we don't use COMSPEC here for two reasons:
512 * 1. the same reason perl on UNIX doesn't use SHELL--rampant and
513 * uncontrolled unportability of the ensuing scripts.
514 * 2. PERL5SHELL could be set to a shell that may not be fit for
515 * interactive use (which is what most programs look in COMSPEC
518 const char* defaultshell = (IsWinNT()
519 ? "cmd.exe /x/d/c" : "command.com /c");
520 const char *usershell = PerlEnv_getenv("PERL5SHELL");
521 w32_perlshell_items = tokenize(usershell ? usershell : defaultshell,
522 &w32_perlshell_tokens,
528 Perl_do_aspawn(pTHX_ SV *really, SV **mark, SV **sp)
540 Newx(argv, (sp - mark) + w32_perlshell_items + 2, char*);
542 if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
547 while (++mark <= sp) {
548 if (*mark && (str = SvPV_nolen(*mark)))
555 status = win32_spawnvp(flag,
556 (const char*)(really ? SvPV_nolen(really) : argv[0]),
557 (const char* const*)argv);
559 if (status < 0 && (errno == ENOEXEC || errno == ENOENT)) {
560 /* possible shell-builtin, invoke with shell */
562 sh_items = w32_perlshell_items;
564 argv[index+sh_items] = argv[index];
565 while (--sh_items >= 0)
566 argv[sh_items] = w32_perlshell_vec[sh_items];
568 status = win32_spawnvp(flag,
569 (const char*)(really ? SvPV_nolen(really) : argv[0]),
570 (const char* const*)argv);
573 if (flag == P_NOWAIT) {
575 PL_statusvalue = -1; /* >16bits hint for pp_system() */
579 if (ckWARN(WARN_EXEC))
580 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't spawn \"%s\": %s", argv[0], strerror(errno));
585 PL_statusvalue = status;
591 /* returns pointer to the next unquoted space or the end of the string */
593 find_next_space(const char *s)
595 bool in_quotes = FALSE;
597 /* ignore doubled backslashes, or backslash+quote */
598 if (*s == '\\' && (s[1] == '\\' || s[1] == '"')) {
601 /* keep track of when we're within quotes */
602 else if (*s == '"') {
604 in_quotes = !in_quotes;
606 /* break it up only at spaces that aren't in quotes */
607 else if (!in_quotes && isSPACE(*s))
616 do_spawn2(pTHX_ const char *cmd, int exectype)
622 BOOL needToTry = TRUE;
625 /* Save an extra exec if possible. See if there are shell
626 * metacharacters in it */
627 if (!has_shell_metachars(cmd)) {
628 Newx(argv, strlen(cmd) / 2 + 2, char*);
629 Newx(cmd2, strlen(cmd) + 1, char);
632 for (s = cmd2; *s;) {
633 while (*s && isSPACE(*s))
637 s = find_next_space(s);
645 status = win32_spawnvp(P_WAIT, argv[0],
646 (const char* const*)argv);
648 case EXECF_SPAWN_NOWAIT:
649 status = win32_spawnvp(P_NOWAIT, argv[0],
650 (const char* const*)argv);
653 status = win32_execvp(argv[0], (const char* const*)argv);
656 if (status != -1 || errno == 0)
666 Newx(argv, w32_perlshell_items + 2, char*);
667 while (++i < w32_perlshell_items)
668 argv[i] = w32_perlshell_vec[i];
669 argv[i++] = (char *)cmd;
673 status = win32_spawnvp(P_WAIT, argv[0],
674 (const char* const*)argv);
676 case EXECF_SPAWN_NOWAIT:
677 status = win32_spawnvp(P_NOWAIT, argv[0],
678 (const char* const*)argv);
681 status = win32_execvp(argv[0], (const char* const*)argv);
687 if (exectype == EXECF_SPAWN_NOWAIT) {
689 PL_statusvalue = -1; /* >16bits hint for pp_system() */
693 if (ckWARN(WARN_EXEC))
694 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s \"%s\": %s",
695 (exectype == EXECF_EXEC ? "exec" : "spawn"),
696 cmd, strerror(errno));
701 PL_statusvalue = status;
707 Perl_do_spawn(pTHX_ char *cmd)
709 return do_spawn2(aTHX_ cmd, EXECF_SPAWN);
713 Perl_do_spawn_nowait(pTHX_ char *cmd)
715 return do_spawn2(aTHX_ cmd, EXECF_SPAWN_NOWAIT);
719 Perl_do_exec(pTHX_ const char *cmd)
721 do_spawn2(aTHX_ cmd, EXECF_EXEC);
725 /* The idea here is to read all the directory names into a string table
726 * (separated by nulls) and when one of the other dir functions is called
727 * return the pointer to the current file name.
730 win32_opendir(const char *filename)
736 char scanname[MAX_PATH+3];
738 WIN32_FIND_DATAA aFindData;
740 len = strlen(filename);
744 /* check to see if filename is a directory */
745 if (win32_stat(filename, &sbuf) < 0 || !S_ISDIR(sbuf.st_mode))
748 /* Get us a DIR structure */
751 /* Create the search pattern */
752 strcpy(scanname, filename);
754 /* bare drive name means look in cwd for drive */
755 if (len == 2 && isALPHA(scanname[0]) && scanname[1] == ':') {
756 scanname[len++] = '.';
757 scanname[len++] = '/';
759 else if (scanname[len-1] != '/' && scanname[len-1] != '\\') {
760 scanname[len++] = '/';
762 scanname[len++] = '*';
763 scanname[len] = '\0';
765 /* do the FindFirstFile call */
766 dirp->handle = FindFirstFileA(PerlDir_mapA(scanname), &aFindData);
767 if (dirp->handle == INVALID_HANDLE_VALUE) {
768 DWORD err = GetLastError();
769 /* FindFirstFile() fails on empty drives! */
771 case ERROR_FILE_NOT_FOUND:
773 case ERROR_NO_MORE_FILES:
774 case ERROR_PATH_NOT_FOUND:
777 case ERROR_NOT_ENOUGH_MEMORY:
788 /* now allocate the first part of the string table for
789 * the filenames that we find.
791 idx = strlen(aFindData.cFileName)+1;
796 Newx(dirp->start, dirp->size, char);
797 strcpy(dirp->start, aFindData.cFileName);
799 dirp->end = dirp->curr = dirp->start;
805 /* Readdir just returns the current string pointer and bumps the
806 * string pointer to the nDllExport entry.
808 DllExport struct direct *
809 win32_readdir(DIR *dirp)
814 /* first set up the structure to return */
815 len = strlen(dirp->curr);
816 strcpy(dirp->dirstr.d_name, dirp->curr);
817 dirp->dirstr.d_namlen = len;
820 dirp->dirstr.d_ino = dirp->curr - dirp->start;
822 /* Now set up for the next call to readdir */
823 dirp->curr += len + 1;
824 if (dirp->curr >= dirp->end) {
827 WIN32_FIND_DATAA aFindData;
829 /* finding the next file that matches the wildcard
830 * (which should be all of them in this directory!).
832 res = FindNextFileA(dirp->handle, &aFindData);
834 long endpos = dirp->end - dirp->start;
835 long newsize = endpos + strlen(aFindData.cFileName) + 1;
836 /* bump the string table size by enough for the
837 * new name and its null terminator */
838 while (newsize > dirp->size) {
839 long curpos = dirp->curr - dirp->start;
841 Renew(dirp->start, dirp->size, char);
842 dirp->curr = dirp->start + curpos;
844 strcpy(dirp->start + endpos, aFindData.cFileName);
845 dirp->end = dirp->start + newsize;
851 return &(dirp->dirstr);
857 /* Telldir returns the current string pointer position */
859 win32_telldir(DIR *dirp)
861 return (dirp->curr - dirp->start);
865 /* Seekdir moves the string pointer to a previously saved position
866 * (returned by telldir).
869 win32_seekdir(DIR *dirp, long loc)
871 dirp->curr = dirp->start + loc;
874 /* Rewinddir resets the string pointer to the start */
876 win32_rewinddir(DIR *dirp)
878 dirp->curr = dirp->start;
881 /* free the memory allocated by opendir */
883 win32_closedir(DIR *dirp)
886 if (dirp->handle != INVALID_HANDLE_VALUE)
887 FindClose(dirp->handle);
888 Safefree(dirp->start);
901 * Just pretend that everyone is a superuser. NT will let us know if
902 * we don\'t really have permission to do something.
905 #define ROOT_UID ((uid_t)0)
906 #define ROOT_GID ((gid_t)0)
935 return (auid == ROOT_UID ? 0 : -1);
941 return (agid == ROOT_GID ? 0 : -1);
948 char *buf = w32_getlogin_buffer;
949 DWORD size = sizeof(w32_getlogin_buffer);
950 if (GetUserName(buf,&size))
956 chown(const char *path, uid_t owner, gid_t group)
963 * XXX this needs strengthening (for PerlIO)
966 int mkstemp(const char *path)
969 char buf[MAX_PATH+1];
973 if (i++ > 10) { /* give up */
977 if (!GetTempFileNameA((LPCSTR)path, "plr", 1, buf)) {
981 fd = PerlLIO_open3(buf, O_CREAT|O_RDWR|O_EXCL, 0600);
991 long child = w32_num_children;
992 while (--child >= 0) {
993 if ((int)w32_child_pids[child] == pid)
1000 remove_dead_process(long child)
1004 CloseHandle(w32_child_handles[child]);
1005 Move(&w32_child_handles[child+1], &w32_child_handles[child],
1006 (w32_num_children-child-1), HANDLE);
1007 Move(&w32_child_pids[child+1], &w32_child_pids[child],
1008 (w32_num_children-child-1), DWORD);
1015 find_pseudo_pid(int pid)
1018 long child = w32_num_pseudo_children;
1019 while (--child >= 0) {
1020 if ((int)w32_pseudo_child_pids[child] == pid)
1027 remove_dead_pseudo_process(long child)
1031 CloseHandle(w32_pseudo_child_handles[child]);
1032 Move(&w32_pseudo_child_handles[child+1], &w32_pseudo_child_handles[child],
1033 (w32_num_pseudo_children-child-1), HANDLE);
1034 Move(&w32_pseudo_child_pids[child+1], &w32_pseudo_child_pids[child],
1035 (w32_num_pseudo_children-child-1), DWORD);
1036 Move(&w32_pseudo_child_message_hwnds[child+1], &w32_pseudo_child_message_hwnds[child],
1037 (w32_num_pseudo_children-child-1), HWND);
1038 w32_num_pseudo_children--;
1044 win32_kill(int pid, int sig)
1052 /* it is a pseudo-forked child */
1053 child = find_pseudo_pid(-pid);
1055 HWND hwnd = w32_pseudo_child_message_hwnds[child];
1056 hProcess = w32_pseudo_child_handles[child];
1059 /* "Does process exist?" use of kill */
1063 /* kill -9 style un-graceful exit */
1064 if (TerminateThread(hProcess, sig)) {
1065 remove_dead_pseudo_process(child);
1072 /* pseudo-process has not yet properly initialized if hwnd isn't set */
1073 while (hwnd == INVALID_HANDLE_VALUE && count < 5) {
1074 /* Yield and wait for the other thread to send us its message_hwnd */
1076 win32_async_check(aTHX);
1079 if (hwnd != INVALID_HANDLE_VALUE) {
1080 /* We fake signals to pseudo-processes using Win32
1081 * message queue. In Win9X the pids are negative already. */
1082 if ((hwnd != NULL && PostMessage(hwnd, WM_USER_KILL, sig, 0)) ||
1083 PostThreadMessage(IsWin95() ? pid : -pid, WM_USER_KILL, sig, 0))
1085 /* It might be us ... */
1094 else if (IsWin95()) {
1102 child = find_pid(pid);
1104 hProcess = w32_child_handles[child];
1107 /* "Does process exist?" use of kill */
1110 if (GenerateConsoleCtrlEvent(CTRL_C_EVENT,pid))
1115 if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,pid))
1118 default: /* For now be backwards compatible with perl5.6 */
1120 if (TerminateProcess(hProcess, sig)) {
1121 remove_dead_process(child);
1130 hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE,
1131 (IsWin95() ? -pid : pid));
1135 /* "Does process exist?" use of kill */
1139 if (GenerateConsoleCtrlEvent(CTRL_C_EVENT,pid))
1144 if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,pid))
1147 default: /* For now be backwards compatible with perl5.6 */
1149 if (TerminateProcess(hProcess, sig))
1154 CloseHandle(hProcess);
1164 win32_stat(const char *path, Stat_t *sbuf)
1167 char buffer[MAX_PATH+1];
1168 int l = strlen(path);
1174 switch(path[l - 1]) {
1175 /* FindFirstFile() and stat() are buggy with a trailing
1176 * backslash, so change it to a forward slash :-( */
1178 if (l >= sizeof(buffer)) {
1179 errno = ENAMETOOLONG;
1182 strncpy(buffer, path, l-1);
1183 buffer[l - 1] = '/';
1187 /* FindFirstFile() is buggy with "x:", so add a dot :-( */
1189 if (l == 2 && isALPHA(path[0])) {
1190 buffer[0] = path[0];
1201 /* We *must* open & close the file once; otherwise file attribute changes */
1202 /* might not yet have propagated to "other" hard links of the same file. */
1203 /* This also gives us an opportunity to determine the number of links. */
1204 path = PerlDir_mapA(path);
1206 handle = CreateFileA(path, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
1207 if (handle != INVALID_HANDLE_VALUE) {
1208 BY_HANDLE_FILE_INFORMATION bhi;
1209 if (GetFileInformationByHandle(handle, &bhi))
1210 nlink = bhi.nNumberOfLinks;
1211 CloseHandle(handle);
1214 /* path will be mapped correctly above */
1215 #if defined(WIN64) || defined(USE_LARGE_FILES)
1216 res = _stati64(path, sbuf);
1218 res = stat(path, sbuf);
1220 sbuf->st_nlink = nlink;
1223 /* CRT is buggy on sharenames, so make sure it really isn't.
1224 * XXX using GetFileAttributesEx() will enable us to set
1225 * sbuf->st_*time (but note that's not available on the
1226 * Windows of 1995) */
1227 DWORD r = GetFileAttributesA(path);
1228 if (r != 0xffffffff && (r & FILE_ATTRIBUTE_DIRECTORY)) {
1229 /* sbuf may still contain old garbage since stat() failed */
1230 Zero(sbuf, 1, Stat_t);
1231 sbuf->st_mode = S_IFDIR | S_IREAD;
1233 if (!(r & FILE_ATTRIBUTE_READONLY))
1234 sbuf->st_mode |= S_IWRITE | S_IEXEC;
1239 if (l == 3 && isALPHA(path[0]) && path[1] == ':'
1240 && (path[2] == '\\' || path[2] == '/'))
1242 /* The drive can be inaccessible, some _stat()s are buggy */
1243 if (!GetVolumeInformationA(path,NULL,0,NULL,NULL,NULL,NULL,0)) {
1249 if (S_ISDIR(sbuf->st_mode))
1250 sbuf->st_mode |= S_IWRITE | S_IEXEC;
1251 else if (S_ISREG(sbuf->st_mode)) {
1253 if (l >= 4 && path[l-4] == '.') {
1254 const char *e = path + l - 3;
1255 if (strnicmp(e,"exe",3)
1256 && strnicmp(e,"bat",3)
1257 && strnicmp(e,"com",3)
1258 && (IsWin95() || strnicmp(e,"cmd",3)))
1259 sbuf->st_mode &= ~S_IEXEC;
1261 sbuf->st_mode |= S_IEXEC;
1264 sbuf->st_mode &= ~S_IEXEC;
1265 /* Propagate permissions to _group_ and _others_ */
1266 perms = sbuf->st_mode & (S_IREAD|S_IWRITE|S_IEXEC);
1267 sbuf->st_mode |= (perms>>3) | (perms>>6);
1274 #define isSLASH(c) ((c) == '/' || (c) == '\\')
1275 #define SKIP_SLASHES(s) \
1277 while (*(s) && isSLASH(*(s))) \
1280 #define COPY_NONSLASHES(d,s) \
1282 while (*(s) && !isSLASH(*(s))) \
1286 /* Find the longname of a given path. path is destructively modified.
1287 * It should have space for at least MAX_PATH characters. */
1289 win32_longpath(char *path)
1291 WIN32_FIND_DATA fdata;
1293 char tmpbuf[MAX_PATH+1];
1294 char *tmpstart = tmpbuf;
1301 if (isALPHA(path[0]) && path[1] == ':') {
1303 *tmpstart++ = path[0];
1307 else if (isSLASH(path[0]) && isSLASH(path[1])) {
1309 *tmpstart++ = path[0];
1310 *tmpstart++ = path[1];
1311 SKIP_SLASHES(start);
1312 COPY_NONSLASHES(tmpstart,start); /* copy machine name */
1314 *tmpstart++ = *start++;
1315 SKIP_SLASHES(start);
1316 COPY_NONSLASHES(tmpstart,start); /* copy share name */
1321 /* copy initial slash, if any */
1322 if (isSLASH(*start)) {
1323 *tmpstart++ = *start++;
1325 SKIP_SLASHES(start);
1328 /* FindFirstFile() expands "." and "..", so we need to pass
1329 * those through unmolested */
1331 && (!start[1] || isSLASH(start[1])
1332 || (start[1] == '.' && (!start[2] || isSLASH(start[2])))))
1334 COPY_NONSLASHES(tmpstart,start); /* copy "." or ".." */
1339 /* if this is the end, bust outta here */
1343 /* now we're at a non-slash; walk up to next slash */
1344 while (*start && !isSLASH(*start))
1347 /* stop and find full name of component */
1350 fhand = FindFirstFile(path,&fdata);
1352 if (fhand != INVALID_HANDLE_VALUE) {
1353 STRLEN len = strlen(fdata.cFileName);
1354 if ((STRLEN)(tmpbuf + sizeof(tmpbuf) - tmpstart) > len) {
1355 strcpy(tmpstart, fdata.cFileName);
1366 /* failed a step, just return without side effects */
1367 /*PerlIO_printf(Perl_debug_log, "Failed to find %s\n", path);*/
1372 strcpy(path,tmpbuf);
1377 win32_getenv(const char *name)
1381 SV *curitem = Nullsv;
1383 needlen = GetEnvironmentVariableA(name,NULL,0);
1385 curitem = sv_2mortal(newSVpvn("", 0));
1387 SvGROW(curitem, needlen+1);
1388 needlen = GetEnvironmentVariableA(name,SvPVX(curitem),
1390 } while (needlen >= SvLEN(curitem));
1391 SvCUR_set(curitem, needlen);
1394 /* allow any environment variables that begin with 'PERL'
1395 to be stored in the registry */
1396 if (strncmp(name, "PERL", 4) == 0)
1397 (void)get_regstr(name, &curitem);
1399 if (curitem && SvCUR(curitem))
1400 return SvPVX(curitem);
1406 win32_putenv(const char *name)
1414 Newx(curitem,strlen(name)+1,char);
1415 strcpy(curitem, name);
1416 val = strchr(curitem, '=');
1418 /* The sane way to deal with the environment.
1419 * Has these advantages over putenv() & co.:
1420 * * enables us to store a truly empty value in the
1421 * environment (like in UNIX).
1422 * * we don't have to deal with RTL globals, bugs and leaks.
1424 * Why you may want to enable USE_WIN32_RTL_ENV:
1425 * * environ[] and RTL functions will not reflect changes,
1426 * which might be an issue if extensions want to access
1427 * the env. via RTL. This cuts both ways, since RTL will
1428 * not see changes made by extensions that call the Win32
1429 * functions directly, either.
1433 if (SetEnvironmentVariableA(curitem, *val ? val : NULL))
1442 filetime_to_clock(PFILETIME ft)
1444 __int64 qw = ft->dwHighDateTime;
1446 qw |= ft->dwLowDateTime;
1447 qw /= 10000; /* File time ticks at 0.1uS, clock at 1mS */
1452 win32_times(struct tms *timebuf)
1457 clock_t process_time_so_far = clock();
1458 if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy,
1460 timebuf->tms_utime = filetime_to_clock(&user);
1461 timebuf->tms_stime = filetime_to_clock(&kernel);
1462 timebuf->tms_cutime = 0;
1463 timebuf->tms_cstime = 0;
1465 /* That failed - e.g. Win95 fallback to clock() */
1466 timebuf->tms_utime = process_time_so_far;
1467 timebuf->tms_stime = 0;
1468 timebuf->tms_cutime = 0;
1469 timebuf->tms_cstime = 0;
1471 return process_time_so_far;
1474 /* fix utime() so it works on directories in NT */
1476 filetime_from_time(PFILETIME pFileTime, time_t Time)
1478 struct tm *pTM = localtime(&Time);
1479 SYSTEMTIME SystemTime;
1485 SystemTime.wYear = pTM->tm_year + 1900;
1486 SystemTime.wMonth = pTM->tm_mon + 1;
1487 SystemTime.wDay = pTM->tm_mday;
1488 SystemTime.wHour = pTM->tm_hour;
1489 SystemTime.wMinute = pTM->tm_min;
1490 SystemTime.wSecond = pTM->tm_sec;
1491 SystemTime.wMilliseconds = 0;
1493 return SystemTimeToFileTime(&SystemTime, &LocalTime) &&
1494 LocalFileTimeToFileTime(&LocalTime, pFileTime);
1498 win32_unlink(const char *filename)
1504 filename = PerlDir_mapA(filename);
1505 attrs = GetFileAttributesA(filename);
1506 if (attrs == 0xFFFFFFFF) {
1510 if (attrs & FILE_ATTRIBUTE_READONLY) {
1511 (void)SetFileAttributesA(filename, attrs & ~FILE_ATTRIBUTE_READONLY);
1512 ret = unlink(filename);
1514 (void)SetFileAttributesA(filename, attrs);
1517 ret = unlink(filename);
1522 win32_utime(const char *filename, struct utimbuf *times)
1529 struct utimbuf TimeBuffer;
1532 filename = PerlDir_mapA(filename);
1533 rc = utime(filename, times);
1535 /* EACCES: path specifies directory or readonly file */
1536 if (rc == 0 || errno != EACCES /* || !IsWinNT() */)
1539 if (times == NULL) {
1540 times = &TimeBuffer;
1541 time(×->actime);
1542 times->modtime = times->actime;
1545 /* This will (and should) still fail on readonly files */
1546 handle = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE,
1547 FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
1548 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1549 if (handle == INVALID_HANDLE_VALUE)
1552 if (GetFileTime(handle, &ftCreate, &ftAccess, &ftWrite) &&
1553 filetime_from_time(&ftAccess, times->actime) &&
1554 filetime_from_time(&ftWrite, times->modtime) &&
1555 SetFileTime(handle, &ftCreate, &ftAccess, &ftWrite))
1560 CloseHandle(handle);
1565 unsigned __int64 ft_i64;
1570 #define Const64(x) x##LL
1572 #define Const64(x) x##i64
1574 /* Number of 100 nanosecond units from 1/1/1601 to 1/1/1970 */
1575 #define EPOCH_BIAS Const64(116444736000000000)
1577 /* NOTE: This does not compute the timezone info (doing so can be expensive,
1578 * and appears to be unsupported even by glibc) */
1580 win32_gettimeofday(struct timeval *tp, void *not_used)
1584 /* this returns time in 100-nanosecond units (i.e. tens of usecs) */
1585 GetSystemTimeAsFileTime(&ft.ft_val);
1587 /* seconds since epoch */
1588 tp->tv_sec = (long)((ft.ft_i64 - EPOCH_BIAS) / Const64(10000000));
1590 /* microseconds remaining */
1591 tp->tv_usec = (long)((ft.ft_i64 / Const64(10)) % Const64(1000000));
1597 win32_uname(struct utsname *name)
1599 struct hostent *hep;
1600 STRLEN nodemax = sizeof(name->nodename)-1;
1603 switch (g_osver.dwPlatformId) {
1604 case VER_PLATFORM_WIN32_WINDOWS:
1605 strcpy(name->sysname, "Windows");
1607 case VER_PLATFORM_WIN32_NT:
1608 strcpy(name->sysname, "Windows NT");
1610 case VER_PLATFORM_WIN32s:
1611 strcpy(name->sysname, "Win32s");
1614 strcpy(name->sysname, "Win32 Unknown");
1619 sprintf(name->release, "%d.%d",
1620 g_osver.dwMajorVersion, g_osver.dwMinorVersion);
1623 sprintf(name->version, "Build %d",
1624 g_osver.dwPlatformId == VER_PLATFORM_WIN32_NT
1625 ? g_osver.dwBuildNumber : (g_osver.dwBuildNumber & 0xffff));
1626 if (g_osver.szCSDVersion[0]) {
1627 char *buf = name->version + strlen(name->version);
1628 sprintf(buf, " (%s)", g_osver.szCSDVersion);
1632 hep = win32_gethostbyname("localhost");
1634 STRLEN len = strlen(hep->h_name);
1635 if (len <= nodemax) {
1636 strcpy(name->nodename, hep->h_name);
1639 strncpy(name->nodename, hep->h_name, nodemax);
1640 name->nodename[nodemax] = '\0';
1645 if (!GetComputerName(name->nodename, &sz))
1646 *name->nodename = '\0';
1649 /* machine (architecture) */
1654 GetSystemInfo(&info);
1656 #if (defined(__BORLANDC__)&&(__BORLANDC__<=0x520)) \
1657 || (defined(__MINGW32__) && !defined(_ANONYMOUS_UNION))
1658 procarch = info.u.s.wProcessorArchitecture;
1660 procarch = info.wProcessorArchitecture;
1663 case PROCESSOR_ARCHITECTURE_INTEL:
1664 arch = "x86"; break;
1665 case PROCESSOR_ARCHITECTURE_MIPS:
1666 arch = "mips"; break;
1667 case PROCESSOR_ARCHITECTURE_ALPHA:
1668 arch = "alpha"; break;
1669 case PROCESSOR_ARCHITECTURE_PPC:
1670 arch = "ppc"; break;
1671 #ifdef PROCESSOR_ARCHITECTURE_SHX
1672 case PROCESSOR_ARCHITECTURE_SHX:
1673 arch = "shx"; break;
1675 #ifdef PROCESSOR_ARCHITECTURE_ARM
1676 case PROCESSOR_ARCHITECTURE_ARM:
1677 arch = "arm"; break;
1679 #ifdef PROCESSOR_ARCHITECTURE_IA64
1680 case PROCESSOR_ARCHITECTURE_IA64:
1681 arch = "ia64"; break;
1683 #ifdef PROCESSOR_ARCHITECTURE_ALPHA64
1684 case PROCESSOR_ARCHITECTURE_ALPHA64:
1685 arch = "alpha64"; break;
1687 #ifdef PROCESSOR_ARCHITECTURE_MSIL
1688 case PROCESSOR_ARCHITECTURE_MSIL:
1689 arch = "msil"; break;
1691 #ifdef PROCESSOR_ARCHITECTURE_AMD64
1692 case PROCESSOR_ARCHITECTURE_AMD64:
1693 arch = "amd64"; break;
1695 #ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
1696 case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
1697 arch = "ia32-64"; break;
1699 #ifdef PROCESSOR_ARCHITECTURE_UNKNOWN
1700 case PROCESSOR_ARCHITECTURE_UNKNOWN:
1701 arch = "unknown"; break;
1704 sprintf(name->machine, "unknown(0x%x)", procarch);
1705 arch = name->machine;
1708 if (name->machine != arch)
1709 strcpy(name->machine, arch);
1714 /* Timing related stuff */
1717 do_raise(pTHX_ int sig)
1719 if (sig < SIG_SIZE) {
1720 Sighandler_t handler = w32_sighandler[sig];
1721 if (handler == SIG_IGN) {
1724 else if (handler != SIG_DFL) {
1729 /* Choose correct default behaviour */
1745 /* Tell caller to exit thread/process as approriate */
1750 sig_terminate(pTHX_ int sig)
1752 Perl_warn(aTHX_ "Terminating on signal SIG%s(%d)\n",PL_sig_name[sig], sig);
1753 /* exit() seems to be safe, my_exit() or die() is a problem in ^C
1760 win32_async_check(pTHX)
1763 HWND hwnd = w32_message_hwnd;
1767 if (hwnd == INVALID_HANDLE_VALUE)
1770 /* Passing PeekMessage -1 as HWND (2nd arg) only get PostThreadMessage() messages
1771 * and ignores window messages - should co-exist better with windows apps e.g. Tk
1776 while (PeekMessage(&msg, hwnd, WM_TIMER, WM_TIMER, PM_REMOVE|PM_NOYIELD) ||
1777 PeekMessage(&msg, hwnd, WM_USER_MIN, WM_USER_MAX, PM_REMOVE|PM_NOYIELD))
1779 switch (msg.message) {
1781 case WM_USER_MESSAGE: {
1782 int child = find_pseudo_pid(msg.wParam);
1784 w32_pseudo_child_message_hwnds[child] = (HWND)msg.lParam;
1789 case WM_USER_KILL: {
1790 /* We use WM_USER to fake kill() with other signals */
1791 int sig = msg.wParam;
1792 if (do_raise(aTHX_ sig))
1793 sig_terminate(aTHX_ sig);
1798 /* alarm() is a one-shot but SetTimer() repeats so kill it */
1799 if (w32_timerid && w32_timerid==msg.wParam) {
1800 KillTimer(w32_message_hwnd, w32_timerid);
1803 /* Now fake a call to signal handler */
1804 if (do_raise(aTHX_ 14))
1805 sig_terminate(aTHX_ 14);
1812 /* Above or other stuff may have set a signal flag */
1813 if (PL_sig_pending) {
1819 /* This function will not return until the timeout has elapsed, or until
1820 * one of the handles is ready. */
1822 win32_msgwait(pTHX_ DWORD count, LPHANDLE handles, DWORD timeout, LPDWORD resultp)
1824 /* We may need several goes at this - so compute when we stop */
1826 if (timeout != INFINITE) {
1827 ticks = GetTickCount();
1831 DWORD result = MsgWaitForMultipleObjects(count,handles,FALSE,timeout-ticks, QS_ALLEVENTS);
1834 if (result == WAIT_TIMEOUT) {
1835 /* Ran out of time - explicit return of zero to avoid -ve if we
1836 have scheduling issues
1840 if (timeout != INFINITE) {
1841 ticks = GetTickCount();
1843 if (result == WAIT_OBJECT_0 + count) {
1844 /* Message has arrived - check it */
1845 (void)win32_async_check(aTHX);
1848 /* Not timeout or message - one of handles is ready */
1852 /* compute time left to wait */
1853 ticks = timeout - ticks;
1854 /* If we are past the end say zero */
1855 return (ticks > 0) ? ticks : 0;
1859 win32_internal_wait(int *status, DWORD timeout)
1861 /* XXX this wait emulation only knows about processes
1862 * spawned via win32_spawnvp(P_NOWAIT, ...).
1866 DWORD exitcode, waitcode;
1869 if (w32_num_pseudo_children) {
1870 win32_msgwait(aTHX_ w32_num_pseudo_children, w32_pseudo_child_handles,
1871 timeout, &waitcode);
1872 /* Time out here if there are no other children to wait for. */
1873 if (waitcode == WAIT_TIMEOUT) {
1874 if (!w32_num_children) {
1878 else if (waitcode != WAIT_FAILED) {
1879 if (waitcode >= WAIT_ABANDONED_0
1880 && waitcode < WAIT_ABANDONED_0 + w32_num_pseudo_children)
1881 i = waitcode - WAIT_ABANDONED_0;
1883 i = waitcode - WAIT_OBJECT_0;
1884 if (GetExitCodeThread(w32_pseudo_child_handles[i], &exitcode)) {
1885 *status = (int)((exitcode & 0xff) << 8);
1886 retval = (int)w32_pseudo_child_pids[i];
1887 remove_dead_pseudo_process(i);
1894 if (!w32_num_children) {
1899 /* if a child exists, wait for it to die */
1900 win32_msgwait(aTHX_ w32_num_children, w32_child_handles, timeout, &waitcode);
1901 if (waitcode == WAIT_TIMEOUT) {
1904 if (waitcode != WAIT_FAILED) {
1905 if (waitcode >= WAIT_ABANDONED_0
1906 && waitcode < WAIT_ABANDONED_0 + w32_num_children)
1907 i = waitcode - WAIT_ABANDONED_0;
1909 i = waitcode - WAIT_OBJECT_0;
1910 if (GetExitCodeProcess(w32_child_handles[i], &exitcode) ) {
1911 *status = (int)((exitcode & 0xff) << 8);
1912 retval = (int)w32_child_pids[i];
1913 remove_dead_process(i);
1918 errno = GetLastError();
1923 win32_waitpid(int pid, int *status, int flags)
1926 DWORD timeout = (flags & WNOHANG) ? 0 : INFINITE;
1929 if (pid == -1) /* XXX threadid == 1 ? */
1930 return win32_internal_wait(status, timeout);
1933 child = find_pseudo_pid(-pid);
1935 HANDLE hThread = w32_pseudo_child_handles[child];
1937 win32_msgwait(aTHX_ 1, &hThread, timeout, &waitcode);
1938 if (waitcode == WAIT_TIMEOUT) {
1941 else if (waitcode == WAIT_OBJECT_0) {
1942 if (GetExitCodeThread(hThread, &waitcode)) {
1943 *status = (int)((waitcode & 0xff) << 8);
1944 retval = (int)w32_pseudo_child_pids[child];
1945 remove_dead_pseudo_process(child);
1952 else if (IsWin95()) {
1961 child = find_pid(pid);
1963 hProcess = w32_child_handles[child];
1964 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
1965 if (waitcode == WAIT_TIMEOUT) {
1968 else if (waitcode == WAIT_OBJECT_0) {
1969 if (GetExitCodeProcess(hProcess, &waitcode)) {
1970 *status = (int)((waitcode & 0xff) << 8);
1971 retval = (int)w32_child_pids[child];
1972 remove_dead_process(child);
1981 hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE,
1982 (IsWin95() ? -pid : pid));
1984 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
1985 if (waitcode == WAIT_TIMEOUT) {
1986 CloseHandle(hProcess);
1989 else if (waitcode == WAIT_OBJECT_0) {
1990 if (GetExitCodeProcess(hProcess, &waitcode)) {
1991 *status = (int)((waitcode & 0xff) << 8);
1992 CloseHandle(hProcess);
1996 CloseHandle(hProcess);
2002 return retval >= 0 ? pid : retval;
2006 win32_wait(int *status)
2008 return win32_internal_wait(status, INFINITE);
2011 DllExport unsigned int
2012 win32_sleep(unsigned int t)
2015 /* Win32 times are in ms so *1000 in and /1000 out */
2016 return win32_msgwait(aTHX_ 0, NULL, t*1000, NULL)/1000;
2019 DllExport unsigned int
2020 win32_alarm(unsigned int sec)
2023 * the 'obvious' implentation is SetTimer() with a callback
2024 * which does whatever receiving SIGALRM would do
2025 * we cannot use SIGALRM even via raise() as it is not
2026 * one of the supported codes in <signal.h>
2030 if (w32_message_hwnd == INVALID_HANDLE_VALUE)
2031 w32_message_hwnd = win32_create_message_window();
2034 if (w32_message_hwnd == NULL)
2035 w32_timerid = SetTimer(NULL, w32_timerid, sec*1000, NULL);
2038 SetTimer(w32_message_hwnd, w32_timerid, sec*1000, NULL);
2043 KillTimer(w32_message_hwnd, w32_timerid);
2050 #ifdef HAVE_DES_FCRYPT
2051 extern char * des_fcrypt(const char *txt, const char *salt, char *cbuf);
2055 win32_crypt(const char *txt, const char *salt)
2058 #ifdef HAVE_DES_FCRYPT
2059 return des_fcrypt(txt, salt, w32_crypt_buffer);
2061 Perl_croak(aTHX_ "The crypt() function is unimplemented due to excessive paranoia.");
2066 #ifdef USE_FIXED_OSFHANDLE
2068 #define FOPEN 0x01 /* file handle open */
2069 #define FNOINHERIT 0x10 /* file handle opened O_NOINHERIT */
2070 #define FAPPEND 0x20 /* file handle opened O_APPEND */
2071 #define FDEV 0x40 /* file handle refers to device */
2072 #define FTEXT 0x80 /* file handle is in text mode */
2075 *int my_open_osfhandle(intptr_t osfhandle, int flags) - open C Runtime file handle
2078 * This function allocates a free C Runtime file handle and associates
2079 * it with the Win32 HANDLE specified by the first parameter. This is a
2080 * temperary fix for WIN95's brain damage GetFileType() error on socket
2081 * we just bypass that call for socket
2083 * This works with MSVC++ 4.0+ or GCC/Mingw32
2086 * intptr_t osfhandle - Win32 HANDLE to associate with C Runtime file handle.
2087 * int flags - flags to associate with C Runtime file handle.
2090 * returns index of entry in fh, if successful
2091 * return -1, if no free entry is found
2095 *******************************************************************************/
2098 * we fake up some parts of the CRT that aren't exported by MSVCRT.dll
2099 * this lets sockets work on Win9X with GCC and should fix the problems
2104 /* create an ioinfo entry, kill its handle, and steal the entry */
2109 HANDLE hF = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
2110 int fh = _open_osfhandle((intptr_t)hF, 0);
2114 EnterCriticalSection(&(_pioinfo(fh)->lock));
2119 my_open_osfhandle(intptr_t osfhandle, int flags)
2122 char fileflags; /* _osfile flags */
2124 /* copy relevant flags from second parameter */
2127 if (flags & O_APPEND)
2128 fileflags |= FAPPEND;
2133 if (flags & O_NOINHERIT)
2134 fileflags |= FNOINHERIT;
2136 /* attempt to allocate a C Runtime file handle */
2137 if ((fh = _alloc_osfhnd()) == -1) {
2138 errno = EMFILE; /* too many open files */
2139 _doserrno = 0L; /* not an OS error */
2140 return -1; /* return error to caller */
2143 /* the file is open. now, set the info in _osfhnd array */
2144 _set_osfhnd(fh, osfhandle);
2146 fileflags |= FOPEN; /* mark as open */
2148 _osfile(fh) = fileflags; /* set osfile entry */
2149 LeaveCriticalSection(&_pioinfo(fh)->lock);
2151 return fh; /* return handle */
2154 #endif /* USE_FIXED_OSFHANDLE */
2156 /* simulate flock by locking a range on the file */
2158 #define LK_ERR(f,i) ((f) ? (i = 0) : (errno = GetLastError()))
2159 #define LK_LEN 0xffff0000
2162 win32_flock(int fd, int oper)
2170 Perl_croak_nocontext("flock() unimplemented on this platform");
2173 fh = (HANDLE)_get_osfhandle(fd);
2174 memset(&o, 0, sizeof(o));
2177 case LOCK_SH: /* shared lock */
2178 LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, 0, &o),i);
2180 case LOCK_EX: /* exclusive lock */
2181 LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o),i);
2183 case LOCK_SH|LOCK_NB: /* non-blocking shared lock */
2184 LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o),i);
2186 case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */
2187 LK_ERR(LockFileEx(fh,
2188 LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
2189 0, LK_LEN, 0, &o),i);
2191 case LOCK_UN: /* unlock lock */
2192 LK_ERR(UnlockFileEx(fh, 0, LK_LEN, 0, &o),i);
2194 default: /* unknown */
2205 * redirected io subsystem for all XS modules
2218 return (&(_environ));
2221 /* the rest are the remapped stdio routines */
2241 win32_ferror(FILE *fp)
2243 return (ferror(fp));
2248 win32_feof(FILE *fp)
2254 * Since the errors returned by the socket error function
2255 * WSAGetLastError() are not known by the library routine strerror
2256 * we have to roll our own.
2260 win32_strerror(int e)
2262 #if !defined __BORLANDC__ && !defined __MINGW32__ /* compiler intolerance */
2263 extern int sys_nerr;
2267 if (e < 0 || e > sys_nerr) {
2272 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0,
2273 w32_strerror_buffer,
2274 sizeof(w32_strerror_buffer), NULL) == 0)
2275 strcpy(w32_strerror_buffer, "Unknown Error");
2277 return w32_strerror_buffer;
2283 win32_str_os_error(void *sv, DWORD dwErr)
2287 dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
2288 |FORMAT_MESSAGE_IGNORE_INSERTS
2289 |FORMAT_MESSAGE_FROM_SYSTEM, NULL,
2290 dwErr, 0, (char *)&sMsg, 1, NULL);
2291 /* strip trailing whitespace and period */
2294 --dwLen; /* dwLen doesn't include trailing null */
2295 } while (0 < dwLen && isSPACE(sMsg[dwLen]));
2296 if ('.' != sMsg[dwLen])
2301 sMsg = (char*)LocalAlloc(0, 64/**sizeof(TCHAR)*/);
2303 dwLen = sprintf(sMsg,
2304 "Unknown error #0x%lX (lookup 0x%lX)",
2305 dwErr, GetLastError());
2309 sv_setpvn((SV*)sv, sMsg, dwLen);
2315 win32_fprintf(FILE *fp, const char *format, ...)
2318 va_start(marker, format); /* Initialize variable arguments. */
2320 return (vfprintf(fp, format, marker));
2324 win32_printf(const char *format, ...)
2327 va_start(marker, format); /* Initialize variable arguments. */
2329 return (vprintf(format, marker));
2333 win32_vfprintf(FILE *fp, const char *format, va_list args)
2335 return (vfprintf(fp, format, args));
2339 win32_vprintf(const char *format, va_list args)
2341 return (vprintf(format, args));
2345 win32_fread(void *buf, size_t size, size_t count, FILE *fp)
2347 return fread(buf, size, count, fp);
2351 win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
2353 return fwrite(buf, size, count, fp);
2356 #define MODE_SIZE 10
2359 win32_fopen(const char *filename, const char *mode)
2367 if (stricmp(filename, "/dev/null")==0)
2370 f = fopen(PerlDir_mapA(filename), mode);
2371 /* avoid buffering headaches for child processes */
2372 if (f && *mode == 'a')
2373 win32_fseek(f, 0, SEEK_END);
2377 #ifndef USE_SOCKETS_AS_HANDLES
2379 #define fdopen my_fdopen
2383 win32_fdopen(int handle, const char *mode)
2387 f = fdopen(handle, (char *) mode);
2388 /* avoid buffering headaches for child processes */
2389 if (f && *mode == 'a')
2390 win32_fseek(f, 0, SEEK_END);
2395 win32_freopen(const char *path, const char *mode, FILE *stream)
2398 if (stricmp(path, "/dev/null")==0)
2401 return freopen(PerlDir_mapA(path), mode, stream);
2405 win32_fclose(FILE *pf)
2407 return my_fclose(pf); /* defined in win32sck.c */
2411 win32_fputs(const char *s,FILE *pf)
2413 return fputs(s, pf);
2417 win32_fputc(int c,FILE *pf)
2423 win32_ungetc(int c,FILE *pf)
2425 return ungetc(c,pf);
2429 win32_getc(FILE *pf)
2435 win32_fileno(FILE *pf)
2441 win32_clearerr(FILE *pf)
2448 win32_fflush(FILE *pf)
2454 win32_ftell(FILE *pf)
2456 #if defined(WIN64) || defined(USE_LARGE_FILES)
2457 #if defined(__BORLANDC__) /* buk */
2458 return win32_tell( fileno( pf ) );
2461 if (fgetpos(pf, &pos))
2471 win32_fseek(FILE *pf, Off_t offset,int origin)
2473 #if defined(WIN64) || defined(USE_LARGE_FILES)
2474 #if defined(__BORLANDC__) /* buk */
2484 if (fgetpos(pf, &pos))
2489 fseek(pf, 0, SEEK_END);
2490 pos = _telli64(fileno(pf));
2499 return fsetpos(pf, &offset);
2502 return fseek(pf, (long)offset, origin);
2507 win32_fgetpos(FILE *pf,fpos_t *p)
2509 #if defined(__BORLANDC__) && defined(USE_LARGE_FILES) /* buk */
2510 if( win32_tell(fileno(pf)) == -1L ) {
2516 return fgetpos(pf, p);
2521 win32_fsetpos(FILE *pf,const fpos_t *p)
2523 #if defined(__BORLANDC__) && defined(USE_LARGE_FILES) /* buk */
2524 return win32_lseek(fileno(pf), *p, SEEK_CUR);
2526 return fsetpos(pf, p);
2531 win32_rewind(FILE *pf)
2541 char prefix[MAX_PATH+1];
2542 char filename[MAX_PATH+1];
2543 DWORD len = GetTempPath(MAX_PATH, prefix);
2544 if (len && len < MAX_PATH) {
2545 if (GetTempFileName(prefix, "plx", 0, filename)) {
2546 HANDLE fh = CreateFile(filename,
2547 DELETE | GENERIC_READ | GENERIC_WRITE,
2551 FILE_ATTRIBUTE_NORMAL
2552 | FILE_FLAG_DELETE_ON_CLOSE,
2554 if (fh != INVALID_HANDLE_VALUE) {
2555 int fd = win32_open_osfhandle((intptr_t)fh, 0);
2557 #if defined(__BORLANDC__)
2558 setmode(fd,O_BINARY);
2560 DEBUG_p(PerlIO_printf(Perl_debug_log,
2561 "Created tmpfile=%s\n",filename));
2573 int fd = win32_tmpfd();
2575 return win32_fdopen(fd, "w+b");
2587 win32_fstat(int fd, Stat_t *sbufptr)
2590 /* A file designated by filehandle is not shown as accessible
2591 * for write operations, probably because it is opened for reading.
2594 BY_HANDLE_FILE_INFORMATION bhfi;
2595 #if defined(WIN64) || defined(USE_LARGE_FILES)
2596 /* Borland 5.5.1 has a 64-bit stat, but only a 32-bit fstat */
2598 int rc = fstat(fd,&tmp);
2600 sbufptr->st_dev = tmp.st_dev;
2601 sbufptr->st_ino = tmp.st_ino;
2602 sbufptr->st_mode = tmp.st_mode;
2603 sbufptr->st_nlink = tmp.st_nlink;
2604 sbufptr->st_uid = tmp.st_uid;
2605 sbufptr->st_gid = tmp.st_gid;
2606 sbufptr->st_rdev = tmp.st_rdev;
2607 sbufptr->st_size = tmp.st_size;
2608 sbufptr->st_atime = tmp.st_atime;
2609 sbufptr->st_mtime = tmp.st_mtime;
2610 sbufptr->st_ctime = tmp.st_ctime;
2612 int rc = fstat(fd,sbufptr);
2615 if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &bhfi)) {
2616 #if defined(WIN64) || defined(USE_LARGE_FILES)
2617 sbufptr->st_size = (bhfi.nFileSizeHigh << 32) + bhfi.nFileSizeLow ;
2619 sbufptr->st_mode &= 0xFE00;
2620 if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
2621 sbufptr->st_mode |= (S_IREAD + (S_IREAD >> 3) + (S_IREAD >> 6));
2623 sbufptr->st_mode |= ((S_IREAD|S_IWRITE) + ((S_IREAD|S_IWRITE) >> 3)
2624 + ((S_IREAD|S_IWRITE) >> 6));
2628 return my_fstat(fd,sbufptr);
2633 win32_pipe(int *pfd, unsigned int size, int mode)
2635 return _pipe(pfd, size, mode);
2639 win32_popenlist(const char *mode, IV narg, SV **args)
2642 Perl_croak(aTHX_ "List form of pipe open not implemented");
2647 * a popen() clone that respects PERL5SHELL
2649 * changed to return PerlIO* rather than FILE * by BKS, 11-11-2000
2653 win32_popen(const char *command, const char *mode)
2655 #ifdef USE_RTL_POPEN
2656 return _popen(command, mode);
2668 /* establish which ends read and write */
2669 if (strchr(mode,'w')) {
2670 stdfd = 0; /* stdin */
2673 nhandle = STD_INPUT_HANDLE;
2675 else if (strchr(mode,'r')) {
2676 stdfd = 1; /* stdout */
2679 nhandle = STD_OUTPUT_HANDLE;
2684 /* set the correct mode */
2685 if (strchr(mode,'b'))
2687 else if (strchr(mode,'t'))
2690 ourmode = _fmode & (O_TEXT | O_BINARY);
2692 /* the child doesn't inherit handles */
2693 ourmode |= O_NOINHERIT;
2695 if (win32_pipe(p, 512, ourmode) == -1)
2698 /* save current stdfd */
2699 if ((oldfd = win32_dup(stdfd)) == -1)
2702 /* save the old std handle (this needs to happen before the
2703 * dup2(), since that might call SetStdHandle() too) */
2706 old_h = GetStdHandle(nhandle);
2708 /* make stdfd go to child end of pipe (implicitly closes stdfd) */
2709 /* stdfd will be inherited by the child */
2710 if (win32_dup2(p[child], stdfd) == -1)
2713 /* close the child end in parent */
2714 win32_close(p[child]);
2716 /* set the new std handle (in case dup2() above didn't) */
2717 SetStdHandle(nhandle, (HANDLE)_get_osfhandle(stdfd));
2719 /* start the child */
2722 if ((childpid = do_spawn_nowait((char*)command)) == -1)
2725 /* revert stdfd to whatever it was before */
2726 if (win32_dup2(oldfd, stdfd) == -1)
2729 /* restore the old std handle (this needs to happen after the
2730 * dup2(), since that might call SetStdHandle() too */
2732 SetStdHandle(nhandle, old_h);
2737 /* close saved handle */
2741 sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid);
2744 /* set process id so that it can be returned by perl's open() */
2745 PL_forkprocess = childpid;
2748 /* we have an fd, return a file stream */
2749 return (PerlIO_fdopen(p[parent], (char *)mode));
2752 /* we don't need to check for errors here */
2756 SetStdHandle(nhandle, old_h);
2761 win32_dup2(oldfd, stdfd);
2766 #endif /* USE_RTL_POPEN */
2774 win32_pclose(PerlIO *pf)
2776 #ifdef USE_RTL_POPEN
2780 int childpid, status;
2784 sv = *av_fetch(w32_fdpid, PerlIO_fileno(pf), TRUE);
2787 childpid = SvIVX(sv);
2804 if (win32_waitpid(childpid, &status, 0) == -1)
2809 #endif /* USE_RTL_POPEN */
2815 LPCWSTR lpExistingFileName,
2816 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
2819 WCHAR wFullName[MAX_PATH+1];
2820 LPVOID lpContext = NULL;
2821 WIN32_STREAM_ID StreamId;
2822 DWORD dwSize = (char*)&StreamId.cStreamName - (char*)&StreamId;
2827 BOOL (__stdcall *pfnBackupWrite)(HANDLE, LPBYTE, DWORD, LPDWORD,
2828 BOOL, BOOL, LPVOID*) =
2829 (BOOL (__stdcall *)(HANDLE, LPBYTE, DWORD, LPDWORD,
2830 BOOL, BOOL, LPVOID*))
2831 GetProcAddress(GetModuleHandle("kernel32.dll"), "BackupWrite");
2832 if (pfnBackupWrite == NULL)
2835 dwLen = GetFullPathNameW(lpFileName, MAX_PATH, wFullName, NULL);
2838 dwLen = (dwLen+1)*sizeof(WCHAR);
2840 handle = CreateFileW(lpExistingFileName, FILE_WRITE_ATTRIBUTES,
2841 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2842 NULL, OPEN_EXISTING, 0, NULL);
2843 if (handle == INVALID_HANDLE_VALUE)
2846 StreamId.dwStreamId = BACKUP_LINK;
2847 StreamId.dwStreamAttributes = 0;
2848 StreamId.dwStreamNameSize = 0;
2849 #if defined(__BORLANDC__) \
2850 ||(defined(__MINGW32__) && !defined(_ANONYMOUS_UNION))
2851 StreamId.Size.u.HighPart = 0;
2852 StreamId.Size.u.LowPart = dwLen;
2854 StreamId.Size.HighPart = 0;
2855 StreamId.Size.LowPart = dwLen;
2858 bSuccess = pfnBackupWrite(handle, (LPBYTE)&StreamId, dwSize, &dwWritten,
2859 FALSE, FALSE, &lpContext);
2861 bSuccess = pfnBackupWrite(handle, (LPBYTE)wFullName, dwLen, &dwWritten,
2862 FALSE, FALSE, &lpContext);
2863 pfnBackupWrite(handle, NULL, 0, &dwWritten, TRUE, FALSE, &lpContext);
2866 CloseHandle(handle);
2871 win32_link(const char *oldname, const char *newname)
2874 BOOL (__stdcall *pfnCreateHardLinkW)(LPCWSTR,LPCWSTR,LPSECURITY_ATTRIBUTES);
2875 WCHAR wOldName[MAX_PATH+1];
2876 WCHAR wNewName[MAX_PATH+1];
2879 Perl_croak(aTHX_ PL_no_func, "link");
2881 pfnCreateHardLinkW =
2882 (BOOL (__stdcall *)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES))
2883 GetProcAddress(GetModuleHandle("kernel32.dll"), "CreateHardLinkW");
2884 if (pfnCreateHardLinkW == NULL)
2885 pfnCreateHardLinkW = Nt4CreateHardLinkW;
2887 if (MultiByteToWideChar(CP_ACP, 0, oldname, -1, wOldName, MAX_PATH+1) &&
2888 MultiByteToWideChar(CP_ACP, 0, newname, -1, wNewName, MAX_PATH+1) &&
2889 (wcscpy(wOldName, PerlDir_mapW(wOldName)),
2890 pfnCreateHardLinkW(PerlDir_mapW(wNewName), wOldName, NULL)))
2894 errno = (GetLastError() == ERROR_FILE_NOT_FOUND) ? ENOENT : EINVAL;
2899 win32_rename(const char *oname, const char *newname)
2901 char szOldName[MAX_PATH+1];
2902 char szNewName[MAX_PATH+1];
2906 /* XXX despite what the documentation says about MoveFileEx(),
2907 * it doesn't work under Windows95!
2910 DWORD dwFlags = MOVEFILE_COPY_ALLOWED;
2911 if (stricmp(newname, oname))
2912 dwFlags |= MOVEFILE_REPLACE_EXISTING;
2913 strcpy(szOldName, PerlDir_mapA(oname));
2914 bResult = MoveFileExA(szOldName,PerlDir_mapA(newname), dwFlags);
2916 DWORD err = GetLastError();
2918 case ERROR_BAD_NET_NAME:
2919 case ERROR_BAD_NETPATH:
2920 case ERROR_BAD_PATHNAME:
2921 case ERROR_FILE_NOT_FOUND:
2922 case ERROR_FILENAME_EXCED_RANGE:
2923 case ERROR_INVALID_DRIVE:
2924 case ERROR_NO_MORE_FILES:
2925 case ERROR_PATH_NOT_FOUND:
2938 char szTmpName[MAX_PATH+1];
2939 char dname[MAX_PATH+1];
2940 char *endname = Nullch;
2942 DWORD from_attr, to_attr;
2944 strcpy(szOldName, PerlDir_mapA(oname));
2945 strcpy(szNewName, PerlDir_mapA(newname));
2947 /* if oname doesn't exist, do nothing */
2948 from_attr = GetFileAttributes(szOldName);
2949 if (from_attr == 0xFFFFFFFF) {
2954 /* if newname exists, rename it to a temporary name so that we
2955 * don't delete it in case oname happens to be the same file
2956 * (but perhaps accessed via a different path)
2958 to_attr = GetFileAttributes(szNewName);
2959 if (to_attr != 0xFFFFFFFF) {
2960 /* if newname is a directory, we fail
2961 * XXX could overcome this with yet more convoluted logic */
2962 if (to_attr & FILE_ATTRIBUTE_DIRECTORY) {
2966 tmplen = strlen(szNewName);
2967 strcpy(szTmpName,szNewName);
2968 endname = szTmpName+tmplen;
2969 for (; endname > szTmpName ; --endname) {
2970 if (*endname == '/' || *endname == '\\') {
2975 if (endname > szTmpName)
2976 endname = strcpy(dname,szTmpName);
2980 /* get a temporary filename in same directory
2981 * XXX is this really the best we can do? */
2982 if (!GetTempFileName((LPCTSTR)endname, "plr", 0, szTmpName)) {
2986 DeleteFile(szTmpName);
2988 retval = rename(szNewName, szTmpName);
2995 /* rename oname to newname */
2996 retval = rename(szOldName, szNewName);
2998 /* if we created a temporary file before ... */
2999 if (endname != Nullch) {
3000 /* ...and rename succeeded, delete temporary file/directory */
3002 DeleteFile(szTmpName);
3003 /* else restore it to what it was */
3005 (void)rename(szTmpName, szNewName);
3012 win32_setmode(int fd, int mode)
3014 return setmode(fd, mode);
3018 win32_chsize(int fd, Off_t size)
3020 #if defined(WIN64) || defined(USE_LARGE_FILES)
3022 Off_t cur, end, extend;
3024 cur = win32_tell(fd);
3027 end = win32_lseek(fd, 0, SEEK_END);
3030 extend = size - end;
3034 else if (extend > 0) {
3035 /* must grow the file, padding with nulls */
3037 int oldmode = win32_setmode(fd, O_BINARY);
3039 memset(b, '\0', sizeof(b));
3041 count = extend >= sizeof(b) ? sizeof(b) : (size_t)extend;
3042 count = win32_write(fd, b, count);
3043 if ((int)count < 0) {
3047 } while ((extend -= count) > 0);
3048 win32_setmode(fd, oldmode);
3051 /* shrink the file */
3052 win32_lseek(fd, size, SEEK_SET);
3053 if (!SetEndOfFile((HANDLE)_get_osfhandle(fd))) {
3059 win32_lseek(fd, cur, SEEK_SET);
3062 return chsize(fd, (long)size);
3067 win32_lseek(int fd, Off_t offset, int origin)
3069 #if defined(WIN64) || defined(USE_LARGE_FILES)
3070 #if defined(__BORLANDC__) /* buk */
3072 pos.QuadPart = offset;
3073 pos.LowPart = SetFilePointer(
3074 (HANDLE)_get_osfhandle(fd),
3079 if (pos.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
3083 return pos.QuadPart;
3085 return _lseeki64(fd, offset, origin);
3088 return lseek(fd, (long)offset, origin);
3095 #if defined(WIN64) || defined(USE_LARGE_FILES)
3096 #if defined(__BORLANDC__) /* buk */
3099 pos.LowPart = SetFilePointer(
3100 (HANDLE)_get_osfhandle(fd),
3105 if (pos.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
3109 return pos.QuadPart;
3110 /* return tell(fd); */
3112 return _telli64(fd);
3120 win32_open(const char *path, int flag, ...)
3127 pmode = va_arg(ap, int);
3130 if (stricmp(path, "/dev/null")==0)
3133 return open(PerlDir_mapA(path), flag, pmode);
3136 /* close() that understands socket */
3137 extern int my_close(int); /* in win32sck.c */
3142 return my_close(fd);
3158 win32_dup2(int fd1,int fd2)
3160 return dup2(fd1,fd2);
3163 #ifdef PERL_MSVCRT_READFIX
3165 #define LF 10 /* line feed */
3166 #define CR 13 /* carriage return */
3167 #define CTRLZ 26 /* ctrl-z means eof for text */
3168 #define FOPEN 0x01 /* file handle open */
3169 #define FEOFLAG 0x02 /* end of file has been encountered */
3170 #define FCRLF 0x04 /* CR-LF across read buffer (in text mode) */
3171 #define FPIPE 0x08 /* file handle refers to a pipe */
3172 #define FAPPEND 0x20 /* file handle opened O_APPEND */
3173 #define FDEV 0x40 /* file handle refers to device */
3174 #define FTEXT 0x80 /* file handle is in text mode */
3175 #define MAX_DESCRIPTOR_COUNT (64*32) /* this is the maximun that MSVCRT can handle */
3178 _fixed_read(int fh, void *buf, unsigned cnt)
3180 int bytes_read; /* number of bytes read */
3181 char *buffer; /* buffer to read to */
3182 int os_read; /* bytes read on OS call */
3183 char *p, *q; /* pointers into buffer */
3184 char peekchr; /* peek-ahead character */
3185 ULONG filepos; /* file position after seek */
3186 ULONG dosretval; /* o.s. return value */
3188 /* validate handle */
3189 if (((unsigned)fh >= (unsigned)MAX_DESCRIPTOR_COUNT) ||
3190 !(_osfile(fh) & FOPEN))
3192 /* out of range -- return error */
3194 _doserrno = 0; /* not o.s. error */
3199 * If lockinitflag is FALSE, assume fd is device
3200 * lockinitflag is set to TRUE by open.
3202 if (_pioinfo(fh)->lockinitflag)
3203 EnterCriticalSection(&(_pioinfo(fh)->lock)); /* lock file */
3205 bytes_read = 0; /* nothing read yet */
3206 buffer = (char*)buf;
3208 if (cnt == 0 || (_osfile(fh) & FEOFLAG)) {
3209 /* nothing to read or at EOF, so return 0 read */
3213 if ((_osfile(fh) & (FPIPE|FDEV)) && _pipech(fh) != LF) {
3214 /* a pipe/device and pipe lookahead non-empty: read the lookahead
3216 *buffer++ = _pipech(fh);
3219 _pipech(fh) = LF; /* mark as empty */
3224 if (!ReadFile((HANDLE)_osfhnd(fh), buffer, cnt, (LPDWORD)&os_read, NULL))
3226 /* ReadFile has reported an error. recognize two special cases.
3228 * 1. map ERROR_ACCESS_DENIED to EBADF
3230 * 2. just return 0 if ERROR_BROKEN_PIPE has occurred. it
3231 * means the handle is a read-handle on a pipe for which
3232 * all write-handles have been closed and all data has been
3235 if ((dosretval = GetLastError()) == ERROR_ACCESS_DENIED) {
3236 /* wrong read/write mode should return EBADF, not EACCES */
3238 _doserrno = dosretval;
3242 else if (dosretval == ERROR_BROKEN_PIPE) {
3252 bytes_read += os_read; /* update bytes read */
3254 if (_osfile(fh) & FTEXT) {
3255 /* now must translate CR-LFs to LFs in the buffer */
3257 /* set CRLF flag to indicate LF at beginning of buffer */
3258 /* if ((os_read != 0) && (*(char *)buf == LF)) */
3259 /* _osfile(fh) |= FCRLF; */
3261 /* _osfile(fh) &= ~FCRLF; */
3263 _osfile(fh) &= ~FCRLF;
3265 /* convert chars in the buffer: p is src, q is dest */
3267 while (p < (char *)buf + bytes_read) {
3269 /* if fh is not a device, set ctrl-z flag */
3270 if (!(_osfile(fh) & FDEV))
3271 _osfile(fh) |= FEOFLAG;
3272 break; /* stop translating */
3277 /* *p is CR, so must check next char for LF */
3278 if (p < (char *)buf + bytes_read - 1) {
3281 *q++ = LF; /* convert CR-LF to LF */
3284 *q++ = *p++; /* store char normally */
3287 /* This is the hard part. We found a CR at end of
3288 buffer. We must peek ahead to see if next char
3293 if (!ReadFile((HANDLE)_osfhnd(fh), &peekchr, 1,
3294 (LPDWORD)&os_read, NULL))
3295 dosretval = GetLastError();
3297 if (dosretval != 0 || os_read == 0) {
3298 /* couldn't read ahead, store CR */
3302 /* peekchr now has the extra character -- we now
3303 have several possibilities:
3304 1. disk file and char is not LF; just seek back
3306 2. disk file and char is LF; store LF, don't seek back
3307 3. pipe/device and char is LF; store LF.
3308 4. pipe/device and char isn't LF, store CR and
3309 put char in pipe lookahead buffer. */
3310 if (_osfile(fh) & (FDEV|FPIPE)) {
3311 /* non-seekable device */
3316 _pipech(fh) = peekchr;
3321 if (peekchr == LF) {
3322 /* nothing read yet; must make some
3325 /* turn on this flag for tell routine */
3326 _osfile(fh) |= FCRLF;
3329 HANDLE osHandle; /* o.s. handle value */
3331 if ((osHandle = (HANDLE)_get_osfhandle(fh)) != (HANDLE)-1)
3333 if ((filepos = SetFilePointer(osHandle, -1, NULL, FILE_CURRENT)) == -1)
3334 dosretval = GetLastError();
3345 /* we now change bytes_read to reflect the true number of chars
3347 bytes_read = q - (char *)buf;
3351 if (_pioinfo(fh)->lockinitflag)
3352 LeaveCriticalSection(&(_pioinfo(fh)->lock)); /* unlock file */
3357 #endif /* PERL_MSVCRT_READFIX */
3360 win32_read(int fd, void *buf, unsigned int cnt)
3362 #ifdef PERL_MSVCRT_READFIX
3363 return _fixed_read(fd, buf, cnt);
3365 return read(fd, buf, cnt);
3370 win32_write(int fd, const void *buf, unsigned int cnt)
3372 return write(fd, buf, cnt);
3376 win32_mkdir(const char *dir, int mode)
3379 return mkdir(PerlDir_mapA(dir)); /* just ignore mode */
3383 win32_rmdir(const char *dir)
3386 return rmdir(PerlDir_mapA(dir));
3390 win32_chdir(const char *dir)
3401 win32_access(const char *path, int mode)
3404 return access(PerlDir_mapA(path), mode);
3408 win32_chmod(const char *path, int mode)
3411 return chmod(PerlDir_mapA(path), mode);
3416 create_command_line(char *cname, STRLEN clen, const char * const *args)
3423 bool bat_file = FALSE;
3424 bool cmd_shell = FALSE;
3425 bool dumb_shell = FALSE;
3426 bool extra_quotes = FALSE;
3427 bool quote_next = FALSE;
3430 cname = (char*)args[0];
3432 /* The NT cmd.exe shell has the following peculiarity that needs to be
3433 * worked around. It strips a leading and trailing dquote when any
3434 * of the following is true:
3435 * 1. the /S switch was used
3436 * 2. there are more than two dquotes
3437 * 3. there is a special character from this set: &<>()@^|
3438 * 4. no whitespace characters within the two dquotes
3439 * 5. string between two dquotes isn't an executable file
3440 * To work around this, we always add a leading and trailing dquote
3441 * to the string, if the first argument is either "cmd.exe" or "cmd",
3442 * and there were at least two or more arguments passed to cmd.exe
3443 * (not including switches).
3444 * XXX the above rules (from "cmd /?") don't seem to be applied
3445 * always, making for the convolutions below :-(
3449 clen = strlen(cname);
3452 && (stricmp(&cname[clen-4], ".bat") == 0
3453 || (IsWinNT() && stricmp(&cname[clen-4], ".cmd") == 0)))
3460 char *exe = strrchr(cname, '/');
3461 char *exe2 = strrchr(cname, '\\');
3468 if (stricmp(exe, "cmd.exe") == 0 || stricmp(exe, "cmd") == 0) {
3472 else if (stricmp(exe, "command.com") == 0
3473 || stricmp(exe, "command") == 0)
3480 DEBUG_p(PerlIO_printf(Perl_debug_log, "Args "));
3481 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3482 STRLEN curlen = strlen(arg);
3483 if (!(arg[0] == '"' && arg[curlen-1] == '"'))
3484 len += 2; /* assume quoting needed (worst case) */
3486 DEBUG_p(PerlIO_printf(Perl_debug_log, "[%s]",arg));
3488 DEBUG_p(PerlIO_printf(Perl_debug_log, "\n"));
3491 Newx(cmd, len, char);
3494 if (bat_file && !IsWin95()) {
3496 extra_quotes = TRUE;
3499 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3501 STRLEN curlen = strlen(arg);
3503 /* we want to protect empty arguments and ones with spaces with
3504 * dquotes, but only if they aren't already there */
3509 else if (quote_next) {
3510 /* see if it really is multiple arguments pretending to
3511 * be one and force a set of quotes around it */
3512 if (*find_next_space(arg))
3515 else if (!(arg[0] == '"' && curlen > 1 && arg[curlen-1] == '"')) {
3517 while (i < curlen) {
3518 if (isSPACE(arg[i])) {
3521 else if (arg[i] == '"') {
3545 && *arg == '/' /* see if arg is "/c", "/x/c", "/x/d/c" etc. */
3546 && stricmp(arg+curlen-2, "/c") == 0)
3548 /* is there a next argument? */
3549 if (args[index+1]) {
3550 /* are there two or more next arguments? */
3551 if (args[index+2]) {
3553 extra_quotes = TRUE;
3556 /* single argument, force quoting if it has spaces */
3572 qualified_path(const char *cmd)
3576 char *fullcmd, *curfullcmd;
3582 fullcmd = (char*)cmd;
3584 if (*fullcmd == '/' || *fullcmd == '\\')
3591 pathstr = PerlEnv_getenv("PATH");
3593 /* worst case: PATH is a single directory; we need additional space
3594 * to append "/", ".exe" and trailing "\0" */
3595 Newx(fullcmd, (pathstr ? strlen(pathstr) : 0) + cmdlen + 6, char);
3596 curfullcmd = fullcmd;
3601 /* start by appending the name to the current prefix */
3602 strcpy(curfullcmd, cmd);
3603 curfullcmd += cmdlen;
3605 /* if it doesn't end with '.', or has no extension, try adding
3606 * a trailing .exe first */
3607 if (cmd[cmdlen-1] != '.'
3608 && (cmdlen < 4 || cmd[cmdlen-4] != '.'))
3610 strcpy(curfullcmd, ".exe");
3611 res = GetFileAttributes(fullcmd);
3612 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3617 /* that failed, try the bare name */
3618 res = GetFileAttributes(fullcmd);
3619 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3622 /* quit if no other path exists, or if cmd already has path */
3623 if (!pathstr || !*pathstr || has_slash)
3626 /* skip leading semis */
3627 while (*pathstr == ';')
3630 /* build a new prefix from scratch */
3631 curfullcmd = fullcmd;
3632 while (*pathstr && *pathstr != ';') {
3633 if (*pathstr == '"') { /* foo;"baz;etc";bar */
3634 pathstr++; /* skip initial '"' */
3635 while (*pathstr && *pathstr != '"') {
3636 *curfullcmd++ = *pathstr++;
3639 pathstr++; /* skip trailing '"' */
3642 *curfullcmd++ = *pathstr++;
3646 pathstr++; /* skip trailing semi */
3647 if (curfullcmd > fullcmd /* append a dir separator */
3648 && curfullcmd[-1] != '/' && curfullcmd[-1] != '\\')
3650 *curfullcmd++ = '\\';
3658 /* The following are just place holders.
3659 * Some hosts may provide and environment that the OS is
3660 * not tracking, therefore, these host must provide that
3661 * environment and the current directory to CreateProcess
3665 win32_get_childenv(void)
3671 win32_free_childenv(void* d)
3676 win32_clearenv(void)
3678 char *envv = GetEnvironmentStrings();
3682 char *end = strchr(cur,'=');
3683 if (end && end != cur) {
3685 SetEnvironmentVariable(cur, NULL);
3687 cur = end + strlen(end+1)+2;
3689 else if ((len = strlen(cur)))
3692 FreeEnvironmentStrings(envv);
3696 win32_get_childdir(void)
3700 char szfilename[MAX_PATH+1];
3702 GetCurrentDirectoryA(MAX_PATH+1, szfilename);
3703 Newx(ptr, strlen(szfilename)+1, char);
3704 strcpy(ptr, szfilename);
3709 win32_free_childdir(char* d)
3716 /* XXX this needs to be made more compatible with the spawnvp()
3717 * provided by the various RTLs. In particular, searching for
3718 * *.{com,bat,cmd} files (as done by the RTLs) is unimplemented.
3719 * This doesn't significantly affect perl itself, because we
3720 * always invoke things using PERL5SHELL if a direct attempt to
3721 * spawn the executable fails.
3723 * XXX splitting and rejoining the commandline between do_aspawn()
3724 * and win32_spawnvp() could also be avoided.
3728 win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
3730 #ifdef USE_RTL_SPAWNVP
3731 return spawnvp(mode, cmdname, (char * const *)argv);
3738 STARTUPINFO StartupInfo;
3739 PROCESS_INFORMATION ProcessInformation;
3742 char *fullcmd = Nullch;
3743 char *cname = (char *)cmdname;
3747 clen = strlen(cname);
3748 /* if command name contains dquotes, must remove them */
3749 if (strchr(cname, '"')) {
3751 Newx(cname,clen+1,char);
3764 cmd = create_command_line(cname, clen, argv);
3766 env = PerlEnv_get_childenv();
3767 dir = PerlEnv_get_childdir();
3770 case P_NOWAIT: /* asynch + remember result */
3771 if (w32_num_children >= MAXIMUM_WAIT_OBJECTS) {
3776 /* Create a new process group so we can use GenerateConsoleCtrlEvent()
3779 create |= CREATE_NEW_PROCESS_GROUP;
3782 case P_WAIT: /* synchronous execution */
3784 default: /* invalid mode */
3789 memset(&StartupInfo,0,sizeof(StartupInfo));
3790 StartupInfo.cb = sizeof(StartupInfo);
3791 memset(&tbl,0,sizeof(tbl));
3792 PerlEnv_get_child_IO(&tbl);
3793 StartupInfo.dwFlags = tbl.dwFlags;
3794 StartupInfo.dwX = tbl.dwX;
3795 StartupInfo.dwY = tbl.dwY;
3796 StartupInfo.dwXSize = tbl.dwXSize;
3797 StartupInfo.dwYSize = tbl.dwYSize;
3798 StartupInfo.dwXCountChars = tbl.dwXCountChars;
3799 StartupInfo.dwYCountChars = tbl.dwYCountChars;
3800 StartupInfo.dwFillAttribute = tbl.dwFillAttribute;
3801 StartupInfo.wShowWindow = tbl.wShowWindow;
3802 StartupInfo.hStdInput = tbl.childStdIn;
3803 StartupInfo.hStdOutput = tbl.childStdOut;
3804 StartupInfo.hStdError = tbl.childStdErr;
3805 if (StartupInfo.hStdInput == INVALID_HANDLE_VALUE &&
3806 StartupInfo.hStdOutput == INVALID_HANDLE_VALUE &&
3807 StartupInfo.hStdError == INVALID_HANDLE_VALUE)
3809 create |= CREATE_NEW_CONSOLE;
3812 StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
3814 if (w32_use_showwindow) {
3815 StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
3816 StartupInfo.wShowWindow = w32_showwindow;
3819 DEBUG_p(PerlIO_printf(Perl_debug_log, "Spawning [%s] with [%s]\n",
3822 if (!CreateProcess(cname, /* search PATH to find executable */
3823 cmd, /* executable, and its arguments */
3824 NULL, /* process attributes */
3825 NULL, /* thread attributes */
3826 TRUE, /* inherit handles */
3827 create, /* creation flags */
3828 (LPVOID)env, /* inherit environment */
3829 dir, /* inherit cwd */
3831 &ProcessInformation))
3833 /* initial NULL argument to CreateProcess() does a PATH
3834 * search, but it always first looks in the directory
3835 * where the current process was started, which behavior
3836 * is undesirable for backward compatibility. So we
3837 * jump through our own hoops by picking out the path
3838 * we really want it to use. */
3840 fullcmd = qualified_path(cname);
3842 if (cname != cmdname)
3845 DEBUG_p(PerlIO_printf(Perl_debug_log,
3846 "Retrying [%s] with same args\n",
3856 if (mode == P_NOWAIT) {
3857 /* asynchronous spawn -- store handle, return PID */
3858 ret = (int)ProcessInformation.dwProcessId;
3859 if (IsWin95() && ret < 0)
3862 w32_child_handles[w32_num_children] = ProcessInformation.hProcess;
3863 w32_child_pids[w32_num_children] = (DWORD)ret;
3868 win32_msgwait(aTHX_ 1, &ProcessInformation.hProcess, INFINITE, NULL);
3869 /* FIXME: if msgwait returned due to message perhaps forward the
3870 "signal" to the process
3872 GetExitCodeProcess(ProcessInformation.hProcess, &status);
3874 CloseHandle(ProcessInformation.hProcess);
3877 CloseHandle(ProcessInformation.hThread);
3880 PerlEnv_free_childenv(env);
3881 PerlEnv_free_childdir(dir);
3883 if (cname != cmdname)
3890 win32_execv(const char *cmdname, const char *const *argv)
3894 /* if this is a pseudo-forked child, we just want to spawn
3895 * the new program, and return */
3897 # ifdef __BORLANDC__
3898 return spawnv(P_WAIT, cmdname, (char *const *)argv);
3900 return spawnv(P_WAIT, cmdname, argv);
3904 return execv(cmdname, (char *const *)argv);
3906 return execv(cmdname, argv);
3911 win32_execvp(const char *cmdname, const char *const *argv)
3915 /* if this is a pseudo-forked child, we just want to spawn
3916 * the new program, and return */
3917 if (w32_pseudo_id) {
3918 int status = win32_spawnvp(P_WAIT, cmdname, (const char *const *)argv);
3928 return execvp(cmdname, (char *const *)argv);
3930 return execvp(cmdname, argv);
3935 win32_perror(const char *str)
3941 win32_setbuf(FILE *pf, char *buf)
3947 win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
3949 return setvbuf(pf, buf, type, size);
3953 win32_flushall(void)
3959 win32_fcloseall(void)
3965 win32_fgets(char *s, int n, FILE *pf)
3967 return fgets(s, n, pf);
3977 win32_fgetc(FILE *pf)
3983 win32_putc(int c, FILE *pf)
3989 win32_puts(const char *s)
4001 win32_putchar(int c)
4008 #ifndef USE_PERL_SBRK
4010 static char *committed = NULL; /* XXX threadead */
4011 static char *base = NULL; /* XXX threadead */
4012 static char *reserved = NULL; /* XXX threadead */
4013 static char *brk = NULL; /* XXX threadead */
4014 static DWORD pagesize = 0; /* XXX threadead */
4017 sbrk(ptrdiff_t need)
4022 GetSystemInfo(&info);
4023 /* Pretend page size is larger so we don't perpetually
4024 * call the OS to commit just one page ...
4026 pagesize = info.dwPageSize << 3;
4028 if (brk+need >= reserved)
4030 DWORD size = brk+need-reserved;
4032 char *prev_committed = NULL;
4033 if (committed && reserved && committed < reserved)
4035 /* Commit last of previous chunk cannot span allocations */
4036 addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
4039 /* Remember where we committed from in case we want to decommit later */
4040 prev_committed = committed;
4041 committed = reserved;
4044 /* Reserve some (more) space
4045 * Contiguous blocks give us greater efficiency, so reserve big blocks -
4046 * this is only address space not memory...
4047 * Note this is a little sneaky, 1st call passes NULL as reserved
4048 * so lets system choose where we start, subsequent calls pass
4049 * the old end address so ask for a contiguous block
4052 if (size < 64*1024*1024)
4053 size = 64*1024*1024;
4054 size = ((size + pagesize - 1) / pagesize) * pagesize;
4055 addr = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
4058 reserved = addr+size;
4068 /* The existing block could not be extended far enough, so decommit
4069 * anything that was just committed above and start anew */
4072 if (!VirtualFree(prev_committed,reserved-prev_committed,MEM_DECOMMIT))
4075 reserved = base = committed = brk = NULL;
4086 if (brk > committed)
4088 DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
4090 if (committed+size > reserved)
4091 size = reserved-committed;
4092 addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
4105 win32_malloc(size_t size)
4107 return malloc(size);
4111 win32_calloc(size_t numitems, size_t size)
4113 return calloc(numitems,size);
4117 win32_realloc(void *block, size_t size)
4119 return realloc(block,size);
4123 win32_free(void *block)
4130 win32_open_osfhandle(intptr_t handle, int flags)
4132 #ifdef USE_FIXED_OSFHANDLE
4134 return my_open_osfhandle(handle, flags);
4136 return _open_osfhandle(handle, flags);
4140 win32_get_osfhandle(int fd)
4142 return (intptr_t)_get_osfhandle(fd);
4146 win32_fdupopen(FILE *pf)
4151 int fileno = win32_dup(win32_fileno(pf));
4153 /* open the file in the same mode */
4155 if((pf)->flags & _F_READ) {
4159 else if((pf)->flags & _F_WRIT) {
4163 else if((pf)->flags & _F_RDWR) {
4169 if((pf)->_flag & _IOREAD) {
4173 else if((pf)->_flag & _IOWRT) {
4177 else if((pf)->_flag & _IORW) {
4184 /* it appears that the binmode is attached to the
4185 * file descriptor so binmode files will be handled
4188 pfdup = win32_fdopen(fileno, mode);
4190 /* move the file pointer to the same position */
4191 if (!fgetpos(pf, &pos)) {
4192 fsetpos(pfdup, &pos);
4198 win32_dynaload(const char* filename)
4201 char buf[MAX_PATH+1];
4204 /* LoadLibrary() doesn't recognize forward slashes correctly,
4205 * so turn 'em back. */
4206 first = strchr(filename, '/');
4208 STRLEN len = strlen(filename);
4209 if (len <= MAX_PATH) {
4210 strcpy(buf, filename);
4211 filename = &buf[first - filename];
4213 if (*filename == '/')
4214 *(char*)filename = '\\';
4220 return LoadLibraryExA(PerlDir_mapA(filename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
4228 XS(w32_SetChildShowWindow)
4231 BOOL use_showwindow = w32_use_showwindow;
4232 /* use "unsigned short" because Perl has redefined "WORD" */
4233 unsigned short showwindow = w32_showwindow;
4236 Perl_croak(aTHX_ "usage: Win32::SetChildShowWindow($showwindow)");
4238 if (items == 0 || !SvOK(ST(0)))
4239 w32_use_showwindow = FALSE;
4241 w32_use_showwindow = TRUE;
4242 w32_showwindow = (unsigned short)SvIV(ST(0));
4247 ST(0) = sv_2mortal(newSViv(showwindow));
4249 ST(0) = &PL_sv_undef;
4257 /* Make the host for current directory */
4258 char* ptr = PerlEnv_get_childdir();
4261 * then it worked, set PV valid,
4262 * else return 'undef'
4265 SV *sv = sv_newmortal();
4267 PerlEnv_free_childdir(ptr);
4269 #ifndef INCOMPLETE_TAINTS
4286 Perl_croak(aTHX_ "usage: Win32::SetCurrentDirectory($cwd)");
4287 if (!PerlDir_chdir(SvPV_nolen(ST(0))))
4294 XS(w32_GetNextAvailDrive)
4298 char root[] = "_:\\";
4303 if (GetDriveType(root) == 1) {
4312 XS(w32_GetLastError)
4316 XSRETURN_IV(GetLastError());
4320 XS(w32_SetLastError)
4324 Perl_croak(aTHX_ "usage: Win32::SetLastError($error)");
4325 SetLastError(SvIV(ST(0)));
4333 char *name = w32_getlogin_buffer;
4334 DWORD size = sizeof(w32_getlogin_buffer);
4336 if (GetUserName(name,&size)) {
4337 /* size includes NULL */
4338 ST(0) = sv_2mortal(newSVpvn(name,size-1));
4348 char name[MAX_COMPUTERNAME_LENGTH+1];
4349 DWORD size = sizeof(name);
4351 if (GetComputerName(name,&size)) {
4352 /* size does NOT include NULL :-( */
4353 ST(0) = sv_2mortal(newSVpvn(name,size));
4364 HINSTANCE hNetApi32 = LoadLibrary("netapi32.dll");
4365 DWORD (__stdcall *pfnNetApiBufferFree)(LPVOID Buffer);
4366 DWORD (__stdcall *pfnNetWkstaGetInfo)(LPWSTR servername, DWORD level,
4370 pfnNetApiBufferFree = (DWORD (__stdcall *)(void *))
4371 GetProcAddress(hNetApi32, "NetApiBufferFree");
4372 pfnNetWkstaGetInfo = (DWORD (__stdcall *)(LPWSTR, DWORD, void *))
4373 GetProcAddress(hNetApi32, "NetWkstaGetInfo");
4376 if (hNetApi32 && pfnNetWkstaGetInfo && pfnNetApiBufferFree) {
4377 /* this way is more reliable, in case user has a local account. */
4379 DWORD dnamelen = sizeof(dname);
4381 DWORD wki100_platform_id;
4382 LPWSTR wki100_computername;
4383 LPWSTR wki100_langroup;
4384 DWORD wki100_ver_major;
4385 DWORD wki100_ver_minor;
4387 /* NERR_Success *is* 0*/
4388 if (0 == pfnNetWkstaGetInfo(NULL, 100, &pwi)) {
4389 if (pwi->wki100_langroup && *(pwi->wki100_langroup)) {
4390 WideCharToMultiByte(CP_ACP, 0, pwi->wki100_langroup,
4391 -1, (LPSTR)dname, dnamelen, NULL, NULL);
4394 WideCharToMultiByte(CP_ACP, 0, pwi->wki100_computername,
4395 -1, (LPSTR)dname, dnamelen, NULL, NULL);
4397 pfnNetApiBufferFree(pwi);
4398 FreeLibrary(hNetApi32);
4401 FreeLibrary(hNetApi32);
4404 /* Win95 doesn't have NetWksta*(), so do it the old way */
4406 DWORD size = sizeof(name);
4408 FreeLibrary(hNetApi32);
4409 if (GetUserName(name,&size)) {
4410 char sid[ONE_K_BUFSIZE];
4411 DWORD sidlen = sizeof(sid);
4413 DWORD dnamelen = sizeof(dname);
4415 if (LookupAccountName(NULL, name, (PSID)&sid, &sidlen,
4416 dname, &dnamelen, &snu)) {
4417 XSRETURN_PV(dname); /* all that for this */
4429 DWORD flags, filecomplen;
4430 if (GetVolumeInformation(NULL, NULL, 0, NULL, &filecomplen,
4431 &flags, fsname, sizeof(fsname))) {
4432 if (GIMME_V == G_ARRAY) {
4433 XPUSHs(sv_2mortal(newSVpvn(fsname,strlen(fsname))));
4434 XPUSHs(sv_2mortal(newSViv(flags)));
4435 XPUSHs(sv_2mortal(newSViv(filecomplen)));
4440 XSRETURN_PV(fsname);
4446 XS(w32_GetOSVersion)
4449 /* Use explicit struct definition because wSuiteMask and
4450 * wProductType are not defined in the VC++ 6.0 headers.
4451 * WORD type has been replaced by unsigned short because
4452 * WORD is already used by Perl itself.
4455 DWORD dwOSVersionInfoSize;
4456 DWORD dwMajorVersion;
4457 DWORD dwMinorVersion;
4458 DWORD dwBuildNumber;
4460 CHAR szCSDVersion[128];
4461 unsigned short wServicePackMajor;
4462 unsigned short wServicePackMinor;
4463 unsigned short wSuiteMask;
4469 osver.dwOSVersionInfoSize = sizeof(osver);
4470 if (!GetVersionExA((OSVERSIONINFOA*)&osver)) {
4472 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
4473 if (!GetVersionExA((OSVERSIONINFOA*)&osver)) {
4477 if (GIMME_V == G_SCALAR) {
4478 XSRETURN_IV(osver.dwPlatformId);
4480 XPUSHs(newSVpvn(osver.szCSDVersion, strlen(osver.szCSDVersion)));
4482 XPUSHs(newSViv(osver.dwMajorVersion));
4483 XPUSHs(newSViv(osver.dwMinorVersion));
4484 XPUSHs(newSViv(osver.dwBuildNumber));
4485 XPUSHs(newSViv(osver.dwPlatformId));
4487 XPUSHs(newSViv(osver.wServicePackMajor));
4488 XPUSHs(newSViv(osver.wServicePackMinor));
4489 XPUSHs(newSViv(osver.wSuiteMask));
4490 XPUSHs(newSViv(osver.wProductType));
4500 XSRETURN_IV(IsWinNT());
4508 XSRETURN_IV(IsWin95());
4512 XS(w32_FormatMessage)
4516 char msgbuf[ONE_K_BUFSIZE];
4519 Perl_croak(aTHX_ "usage: Win32::FormatMessage($errno)");
4521 if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,
4522 &source, SvIV(ST(0)), 0,
4523 msgbuf, sizeof(msgbuf)-1, NULL))
4525 XSRETURN_PV(msgbuf);
4538 PROCESS_INFORMATION stProcInfo;
4539 STARTUPINFO stStartInfo;
4540 BOOL bSuccess = FALSE;
4543 Perl_croak(aTHX_ "usage: Win32::Spawn($cmdName, $args, $PID)");
4545 cmd = SvPV_nolen(ST(0));
4546 args = SvPV_nolen(ST(1));
4548 env = PerlEnv_get_childenv();
4549 dir = PerlEnv_get_childdir();
4551 memset(&stStartInfo, 0, sizeof(stStartInfo)); /* Clear the block */
4552 stStartInfo.cb = sizeof(stStartInfo); /* Set the structure size */
4553 stStartInfo.dwFlags = STARTF_USESHOWWINDOW; /* Enable wShowWindow control */
4554 stStartInfo.wShowWindow = SW_SHOWMINNOACTIVE; /* Start min (normal) */
4557 cmd, /* Image path */
4558 args, /* Arguments for command line */
4559 NULL, /* Default process security */
4560 NULL, /* Default thread security */
4561 FALSE, /* Must be TRUE to use std handles */
4562 NORMAL_PRIORITY_CLASS, /* No special scheduling */
4563 env, /* Inherit our environment block */
4564 dir, /* Inherit our currrent directory */
4565 &stStartInfo, /* -> Startup info */
4566 &stProcInfo)) /* <- Process info (if OK) */
4568 int pid = (int)stProcInfo.dwProcessId;
4569 if (IsWin95() && pid < 0)
4571 sv_setiv(ST(2), pid);
4572 CloseHandle(stProcInfo.hThread);/* library source code does this. */
4575 PerlEnv_free_childenv(env);
4576 PerlEnv_free_childdir(dir);
4577 XSRETURN_IV(bSuccess);
4581 XS(w32_GetTickCount)
4584 DWORD msec = GetTickCount();
4592 XS(w32_GetShortPathName)
4599 Perl_croak(aTHX_ "usage: Win32::GetShortPathName($longPathName)");
4601 shortpath = sv_mortalcopy(ST(0));
4602 SvUPGRADE(shortpath, SVt_PV);
4603 if (!SvPVX(shortpath) || !SvLEN(shortpath))
4606 /* src == target is allowed */
4608 len = GetShortPathName(SvPVX(shortpath),
4611 } while (len >= SvLEN(shortpath) && sv_grow(shortpath,len+1));
4613 SvCUR_set(shortpath,len);
4614 *SvEND(shortpath) = '\0';
4622 XS(w32_GetFullPathName)
4629 STRLEN filename_len;
4633 Perl_croak(aTHX_ "usage: Win32::GetFullPathName($filename)");
4636 filename_p = SvPV(filename, filename_len);
4637 fullpath = sv_2mortal(newSVpvn(filename_p, filename_len));
4638 if (!SvPVX(fullpath) || !SvLEN(fullpath))
4642 len = GetFullPathName(SvPVX(filename),
4646 } while (len >= SvLEN(fullpath) && sv_grow(fullpath,len+1));
4648 if (GIMME_V == G_ARRAY) {
4651 XST_mPV(1,filepart);
4652 len = filepart - SvPVX(fullpath);
4659 SvCUR_set(fullpath,len);
4660 *SvEND(fullpath) = '\0';
4668 XS(w32_GetLongPathName)
4672 char tmpbuf[MAX_PATH+1];
4677 Perl_croak(aTHX_ "usage: Win32::GetLongPathName($pathname)");
4680 pathstr = SvPV(path,len);
4681 strcpy(tmpbuf, pathstr);
4682 pathstr = win32_longpath(tmpbuf);
4684 ST(0) = sv_2mortal(newSVpvn(pathstr, strlen(pathstr)));
4695 Perl_croak(aTHX_ "usage: Win32::Sleep($milliseconds)");
4705 char szSourceFile[MAX_PATH+1];
4708 Perl_croak(aTHX_ "usage: Win32::CopyFile($from, $to, $overwrite)");
4709 strcpy(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(0))));
4710 bResult = CopyFileA(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(1))), !SvTRUE(ST(2)));
4717 Perl_init_os_extras(void)
4720 char *file = __FILE__;
4723 /* these names are Activeware compatible */
4724 newXS("Win32::GetCwd", w32_GetCwd, file);
4725 newXS("Win32::SetCwd", w32_SetCwd, file);
4726 newXS("Win32::GetNextAvailDrive", w32_GetNextAvailDrive, file);
4727 newXS("Win32::GetLastError", w32_GetLastError, file);
4728 newXS("Win32::SetLastError", w32_SetLastError, file);
4729 newXS("Win32::LoginName", w32_LoginName, file);
4730 newXS("Win32::NodeName", w32_NodeName, file);
4731 newXS("Win32::DomainName", w32_DomainName, file);
4732 newXS("Win32::FsType", w32_FsType, file);
4733 newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
4734 newXS("Win32::IsWinNT", w32_IsWinNT, file);
4735 newXS("Win32::IsWin95", w32_IsWin95, file);
4736 newXS("Win32::FormatMessage", w32_FormatMessage, file);
4737 newXS("Win32::Spawn", w32_Spawn, file);
4738 newXS("Win32::GetTickCount", w32_GetTickCount, file);
4739 newXS("Win32::GetShortPathName", w32_GetShortPathName, file);
4740 newXS("Win32::GetFullPathName", w32_GetFullPathName, file);
4741 newXS("Win32::GetLongPathName", w32_GetLongPathName, file);
4742 newXS("Win32::CopyFile", w32_CopyFile, file);
4743 newXS("Win32::Sleep", w32_Sleep, file);
4744 newXS("Win32::SetChildShowWindow", w32_SetChildShowWindow, file);
4746 /* XXX Bloat Alert! The following Activeware preloads really
4747 * ought to be part of Win32::Sys::*, so they're not included
4750 /* LookupAccountName
4752 * InitiateSystemShutdown
4753 * AbortSystemShutdown
4754 * ExpandEnvrironmentStrings
4759 win32_signal_context(void)
4764 my_perl = PL_curinterp;
4765 PERL_SET_THX(my_perl);
4769 return PL_curinterp;
4775 win32_ctrlhandler(DWORD dwCtrlType)
4778 dTHXa(PERL_GET_SIG_CONTEXT);
4784 switch(dwCtrlType) {
4785 case CTRL_CLOSE_EVENT:
4786 /* A signal that the system sends to all processes attached to a console when
4787 the user closes the console (either by choosing the Close command from the
4788 console window's System menu, or by choosing the End Task command from the
4791 if (do_raise(aTHX_ 1)) /* SIGHUP */
4792 sig_terminate(aTHX_ 1);
4796 /* A CTRL+c signal was received */
4797 if (do_raise(aTHX_ SIGINT))
4798 sig_terminate(aTHX_ SIGINT);
4801 case CTRL_BREAK_EVENT:
4802 /* A CTRL+BREAK signal was received */
4803 if (do_raise(aTHX_ SIGBREAK))
4804 sig_terminate(aTHX_ SIGBREAK);
4807 case CTRL_LOGOFF_EVENT:
4808 /* A signal that the system sends to all console processes when a user is logging
4809 off. This signal does not indicate which user is logging off, so no
4810 assumptions can be made.
4813 case CTRL_SHUTDOWN_EVENT:
4814 /* A signal that the system sends to all console processes when the system is
4817 if (do_raise(aTHX_ SIGTERM))
4818 sig_terminate(aTHX_ SIGTERM);
4828 Perl_win32_init(int *argcp, char ***argvp)
4830 /* Disable floating point errors, Perl will trap the ones we
4831 * care about. VC++ RTL defaults to switching these off
4832 * already, but the Borland RTL doesn't. Since we don't
4833 * want to be at the vendor's whim on the default, we set
4834 * it explicitly here.
4836 #if !defined(_ALPHA_) && !defined(__GNUC__)
4837 _control87(MCW_EM, MCW_EM);
4843 Perl_win32_term(void)
4850 win32_get_child_IO(child_IO_table* ptbl)
4852 ptbl->childStdIn = GetStdHandle(STD_INPUT_HANDLE);
4853 ptbl->childStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
4854 ptbl->childStdErr = GetStdHandle(STD_ERROR_HANDLE);
4858 win32_signal(int sig, Sighandler_t subcode)
4861 if (sig < SIG_SIZE) {
4862 int save_errno = errno;
4863 Sighandler_t result = signal(sig, subcode);
4864 if (result == SIG_ERR) {
4865 result = w32_sighandler[sig];
4868 w32_sighandler[sig] = subcode;
4878 #ifdef HAVE_INTERP_INTERN
4882 win32_csighandler(int sig)
4885 dTHXa(PERL_GET_SIG_CONTEXT);
4886 Perl_warn(aTHX_ "Got signal %d",sig);