3 * (c) 1995 Microsoft Corporation. All rights reserved.
4 * Developed by hip communications inc., http://info.hip.com/info/
5 * Portions (c) 1993 Intergraph Corporation. All rights reserved.
7 * You may distribute under the terms of either the GNU General Public
8 * License or the Artistic License, as specified in the README file.
10 #define PERLIO_NOT_STDIO 0
11 #define WIN32_LEAN_AND_MEAN
12 #define WIN32IO_IS_STDIO
18 #ifndef __MINGW32__ /* GCC/Mingw32-2.95.2 forgot the WINAPI on CommandLineToArgvW() */
19 # include <shellapi.h>
21 LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCommandLine, int * pNumArgs);
27 /* #include "config.h" */
29 #if !defined(PERLIO_IS_STDIO) && !defined(USE_SFIO)
38 #define PERL_NO_GET_CONTEXT
44 /* assert.h conflicts with #define of assert in perl.h */
51 #if defined(_MSC_VER) || defined(__MINGW32__)
52 #include <sys/utime.h>
57 /* Mingw32 defaults to globing command line
58 * So we turn it off like this:
63 #if defined(__MINGW32__)
64 /* Mingw32 is missing some prototypes */
65 FILE * _wfopen(LPCWSTR wszFileName, LPCWSTR wszMode);
66 FILE * _wfdopen(int nFd, LPCWSTR wszMode);
67 FILE * _freopen(LPCWSTR wszFileName, LPCWSTR wszMode, FILE * pOldStream);
72 #if defined(__BORLANDC__)
74 # define _utimbuf utimbuf
79 #define EXECF_SPAWN_NOWAIT 3
81 #if defined(PERL_IMPLICIT_SYS)
82 # undef win32_get_privlib
83 # define win32_get_privlib g_win32_get_privlib
84 # undef win32_get_sitelib
85 # define win32_get_sitelib g_win32_get_sitelib
86 # undef win32_get_vendorlib
87 # define win32_get_vendorlib g_win32_get_vendorlib
89 # define do_spawn g_do_spawn
91 # define getlogin g_getlogin
94 static void get_shell(void);
95 static long tokenize(const char *str, char **dest, char ***destv);
96 int do_spawn2(char *cmd, int exectype);
97 static BOOL has_shell_metachars(char *ptr);
98 static long filetime_to_clock(PFILETIME ft);
99 static BOOL filetime_from_time(PFILETIME ft, time_t t);
100 static char * get_emd_part(SV **leading, char *trailing, ...);
101 static void remove_dead_process(long deceased);
102 static long find_pid(int pid);
103 static char * qualified_path(const char *cmd);
104 static char * win32_get_xlib(const char *pl, const char *xlib,
105 const char *libname);
108 static void remove_dead_pseudo_process(long child);
109 static long find_pseudo_pid(int pid);
113 HANDLE w32_perldll_handle = INVALID_HANDLE_VALUE;
114 char w32_module_name[MAX_PATH+1];
117 static DWORD w32_platform = (DWORD)-1;
119 #define ONE_K_BUFSIZE 1024
124 return (win32_os_id() == VER_PLATFORM_WIN32_WINDOWS);
130 return (win32_os_id() == VER_PLATFORM_WIN32_NT);
134 set_w32_module_name(void)
137 GetModuleFileName((HMODULE)((w32_perldll_handle == INVALID_HANDLE_VALUE)
138 ? GetModuleHandle(NULL)
139 : w32_perldll_handle),
140 w32_module_name, sizeof(w32_module_name));
142 /* try to get full path to binary (which may be mangled when perl is
143 * run from a 16-bit app) */
144 /*PerlIO_printf(Perl_debug_log, "Before %s\n", w32_module_name);*/
145 (void)win32_longpath(w32_module_name);
146 /*PerlIO_printf(Perl_debug_log, "After %s\n", w32_module_name);*/
148 /* normalize to forward slashes */
149 ptr = w32_module_name;
157 /* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
159 get_regstr_from(HKEY hkey, const char *valuename, SV **svp)
161 /* Retrieve a REG_SZ or REG_EXPAND_SZ from the registry */
164 const char *subkey = "Software\\Perl";
168 retval = RegOpenKeyEx(hkey, subkey, 0, KEY_READ, &handle);
169 if (retval == ERROR_SUCCESS) {
171 retval = RegQueryValueEx(handle, valuename, 0, &type, NULL, &datalen);
172 if (retval == ERROR_SUCCESS
173 && (type == REG_SZ || type == REG_EXPAND_SZ))
177 *svp = sv_2mortal(newSVpvn("",0));
178 SvGROW(*svp, datalen);
179 retval = RegQueryValueEx(handle, valuename, 0, NULL,
180 (PBYTE)SvPVX(*svp), &datalen);
181 if (retval == ERROR_SUCCESS) {
183 SvCUR_set(*svp,datalen-1);
191 /* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
193 get_regstr(const char *valuename, SV **svp)
195 char *str = get_regstr_from(HKEY_CURRENT_USER, valuename, svp);
197 str = get_regstr_from(HKEY_LOCAL_MACHINE, valuename, svp);
201 /* *prev_pathp (if non-NULL) is expected to be POK (valid allocated SvPVX(sv)) */
203 get_emd_part(SV **prev_pathp, char *trailing_path, ...)
207 char mod_name[MAX_PATH+1];
211 int oldsize, newsize;
214 va_start(ap, trailing_path);
215 strip = va_arg(ap, char *);
217 sprintf(base, "%d.%d", (int)PERL_REVISION, (int)PERL_VERSION);
218 baselen = strlen(base);
220 if (!*w32_module_name) {
221 set_w32_module_name();
223 strcpy(mod_name, w32_module_name);
224 ptr = strrchr(mod_name, '/');
225 while (ptr && strip) {
226 /* look for directories to skip back */
229 ptr = strrchr(mod_name, '/');
230 /* avoid stripping component if there is no slash,
231 * or it doesn't match ... */
232 if (!ptr || stricmp(ptr+1, strip) != 0) {
233 /* ... but not if component matches m|5\.$patchlevel.*| */
234 if (!ptr || !(*strip == '5' && *(ptr+1) == '5'
235 && strncmp(strip, base, baselen) == 0
236 && strncmp(ptr+1, base, baselen) == 0))
242 strip = va_arg(ap, char *);
250 strcpy(++ptr, trailing_path);
252 /* only add directory if it exists */
253 if (GetFileAttributes(mod_name) != (DWORD) -1) {
254 /* directory exists */
257 *prev_pathp = sv_2mortal(newSVpvn("",0));
258 sv_catpvn(*prev_pathp, ";", 1);
259 sv_catpv(*prev_pathp, mod_name);
260 return SvPVX(*prev_pathp);
267 win32_get_privlib(const char *pl)
270 char *stdlib = "lib";
271 char buffer[MAX_PATH+1];
274 /* $stdlib = $HKCU{"lib-$]"} || $HKLM{"lib-$]"} || $HKCU{"lib"} || $HKLM{"lib"} || ""; */
275 sprintf(buffer, "%s-%s", stdlib, pl);
276 if (!get_regstr(buffer, &sv))
277 (void)get_regstr(stdlib, &sv);
279 /* $stdlib .= ";$EMD/../../lib" */
280 return get_emd_part(&sv, stdlib, ARCHNAME, "bin", Nullch);
284 win32_get_xlib(const char *pl, const char *xlib, const char *libname)
288 char pathstr[MAX_PATH+1];
294 /* $HKCU{"$xlib-$]"} || $HKLM{"$xlib-$]"} . ---; */
295 sprintf(regstr, "%s-%s", xlib, pl);
296 (void)get_regstr(regstr, &sv1);
299 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/$]/lib"; */
300 sprintf(pathstr, "%s/%s/lib", libname, pl);
301 (void)get_emd_part(&sv1, pathstr, ARCHNAME, "bin", pl, Nullch);
303 /* $HKCU{$xlib} || $HKLM{$xlib} . ---; */
304 (void)get_regstr(xlib, &sv2);
307 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/lib"; */
308 sprintf(pathstr, "%s/lib", libname);
309 (void)get_emd_part(&sv2, pathstr, ARCHNAME, "bin", pl, Nullch);
318 sv_catpvn(sv1, ";", 1);
325 win32_get_sitelib(const char *pl)
327 return win32_get_xlib(pl, "sitelib", "site");
330 #ifndef PERL_VENDORLIB_NAME
331 # define PERL_VENDORLIB_NAME "vendor"
335 win32_get_vendorlib(const char *pl)
337 return win32_get_xlib(pl, "vendorlib", PERL_VENDORLIB_NAME);
341 has_shell_metachars(char *ptr)
347 * Scan string looking for redirection (< or >) or pipe
348 * characters (|) that are not in a quoted string.
349 * Shell variable interpolation (%VAR%) can also happen inside strings.
381 #if !defined(PERL_IMPLICIT_SYS)
382 /* since the current process environment is being updated in util.c
383 * the library functions will get the correct environment
386 Perl_my_popen(pTHX_ char *cmd, char *mode)
389 #define fixcmd(x) { \
390 char *pspace = strchr((x),' '); \
393 while (p < pspace) { \
404 PERL_FLUSHALL_FOR_CHILD;
405 return win32_popen(cmd, mode);
409 Perl_my_pclose(pTHX_ PerlIO *fp)
411 return win32_pclose(fp);
415 DllExport unsigned long
418 static OSVERSIONINFO osver;
420 if (osver.dwPlatformId != w32_platform) {
421 memset(&osver, 0, sizeof(OSVERSIONINFO));
422 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
423 GetVersionEx(&osver);
424 w32_platform = osver.dwPlatformId;
426 return (unsigned long)w32_platform;
436 return -((int)w32_pseudo_id);
439 /* Windows 9x appears to always reports a pid for threads and processes
440 * that has the high bit set. So we treat the lower 31 bits as the
441 * "real" PID for Perl's purposes. */
442 if (IsWin95() && pid < 0)
447 /* Tokenize a string. Words are null-separated, and the list
448 * ends with a doubled null. Any character (except null and
449 * including backslash) may be escaped by preceding it with a
450 * backslash (the backslash will be stripped).
451 * Returns number of words in result buffer.
454 tokenize(const char *str, char **dest, char ***destv)
456 char *retstart = Nullch;
457 char **retvstart = 0;
461 int slen = strlen(str);
463 register char **retv;
464 New(1307, ret, slen+2, char);
465 New(1308, retv, (slen+3)/2, char*);
473 if (*ret == '\\' && *str)
475 else if (*ret == ' ') {
491 retvstart[items] = Nullch;
504 if (!w32_perlshell_tokens) {
505 /* we don't use COMSPEC here for two reasons:
506 * 1. the same reason perl on UNIX doesn't use SHELL--rampant and
507 * uncontrolled unportability of the ensuing scripts.
508 * 2. PERL5SHELL could be set to a shell that may not be fit for
509 * interactive use (which is what most programs look in COMSPEC
512 const char* defaultshell = (IsWinNT()
513 ? "cmd.exe /x/c" : "command.com /c");
514 const char *usershell = PerlEnv_getenv("PERL5SHELL");
515 w32_perlshell_items = tokenize(usershell ? usershell : defaultshell,
516 &w32_perlshell_tokens,
522 do_aspawn(void *vreally, void **vmark, void **vsp)
525 SV *really = (SV*)vreally;
526 SV **mark = (SV**)vmark;
538 New(1306, argv, (sp - mark) + w32_perlshell_items + 2, char*);
540 if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
545 while (++mark <= sp) {
546 if (*mark && (str = SvPV_nolen(*mark)))
553 status = win32_spawnvp(flag,
554 (const char*)(really ? SvPV_nolen(really) : argv[0]),
555 (const char* const*)argv);
557 if (status < 0 && (errno == ENOEXEC || errno == ENOENT)) {
558 /* possible shell-builtin, invoke with shell */
560 sh_items = w32_perlshell_items;
562 argv[index+sh_items] = argv[index];
563 while (--sh_items >= 0)
564 argv[sh_items] = w32_perlshell_vec[sh_items];
566 status = win32_spawnvp(flag,
567 (const char*)(really ? SvPV_nolen(really) : argv[0]),
568 (const char* const*)argv);
571 if (flag == P_NOWAIT) {
573 PL_statusvalue = -1; /* >16bits hint for pp_system() */
577 if (ckWARN(WARN_EXEC))
578 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't spawn \"%s\": %s", argv[0], strerror(errno));
583 PL_statusvalue = status;
589 /* returns pointer to the next unquoted space or the end of the string */
591 find_next_space(const char *s)
593 bool in_quotes = FALSE;
595 /* ignore doubled backslashes, or backslash+quote */
596 if (*s == '\\' && (s[1] == '\\' || s[1] == '"')) {
599 /* keep track of when we're within quotes */
600 else if (*s == '"') {
602 in_quotes = !in_quotes;
604 /* break it up only at spaces that aren't in quotes */
605 else if (!in_quotes && isSPACE(*s))
614 do_spawn2(char *cmd, int exectype)
621 BOOL needToTry = TRUE;
624 /* Save an extra exec if possible. See if there are shell
625 * metacharacters in it */
626 if (!has_shell_metachars(cmd)) {
627 New(1301,argv, strlen(cmd) / 2 + 2, char*);
628 New(1302,cmd2, strlen(cmd) + 1, char);
631 for (s = cmd2; *s;) {
632 while (*s && isSPACE(*s))
636 s = find_next_space(s);
644 status = win32_spawnvp(P_WAIT, argv[0],
645 (const char* const*)argv);
647 case EXECF_SPAWN_NOWAIT:
648 status = win32_spawnvp(P_NOWAIT, argv[0],
649 (const char* const*)argv);
652 status = win32_execvp(argv[0], (const char* const*)argv);
655 if (status != -1 || errno == 0)
665 New(1306, argv, w32_perlshell_items + 2, char*);
666 while (++i < w32_perlshell_items)
667 argv[i] = w32_perlshell_vec[i];
672 status = win32_spawnvp(P_WAIT, argv[0],
673 (const char* const*)argv);
675 case EXECF_SPAWN_NOWAIT:
676 status = win32_spawnvp(P_NOWAIT, argv[0],
677 (const char* const*)argv);
680 status = win32_execvp(argv[0], (const char* const*)argv);
686 if (exectype == EXECF_SPAWN_NOWAIT) {
688 PL_statusvalue = -1; /* >16bits hint for pp_system() */
692 if (ckWARN(WARN_EXEC))
693 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s \"%s\": %s",
694 (exectype == EXECF_EXEC ? "exec" : "spawn"),
695 cmd, strerror(errno));
700 PL_statusvalue = status;
708 return do_spawn2(cmd, EXECF_SPAWN);
712 do_spawn_nowait(char *cmd)
714 return do_spawn2(cmd, EXECF_SPAWN_NOWAIT);
718 Perl_do_exec(pTHX_ char *cmd)
720 do_spawn2(cmd, EXECF_EXEC);
724 /* The idea here is to read all the directory names into a string table
725 * (separated by nulls) and when one of the other dir functions is called
726 * return the pointer to the current file name.
729 win32_opendir(char *filename)
735 char scanname[MAX_PATH+3];
737 WIN32_FIND_DATAA aFindData;
738 WIN32_FIND_DATAW wFindData;
740 char buffer[MAX_PATH*2];
741 WCHAR wbuffer[MAX_PATH+1];
744 len = strlen(filename);
748 /* check to see if filename is a directory */
749 if (win32_stat(filename, &sbuf) < 0 || !S_ISDIR(sbuf.st_mode))
752 /* Get us a DIR structure */
753 Newz(1303, dirp, 1, DIR);
755 /* Create the search pattern */
756 strcpy(scanname, filename);
758 /* bare drive name means look in cwd for drive */
759 if (len == 2 && isALPHA(scanname[0]) && scanname[1] == ':') {
760 scanname[len++] = '.';
761 scanname[len++] = '/';
763 else if (scanname[len-1] != '/' && scanname[len-1] != '\\') {
764 scanname[len++] = '/';
766 scanname[len++] = '*';
767 scanname[len] = '\0';
769 /* do the FindFirstFile call */
771 A2WHELPER(scanname, wbuffer, sizeof(wbuffer));
772 fh = FindFirstFileW(PerlDir_mapW(wbuffer), &wFindData);
775 fh = FindFirstFileA(PerlDir_mapA(scanname), &aFindData);
778 if (fh == INVALID_HANDLE_VALUE) {
779 DWORD err = GetLastError();
780 /* FindFirstFile() fails on empty drives! */
782 case ERROR_FILE_NOT_FOUND:
784 case ERROR_NO_MORE_FILES:
785 case ERROR_PATH_NOT_FOUND:
788 case ERROR_NOT_ENOUGH_MEMORY:
799 /* now allocate the first part of the string table for
800 * the filenames that we find.
803 W2AHELPER(wFindData.cFileName, buffer, sizeof(buffer));
807 ptr = aFindData.cFileName;
814 New(1304, dirp->start, dirp->size, char);
815 strcpy(dirp->start, ptr);
817 dirp->end = dirp->curr = dirp->start;
823 /* Readdir just returns the current string pointer and bumps the
824 * string pointer to the nDllExport entry.
826 DllExport struct direct *
827 win32_readdir(DIR *dirp)
832 /* first set up the structure to return */
833 len = strlen(dirp->curr);
834 strcpy(dirp->dirstr.d_name, dirp->curr);
835 dirp->dirstr.d_namlen = len;
838 dirp->dirstr.d_ino = dirp->curr - dirp->start;
840 /* Now set up for the next call to readdir */
841 dirp->curr += len + 1;
842 if (dirp->curr >= dirp->end) {
846 WIN32_FIND_DATAW wFindData;
847 WIN32_FIND_DATAA aFindData;
848 char buffer[MAX_PATH*2];
850 /* finding the next file that matches the wildcard
851 * (which should be all of them in this directory!).
854 res = FindNextFileW(dirp->handle, &wFindData);
856 W2AHELPER(wFindData.cFileName, buffer, sizeof(buffer));
861 res = FindNextFileA(dirp->handle, &aFindData);
863 ptr = aFindData.cFileName;
866 long endpos = dirp->end - dirp->start;
867 long newsize = endpos + strlen(ptr) + 1;
868 /* bump the string table size by enough for the
869 * new name and its null terminator */
870 while (newsize > dirp->size) {
871 long curpos = dirp->curr - dirp->start;
873 Renew(dirp->start, dirp->size, char);
874 dirp->curr = dirp->start + curpos;
876 strcpy(dirp->start + endpos, ptr);
877 dirp->end = dirp->start + newsize;
883 return &(dirp->dirstr);
889 /* Telldir returns the current string pointer position */
891 win32_telldir(DIR *dirp)
893 return (dirp->curr - dirp->start);
897 /* Seekdir moves the string pointer to a previously saved position
898 * (returned by telldir).
901 win32_seekdir(DIR *dirp, long loc)
903 dirp->curr = dirp->start + loc;
906 /* Rewinddir resets the string pointer to the start */
908 win32_rewinddir(DIR *dirp)
910 dirp->curr = dirp->start;
913 /* free the memory allocated by opendir */
915 win32_closedir(DIR *dirp)
918 if (dirp->handle != INVALID_HANDLE_VALUE)
919 FindClose(dirp->handle);
920 Safefree(dirp->start);
933 * Just pretend that everyone is a superuser. NT will let us know if
934 * we don\'t really have permission to do something.
937 #define ROOT_UID ((uid_t)0)
938 #define ROOT_GID ((gid_t)0)
967 return (auid == ROOT_UID ? 0 : -1);
973 return (agid == ROOT_GID ? 0 : -1);
980 char *buf = w32_getlogin_buffer;
981 DWORD size = sizeof(w32_getlogin_buffer);
982 if (GetUserName(buf,&size))
988 chown(const char *path, uid_t owner, gid_t group)
995 * XXX this needs strengthening (for PerlIO)
998 int mkstemp(const char *path)
1001 char buf[MAX_PATH+1];
1005 if (i++ > 10) { /* give up */
1009 if (!GetTempFileNameA((LPCSTR)path, "plr", 1, buf)) {
1013 fd = PerlLIO_open3(buf, O_CREAT|O_RDWR|O_EXCL, 0600);
1023 long child = w32_num_children;
1024 while (--child >= 0) {
1025 if (w32_child_pids[child] == pid)
1032 remove_dead_process(long child)
1036 CloseHandle(w32_child_handles[child]);
1037 Move(&w32_child_handles[child+1], &w32_child_handles[child],
1038 (w32_num_children-child-1), HANDLE);
1039 Move(&w32_child_pids[child+1], &w32_child_pids[child],
1040 (w32_num_children-child-1), DWORD);
1047 find_pseudo_pid(int pid)
1050 long child = w32_num_pseudo_children;
1051 while (--child >= 0) {
1052 if (w32_pseudo_child_pids[child] == pid)
1059 remove_dead_pseudo_process(long child)
1063 CloseHandle(w32_pseudo_child_handles[child]);
1064 Move(&w32_pseudo_child_handles[child+1], &w32_pseudo_child_handles[child],
1065 (w32_num_pseudo_children-child-1), HANDLE);
1066 Move(&w32_pseudo_child_pids[child+1], &w32_pseudo_child_pids[child],
1067 (w32_num_pseudo_children-child-1), DWORD);
1068 w32_num_pseudo_children--;
1074 win32_kill(int pid, int sig)
1081 /* it is a pseudo-forked child */
1082 child = find_pseudo_pid(-pid);
1084 hProcess = w32_pseudo_child_handles[child];
1087 /* "Does process exist?" use of kill */
1090 /* kill -9 style un-graceful exit */
1091 if (TerminateThread(hProcess, sig)) {
1092 remove_dead_pseudo_process(child);
1097 /* We fake signals to pseudo-processes using Win32
1098 * message queue. In Win9X the pids are negative already. */
1099 if (PostThreadMessage(IsWin95() ? pid : -pid,WM_USER,sig,0)) {
1100 /* It might be us ... */
1107 else if (IsWin95()) {
1115 child = find_pid(pid);
1117 hProcess = w32_child_handles[child];
1120 /* "Does process exist?" use of kill */
1123 if (GenerateConsoleCtrlEvent(CTRL_C_EVENT,pid))
1126 default: /* For now be backwards compatible with perl5.6 */
1128 if (TerminateProcess(hProcess, sig)) {
1129 remove_dead_process(child);
1137 hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE,
1138 (IsWin95() ? -pid : pid));
1142 /* "Does process exist?" use of kill */
1145 if (GenerateConsoleCtrlEvent(CTRL_C_EVENT,pid))
1148 default: /* For now be backwards compatible with perl5.6 */
1150 if (TerminateProcess(hProcess, sig)) {
1151 CloseHandle(hProcess);
1163 win32_stat(const char *path, Stat_t *sbuf)
1166 char buffer[MAX_PATH+1];
1167 int l = strlen(path);
1169 WCHAR wbuffer[MAX_PATH+1];
1175 switch(path[l - 1]) {
1176 /* FindFirstFile() and stat() are buggy with a trailing
1177 * backslash, so change it to a forward slash :-( */
1179 strncpy(buffer, path, l-1);
1180 buffer[l - 1] = '/';
1184 /* FindFirstFile() is buggy with "x:", so add a dot :-( */
1186 if (l == 2 && isALPHA(path[0])) {
1187 buffer[0] = path[0];
1198 /* We *must* open & close the file once; otherwise file attribute changes */
1199 /* might not yet have propagated to "other" hard links of the same file. */
1200 /* This also gives us an opportunity to determine the number of links. */
1202 A2WHELPER(path, wbuffer, sizeof(wbuffer));
1203 pwbuffer = PerlDir_mapW(wbuffer);
1204 handle = CreateFileW(pwbuffer, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
1207 path = PerlDir_mapA(path);
1209 handle = CreateFileA(path, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
1211 if (handle != INVALID_HANDLE_VALUE) {
1212 BY_HANDLE_FILE_INFORMATION bhi;
1213 if (GetFileInformationByHandle(handle, &bhi))
1214 nlink = bhi.nNumberOfLinks;
1215 CloseHandle(handle);
1218 /* pwbuffer or path will be mapped correctly above */
1220 #if defined(WIN64) || defined(USE_LARGE_FILES)
1221 res = _wstati64(pwbuffer, sbuf);
1223 res = _wstat(pwbuffer, sbuf);
1227 #if defined(WIN64) || defined(USE_LARGE_FILES)
1228 res = _stati64(path, sbuf);
1230 res = stat(path, sbuf);
1233 sbuf->st_nlink = nlink;
1236 /* CRT is buggy on sharenames, so make sure it really isn't.
1237 * XXX using GetFileAttributesEx() will enable us to set
1238 * sbuf->st_*time (but note that's not available on the
1239 * Windows of 1995) */
1242 r = GetFileAttributesW(pwbuffer);
1245 r = GetFileAttributesA(path);
1247 if (r != 0xffffffff && (r & FILE_ATTRIBUTE_DIRECTORY)) {
1248 /* sbuf may still contain old garbage since stat() failed */
1249 Zero(sbuf, 1, Stat_t);
1250 sbuf->st_mode = S_IFDIR | S_IREAD;
1252 if (!(r & FILE_ATTRIBUTE_READONLY))
1253 sbuf->st_mode |= S_IWRITE | S_IEXEC;
1258 if (l == 3 && isALPHA(path[0]) && path[1] == ':'
1259 && (path[2] == '\\' || path[2] == '/'))
1261 /* The drive can be inaccessible, some _stat()s are buggy */
1263 ? !GetVolumeInformationW(pwbuffer,NULL,0,NULL,NULL,NULL,NULL,0)
1264 : !GetVolumeInformationA(path,NULL,0,NULL,NULL,NULL,NULL,0)) {
1270 if (S_ISDIR(sbuf->st_mode))
1271 sbuf->st_mode |= S_IWRITE | S_IEXEC;
1272 else if (S_ISREG(sbuf->st_mode)) {
1274 if (l >= 4 && path[l-4] == '.') {
1275 const char *e = path + l - 3;
1276 if (strnicmp(e,"exe",3)
1277 && strnicmp(e,"bat",3)
1278 && strnicmp(e,"com",3)
1279 && (IsWin95() || strnicmp(e,"cmd",3)))
1280 sbuf->st_mode &= ~S_IEXEC;
1282 sbuf->st_mode |= S_IEXEC;
1285 sbuf->st_mode &= ~S_IEXEC;
1286 /* Propagate permissions to _group_ and _others_ */
1287 perms = sbuf->st_mode & (S_IREAD|S_IWRITE|S_IEXEC);
1288 sbuf->st_mode |= (perms>>3) | (perms>>6);
1295 #define isSLASH(c) ((c) == '/' || (c) == '\\')
1296 #define SKIP_SLASHES(s) \
1298 while (*(s) && isSLASH(*(s))) \
1301 #define COPY_NONSLASHES(d,s) \
1303 while (*(s) && !isSLASH(*(s))) \
1307 /* Find the longname of a given path. path is destructively modified.
1308 * It should have space for at least MAX_PATH characters. */
1310 win32_longpath(char *path)
1312 WIN32_FIND_DATA fdata;
1314 char tmpbuf[MAX_PATH+1];
1315 char *tmpstart = tmpbuf;
1322 if (isALPHA(path[0]) && path[1] == ':') {
1324 *tmpstart++ = path[0];
1328 else if (isSLASH(path[0]) && isSLASH(path[1])) {
1330 *tmpstart++ = path[0];
1331 *tmpstart++ = path[1];
1332 SKIP_SLASHES(start);
1333 COPY_NONSLASHES(tmpstart,start); /* copy machine name */
1335 *tmpstart++ = *start++;
1336 SKIP_SLASHES(start);
1337 COPY_NONSLASHES(tmpstart,start); /* copy share name */
1342 /* copy initial slash, if any */
1343 if (isSLASH(*start)) {
1344 *tmpstart++ = *start++;
1346 SKIP_SLASHES(start);
1349 /* FindFirstFile() expands "." and "..", so we need to pass
1350 * those through unmolested */
1352 && (!start[1] || isSLASH(start[1])
1353 || (start[1] == '.' && (!start[2] || isSLASH(start[2])))))
1355 COPY_NONSLASHES(tmpstart,start); /* copy "." or ".." */
1360 /* if this is the end, bust outta here */
1364 /* now we're at a non-slash; walk up to next slash */
1365 while (*start && !isSLASH(*start))
1368 /* stop and find full name of component */
1371 fhand = FindFirstFile(path,&fdata);
1373 if (fhand != INVALID_HANDLE_VALUE) {
1374 STRLEN len = strlen(fdata.cFileName);
1375 if ((STRLEN)(tmpbuf + sizeof(tmpbuf) - tmpstart) > len) {
1376 strcpy(tmpstart, fdata.cFileName);
1387 /* failed a step, just return without side effects */
1388 /*PerlIO_printf(Perl_debug_log, "Failed to find %s\n", path);*/
1393 strcpy(path,tmpbuf);
1398 win32_getenv(const char *name)
1401 WCHAR wBuffer[MAX_PATH+1];
1403 SV *curitem = Nullsv;
1406 A2WHELPER(name, wBuffer, sizeof(wBuffer));
1407 needlen = GetEnvironmentVariableW(wBuffer, NULL, 0);
1410 needlen = GetEnvironmentVariableA(name,NULL,0);
1412 curitem = sv_2mortal(newSVpvn("", 0));
1416 SvGROW(curitem, (needlen+1)*sizeof(WCHAR));
1417 needlen = GetEnvironmentVariableW(wBuffer,
1418 (WCHAR*)SvPVX(curitem),
1420 } while (needlen >= SvLEN(curitem)/sizeof(WCHAR));
1421 SvCUR_set(curitem, (needlen*sizeof(WCHAR))+1);
1422 acuritem = sv_2mortal(newSVsv(curitem));
1423 W2AHELPER((WCHAR*)SvPVX(acuritem), SvPVX(curitem), SvCUR(curitem));
1427 SvGROW(curitem, needlen+1);
1428 needlen = GetEnvironmentVariableA(name,SvPVX(curitem),
1430 } while (needlen >= SvLEN(curitem));
1431 SvCUR_set(curitem, needlen);
1435 /* allow any environment variables that begin with 'PERL'
1436 to be stored in the registry */
1437 if (strncmp(name, "PERL", 4) == 0)
1438 (void)get_regstr(name, &curitem);
1440 if (curitem && SvCUR(curitem))
1441 return SvPVX(curitem);
1447 win32_putenv(const char *name)
1454 int length, relval = -1;
1458 length = strlen(name)+1;
1459 New(1309,wCuritem,length,WCHAR);
1460 A2WHELPER(name, wCuritem, length*sizeof(WCHAR));
1461 wVal = wcschr(wCuritem, '=');
1464 if (SetEnvironmentVariableW(wCuritem, *wVal ? wVal : NULL))
1470 New(1309,curitem,strlen(name)+1,char);
1471 strcpy(curitem, name);
1472 val = strchr(curitem, '=');
1474 /* The sane way to deal with the environment.
1475 * Has these advantages over putenv() & co.:
1476 * * enables us to store a truly empty value in the
1477 * environment (like in UNIX).
1478 * * we don't have to deal with RTL globals, bugs and leaks.
1480 * Why you may want to enable USE_WIN32_RTL_ENV:
1481 * * environ[] and RTL functions will not reflect changes,
1482 * which might be an issue if extensions want to access
1483 * the env. via RTL. This cuts both ways, since RTL will
1484 * not see changes made by extensions that call the Win32
1485 * functions directly, either.
1489 if (SetEnvironmentVariableA(curitem, *val ? val : NULL))
1499 filetime_to_clock(PFILETIME ft)
1501 __int64 qw = ft->dwHighDateTime;
1503 qw |= ft->dwLowDateTime;
1504 qw /= 10000; /* File time ticks at 0.1uS, clock at 1mS */
1509 win32_times(struct tms *timebuf)
1514 clock_t process_time_so_far = clock();
1515 if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy,
1517 timebuf->tms_utime = filetime_to_clock(&user);
1518 timebuf->tms_stime = filetime_to_clock(&kernel);
1519 timebuf->tms_cutime = 0;
1520 timebuf->tms_cstime = 0;
1522 /* That failed - e.g. Win95 fallback to clock() */
1523 timebuf->tms_utime = process_time_so_far;
1524 timebuf->tms_stime = 0;
1525 timebuf->tms_cutime = 0;
1526 timebuf->tms_cstime = 0;
1528 return process_time_so_far;
1531 /* fix utime() so it works on directories in NT */
1533 filetime_from_time(PFILETIME pFileTime, time_t Time)
1535 struct tm *pTM = localtime(&Time);
1536 SYSTEMTIME SystemTime;
1542 SystemTime.wYear = pTM->tm_year + 1900;
1543 SystemTime.wMonth = pTM->tm_mon + 1;
1544 SystemTime.wDay = pTM->tm_mday;
1545 SystemTime.wHour = pTM->tm_hour;
1546 SystemTime.wMinute = pTM->tm_min;
1547 SystemTime.wSecond = pTM->tm_sec;
1548 SystemTime.wMilliseconds = 0;
1550 return SystemTimeToFileTime(&SystemTime, &LocalTime) &&
1551 LocalFileTimeToFileTime(&LocalTime, pFileTime);
1555 win32_unlink(const char *filename)
1562 WCHAR wBuffer[MAX_PATH+1];
1565 A2WHELPER(filename, wBuffer, sizeof(wBuffer));
1566 pwBuffer = PerlDir_mapW(wBuffer);
1567 attrs = GetFileAttributesW(pwBuffer);
1568 if (attrs == 0xFFFFFFFF)
1570 if (attrs & FILE_ATTRIBUTE_READONLY) {
1571 (void)SetFileAttributesW(pwBuffer, attrs & ~FILE_ATTRIBUTE_READONLY);
1572 ret = _wunlink(pwBuffer);
1574 (void)SetFileAttributesW(pwBuffer, attrs);
1577 ret = _wunlink(pwBuffer);
1580 filename = PerlDir_mapA(filename);
1581 attrs = GetFileAttributesA(filename);
1582 if (attrs == 0xFFFFFFFF)
1584 if (attrs & FILE_ATTRIBUTE_READONLY) {
1585 (void)SetFileAttributesA(filename, attrs & ~FILE_ATTRIBUTE_READONLY);
1586 ret = unlink(filename);
1588 (void)SetFileAttributesA(filename, attrs);
1591 ret = unlink(filename);
1600 win32_utime(const char *filename, struct utimbuf *times)
1607 struct utimbuf TimeBuffer;
1608 WCHAR wbuffer[MAX_PATH+1];
1613 A2WHELPER(filename, wbuffer, sizeof(wbuffer));
1614 pwbuffer = PerlDir_mapW(wbuffer);
1615 rc = _wutime(pwbuffer, (struct _utimbuf*)times);
1618 filename = PerlDir_mapA(filename);
1619 rc = utime(filename, times);
1621 /* EACCES: path specifies directory or readonly file */
1622 if (rc == 0 || errno != EACCES /* || !IsWinNT() */)
1625 if (times == NULL) {
1626 times = &TimeBuffer;
1627 time(×->actime);
1628 times->modtime = times->actime;
1631 /* This will (and should) still fail on readonly files */
1633 handle = CreateFileW(pwbuffer, GENERIC_READ | GENERIC_WRITE,
1634 FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
1635 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1638 handle = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE,
1639 FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
1640 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1642 if (handle == INVALID_HANDLE_VALUE)
1645 if (GetFileTime(handle, &ftCreate, &ftAccess, &ftWrite) &&
1646 filetime_from_time(&ftAccess, times->actime) &&
1647 filetime_from_time(&ftWrite, times->modtime) &&
1648 SetFileTime(handle, &ftCreate, &ftAccess, &ftWrite))
1653 CloseHandle(handle);
1658 win32_uname(struct utsname *name)
1660 struct hostent *hep;
1661 STRLEN nodemax = sizeof(name->nodename)-1;
1662 OSVERSIONINFO osver;
1664 memset(&osver, 0, sizeof(OSVERSIONINFO));
1665 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1666 if (GetVersionEx(&osver)) {
1668 switch (osver.dwPlatformId) {
1669 case VER_PLATFORM_WIN32_WINDOWS:
1670 strcpy(name->sysname, "Windows");
1672 case VER_PLATFORM_WIN32_NT:
1673 strcpy(name->sysname, "Windows NT");
1675 case VER_PLATFORM_WIN32s:
1676 strcpy(name->sysname, "Win32s");
1679 strcpy(name->sysname, "Win32 Unknown");
1684 sprintf(name->release, "%d.%d",
1685 osver.dwMajorVersion, osver.dwMinorVersion);
1688 sprintf(name->version, "Build %d",
1689 osver.dwPlatformId == VER_PLATFORM_WIN32_NT
1690 ? osver.dwBuildNumber : (osver.dwBuildNumber & 0xffff));
1691 if (osver.szCSDVersion[0]) {
1692 char *buf = name->version + strlen(name->version);
1693 sprintf(buf, " (%s)", osver.szCSDVersion);
1697 *name->sysname = '\0';
1698 *name->version = '\0';
1699 *name->release = '\0';
1703 hep = win32_gethostbyname("localhost");
1705 STRLEN len = strlen(hep->h_name);
1706 if (len <= nodemax) {
1707 strcpy(name->nodename, hep->h_name);
1710 strncpy(name->nodename, hep->h_name, nodemax);
1711 name->nodename[nodemax] = '\0';
1716 if (!GetComputerName(name->nodename, &sz))
1717 *name->nodename = '\0';
1720 /* machine (architecture) */
1724 GetSystemInfo(&info);
1726 #if (defined(__BORLANDC__)&&(__BORLANDC__<=0x520)) \
1727 || (defined(__MINGW32__) && !defined(_ANONYMOUS_UNION))
1728 switch (info.u.s.wProcessorArchitecture) {
1730 switch (info.wProcessorArchitecture) {
1732 case PROCESSOR_ARCHITECTURE_INTEL:
1733 arch = "x86"; break;
1734 case PROCESSOR_ARCHITECTURE_MIPS:
1735 arch = "mips"; break;
1736 case PROCESSOR_ARCHITECTURE_ALPHA:
1737 arch = "alpha"; break;
1738 case PROCESSOR_ARCHITECTURE_PPC:
1739 arch = "ppc"; break;
1741 arch = "unknown"; break;
1743 strcpy(name->machine, arch);
1748 /* Timing related stuff */
1751 do_raise(pTHX_ int sig)
1753 if (sig < SIG_SIZE) {
1754 Sighandler_t handler = w32_sighandler[sig];
1755 if (handler == SIG_IGN) {
1758 else if (handler != SIG_DFL) {
1763 /* Choose correct default behaviour */
1779 /* Tell caller to exit thread/process as approriate */
1784 sig_terminate(pTHX_ int sig)
1786 Perl_warn(aTHX_ "Terminating on signal SIG%s(%d)\n",PL_sig_name[sig], sig);
1787 /* exit() seems to be safe, my_exit() or die() is a problem in ^C
1794 win32_async_check(pTHX)
1798 /* Passing PeekMessage -1 as HWND (2nd arg) only get PostThreadMessage() messages
1799 * and ignores window messages - should co-exist better with windows apps e.g. Tk
1801 while (PeekMessage(&msg, (HWND)-1, 0, 0, PM_REMOVE|PM_NOYIELD)) {
1803 switch(msg.message) {
1806 /* Perhaps some other messages could map to signals ? ... */
1809 /* Treat WM_QUIT like SIGHUP? */
1815 /* We use WM_USER to fake kill() with other signals */
1819 if (do_raise(aTHX_ sig)) {
1820 sig_terminate(aTHX_ sig);
1826 /* alarm() is a one-shot but SetTimer() repeats so kill it */
1828 KillTimer(NULL,w32_timerid);
1831 /* Now fake a call to signal handler */
1832 if (do_raise(aTHX_ 14)) {
1833 sig_terminate(aTHX_ 14);
1838 /* Otherwise do normal Win32 thing - in case it is useful */
1840 TranslateMessage(&msg);
1841 DispatchMessage(&msg);
1848 /* Above or other stuff may have set a signal flag */
1849 if (PL_sig_pending) {
1856 win32_msgwait(pTHX_ DWORD count, LPHANDLE handles, DWORD timeout, LPDWORD resultp)
1858 /* We may need several goes at this - so compute when we stop */
1860 if (timeout != INFINITE) {
1861 ticks = GetTickCount();
1865 DWORD result = MsgWaitForMultipleObjects(count,handles,FALSE,timeout-ticks, QS_ALLEVENTS);
1868 if (result == WAIT_TIMEOUT) {
1869 /* Ran out of time - explicit return of zero to avoid -ve if we
1870 have scheduling issues
1874 if (timeout != INFINITE) {
1875 ticks = GetTickCount();
1877 if (result == WAIT_OBJECT_0 + count) {
1878 /* Message has arrived - check it */
1879 if (win32_async_check(aTHX)) {
1880 /* was one of ours */
1885 /* Not timeout or message - one of handles is ready */
1889 /* compute time left to wait */
1890 ticks = timeout - ticks;
1891 /* If we are past the end say zero */
1892 return (ticks > 0) ? ticks : 0;
1896 win32_internal_wait(int *status, DWORD timeout)
1898 /* XXX this wait emulation only knows about processes
1899 * spawned via win32_spawnvp(P_NOWAIT, ...).
1903 DWORD exitcode, waitcode;
1906 if (w32_num_pseudo_children) {
1907 win32_msgwait(aTHX_ w32_num_pseudo_children, w32_pseudo_child_handles,
1908 timeout, &waitcode);
1909 /* Time out here if there are no other children to wait for. */
1910 if (waitcode == WAIT_TIMEOUT) {
1911 if (!w32_num_children) {
1915 else if (waitcode != WAIT_FAILED) {
1916 if (waitcode >= WAIT_ABANDONED_0
1917 && waitcode < WAIT_ABANDONED_0 + w32_num_pseudo_children)
1918 i = waitcode - WAIT_ABANDONED_0;
1920 i = waitcode - WAIT_OBJECT_0;
1921 if (GetExitCodeThread(w32_pseudo_child_handles[i], &exitcode)) {
1922 *status = (int)((exitcode & 0xff) << 8);
1923 retval = (int)w32_pseudo_child_pids[i];
1924 remove_dead_pseudo_process(i);
1931 if (!w32_num_children) {
1936 /* if a child exists, wait for it to die */
1937 win32_msgwait(aTHX_ w32_num_children, w32_child_handles, timeout, &waitcode);
1938 if (waitcode == WAIT_TIMEOUT) {
1941 if (waitcode != WAIT_FAILED) {
1942 if (waitcode >= WAIT_ABANDONED_0
1943 && waitcode < WAIT_ABANDONED_0 + w32_num_children)
1944 i = waitcode - WAIT_ABANDONED_0;
1946 i = waitcode - WAIT_OBJECT_0;
1947 if (GetExitCodeProcess(w32_child_handles[i], &exitcode) ) {
1948 *status = (int)((exitcode & 0xff) << 8);
1949 retval = (int)w32_child_pids[i];
1950 remove_dead_process(i);
1956 errno = GetLastError();
1961 win32_waitpid(int pid, int *status, int flags)
1964 DWORD timeout = (flags & WNOHANG) ? 0 : INFINITE;
1967 if (pid == -1) /* XXX threadid == 1 ? */
1968 return win32_internal_wait(status, timeout);
1971 child = find_pseudo_pid(-pid);
1973 HANDLE hThread = w32_pseudo_child_handles[child];
1975 win32_msgwait(aTHX_ 1, &hThread, timeout, &waitcode);
1976 if (waitcode == WAIT_TIMEOUT) {
1979 else if (waitcode == WAIT_OBJECT_0) {
1980 if (GetExitCodeThread(hThread, &waitcode)) {
1981 *status = (int)((waitcode & 0xff) << 8);
1982 retval = (int)w32_pseudo_child_pids[child];
1983 remove_dead_pseudo_process(child);
1990 else if (IsWin95()) {
1999 child = find_pid(pid);
2001 hProcess = w32_child_handles[child];
2002 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
2003 if (waitcode == WAIT_TIMEOUT) {
2006 else if (waitcode == WAIT_OBJECT_0) {
2007 if (GetExitCodeProcess(hProcess, &waitcode)) {
2008 *status = (int)((waitcode & 0xff) << 8);
2009 retval = (int)w32_child_pids[child];
2010 remove_dead_process(child);
2019 hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE,
2020 (IsWin95() ? -pid : pid));
2022 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
2023 if (waitcode == WAIT_TIMEOUT) {
2026 else if (waitcode == WAIT_OBJECT_0) {
2027 if (GetExitCodeProcess(hProcess, &waitcode)) {
2028 *status = (int)((waitcode & 0xff) << 8);
2029 CloseHandle(hProcess);
2033 CloseHandle(hProcess);
2039 return retval >= 0 ? pid : retval;
2043 win32_wait(int *status)
2045 return win32_internal_wait(status, INFINITE);
2048 DllExport unsigned int
2049 win32_sleep(unsigned int t)
2052 /* Win32 times are in ms so *1000 in and /1000 out */
2053 return win32_msgwait(aTHX_ 0, NULL, t*1000, NULL)/1000;
2056 DllExport unsigned int
2057 win32_alarm(unsigned int sec)
2060 * the 'obvious' implentation is SetTimer() with a callback
2061 * which does whatever receiving SIGALRM would do
2062 * we cannot use SIGALRM even via raise() as it is not
2063 * one of the supported codes in <signal.h>
2067 w32_timerid = SetTimer(NULL,w32_timerid,sec*1000,NULL);
2071 KillTimer(NULL,w32_timerid);
2078 #ifdef HAVE_DES_FCRYPT
2079 extern char * des_fcrypt(const char *txt, const char *salt, char *cbuf);
2083 win32_crypt(const char *txt, const char *salt)
2086 #ifdef HAVE_DES_FCRYPT
2087 return des_fcrypt(txt, salt, w32_crypt_buffer);
2089 Perl_croak(aTHX_ "The crypt() function is unimplemented due to excessive paranoia.");
2094 #ifdef USE_FIXED_OSFHANDLE
2096 #define FOPEN 0x01 /* file handle open */
2097 #define FNOINHERIT 0x10 /* file handle opened O_NOINHERIT */
2098 #define FAPPEND 0x20 /* file handle opened O_APPEND */
2099 #define FDEV 0x40 /* file handle refers to device */
2100 #define FTEXT 0x80 /* file handle is in text mode */
2103 *int my_open_osfhandle(intptr_t osfhandle, int flags) - open C Runtime file handle
2106 * This function allocates a free C Runtime file handle and associates
2107 * it with the Win32 HANDLE specified by the first parameter. This is a
2108 * temperary fix for WIN95's brain damage GetFileType() error on socket
2109 * we just bypass that call for socket
2111 * This works with MSVC++ 4.0+ or GCC/Mingw32
2114 * intptr_t osfhandle - Win32 HANDLE to associate with C Runtime file handle.
2115 * int flags - flags to associate with C Runtime file handle.
2118 * returns index of entry in fh, if successful
2119 * return -1, if no free entry is found
2123 *******************************************************************************/
2126 * we fake up some parts of the CRT that aren't exported by MSVCRT.dll
2127 * this lets sockets work on Win9X with GCC and should fix the problems
2132 /* create an ioinfo entry, kill its handle, and steal the entry */
2137 HANDLE hF = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
2138 int fh = _open_osfhandle((intptr_t)hF, 0);
2142 EnterCriticalSection(&(_pioinfo(fh)->lock));
2147 my_open_osfhandle(intptr_t osfhandle, int flags)
2150 char fileflags; /* _osfile flags */
2152 /* copy relevant flags from second parameter */
2155 if (flags & O_APPEND)
2156 fileflags |= FAPPEND;
2161 if (flags & O_NOINHERIT)
2162 fileflags |= FNOINHERIT;
2164 /* attempt to allocate a C Runtime file handle */
2165 if ((fh = _alloc_osfhnd()) == -1) {
2166 errno = EMFILE; /* too many open files */
2167 _doserrno = 0L; /* not an OS error */
2168 return -1; /* return error to caller */
2171 /* the file is open. now, set the info in _osfhnd array */
2172 _set_osfhnd(fh, osfhandle);
2174 fileflags |= FOPEN; /* mark as open */
2176 _osfile(fh) = fileflags; /* set osfile entry */
2177 LeaveCriticalSection(&_pioinfo(fh)->lock);
2179 return fh; /* return handle */
2182 #endif /* USE_FIXED_OSFHANDLE */
2184 /* simulate flock by locking a range on the file */
2186 #define LK_ERR(f,i) ((f) ? (i = 0) : (errno = GetLastError()))
2187 #define LK_LEN 0xffff0000
2190 win32_flock(int fd, int oper)
2198 Perl_croak_nocontext("flock() unimplemented on this platform");
2201 fh = (HANDLE)_get_osfhandle(fd);
2202 memset(&o, 0, sizeof(o));
2205 case LOCK_SH: /* shared lock */
2206 LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, 0, &o),i);
2208 case LOCK_EX: /* exclusive lock */
2209 LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o),i);
2211 case LOCK_SH|LOCK_NB: /* non-blocking shared lock */
2212 LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o),i);
2214 case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */
2215 LK_ERR(LockFileEx(fh,
2216 LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
2217 0, LK_LEN, 0, &o),i);
2219 case LOCK_UN: /* unlock lock */
2220 LK_ERR(UnlockFileEx(fh, 0, LK_LEN, 0, &o),i);
2222 default: /* unknown */
2233 * redirected io subsystem for all XS modules
2246 return (&(_environ));
2249 /* the rest are the remapped stdio routines */
2269 win32_ferror(FILE *fp)
2271 return (ferror(fp));
2276 win32_feof(FILE *fp)
2282 * Since the errors returned by the socket error function
2283 * WSAGetLastError() are not known by the library routine strerror
2284 * we have to roll our own.
2288 win32_strerror(int e)
2290 #if !defined __BORLANDC__ && !defined __MINGW32__ /* compiler intolerance */
2291 extern int sys_nerr;
2295 if (e < 0 || e > sys_nerr) {
2300 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0,
2301 w32_strerror_buffer,
2302 sizeof(w32_strerror_buffer), NULL) == 0)
2303 strcpy(w32_strerror_buffer, "Unknown Error");
2305 return w32_strerror_buffer;
2311 win32_str_os_error(void *sv, DWORD dwErr)
2315 dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
2316 |FORMAT_MESSAGE_IGNORE_INSERTS
2317 |FORMAT_MESSAGE_FROM_SYSTEM, NULL,
2318 dwErr, 0, (char *)&sMsg, 1, NULL);
2319 /* strip trailing whitespace and period */
2322 --dwLen; /* dwLen doesn't include trailing null */
2323 } while (0 < dwLen && isSPACE(sMsg[dwLen]));
2324 if ('.' != sMsg[dwLen])
2329 sMsg = (char*)LocalAlloc(0, 64/**sizeof(TCHAR)*/);
2331 dwLen = sprintf(sMsg,
2332 "Unknown error #0x%lX (lookup 0x%lX)",
2333 dwErr, GetLastError());
2337 sv_setpvn((SV*)sv, sMsg, dwLen);
2343 win32_fprintf(FILE *fp, const char *format, ...)
2346 va_start(marker, format); /* Initialize variable arguments. */
2348 return (vfprintf(fp, format, marker));
2352 win32_printf(const char *format, ...)
2355 va_start(marker, format); /* Initialize variable arguments. */
2357 return (vprintf(format, marker));
2361 win32_vfprintf(FILE *fp, const char *format, va_list args)
2363 return (vfprintf(fp, format, args));
2367 win32_vprintf(const char *format, va_list args)
2369 return (vprintf(format, args));
2373 win32_fread(void *buf, size_t size, size_t count, FILE *fp)
2375 return fread(buf, size, count, fp);
2379 win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
2381 return fwrite(buf, size, count, fp);
2384 #define MODE_SIZE 10
2387 win32_fopen(const char *filename, const char *mode)
2390 WCHAR wMode[MODE_SIZE], wBuffer[MAX_PATH+1];
2396 if (stricmp(filename, "/dev/null")==0)
2400 A2WHELPER(mode, wMode, sizeof(wMode));
2401 A2WHELPER(filename, wBuffer, sizeof(wBuffer));
2402 f = _wfopen(PerlDir_mapW(wBuffer), wMode);
2405 f = fopen(PerlDir_mapA(filename), mode);
2406 /* avoid buffering headaches for child processes */
2407 if (f && *mode == 'a')
2408 win32_fseek(f, 0, SEEK_END);
2412 #ifndef USE_SOCKETS_AS_HANDLES
2414 #define fdopen my_fdopen
2418 win32_fdopen(int handle, const char *mode)
2421 WCHAR wMode[MODE_SIZE];
2424 A2WHELPER(mode, wMode, sizeof(wMode));
2425 f = _wfdopen(handle, wMode);
2428 f = fdopen(handle, (char *) mode);
2429 /* avoid buffering headaches for child processes */
2430 if (f && *mode == 'a')
2431 win32_fseek(f, 0, SEEK_END);
2436 win32_freopen(const char *path, const char *mode, FILE *stream)
2439 WCHAR wMode[MODE_SIZE], wBuffer[MAX_PATH+1];
2440 if (stricmp(path, "/dev/null")==0)
2444 A2WHELPER(mode, wMode, sizeof(wMode));
2445 A2WHELPER(path, wBuffer, sizeof(wBuffer));
2446 return _wfreopen(PerlDir_mapW(wBuffer), wMode, stream);
2448 return freopen(PerlDir_mapA(path), mode, stream);
2452 win32_fclose(FILE *pf)
2454 return my_fclose(pf); /* defined in win32sck.c */
2458 win32_fputs(const char *s,FILE *pf)
2460 return fputs(s, pf);
2464 win32_fputc(int c,FILE *pf)
2470 win32_ungetc(int c,FILE *pf)
2472 return ungetc(c,pf);
2476 win32_getc(FILE *pf)
2482 win32_fileno(FILE *pf)
2488 win32_clearerr(FILE *pf)
2495 win32_fflush(FILE *pf)
2501 win32_ftell(FILE *pf)
2503 #if defined(WIN64) || defined(USE_LARGE_FILES)
2505 if (fgetpos(pf, &pos))
2514 win32_fseek(FILE *pf, Off_t offset,int origin)
2516 #if defined(WIN64) || defined(USE_LARGE_FILES)
2520 if (fgetpos(pf, &pos))
2525 fseek(pf, 0, SEEK_END);
2526 pos = _telli64(fileno(pf));
2535 return fsetpos(pf, &offset);
2537 return fseek(pf, offset, origin);
2542 win32_fgetpos(FILE *pf,fpos_t *p)
2544 return fgetpos(pf, p);
2548 win32_fsetpos(FILE *pf,const fpos_t *p)
2550 return fsetpos(pf, p);
2554 win32_rewind(FILE *pf)
2564 char prefix[MAX_PATH+1];
2565 char filename[MAX_PATH+1];
2566 DWORD len = GetTempPath(MAX_PATH, prefix);
2567 if (len && len < MAX_PATH) {
2568 if (GetTempFileName(prefix, "plx", 0, filename)) {
2569 HANDLE fh = CreateFile(filename,
2570 DELETE | GENERIC_READ | GENERIC_WRITE,
2574 FILE_ATTRIBUTE_NORMAL
2575 | FILE_FLAG_DELETE_ON_CLOSE,
2577 if (fh != INVALID_HANDLE_VALUE) {
2578 int fd = win32_open_osfhandle((intptr_t)fh, 0);
2580 #if defined(__BORLANDC__)
2581 setmode(fd,O_BINARY);
2583 DEBUG_p(PerlIO_printf(Perl_debug_log,
2584 "Created tmpfile=%s\n",filename));
2585 return fdopen(fd, "w+b");
2601 win32_fstat(int fd, Stat_t *sbufptr)
2604 /* A file designated by filehandle is not shown as accessible
2605 * for write operations, probably because it is opened for reading.
2608 int rc = fstat(fd,sbufptr);
2609 BY_HANDLE_FILE_INFORMATION bhfi;
2610 if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &bhfi)) {
2611 sbufptr->st_mode &= 0xFE00;
2612 if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
2613 sbufptr->st_mode |= (S_IREAD + (S_IREAD >> 3) + (S_IREAD >> 6));
2615 sbufptr->st_mode |= ((S_IREAD|S_IWRITE) + ((S_IREAD|S_IWRITE) >> 3)
2616 + ((S_IREAD|S_IWRITE) >> 6));
2620 return my_fstat(fd,sbufptr);
2625 win32_pipe(int *pfd, unsigned int size, int mode)
2627 return _pipe(pfd, size, mode);
2631 win32_popenlist(const char *mode, IV narg, SV **args)
2634 Perl_croak(aTHX_ "List form of pipe open not implemented");
2639 * a popen() clone that respects PERL5SHELL
2641 * changed to return PerlIO* rather than FILE * by BKS, 11-11-2000
2645 win32_popen(const char *command, const char *mode)
2647 #ifdef USE_RTL_POPEN
2648 return _popen(command, mode);
2656 /* establish which ends read and write */
2657 if (strchr(mode,'w')) {
2658 stdfd = 0; /* stdin */
2662 else if (strchr(mode,'r')) {
2663 stdfd = 1; /* stdout */
2670 /* set the correct mode */
2671 if (strchr(mode,'b'))
2673 else if (strchr(mode,'t'))
2676 ourmode = _fmode & (O_TEXT | O_BINARY);
2678 /* the child doesn't inherit handles */
2679 ourmode |= O_NOINHERIT;
2681 if (win32_pipe( p, 512, ourmode) == -1)
2684 /* save current stdfd */
2685 if ((oldfd = win32_dup(stdfd)) == -1)
2688 /* make stdfd go to child end of pipe (implicitly closes stdfd) */
2689 /* stdfd will be inherited by the child */
2690 if (win32_dup2(p[child], stdfd) == -1)
2693 /* close the child end in parent */
2694 win32_close(p[child]);
2696 /* start the child */
2699 if ((childpid = do_spawn_nowait((char*)command)) == -1)
2702 /* revert stdfd to whatever it was before */
2703 if (win32_dup2(oldfd, stdfd) == -1)
2706 /* close saved handle */
2710 sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid);
2713 /* set process id so that it can be returned by perl's open() */
2714 PL_forkprocess = childpid;
2717 /* we have an fd, return a file stream */
2718 return (PerlIO_fdopen(p[parent], (char *)mode));
2721 /* we don't need to check for errors here */
2725 win32_dup2(oldfd, stdfd);
2730 #endif /* USE_RTL_POPEN */
2738 win32_pclose(PerlIO *pf)
2740 #ifdef USE_RTL_POPEN
2744 int childpid, status;
2748 sv = *av_fetch(w32_fdpid, PerlIO_fileno(pf), TRUE);
2751 childpid = SvIVX(sv);
2768 if (win32_waitpid(childpid, &status, 0) == -1)
2773 #endif /* USE_RTL_POPEN */
2779 LPCWSTR lpExistingFileName,
2780 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
2783 WCHAR wFullName[MAX_PATH+1];
2784 LPVOID lpContext = NULL;
2785 WIN32_STREAM_ID StreamId;
2786 DWORD dwSize = (char*)&StreamId.cStreamName - (char*)&StreamId;
2791 BOOL (__stdcall *pfnBackupWrite)(HANDLE, LPBYTE, DWORD, LPDWORD,
2792 BOOL, BOOL, LPVOID*) =
2793 (BOOL (__stdcall *)(HANDLE, LPBYTE, DWORD, LPDWORD,
2794 BOOL, BOOL, LPVOID*))
2795 GetProcAddress(GetModuleHandle("kernel32.dll"), "BackupWrite");
2796 if (pfnBackupWrite == NULL)
2799 dwLen = GetFullPathNameW(lpFileName, MAX_PATH, wFullName, NULL);
2802 dwLen = (dwLen+1)*sizeof(WCHAR);
2804 handle = CreateFileW(lpExistingFileName, FILE_WRITE_ATTRIBUTES,
2805 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2806 NULL, OPEN_EXISTING, 0, NULL);
2807 if (handle == INVALID_HANDLE_VALUE)
2810 StreamId.dwStreamId = BACKUP_LINK;
2811 StreamId.dwStreamAttributes = 0;
2812 StreamId.dwStreamNameSize = 0;
2813 #if defined(__BORLANDC__) \
2814 ||(defined(__MINGW32__) && !defined(_ANONYMOUS_UNION))
2815 StreamId.Size.u.HighPart = 0;
2816 StreamId.Size.u.LowPart = dwLen;
2818 StreamId.Size.HighPart = 0;
2819 StreamId.Size.LowPart = dwLen;
2822 bSuccess = pfnBackupWrite(handle, (LPBYTE)&StreamId, dwSize, &dwWritten,
2823 FALSE, FALSE, &lpContext);
2825 bSuccess = pfnBackupWrite(handle, (LPBYTE)wFullName, dwLen, &dwWritten,
2826 FALSE, FALSE, &lpContext);
2827 pfnBackupWrite(handle, NULL, 0, &dwWritten, TRUE, FALSE, &lpContext);
2830 CloseHandle(handle);
2835 win32_link(const char *oldname, const char *newname)
2838 BOOL (__stdcall *pfnCreateHardLinkW)(LPCWSTR,LPCWSTR,LPSECURITY_ATTRIBUTES);
2839 WCHAR wOldName[MAX_PATH+1];
2840 WCHAR wNewName[MAX_PATH+1];
2843 Perl_croak(aTHX_ PL_no_func, "link");
2845 pfnCreateHardLinkW =
2846 (BOOL (__stdcall *)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES))
2847 GetProcAddress(GetModuleHandle("kernel32.dll"), "CreateHardLinkW");
2848 if (pfnCreateHardLinkW == NULL)
2849 pfnCreateHardLinkW = Nt4CreateHardLinkW;
2851 if ((A2WHELPER(oldname, wOldName, sizeof(wOldName))) &&
2852 (A2WHELPER(newname, wNewName, sizeof(wNewName))) &&
2853 (wcscpy(wOldName, PerlDir_mapW(wOldName)),
2854 pfnCreateHardLinkW(PerlDir_mapW(wNewName), wOldName, NULL)))
2858 errno = (GetLastError() == ERROR_FILE_NOT_FOUND) ? ENOENT : EINVAL;
2863 win32_rename(const char *oname, const char *newname)
2865 WCHAR wOldName[MAX_PATH+1];
2866 WCHAR wNewName[MAX_PATH+1];
2867 char szOldName[MAX_PATH+1];
2868 char szNewName[MAX_PATH+1];
2872 /* XXX despite what the documentation says about MoveFileEx(),
2873 * it doesn't work under Windows95!
2876 DWORD dwFlags = MOVEFILE_COPY_ALLOWED;
2878 A2WHELPER(oname, wOldName, sizeof(wOldName));
2879 A2WHELPER(newname, wNewName, sizeof(wNewName));
2880 if (wcsicmp(wNewName, wOldName))
2881 dwFlags |= MOVEFILE_REPLACE_EXISTING;
2882 wcscpy(wOldName, PerlDir_mapW(wOldName));
2883 bResult = MoveFileExW(wOldName,PerlDir_mapW(wNewName), dwFlags);
2886 if (stricmp(newname, oname))
2887 dwFlags |= MOVEFILE_REPLACE_EXISTING;
2888 strcpy(szOldName, PerlDir_mapA(oname));
2889 bResult = MoveFileExA(szOldName,PerlDir_mapA(newname), dwFlags);
2892 DWORD err = GetLastError();
2894 case ERROR_BAD_NET_NAME:
2895 case ERROR_BAD_NETPATH:
2896 case ERROR_BAD_PATHNAME:
2897 case ERROR_FILE_NOT_FOUND:
2898 case ERROR_FILENAME_EXCED_RANGE:
2899 case ERROR_INVALID_DRIVE:
2900 case ERROR_NO_MORE_FILES:
2901 case ERROR_PATH_NOT_FOUND:
2914 char szTmpName[MAX_PATH+1];
2915 char dname[MAX_PATH+1];
2916 char *endname = Nullch;
2918 DWORD from_attr, to_attr;
2920 strcpy(szOldName, PerlDir_mapA(oname));
2921 strcpy(szNewName, PerlDir_mapA(newname));
2923 /* if oname doesn't exist, do nothing */
2924 from_attr = GetFileAttributes(szOldName);
2925 if (from_attr == 0xFFFFFFFF) {
2930 /* if newname exists, rename it to a temporary name so that we
2931 * don't delete it in case oname happens to be the same file
2932 * (but perhaps accessed via a different path)
2934 to_attr = GetFileAttributes(szNewName);
2935 if (to_attr != 0xFFFFFFFF) {
2936 /* if newname is a directory, we fail
2937 * XXX could overcome this with yet more convoluted logic */
2938 if (to_attr & FILE_ATTRIBUTE_DIRECTORY) {
2942 tmplen = strlen(szNewName);
2943 strcpy(szTmpName,szNewName);
2944 endname = szTmpName+tmplen;
2945 for (; endname > szTmpName ; --endname) {
2946 if (*endname == '/' || *endname == '\\') {
2951 if (endname > szTmpName)
2952 endname = strcpy(dname,szTmpName);
2956 /* get a temporary filename in same directory
2957 * XXX is this really the best we can do? */
2958 if (!GetTempFileName((LPCTSTR)endname, "plr", 0, szTmpName)) {
2962 DeleteFile(szTmpName);
2964 retval = rename(szNewName, szTmpName);
2971 /* rename oname to newname */
2972 retval = rename(szOldName, szNewName);
2974 /* if we created a temporary file before ... */
2975 if (endname != Nullch) {
2976 /* ...and rename succeeded, delete temporary file/directory */
2978 DeleteFile(szTmpName);
2979 /* else restore it to what it was */
2981 (void)rename(szTmpName, szNewName);
2988 win32_setmode(int fd, int mode)
2990 return setmode(fd, mode);
2994 win32_lseek(int fd, Off_t offset, int origin)
2996 #if defined(WIN64) || defined(USE_LARGE_FILES)
2997 return _lseeki64(fd, offset, origin);
2999 return lseek(fd, offset, origin);
3006 #if defined(WIN64) || defined(USE_LARGE_FILES)
3007 return _telli64(fd);
3014 win32_open(const char *path, int flag, ...)
3019 WCHAR wBuffer[MAX_PATH+1];
3022 pmode = va_arg(ap, int);
3025 if (stricmp(path, "/dev/null")==0)
3029 A2WHELPER(path, wBuffer, sizeof(wBuffer));
3030 return _wopen(PerlDir_mapW(wBuffer), flag, pmode);
3032 return open(PerlDir_mapA(path), flag, pmode);
3035 /* close() that understands socket */
3036 extern int my_close(int); /* in win32sck.c */
3041 return my_close(fd);
3057 win32_dup2(int fd1,int fd2)
3059 return dup2(fd1,fd2);
3062 #ifdef PERL_MSVCRT_READFIX
3064 #define LF 10 /* line feed */
3065 #define CR 13 /* carriage return */
3066 #define CTRLZ 26 /* ctrl-z means eof for text */
3067 #define FOPEN 0x01 /* file handle open */
3068 #define FEOFLAG 0x02 /* end of file has been encountered */
3069 #define FCRLF 0x04 /* CR-LF across read buffer (in text mode) */
3070 #define FPIPE 0x08 /* file handle refers to a pipe */
3071 #define FAPPEND 0x20 /* file handle opened O_APPEND */
3072 #define FDEV 0x40 /* file handle refers to device */
3073 #define FTEXT 0x80 /* file handle is in text mode */
3074 #define MAX_DESCRIPTOR_COUNT (64*32) /* this is the maximun that MSVCRT can handle */
3077 _fixed_read(int fh, void *buf, unsigned cnt)
3079 int bytes_read; /* number of bytes read */
3080 char *buffer; /* buffer to read to */
3081 int os_read; /* bytes read on OS call */
3082 char *p, *q; /* pointers into buffer */
3083 char peekchr; /* peek-ahead character */
3084 ULONG filepos; /* file position after seek */
3085 ULONG dosretval; /* o.s. return value */
3087 /* validate handle */
3088 if (((unsigned)fh >= (unsigned)MAX_DESCRIPTOR_COUNT) ||
3089 !(_osfile(fh) & FOPEN))
3091 /* out of range -- return error */
3093 _doserrno = 0; /* not o.s. error */
3098 * If lockinitflag is FALSE, assume fd is device
3099 * lockinitflag is set to TRUE by open.
3101 if (_pioinfo(fh)->lockinitflag)
3102 EnterCriticalSection(&(_pioinfo(fh)->lock)); /* lock file */
3104 bytes_read = 0; /* nothing read yet */
3105 buffer = (char*)buf;
3107 if (cnt == 0 || (_osfile(fh) & FEOFLAG)) {
3108 /* nothing to read or at EOF, so return 0 read */
3112 if ((_osfile(fh) & (FPIPE|FDEV)) && _pipech(fh) != LF) {
3113 /* a pipe/device and pipe lookahead non-empty: read the lookahead
3115 *buffer++ = _pipech(fh);
3118 _pipech(fh) = LF; /* mark as empty */
3123 if (!ReadFile((HANDLE)_osfhnd(fh), buffer, cnt, (LPDWORD)&os_read, NULL))
3125 /* ReadFile has reported an error. recognize two special cases.
3127 * 1. map ERROR_ACCESS_DENIED to EBADF
3129 * 2. just return 0 if ERROR_BROKEN_PIPE has occurred. it
3130 * means the handle is a read-handle on a pipe for which
3131 * all write-handles have been closed and all data has been
3134 if ((dosretval = GetLastError()) == ERROR_ACCESS_DENIED) {
3135 /* wrong read/write mode should return EBADF, not EACCES */
3137 _doserrno = dosretval;
3141 else if (dosretval == ERROR_BROKEN_PIPE) {
3151 bytes_read += os_read; /* update bytes read */
3153 if (_osfile(fh) & FTEXT) {
3154 /* now must translate CR-LFs to LFs in the buffer */
3156 /* set CRLF flag to indicate LF at beginning of buffer */
3157 /* if ((os_read != 0) && (*(char *)buf == LF)) */
3158 /* _osfile(fh) |= FCRLF; */
3160 /* _osfile(fh) &= ~FCRLF; */
3162 _osfile(fh) &= ~FCRLF;
3164 /* convert chars in the buffer: p is src, q is dest */
3166 while (p < (char *)buf + bytes_read) {
3168 /* if fh is not a device, set ctrl-z flag */
3169 if (!(_osfile(fh) & FDEV))
3170 _osfile(fh) |= FEOFLAG;
3171 break; /* stop translating */
3176 /* *p is CR, so must check next char for LF */
3177 if (p < (char *)buf + bytes_read - 1) {
3180 *q++ = LF; /* convert CR-LF to LF */
3183 *q++ = *p++; /* store char normally */
3186 /* This is the hard part. We found a CR at end of
3187 buffer. We must peek ahead to see if next char
3192 if (!ReadFile((HANDLE)_osfhnd(fh), &peekchr, 1,
3193 (LPDWORD)&os_read, NULL))
3194 dosretval = GetLastError();
3196 if (dosretval != 0 || os_read == 0) {
3197 /* couldn't read ahead, store CR */
3201 /* peekchr now has the extra character -- we now
3202 have several possibilities:
3203 1. disk file and char is not LF; just seek back
3205 2. disk file and char is LF; store LF, don't seek back
3206 3. pipe/device and char is LF; store LF.
3207 4. pipe/device and char isn't LF, store CR and
3208 put char in pipe lookahead buffer. */
3209 if (_osfile(fh) & (FDEV|FPIPE)) {
3210 /* non-seekable device */
3215 _pipech(fh) = peekchr;
3220 if (peekchr == LF) {
3221 /* nothing read yet; must make some
3224 /* turn on this flag for tell routine */
3225 _osfile(fh) |= FCRLF;
3228 HANDLE osHandle; /* o.s. handle value */
3230 if ((osHandle = (HANDLE)_get_osfhandle(fh)) != (HANDLE)-1)
3232 if ((filepos = SetFilePointer(osHandle, -1, NULL, FILE_CURRENT)) == -1)
3233 dosretval = GetLastError();
3244 /* we now change bytes_read to reflect the true number of chars
3246 bytes_read = q - (char *)buf;
3250 if (_pioinfo(fh)->lockinitflag)
3251 LeaveCriticalSection(&(_pioinfo(fh)->lock)); /* unlock file */
3256 #endif /* PERL_MSVCRT_READFIX */
3259 win32_read(int fd, void *buf, unsigned int cnt)
3261 #ifdef PERL_MSVCRT_READFIX
3262 return _fixed_read(fd, buf, cnt);
3264 return read(fd, buf, cnt);
3269 win32_write(int fd, const void *buf, unsigned int cnt)
3271 return write(fd, buf, cnt);
3275 win32_mkdir(const char *dir, int mode)
3279 WCHAR wBuffer[MAX_PATH+1];
3280 A2WHELPER(dir, wBuffer, sizeof(wBuffer));
3281 return _wmkdir(PerlDir_mapW(wBuffer));
3283 return mkdir(PerlDir_mapA(dir)); /* just ignore mode */
3287 win32_rmdir(const char *dir)
3291 WCHAR wBuffer[MAX_PATH+1];
3292 A2WHELPER(dir, wBuffer, sizeof(wBuffer));
3293 return _wrmdir(PerlDir_mapW(wBuffer));
3295 return rmdir(PerlDir_mapA(dir));
3299 win32_chdir(const char *dir)
3307 WCHAR wBuffer[MAX_PATH+1];
3308 A2WHELPER(dir, wBuffer, sizeof(wBuffer));
3309 return _wchdir(wBuffer);
3315 win32_access(const char *path, int mode)
3319 WCHAR wBuffer[MAX_PATH+1];
3320 A2WHELPER(path, wBuffer, sizeof(wBuffer));
3321 return _waccess(PerlDir_mapW(wBuffer), mode);
3323 return access(PerlDir_mapA(path), mode);
3327 win32_chmod(const char *path, int mode)
3331 WCHAR wBuffer[MAX_PATH+1];
3332 A2WHELPER(path, wBuffer, sizeof(wBuffer));
3333 return _wchmod(PerlDir_mapW(wBuffer), mode);
3335 return chmod(PerlDir_mapA(path), mode);
3340 create_command_line(char *cname, STRLEN clen, const char * const *args)
3347 bool bat_file = FALSE;
3348 bool cmd_shell = FALSE;
3349 bool dumb_shell = FALSE;
3350 bool extra_quotes = FALSE;
3351 bool quote_next = FALSE;
3354 cname = (char*)args[0];
3356 /* The NT cmd.exe shell has the following peculiarity that needs to be
3357 * worked around. It strips a leading and trailing dquote when any
3358 * of the following is true:
3359 * 1. the /S switch was used
3360 * 2. there are more than two dquotes
3361 * 3. there is a special character from this set: &<>()@^|
3362 * 4. no whitespace characters within the two dquotes
3363 * 5. string between two dquotes isn't an executable file
3364 * To work around this, we always add a leading and trailing dquote
3365 * to the string, if the first argument is either "cmd.exe" or "cmd",
3366 * and there were at least two or more arguments passed to cmd.exe
3367 * (not including switches).
3368 * XXX the above rules (from "cmd /?") don't seem to be applied
3369 * always, making for the convolutions below :-(
3373 clen = strlen(cname);
3376 && (stricmp(&cname[clen-4], ".bat") == 0
3377 || (IsWinNT() && stricmp(&cname[clen-4], ".cmd") == 0)))
3383 char *exe = strrchr(cname, '/');
3384 char *exe2 = strrchr(cname, '\\');
3391 if (stricmp(exe, "cmd.exe") == 0 || stricmp(exe, "cmd") == 0) {
3395 else if (stricmp(exe, "command.com") == 0
3396 || stricmp(exe, "command") == 0)
3403 DEBUG_p(PerlIO_printf(Perl_debug_log, "Args "));
3404 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3405 STRLEN curlen = strlen(arg);
3406 if (!(arg[0] == '"' && arg[curlen-1] == '"'))
3407 len += 2; /* assume quoting needed (worst case) */
3409 DEBUG_p(PerlIO_printf(Perl_debug_log, "[%s]",arg));
3411 DEBUG_p(PerlIO_printf(Perl_debug_log, "\n"));
3414 New(1310, cmd, len, char);
3419 extra_quotes = TRUE;
3422 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3424 STRLEN curlen = strlen(arg);
3426 /* we want to protect empty arguments and ones with spaces with
3427 * dquotes, but only if they aren't already there */
3432 else if (quote_next) {
3433 /* see if it really is multiple arguments pretending to
3434 * be one and force a set of quotes around it */
3435 if (*find_next_space(arg))
3438 else if (!(arg[0] == '"' && curlen > 1 && arg[curlen-1] == '"')) {
3440 while (i < curlen) {
3441 if (isSPACE(arg[i])) {
3444 else if (arg[i] == '"') {
3467 && (stricmp(arg, "/x/c") == 0 || stricmp(arg, "/c") == 0))
3469 /* is there a next argument? */
3470 if (args[index+1]) {
3471 /* are there two or more next arguments? */
3472 if (args[index+2]) {
3474 extra_quotes = TRUE;
3477 /* single argument, force quoting if it has spaces */
3493 qualified_path(const char *cmd)
3497 char *fullcmd, *curfullcmd;
3503 fullcmd = (char*)cmd;
3505 if (*fullcmd == '/' || *fullcmd == '\\')
3512 pathstr = PerlEnv_getenv("PATH");
3513 New(0, fullcmd, MAX_PATH+1, char);
3514 curfullcmd = fullcmd;
3519 /* start by appending the name to the current prefix */
3520 strcpy(curfullcmd, cmd);
3521 curfullcmd += cmdlen;
3523 /* if it doesn't end with '.', or has no extension, try adding
3524 * a trailing .exe first */
3525 if (cmd[cmdlen-1] != '.'
3526 && (cmdlen < 4 || cmd[cmdlen-4] != '.'))
3528 strcpy(curfullcmd, ".exe");
3529 res = GetFileAttributes(fullcmd);
3530 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3535 /* that failed, try the bare name */
3536 res = GetFileAttributes(fullcmd);
3537 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3540 /* quit if no other path exists, or if cmd already has path */
3541 if (!pathstr || !*pathstr || has_slash)
3544 /* skip leading semis */
3545 while (*pathstr == ';')
3548 /* build a new prefix from scratch */
3549 curfullcmd = fullcmd;
3550 while (*pathstr && *pathstr != ';') {
3551 if (*pathstr == '"') { /* foo;"baz;etc";bar */
3552 pathstr++; /* skip initial '"' */
3553 while (*pathstr && *pathstr != '"') {
3554 if (curfullcmd-fullcmd < MAX_PATH-cmdlen-5)
3555 *curfullcmd++ = *pathstr;
3559 pathstr++; /* skip trailing '"' */
3562 if (curfullcmd-fullcmd < MAX_PATH-cmdlen-5)
3563 *curfullcmd++ = *pathstr;
3568 pathstr++; /* skip trailing semi */
3569 if (curfullcmd > fullcmd /* append a dir separator */
3570 && curfullcmd[-1] != '/' && curfullcmd[-1] != '\\')
3572 *curfullcmd++ = '\\';
3580 /* The following are just place holders.
3581 * Some hosts may provide and environment that the OS is
3582 * not tracking, therefore, these host must provide that
3583 * environment and the current directory to CreateProcess
3587 win32_get_childenv(void)
3593 win32_free_childenv(void* d)
3598 win32_clearenv(void)
3600 char *envv = GetEnvironmentStrings();
3604 char *end = strchr(cur,'=');
3605 if (end && end != cur) {
3607 SetEnvironmentVariable(cur, NULL);
3609 cur = end + strlen(end+1)+2;
3611 else if ((len = strlen(cur)))
3614 FreeEnvironmentStrings(envv);
3618 win32_get_childdir(void)
3622 char szfilename[(MAX_PATH+1)*2];
3624 WCHAR wfilename[MAX_PATH+1];
3625 GetCurrentDirectoryW(MAX_PATH+1, wfilename);
3626 W2AHELPER(wfilename, szfilename, sizeof(szfilename));
3629 GetCurrentDirectoryA(MAX_PATH+1, szfilename);
3632 New(0, ptr, strlen(szfilename)+1, char);
3633 strcpy(ptr, szfilename);
3638 win32_free_childdir(char* d)
3645 /* XXX this needs to be made more compatible with the spawnvp()
3646 * provided by the various RTLs. In particular, searching for
3647 * *.{com,bat,cmd} files (as done by the RTLs) is unimplemented.
3648 * This doesn't significantly affect perl itself, because we
3649 * always invoke things using PERL5SHELL if a direct attempt to
3650 * spawn the executable fails.
3652 * XXX splitting and rejoining the commandline between do_aspawn()
3653 * and win32_spawnvp() could also be avoided.
3657 win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
3659 #ifdef USE_RTL_SPAWNVP
3660 return spawnvp(mode, cmdname, (char * const *)argv);
3667 STARTUPINFO StartupInfo;
3668 PROCESS_INFORMATION ProcessInformation;
3671 char *fullcmd = Nullch;
3672 char *cname = (char *)cmdname;
3676 clen = strlen(cname);
3677 /* if command name contains dquotes, must remove them */
3678 if (strchr(cname, '"')) {
3680 New(0,cname,clen+1,char);
3693 cmd = create_command_line(cname, clen, argv);
3695 env = PerlEnv_get_childenv();
3696 dir = PerlEnv_get_childdir();
3699 case P_NOWAIT: /* asynch + remember result */
3700 if (w32_num_children >= MAXIMUM_WAIT_OBJECTS) {
3705 /* Create a new process group so we can use GenerateConsoleCtrlEvent()
3708 create |= CREATE_NEW_PROCESS_GROUP;
3711 case P_WAIT: /* synchronous execution */
3713 default: /* invalid mode */
3718 memset(&StartupInfo,0,sizeof(StartupInfo));
3719 StartupInfo.cb = sizeof(StartupInfo);
3720 memset(&tbl,0,sizeof(tbl));
3721 PerlEnv_get_child_IO(&tbl);
3722 StartupInfo.dwFlags = tbl.dwFlags;
3723 StartupInfo.dwX = tbl.dwX;
3724 StartupInfo.dwY = tbl.dwY;
3725 StartupInfo.dwXSize = tbl.dwXSize;
3726 StartupInfo.dwYSize = tbl.dwYSize;
3727 StartupInfo.dwXCountChars = tbl.dwXCountChars;
3728 StartupInfo.dwYCountChars = tbl.dwYCountChars;
3729 StartupInfo.dwFillAttribute = tbl.dwFillAttribute;
3730 StartupInfo.wShowWindow = tbl.wShowWindow;
3731 StartupInfo.hStdInput = tbl.childStdIn;
3732 StartupInfo.hStdOutput = tbl.childStdOut;
3733 StartupInfo.hStdError = tbl.childStdErr;
3734 if (StartupInfo.hStdInput != INVALID_HANDLE_VALUE &&
3735 StartupInfo.hStdOutput != INVALID_HANDLE_VALUE &&
3736 StartupInfo.hStdError != INVALID_HANDLE_VALUE)
3738 StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
3741 create |= CREATE_NEW_CONSOLE;
3743 if (w32_use_showwindow) {
3744 StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
3745 StartupInfo.wShowWindow = w32_showwindow;
3748 DEBUG_p(PerlIO_printf(Perl_debug_log, "Spawning [%s] with [%s]\n",
3751 if (!CreateProcess(cname, /* search PATH to find executable */
3752 cmd, /* executable, and its arguments */
3753 NULL, /* process attributes */
3754 NULL, /* thread attributes */
3755 TRUE, /* inherit handles */
3756 create, /* creation flags */
3757 (LPVOID)env, /* inherit environment */
3758 dir, /* inherit cwd */
3760 &ProcessInformation))
3762 /* initial NULL argument to CreateProcess() does a PATH
3763 * search, but it always first looks in the directory
3764 * where the current process was started, which behavior
3765 * is undesirable for backward compatibility. So we
3766 * jump through our own hoops by picking out the path
3767 * we really want it to use. */
3769 fullcmd = qualified_path(cname);
3771 if (cname != cmdname)
3774 DEBUG_p(PerlIO_printf(Perl_debug_log,
3775 "Retrying [%s] with same args\n",
3785 if (mode == P_NOWAIT) {
3786 /* asynchronous spawn -- store handle, return PID */
3787 ret = (int)ProcessInformation.dwProcessId;
3788 if (IsWin95() && ret < 0)
3791 w32_child_handles[w32_num_children] = ProcessInformation.hProcess;
3792 w32_child_pids[w32_num_children] = (DWORD)ret;
3797 win32_msgwait(aTHX_ 1, &ProcessInformation.hProcess, INFINITE, NULL);
3798 /* FIXME: if msgwait returned due to message perhaps forward the
3799 "signal" to the process
3801 GetExitCodeProcess(ProcessInformation.hProcess, &status);
3803 CloseHandle(ProcessInformation.hProcess);
3806 CloseHandle(ProcessInformation.hThread);
3809 PerlEnv_free_childenv(env);
3810 PerlEnv_free_childdir(dir);
3812 if (cname != cmdname)
3819 win32_execv(const char *cmdname, const char *const *argv)
3823 /* if this is a pseudo-forked child, we just want to spawn
3824 * the new program, and return */
3826 return spawnv(P_WAIT, cmdname, (char *const *)argv);
3828 return execv(cmdname, (char *const *)argv);
3832 win32_execvp(const char *cmdname, const char *const *argv)
3836 /* if this is a pseudo-forked child, we just want to spawn
3837 * the new program, and return */
3838 if (w32_pseudo_id) {
3839 int status = win32_spawnvp(P_WAIT, cmdname, (char *const *)argv);
3848 return execvp(cmdname, (char *const *)argv);
3852 win32_perror(const char *str)
3858 win32_setbuf(FILE *pf, char *buf)
3864 win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
3866 return setvbuf(pf, buf, type, size);
3870 win32_flushall(void)
3876 win32_fcloseall(void)
3882 win32_fgets(char *s, int n, FILE *pf)
3884 return fgets(s, n, pf);
3894 win32_fgetc(FILE *pf)
3900 win32_putc(int c, FILE *pf)
3906 win32_puts(const char *s)
3918 win32_putchar(int c)
3925 #ifndef USE_PERL_SBRK
3927 static char *committed = NULL; /* XXX threadead */
3928 static char *base = NULL; /* XXX threadead */
3929 static char *reserved = NULL; /* XXX threadead */
3930 static char *brk = NULL; /* XXX threadead */
3931 static DWORD pagesize = 0; /* XXX threadead */
3932 static DWORD allocsize = 0; /* XXX threadead */
3935 sbrk(ptrdiff_t need)
3940 GetSystemInfo(&info);
3941 /* Pretend page size is larger so we don't perpetually
3942 * call the OS to commit just one page ...
3944 pagesize = info.dwPageSize << 3;
3945 allocsize = info.dwAllocationGranularity;
3947 /* This scheme fails eventually if request for contiguous
3948 * block is denied so reserve big blocks - this is only
3949 * address space not memory ...
3951 if (brk+need >= reserved)
3953 DWORD size = 64*1024*1024;
3955 if (committed && reserved && committed < reserved)
3957 /* Commit last of previous chunk cannot span allocations */
3958 addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
3960 committed = reserved;
3962 /* Reserve some (more) space
3963 * Note this is a little sneaky, 1st call passes NULL as reserved
3964 * so lets system choose where we start, subsequent calls pass
3965 * the old end address so ask for a contiguous block
3967 addr = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
3970 reserved = addr+size;
3985 if (brk > committed)
3987 DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
3988 char *addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
4003 win32_malloc(size_t size)
4005 return malloc(size);
4009 win32_calloc(size_t numitems, size_t size)
4011 return calloc(numitems,size);
4015 win32_realloc(void *block, size_t size)
4017 return realloc(block,size);
4021 win32_free(void *block)
4028 win32_open_osfhandle(intptr_t handle, int flags)
4030 #ifdef USE_FIXED_OSFHANDLE
4032 return my_open_osfhandle(handle, flags);
4034 return _open_osfhandle(handle, flags);
4038 win32_get_osfhandle(int fd)
4040 return (intptr_t)_get_osfhandle(fd);
4044 win32_dynaload(const char* filename)
4048 char buf[MAX_PATH+1];
4051 /* LoadLibrary() doesn't recognize forward slashes correctly,
4052 * so turn 'em back. */
4053 first = strchr(filename, '/');
4055 STRLEN len = strlen(filename);
4056 if (len <= MAX_PATH) {
4057 strcpy(buf, filename);
4058 filename = &buf[first - filename];
4060 if (*filename == '/')
4061 *(char*)filename = '\\';
4068 WCHAR wfilename[MAX_PATH+1];
4069 A2WHELPER(filename, wfilename, sizeof(wfilename));
4070 hModule = LoadLibraryExW(PerlDir_mapW(wfilename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
4073 hModule = LoadLibraryExA(PerlDir_mapA(filename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
4083 XS(w32_SetChildShowWindow)
4086 BOOL use_showwindow = w32_use_showwindow;
4087 /* use "unsigned short" because Perl has redefined "WORD" */
4088 unsigned short showwindow = w32_showwindow;
4091 Perl_croak(aTHX_ "usage: Win32::SetChildShowWindow($showwindow)");
4093 if (items == 0 || !SvOK(ST(0)))
4094 w32_use_showwindow = FALSE;
4096 w32_use_showwindow = TRUE;
4097 w32_showwindow = (unsigned short)SvIV(ST(0));
4102 ST(0) = sv_2mortal(newSViv(showwindow));
4104 ST(0) = &PL_sv_undef;
4112 /* Make the host for current directory */
4113 char* ptr = PerlEnv_get_childdir();
4116 * then it worked, set PV valid,
4117 * else return 'undef'
4120 SV *sv = sv_newmortal();
4122 PerlEnv_free_childdir(ptr);
4124 #ifndef INCOMPLETE_TAINTS
4141 Perl_croak(aTHX_ "usage: Win32::SetCurrentDirectory($cwd)");
4142 if (!PerlDir_chdir(SvPV_nolen(ST(0))))
4149 XS(w32_GetNextAvailDrive)
4153 char root[] = "_:\\";
4158 if (GetDriveType(root) == 1) {
4167 XS(w32_GetLastError)
4171 XSRETURN_IV(GetLastError());
4175 XS(w32_SetLastError)
4179 Perl_croak(aTHX_ "usage: Win32::SetLastError($error)");
4180 SetLastError(SvIV(ST(0)));
4188 char *name = w32_getlogin_buffer;
4189 DWORD size = sizeof(w32_getlogin_buffer);
4191 if (GetUserName(name,&size)) {
4192 /* size includes NULL */
4193 ST(0) = sv_2mortal(newSVpvn(name,size-1));
4203 char name[MAX_COMPUTERNAME_LENGTH+1];
4204 DWORD size = sizeof(name);
4206 if (GetComputerName(name,&size)) {
4207 /* size does NOT include NULL :-( */
4208 ST(0) = sv_2mortal(newSVpvn(name,size));
4219 HINSTANCE hNetApi32 = LoadLibrary("netapi32.dll");
4220 DWORD (__stdcall *pfnNetApiBufferFree)(LPVOID Buffer);
4221 DWORD (__stdcall *pfnNetWkstaGetInfo)(LPWSTR servername, DWORD level,
4225 pfnNetApiBufferFree = (DWORD (__stdcall *)(void *))
4226 GetProcAddress(hNetApi32, "NetApiBufferFree");
4227 pfnNetWkstaGetInfo = (DWORD (__stdcall *)(LPWSTR, DWORD, void *))
4228 GetProcAddress(hNetApi32, "NetWkstaGetInfo");
4231 if (hNetApi32 && pfnNetWkstaGetInfo && pfnNetApiBufferFree) {
4232 /* this way is more reliable, in case user has a local account. */
4234 DWORD dnamelen = sizeof(dname);
4236 DWORD wki100_platform_id;
4237 LPWSTR wki100_computername;
4238 LPWSTR wki100_langroup;
4239 DWORD wki100_ver_major;
4240 DWORD wki100_ver_minor;
4242 /* NERR_Success *is* 0*/
4243 if (0 == pfnNetWkstaGetInfo(NULL, 100, &pwi)) {
4244 if (pwi->wki100_langroup && *(pwi->wki100_langroup)) {
4245 WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_langroup,
4246 -1, (LPSTR)dname, dnamelen, NULL, NULL);
4249 WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_computername,
4250 -1, (LPSTR)dname, dnamelen, NULL, NULL);
4252 pfnNetApiBufferFree(pwi);
4253 FreeLibrary(hNetApi32);
4256 FreeLibrary(hNetApi32);
4259 /* Win95 doesn't have NetWksta*(), so do it the old way */
4261 DWORD size = sizeof(name);
4263 FreeLibrary(hNetApi32);
4264 if (GetUserName(name,&size)) {
4265 char sid[ONE_K_BUFSIZE];
4266 DWORD sidlen = sizeof(sid);
4268 DWORD dnamelen = sizeof(dname);
4270 if (LookupAccountName(NULL, name, (PSID)&sid, &sidlen,
4271 dname, &dnamelen, &snu)) {
4272 XSRETURN_PV(dname); /* all that for this */
4284 DWORD flags, filecomplen;
4285 if (GetVolumeInformation(NULL, NULL, 0, NULL, &filecomplen,
4286 &flags, fsname, sizeof(fsname))) {
4287 if (GIMME_V == G_ARRAY) {
4288 XPUSHs(sv_2mortal(newSVpvn(fsname,strlen(fsname))));
4289 XPUSHs(sv_2mortal(newSViv(flags)));
4290 XPUSHs(sv_2mortal(newSViv(filecomplen)));
4295 XSRETURN_PV(fsname);
4301 XS(w32_GetOSVersion)
4304 OSVERSIONINFOA osver;
4307 OSVERSIONINFOW osverw;
4308 char szCSDVersion[sizeof(osverw.szCSDVersion)];
4309 osverw.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
4310 if (!GetVersionExW(&osverw)) {
4313 W2AHELPER(osverw.szCSDVersion, szCSDVersion, sizeof(szCSDVersion));
4314 XPUSHs(newSVpvn(szCSDVersion, strlen(szCSDVersion)));
4315 osver.dwMajorVersion = osverw.dwMajorVersion;
4316 osver.dwMinorVersion = osverw.dwMinorVersion;
4317 osver.dwBuildNumber = osverw.dwBuildNumber;
4318 osver.dwPlatformId = osverw.dwPlatformId;
4321 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
4322 if (!GetVersionExA(&osver)) {
4325 XPUSHs(newSVpvn(osver.szCSDVersion, strlen(osver.szCSDVersion)));
4327 XPUSHs(newSViv(osver.dwMajorVersion));
4328 XPUSHs(newSViv(osver.dwMinorVersion));
4329 XPUSHs(newSViv(osver.dwBuildNumber));
4330 XPUSHs(newSViv(osver.dwPlatformId));
4339 XSRETURN_IV(IsWinNT());
4347 XSRETURN_IV(IsWin95());
4351 XS(w32_FormatMessage)
4355 char msgbuf[ONE_K_BUFSIZE];
4358 Perl_croak(aTHX_ "usage: Win32::FormatMessage($errno)");
4361 WCHAR wmsgbuf[ONE_K_BUFSIZE];
4362 if (FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
4363 &source, SvIV(ST(0)), 0,
4364 wmsgbuf, ONE_K_BUFSIZE-1, NULL))
4366 W2AHELPER(wmsgbuf, msgbuf, sizeof(msgbuf));
4367 XSRETURN_PV(msgbuf);
4371 if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,
4372 &source, SvIV(ST(0)), 0,
4373 msgbuf, sizeof(msgbuf)-1, NULL))
4374 XSRETURN_PV(msgbuf);
4387 PROCESS_INFORMATION stProcInfo;
4388 STARTUPINFO stStartInfo;
4389 BOOL bSuccess = FALSE;
4392 Perl_croak(aTHX_ "usage: Win32::Spawn($cmdName, $args, $PID)");
4394 cmd = SvPV_nolen(ST(0));
4395 args = SvPV_nolen(ST(1));
4397 env = PerlEnv_get_childenv();
4398 dir = PerlEnv_get_childdir();
4400 memset(&stStartInfo, 0, sizeof(stStartInfo)); /* Clear the block */
4401 stStartInfo.cb = sizeof(stStartInfo); /* Set the structure size */
4402 stStartInfo.dwFlags = STARTF_USESHOWWINDOW; /* Enable wShowWindow control */
4403 stStartInfo.wShowWindow = SW_SHOWMINNOACTIVE; /* Start min (normal) */
4406 cmd, /* Image path */
4407 args, /* Arguments for command line */
4408 NULL, /* Default process security */
4409 NULL, /* Default thread security */
4410 FALSE, /* Must be TRUE to use std handles */
4411 NORMAL_PRIORITY_CLASS, /* No special scheduling */
4412 env, /* Inherit our environment block */
4413 dir, /* Inherit our currrent directory */
4414 &stStartInfo, /* -> Startup info */
4415 &stProcInfo)) /* <- Process info (if OK) */
4417 int pid = (int)stProcInfo.dwProcessId;
4418 if (IsWin95() && pid < 0)
4420 sv_setiv(ST(2), pid);
4421 CloseHandle(stProcInfo.hThread);/* library source code does this. */
4424 PerlEnv_free_childenv(env);
4425 PerlEnv_free_childdir(dir);
4426 XSRETURN_IV(bSuccess);
4430 XS(w32_GetTickCount)
4433 DWORD msec = GetTickCount();
4441 XS(w32_GetShortPathName)
4448 Perl_croak(aTHX_ "usage: Win32::GetShortPathName($longPathName)");
4450 shortpath = sv_mortalcopy(ST(0));
4451 SvUPGRADE(shortpath, SVt_PV);
4452 if (!SvPVX(shortpath) || !SvLEN(shortpath))
4455 /* src == target is allowed */
4457 len = GetShortPathName(SvPVX(shortpath),
4460 } while (len >= SvLEN(shortpath) && sv_grow(shortpath,len+1));
4462 SvCUR_set(shortpath,len);
4470 XS(w32_GetFullPathName)
4479 Perl_croak(aTHX_ "usage: Win32::GetFullPathName($filename)");
4482 fullpath = sv_mortalcopy(filename);
4483 SvUPGRADE(fullpath, SVt_PV);
4484 if (!SvPVX(fullpath) || !SvLEN(fullpath))
4488 len = GetFullPathName(SvPVX(filename),
4492 } while (len >= SvLEN(fullpath) && sv_grow(fullpath,len+1));
4494 if (GIMME_V == G_ARRAY) {
4496 XST_mPV(1,filepart);
4497 len = filepart - SvPVX(fullpath);
4500 SvCUR_set(fullpath,len);
4508 XS(w32_GetLongPathName)
4512 char tmpbuf[MAX_PATH+1];
4517 Perl_croak(aTHX_ "usage: Win32::GetLongPathName($pathname)");
4520 pathstr = SvPV(path,len);
4521 strcpy(tmpbuf, pathstr);
4522 pathstr = win32_longpath(tmpbuf);
4524 ST(0) = sv_2mortal(newSVpvn(pathstr, strlen(pathstr)));
4535 Perl_croak(aTHX_ "usage: Win32::Sleep($milliseconds)");
4546 Perl_croak(aTHX_ "usage: Win32::CopyFile($from, $to, $overwrite)");
4548 WCHAR wSourceFile[MAX_PATH+1];
4549 WCHAR wDestFile[MAX_PATH+1];
4550 A2WHELPER(SvPV_nolen(ST(0)), wSourceFile, sizeof(wSourceFile));
4551 wcscpy(wSourceFile, PerlDir_mapW(wSourceFile));
4552 A2WHELPER(SvPV_nolen(ST(1)), wDestFile, sizeof(wDestFile));
4553 bResult = CopyFileW(wSourceFile, PerlDir_mapW(wDestFile), !SvTRUE(ST(2)));
4556 char szSourceFile[MAX_PATH+1];
4557 strcpy(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(0))));
4558 bResult = CopyFileA(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(1))), !SvTRUE(ST(2)));
4567 Perl_init_os_extras(void)
4570 char *file = __FILE__;
4573 /* these names are Activeware compatible */
4574 newXS("Win32::GetCwd", w32_GetCwd, file);
4575 newXS("Win32::SetCwd", w32_SetCwd, file);
4576 newXS("Win32::GetNextAvailDrive", w32_GetNextAvailDrive, file);
4577 newXS("Win32::GetLastError", w32_GetLastError, file);
4578 newXS("Win32::SetLastError", w32_SetLastError, file);
4579 newXS("Win32::LoginName", w32_LoginName, file);
4580 newXS("Win32::NodeName", w32_NodeName, file);
4581 newXS("Win32::DomainName", w32_DomainName, file);
4582 newXS("Win32::FsType", w32_FsType, file);
4583 newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
4584 newXS("Win32::IsWinNT", w32_IsWinNT, file);
4585 newXS("Win32::IsWin95", w32_IsWin95, file);
4586 newXS("Win32::FormatMessage", w32_FormatMessage, file);
4587 newXS("Win32::Spawn", w32_Spawn, file);
4588 newXS("Win32::GetTickCount", w32_GetTickCount, file);
4589 newXS("Win32::GetShortPathName", w32_GetShortPathName, file);
4590 newXS("Win32::GetFullPathName", w32_GetFullPathName, file);
4591 newXS("Win32::GetLongPathName", w32_GetLongPathName, file);
4592 newXS("Win32::CopyFile", w32_CopyFile, file);
4593 newXS("Win32::Sleep", w32_Sleep, file);
4594 newXS("Win32::SetChildShowWindow", w32_SetChildShowWindow, file);
4596 /* XXX Bloat Alert! The following Activeware preloads really
4597 * ought to be part of Win32::Sys::*, so they're not included
4600 /* LookupAccountName
4602 * InitiateSystemShutdown
4603 * AbortSystemShutdown
4604 * ExpandEnvrironmentStrings
4611 win32_signal_context(void)
4615 my_perl = PL_curinterp;
4616 PERL_SET_THX(my_perl);
4624 win32_ctrlhandler(DWORD dwCtrlType)
4627 dTHXa(PERL_GET_SIG_CONTEXT);
4633 switch(dwCtrlType) {
4634 case CTRL_CLOSE_EVENT:
4635 /* A signal that the system sends to all processes attached to a console when
4636 the user closes the console (either by choosing the Close command from the
4637 console window's System menu, or by choosing the End Task command from the
4640 if (do_raise(aTHX_ 1)) /* SIGHUP */
4641 sig_terminate(aTHX_ 1);
4645 /* A CTRL+c signal was received */
4646 if (do_raise(aTHX_ SIGINT))
4647 sig_terminate(aTHX_ SIGINT);
4650 case CTRL_BREAK_EVENT:
4651 /* A CTRL+BREAK signal was received */
4652 if (do_raise(aTHX_ SIGBREAK))
4653 sig_terminate(aTHX_ SIGBREAK);
4656 case CTRL_LOGOFF_EVENT:
4657 /* A signal that the system sends to all console processes when a user is logging
4658 off. This signal does not indicate which user is logging off, so no
4659 assumptions can be made.
4662 case CTRL_SHUTDOWN_EVENT:
4663 /* A signal that the system sends to all console processes when the system is
4666 if (do_raise(aTHX_ SIGTERM))
4667 sig_terminate(aTHX_ SIGTERM);
4677 Perl_win32_init(int *argcp, char ***argvp)
4679 /* Disable floating point errors, Perl will trap the ones we
4680 * care about. VC++ RTL defaults to switching these off
4681 * already, but the Borland RTL doesn't. Since we don't
4682 * want to be at the vendor's whim on the default, we set
4683 * it explicitly here.
4685 #if !defined(_ALPHA_) && !defined(__GNUC__)
4686 _control87(MCW_EM, MCW_EM);
4692 win32_get_child_IO(child_IO_table* ptbl)
4694 ptbl->childStdIn = GetStdHandle(STD_INPUT_HANDLE);
4695 ptbl->childStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
4696 ptbl->childStdErr = GetStdHandle(STD_ERROR_HANDLE);
4700 win32_signal(int sig, Sighandler_t subcode)
4703 if (sig < SIG_SIZE) {
4704 int save_errno = errno;
4705 Sighandler_t result = signal(sig, subcode);
4706 if (result == SIG_ERR) {
4707 result = w32_sighandler[sig];
4710 w32_sighandler[sig] = subcode;
4720 #ifdef HAVE_INTERP_INTERN
4724 win32_csighandler(int sig)
4727 dTHXa(PERL_GET_SIG_CONTEXT);
4728 Perl_warn(aTHX_ "Got signal %d",sig);
4734 Perl_sys_intern_init(pTHX)
4737 w32_perlshell_tokens = Nullch;
4738 w32_perlshell_vec = (char**)NULL;
4739 w32_perlshell_items = 0;
4740 w32_fdpid = newAV();
4741 New(1313, w32_children, 1, child_tab);
4742 w32_num_children = 0;
4743 # ifdef USE_ITHREADS
4745 New(1313, w32_pseudo_children, 1, child_tab);
4746 w32_num_pseudo_children = 0;
4748 w32_init_socktype = 0;
4751 for (i=0; i < SIG_SIZE; i++) {
4752 w32_sighandler[i] = SIG_DFL;
4755 if (my_perl == PL_curinterp) {
4759 /* Force C runtime signal stuff to set its console handler */
4760 signal(SIGINT,&win32_csighandler);
4761 signal(SIGBREAK,&win32_csighandler);
4762 /* Push our handler on top */
4763 SetConsoleCtrlHandler(win32_ctrlhandler,TRUE);
4768 Perl_sys_intern_clear(pTHX)
4770 Safefree(w32_perlshell_tokens);
4771 Safefree(w32_perlshell_vec);
4772 /* NOTE: w32_fdpid is freed by sv_clean_all() */
4773 Safefree(w32_children);
4775 KillTimer(NULL,w32_timerid);
4778 # ifdef MULTIPLICITY
4779 if (my_perl == PL_curinterp) {
4783 SetConsoleCtrlHandler(win32_ctrlhandler,FALSE);
4785 # ifdef USE_ITHREADS
4786 Safefree(w32_pseudo_children);
4790 # ifdef USE_ITHREADS
4793 Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
4795 dst->perlshell_tokens = Nullch;
4796 dst->perlshell_vec = (char**)NULL;
4797 dst->perlshell_items = 0;
4798 dst->fdpid = newAV();
4799 Newz(1313, dst->children, 1, child_tab);
4801 Newz(1313, dst->pseudo_children, 1, child_tab);
4802 dst->thr_intern.Winit_socktype = 0;
4804 dst->poll_count = 0;
4805 Copy(src->sigtable,dst->sigtable,SIG_SIZE,Sighandler_t);
4807 # endif /* USE_ITHREADS */
4808 #endif /* HAVE_INTERP_INTERN */
4811 win32_free_argvw(pTHX_ void *ptr)
4813 char** argv = (char**)ptr;
4821 win32_argv2utf8(int argc, char** argv)
4826 LPWSTR* lpwStr = CommandLineToArgvW(GetCommandLineW(), &wargc);
4827 if (lpwStr && argc) {
4829 length = WideCharToMultiByte(CP_UTF8, 0, lpwStr[--wargc], -1, NULL, 0, NULL, NULL);
4830 Newz(0, psz, length, char);
4831 WideCharToMultiByte(CP_UTF8, 0, lpwStr[wargc], -1, psz, length, NULL, NULL);
4834 call_atexit(win32_free_argvw, argv);
4836 GlobalFree((HGLOBAL)lpwStr);