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];
213 va_start(ap, trailing_path);
214 strip = va_arg(ap, char *);
216 sprintf(base, "%d.%d", (int)PERL_REVISION, (int)PERL_VERSION);
217 baselen = strlen(base);
219 if (!*w32_module_name) {
220 set_w32_module_name();
222 strcpy(mod_name, w32_module_name);
223 ptr = strrchr(mod_name, '/');
224 while (ptr && strip) {
225 /* look for directories to skip back */
228 ptr = strrchr(mod_name, '/');
229 /* avoid stripping component if there is no slash,
230 * or it doesn't match ... */
231 if (!ptr || stricmp(ptr+1, strip) != 0) {
232 /* ... but not if component matches m|5\.$patchlevel.*| */
233 if (!ptr || !(*strip == '5' && *(ptr+1) == '5'
234 && strncmp(strip, base, baselen) == 0
235 && strncmp(ptr+1, base, baselen) == 0))
241 strip = va_arg(ap, char *);
249 strcpy(++ptr, trailing_path);
251 /* only add directory if it exists */
252 if (GetFileAttributes(mod_name) != (DWORD) -1) {
253 /* directory exists */
256 *prev_pathp = sv_2mortal(newSVpvn("",0));
257 sv_catpvn(*prev_pathp, ";", 1);
258 sv_catpv(*prev_pathp, mod_name);
259 return SvPVX(*prev_pathp);
266 win32_get_privlib(const char *pl)
269 char *stdlib = "lib";
270 char buffer[MAX_PATH+1];
273 /* $stdlib = $HKCU{"lib-$]"} || $HKLM{"lib-$]"} || $HKCU{"lib"} || $HKLM{"lib"} || ""; */
274 sprintf(buffer, "%s-%s", stdlib, pl);
275 if (!get_regstr(buffer, &sv))
276 (void)get_regstr(stdlib, &sv);
278 /* $stdlib .= ";$EMD/../../lib" */
279 return get_emd_part(&sv, stdlib, ARCHNAME, "bin", Nullch);
283 win32_get_xlib(const char *pl, const char *xlib, const char *libname)
287 char pathstr[MAX_PATH+1];
291 /* $HKCU{"$xlib-$]"} || $HKLM{"$xlib-$]"} . ---; */
292 sprintf(regstr, "%s-%s", xlib, pl);
293 (void)get_regstr(regstr, &sv1);
296 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/$]/lib"; */
297 sprintf(pathstr, "%s/%s/lib", libname, pl);
298 (void)get_emd_part(&sv1, pathstr, ARCHNAME, "bin", pl, Nullch);
300 /* $HKCU{$xlib} || $HKLM{$xlib} . ---; */
301 (void)get_regstr(xlib, &sv2);
304 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/lib"; */
305 sprintf(pathstr, "%s/lib", libname);
306 (void)get_emd_part(&sv2, pathstr, ARCHNAME, "bin", pl, Nullch);
315 sv_catpvn(sv1, ";", 1);
322 win32_get_sitelib(const char *pl)
324 return win32_get_xlib(pl, "sitelib", "site");
327 #ifndef PERL_VENDORLIB_NAME
328 # define PERL_VENDORLIB_NAME "vendor"
332 win32_get_vendorlib(const char *pl)
334 return win32_get_xlib(pl, "vendorlib", PERL_VENDORLIB_NAME);
338 has_shell_metachars(char *ptr)
344 * Scan string looking for redirection (< or >) or pipe
345 * characters (|) that are not in a quoted string.
346 * Shell variable interpolation (%VAR%) can also happen inside strings.
378 #if !defined(PERL_IMPLICIT_SYS)
379 /* since the current process environment is being updated in util.c
380 * the library functions will get the correct environment
383 Perl_my_popen(pTHX_ char *cmd, char *mode)
386 #define fixcmd(x) { \
387 char *pspace = strchr((x),' '); \
390 while (p < pspace) { \
401 PERL_FLUSHALL_FOR_CHILD;
402 return win32_popen(cmd, mode);
406 Perl_my_pclose(pTHX_ PerlIO *fp)
408 return win32_pclose(fp);
412 DllExport unsigned long
415 static OSVERSIONINFO osver;
417 if (osver.dwPlatformId != w32_platform) {
418 memset(&osver, 0, sizeof(OSVERSIONINFO));
419 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
420 GetVersionEx(&osver);
421 w32_platform = osver.dwPlatformId;
423 return (unsigned long)w32_platform;
433 return -((int)w32_pseudo_id);
436 /* Windows 9x appears to always reports a pid for threads and processes
437 * that has the high bit set. So we treat the lower 31 bits as the
438 * "real" PID for Perl's purposes. */
439 if (IsWin95() && pid < 0)
444 /* Tokenize a string. Words are null-separated, and the list
445 * ends with a doubled null. Any character (except null and
446 * including backslash) may be escaped by preceding it with a
447 * backslash (the backslash will be stripped).
448 * Returns number of words in result buffer.
451 tokenize(const char *str, char **dest, char ***destv)
453 char *retstart = Nullch;
454 char **retvstart = 0;
458 int slen = strlen(str);
460 register char **retv;
461 New(1307, ret, slen+2, char);
462 New(1308, retv, (slen+3)/2, char*);
470 if (*ret == '\\' && *str)
472 else if (*ret == ' ') {
488 retvstart[items] = Nullch;
501 if (!w32_perlshell_tokens) {
502 /* we don't use COMSPEC here for two reasons:
503 * 1. the same reason perl on UNIX doesn't use SHELL--rampant and
504 * uncontrolled unportability of the ensuing scripts.
505 * 2. PERL5SHELL could be set to a shell that may not be fit for
506 * interactive use (which is what most programs look in COMSPEC
509 const char* defaultshell = (IsWinNT()
510 ? "cmd.exe /x/c" : "command.com /c");
511 const char *usershell = PerlEnv_getenv("PERL5SHELL");
512 w32_perlshell_items = tokenize(usershell ? usershell : defaultshell,
513 &w32_perlshell_tokens,
519 do_aspawn(void *vreally, void **vmark, void **vsp)
522 SV *really = (SV*)vreally;
523 SV **mark = (SV**)vmark;
535 New(1306, argv, (sp - mark) + w32_perlshell_items + 2, char*);
537 if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
542 while (++mark <= sp) {
543 if (*mark && (str = SvPV_nolen(*mark)))
550 status = win32_spawnvp(flag,
551 (const char*)(really ? SvPV_nolen(really) : argv[0]),
552 (const char* const*)argv);
554 if (status < 0 && (errno == ENOEXEC || errno == ENOENT)) {
555 /* possible shell-builtin, invoke with shell */
557 sh_items = w32_perlshell_items;
559 argv[index+sh_items] = argv[index];
560 while (--sh_items >= 0)
561 argv[sh_items] = w32_perlshell_vec[sh_items];
563 status = win32_spawnvp(flag,
564 (const char*)(really ? SvPV_nolen(really) : argv[0]),
565 (const char* const*)argv);
568 if (flag == P_NOWAIT) {
570 PL_statusvalue = -1; /* >16bits hint for pp_system() */
574 if (ckWARN(WARN_EXEC))
575 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't spawn \"%s\": %s", argv[0], strerror(errno));
580 PL_statusvalue = status;
586 /* returns pointer to the next unquoted space or the end of the string */
588 find_next_space(const char *s)
590 bool in_quotes = FALSE;
592 /* ignore doubled backslashes, or backslash+quote */
593 if (*s == '\\' && (s[1] == '\\' || s[1] == '"')) {
596 /* keep track of when we're within quotes */
597 else if (*s == '"') {
599 in_quotes = !in_quotes;
601 /* break it up only at spaces that aren't in quotes */
602 else if (!in_quotes && isSPACE(*s))
611 do_spawn2(char *cmd, int exectype)
618 BOOL needToTry = TRUE;
621 /* Save an extra exec if possible. See if there are shell
622 * metacharacters in it */
623 if (!has_shell_metachars(cmd)) {
624 New(1301,argv, strlen(cmd) / 2 + 2, char*);
625 New(1302,cmd2, strlen(cmd) + 1, char);
628 for (s = cmd2; *s;) {
629 while (*s && isSPACE(*s))
633 s = find_next_space(s);
641 status = win32_spawnvp(P_WAIT, argv[0],
642 (const char* const*)argv);
644 case EXECF_SPAWN_NOWAIT:
645 status = win32_spawnvp(P_NOWAIT, argv[0],
646 (const char* const*)argv);
649 status = win32_execvp(argv[0], (const char* const*)argv);
652 if (status != -1 || errno == 0)
662 New(1306, argv, w32_perlshell_items + 2, char*);
663 while (++i < w32_perlshell_items)
664 argv[i] = w32_perlshell_vec[i];
669 status = win32_spawnvp(P_WAIT, argv[0],
670 (const char* const*)argv);
672 case EXECF_SPAWN_NOWAIT:
673 status = win32_spawnvp(P_NOWAIT, argv[0],
674 (const char* const*)argv);
677 status = win32_execvp(argv[0], (const char* const*)argv);
683 if (exectype == EXECF_SPAWN_NOWAIT) {
685 PL_statusvalue = -1; /* >16bits hint for pp_system() */
689 if (ckWARN(WARN_EXEC))
690 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s \"%s\": %s",
691 (exectype == EXECF_EXEC ? "exec" : "spawn"),
692 cmd, strerror(errno));
697 PL_statusvalue = status;
705 return do_spawn2(cmd, EXECF_SPAWN);
709 do_spawn_nowait(char *cmd)
711 return do_spawn2(cmd, EXECF_SPAWN_NOWAIT);
715 Perl_do_exec(pTHX_ char *cmd)
717 do_spawn2(cmd, EXECF_EXEC);
721 /* The idea here is to read all the directory names into a string table
722 * (separated by nulls) and when one of the other dir functions is called
723 * return the pointer to the current file name.
726 win32_opendir(char *filename)
732 char scanname[MAX_PATH+3];
734 WIN32_FIND_DATAA aFindData;
735 WIN32_FIND_DATAW wFindData;
737 char buffer[MAX_PATH*2];
738 WCHAR wbuffer[MAX_PATH+1];
741 len = strlen(filename);
745 /* check to see if filename is a directory */
746 if (win32_stat(filename, &sbuf) < 0 || !S_ISDIR(sbuf.st_mode))
749 /* Get us a DIR structure */
750 Newz(1303, dirp, 1, DIR);
752 /* Create the search pattern */
753 strcpy(scanname, filename);
755 /* bare drive name means look in cwd for drive */
756 if (len == 2 && isALPHA(scanname[0]) && scanname[1] == ':') {
757 scanname[len++] = '.';
758 scanname[len++] = '/';
760 else if (scanname[len-1] != '/' && scanname[len-1] != '\\') {
761 scanname[len++] = '/';
763 scanname[len++] = '*';
764 scanname[len] = '\0';
766 /* do the FindFirstFile call */
768 A2WHELPER(scanname, wbuffer, sizeof(wbuffer));
769 fh = FindFirstFileW(PerlDir_mapW(wbuffer), &wFindData);
772 fh = FindFirstFileA(PerlDir_mapA(scanname), &aFindData);
775 if (fh == INVALID_HANDLE_VALUE) {
776 DWORD err = GetLastError();
777 /* FindFirstFile() fails on empty drives! */
779 case ERROR_FILE_NOT_FOUND:
781 case ERROR_NO_MORE_FILES:
782 case ERROR_PATH_NOT_FOUND:
785 case ERROR_NOT_ENOUGH_MEMORY:
796 /* now allocate the first part of the string table for
797 * the filenames that we find.
800 W2AHELPER(wFindData.cFileName, buffer, sizeof(buffer));
804 ptr = aFindData.cFileName;
811 New(1304, dirp->start, dirp->size, char);
812 strcpy(dirp->start, ptr);
814 dirp->end = dirp->curr = dirp->start;
820 /* Readdir just returns the current string pointer and bumps the
821 * string pointer to the nDllExport entry.
823 DllExport struct direct *
824 win32_readdir(DIR *dirp)
829 /* first set up the structure to return */
830 len = strlen(dirp->curr);
831 strcpy(dirp->dirstr.d_name, dirp->curr);
832 dirp->dirstr.d_namlen = len;
835 dirp->dirstr.d_ino = dirp->curr - dirp->start;
837 /* Now set up for the next call to readdir */
838 dirp->curr += len + 1;
839 if (dirp->curr >= dirp->end) {
843 WIN32_FIND_DATAW wFindData;
844 WIN32_FIND_DATAA aFindData;
845 char buffer[MAX_PATH*2];
847 /* finding the next file that matches the wildcard
848 * (which should be all of them in this directory!).
851 res = FindNextFileW(dirp->handle, &wFindData);
853 W2AHELPER(wFindData.cFileName, buffer, sizeof(buffer));
858 res = FindNextFileA(dirp->handle, &aFindData);
860 ptr = aFindData.cFileName;
863 long endpos = dirp->end - dirp->start;
864 long newsize = endpos + strlen(ptr) + 1;
865 /* bump the string table size by enough for the
866 * new name and its null terminator */
867 while (newsize > dirp->size) {
868 long curpos = dirp->curr - dirp->start;
870 Renew(dirp->start, dirp->size, char);
871 dirp->curr = dirp->start + curpos;
873 strcpy(dirp->start + endpos, ptr);
874 dirp->end = dirp->start + newsize;
880 return &(dirp->dirstr);
886 /* Telldir returns the current string pointer position */
888 win32_telldir(DIR *dirp)
890 return (dirp->curr - dirp->start);
894 /* Seekdir moves the string pointer to a previously saved position
895 * (returned by telldir).
898 win32_seekdir(DIR *dirp, long loc)
900 dirp->curr = dirp->start + loc;
903 /* Rewinddir resets the string pointer to the start */
905 win32_rewinddir(DIR *dirp)
907 dirp->curr = dirp->start;
910 /* free the memory allocated by opendir */
912 win32_closedir(DIR *dirp)
915 if (dirp->handle != INVALID_HANDLE_VALUE)
916 FindClose(dirp->handle);
917 Safefree(dirp->start);
930 * Just pretend that everyone is a superuser. NT will let us know if
931 * we don\'t really have permission to do something.
934 #define ROOT_UID ((uid_t)0)
935 #define ROOT_GID ((gid_t)0)
964 return (auid == ROOT_UID ? 0 : -1);
970 return (agid == ROOT_GID ? 0 : -1);
977 char *buf = w32_getlogin_buffer;
978 DWORD size = sizeof(w32_getlogin_buffer);
979 if (GetUserName(buf,&size))
985 chown(const char *path, uid_t owner, gid_t group)
992 * XXX this needs strengthening (for PerlIO)
995 int mkstemp(const char *path)
998 char buf[MAX_PATH+1];
1002 if (i++ > 10) { /* give up */
1006 if (!GetTempFileNameA((LPCSTR)path, "plr", 1, buf)) {
1010 fd = PerlLIO_open3(buf, O_CREAT|O_RDWR|O_EXCL, 0600);
1020 long child = w32_num_children;
1021 while (--child >= 0) {
1022 if ((int)w32_child_pids[child] == pid)
1029 remove_dead_process(long child)
1033 CloseHandle(w32_child_handles[child]);
1034 Move(&w32_child_handles[child+1], &w32_child_handles[child],
1035 (w32_num_children-child-1), HANDLE);
1036 Move(&w32_child_pids[child+1], &w32_child_pids[child],
1037 (w32_num_children-child-1), DWORD);
1044 find_pseudo_pid(int pid)
1047 long child = w32_num_pseudo_children;
1048 while (--child >= 0) {
1049 if ((int)w32_pseudo_child_pids[child] == pid)
1056 remove_dead_pseudo_process(long child)
1060 CloseHandle(w32_pseudo_child_handles[child]);
1061 Move(&w32_pseudo_child_handles[child+1], &w32_pseudo_child_handles[child],
1062 (w32_num_pseudo_children-child-1), HANDLE);
1063 Move(&w32_pseudo_child_pids[child+1], &w32_pseudo_child_pids[child],
1064 (w32_num_pseudo_children-child-1), DWORD);
1065 w32_num_pseudo_children--;
1071 win32_kill(int pid, int sig)
1078 /* it is a pseudo-forked child */
1079 child = find_pseudo_pid(-pid);
1081 hProcess = w32_pseudo_child_handles[child];
1084 /* "Does process exist?" use of kill */
1087 /* kill -9 style un-graceful exit */
1088 if (TerminateThread(hProcess, sig)) {
1089 remove_dead_pseudo_process(child);
1094 /* We fake signals to pseudo-processes using Win32
1095 * message queue. In Win9X the pids are negative already. */
1096 if (PostThreadMessage(IsWin95() ? pid : -pid,WM_USER,sig,0)) {
1097 /* It might be us ... */
1104 else if (IsWin95()) {
1112 child = find_pid(pid);
1114 hProcess = w32_child_handles[child];
1117 /* "Does process exist?" use of kill */
1120 if (GenerateConsoleCtrlEvent(CTRL_C_EVENT,pid))
1123 default: /* For now be backwards compatible with perl5.6 */
1125 if (TerminateProcess(hProcess, sig)) {
1126 remove_dead_process(child);
1134 hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE,
1135 (IsWin95() ? -pid : pid));
1139 /* "Does process exist?" use of kill */
1142 if (GenerateConsoleCtrlEvent(CTRL_C_EVENT,pid))
1145 default: /* For now be backwards compatible with perl5.6 */
1147 if (TerminateProcess(hProcess, sig)) {
1148 CloseHandle(hProcess);
1160 win32_stat(const char *path, Stat_t *sbuf)
1163 char buffer[MAX_PATH+1];
1164 int l = strlen(path);
1166 WCHAR wbuffer[MAX_PATH+1];
1172 switch(path[l - 1]) {
1173 /* FindFirstFile() and stat() are buggy with a trailing
1174 * backslash, so change it to a forward slash :-( */
1176 strncpy(buffer, path, l-1);
1177 buffer[l - 1] = '/';
1181 /* FindFirstFile() is buggy with "x:", so add a dot :-( */
1183 if (l == 2 && isALPHA(path[0])) {
1184 buffer[0] = path[0];
1195 /* We *must* open & close the file once; otherwise file attribute changes */
1196 /* might not yet have propagated to "other" hard links of the same file. */
1197 /* This also gives us an opportunity to determine the number of links. */
1199 A2WHELPER(path, wbuffer, sizeof(wbuffer));
1200 pwbuffer = PerlDir_mapW(wbuffer);
1201 handle = CreateFileW(pwbuffer, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
1204 path = PerlDir_mapA(path);
1206 handle = CreateFileA(path, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
1208 if (handle != INVALID_HANDLE_VALUE) {
1209 BY_HANDLE_FILE_INFORMATION bhi;
1210 if (GetFileInformationByHandle(handle, &bhi))
1211 nlink = bhi.nNumberOfLinks;
1212 CloseHandle(handle);
1215 /* pwbuffer or path will be mapped correctly above */
1217 #if defined(WIN64) || defined(USE_LARGE_FILES)
1218 res = _wstati64(pwbuffer, sbuf);
1220 res = _wstat(pwbuffer, (struct _stat*)sbuf);
1224 #if defined(WIN64) || defined(USE_LARGE_FILES)
1225 res = _stati64(path, sbuf);
1227 res = stat(path, sbuf);
1230 sbuf->st_nlink = nlink;
1233 /* CRT is buggy on sharenames, so make sure it really isn't.
1234 * XXX using GetFileAttributesEx() will enable us to set
1235 * sbuf->st_*time (but note that's not available on the
1236 * Windows of 1995) */
1239 r = GetFileAttributesW(pwbuffer);
1242 r = GetFileAttributesA(path);
1244 if (r != 0xffffffff && (r & FILE_ATTRIBUTE_DIRECTORY)) {
1245 /* sbuf may still contain old garbage since stat() failed */
1246 Zero(sbuf, 1, Stat_t);
1247 sbuf->st_mode = S_IFDIR | S_IREAD;
1249 if (!(r & FILE_ATTRIBUTE_READONLY))
1250 sbuf->st_mode |= S_IWRITE | S_IEXEC;
1255 if (l == 3 && isALPHA(path[0]) && path[1] == ':'
1256 && (path[2] == '\\' || path[2] == '/'))
1258 /* The drive can be inaccessible, some _stat()s are buggy */
1260 ? !GetVolumeInformationW(pwbuffer,NULL,0,NULL,NULL,NULL,NULL,0)
1261 : !GetVolumeInformationA(path,NULL,0,NULL,NULL,NULL,NULL,0)) {
1267 if (S_ISDIR(sbuf->st_mode))
1268 sbuf->st_mode |= S_IWRITE | S_IEXEC;
1269 else if (S_ISREG(sbuf->st_mode)) {
1271 if (l >= 4 && path[l-4] == '.') {
1272 const char *e = path + l - 3;
1273 if (strnicmp(e,"exe",3)
1274 && strnicmp(e,"bat",3)
1275 && strnicmp(e,"com",3)
1276 && (IsWin95() || strnicmp(e,"cmd",3)))
1277 sbuf->st_mode &= ~S_IEXEC;
1279 sbuf->st_mode |= S_IEXEC;
1282 sbuf->st_mode &= ~S_IEXEC;
1283 /* Propagate permissions to _group_ and _others_ */
1284 perms = sbuf->st_mode & (S_IREAD|S_IWRITE|S_IEXEC);
1285 sbuf->st_mode |= (perms>>3) | (perms>>6);
1292 #define isSLASH(c) ((c) == '/' || (c) == '\\')
1293 #define SKIP_SLASHES(s) \
1295 while (*(s) && isSLASH(*(s))) \
1298 #define COPY_NONSLASHES(d,s) \
1300 while (*(s) && !isSLASH(*(s))) \
1304 /* Find the longname of a given path. path is destructively modified.
1305 * It should have space for at least MAX_PATH characters. */
1307 win32_longpath(char *path)
1309 WIN32_FIND_DATA fdata;
1311 char tmpbuf[MAX_PATH+1];
1312 char *tmpstart = tmpbuf;
1319 if (isALPHA(path[0]) && path[1] == ':') {
1321 *tmpstart++ = path[0];
1325 else if (isSLASH(path[0]) && isSLASH(path[1])) {
1327 *tmpstart++ = path[0];
1328 *tmpstart++ = path[1];
1329 SKIP_SLASHES(start);
1330 COPY_NONSLASHES(tmpstart,start); /* copy machine name */
1332 *tmpstart++ = *start++;
1333 SKIP_SLASHES(start);
1334 COPY_NONSLASHES(tmpstart,start); /* copy share name */
1339 /* copy initial slash, if any */
1340 if (isSLASH(*start)) {
1341 *tmpstart++ = *start++;
1343 SKIP_SLASHES(start);
1346 /* FindFirstFile() expands "." and "..", so we need to pass
1347 * those through unmolested */
1349 && (!start[1] || isSLASH(start[1])
1350 || (start[1] == '.' && (!start[2] || isSLASH(start[2])))))
1352 COPY_NONSLASHES(tmpstart,start); /* copy "." or ".." */
1357 /* if this is the end, bust outta here */
1361 /* now we're at a non-slash; walk up to next slash */
1362 while (*start && !isSLASH(*start))
1365 /* stop and find full name of component */
1368 fhand = FindFirstFile(path,&fdata);
1370 if (fhand != INVALID_HANDLE_VALUE) {
1371 STRLEN len = strlen(fdata.cFileName);
1372 if ((STRLEN)(tmpbuf + sizeof(tmpbuf) - tmpstart) > len) {
1373 strcpy(tmpstart, fdata.cFileName);
1384 /* failed a step, just return without side effects */
1385 /*PerlIO_printf(Perl_debug_log, "Failed to find %s\n", path);*/
1390 strcpy(path,tmpbuf);
1395 win32_getenv(const char *name)
1398 WCHAR wBuffer[MAX_PATH+1];
1400 SV *curitem = Nullsv;
1403 A2WHELPER(name, wBuffer, sizeof(wBuffer));
1404 needlen = GetEnvironmentVariableW(wBuffer, NULL, 0);
1407 needlen = GetEnvironmentVariableA(name,NULL,0);
1409 curitem = sv_2mortal(newSVpvn("", 0));
1413 SvGROW(curitem, (needlen+1)*sizeof(WCHAR));
1414 needlen = GetEnvironmentVariableW(wBuffer,
1415 (WCHAR*)SvPVX(curitem),
1417 } while (needlen >= SvLEN(curitem)/sizeof(WCHAR));
1418 SvCUR_set(curitem, (needlen*sizeof(WCHAR))+1);
1419 acuritem = sv_2mortal(newSVsv(curitem));
1420 W2AHELPER((WCHAR*)SvPVX(acuritem), SvPVX(curitem), SvCUR(curitem));
1424 SvGROW(curitem, needlen+1);
1425 needlen = GetEnvironmentVariableA(name,SvPVX(curitem),
1427 } while (needlen >= SvLEN(curitem));
1428 SvCUR_set(curitem, needlen);
1432 /* allow any environment variables that begin with 'PERL'
1433 to be stored in the registry */
1434 if (strncmp(name, "PERL", 4) == 0)
1435 (void)get_regstr(name, &curitem);
1437 if (curitem && SvCUR(curitem))
1438 return SvPVX(curitem);
1444 win32_putenv(const char *name)
1451 int length, relval = -1;
1455 length = strlen(name)+1;
1456 New(1309,wCuritem,length,WCHAR);
1457 A2WHELPER(name, wCuritem, length*sizeof(WCHAR));
1458 wVal = wcschr(wCuritem, '=');
1461 if (SetEnvironmentVariableW(wCuritem, *wVal ? wVal : NULL))
1467 New(1309,curitem,strlen(name)+1,char);
1468 strcpy(curitem, name);
1469 val = strchr(curitem, '=');
1471 /* The sane way to deal with the environment.
1472 * Has these advantages over putenv() & co.:
1473 * * enables us to store a truly empty value in the
1474 * environment (like in UNIX).
1475 * * we don't have to deal with RTL globals, bugs and leaks.
1477 * Why you may want to enable USE_WIN32_RTL_ENV:
1478 * * environ[] and RTL functions will not reflect changes,
1479 * which might be an issue if extensions want to access
1480 * the env. via RTL. This cuts both ways, since RTL will
1481 * not see changes made by extensions that call the Win32
1482 * functions directly, either.
1486 if (SetEnvironmentVariableA(curitem, *val ? val : NULL))
1496 filetime_to_clock(PFILETIME ft)
1498 __int64 qw = ft->dwHighDateTime;
1500 qw |= ft->dwLowDateTime;
1501 qw /= 10000; /* File time ticks at 0.1uS, clock at 1mS */
1506 win32_times(struct tms *timebuf)
1511 clock_t process_time_so_far = clock();
1512 if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy,
1514 timebuf->tms_utime = filetime_to_clock(&user);
1515 timebuf->tms_stime = filetime_to_clock(&kernel);
1516 timebuf->tms_cutime = 0;
1517 timebuf->tms_cstime = 0;
1519 /* That failed - e.g. Win95 fallback to clock() */
1520 timebuf->tms_utime = process_time_so_far;
1521 timebuf->tms_stime = 0;
1522 timebuf->tms_cutime = 0;
1523 timebuf->tms_cstime = 0;
1525 return process_time_so_far;
1528 /* fix utime() so it works on directories in NT */
1530 filetime_from_time(PFILETIME pFileTime, time_t Time)
1532 struct tm *pTM = localtime(&Time);
1533 SYSTEMTIME SystemTime;
1539 SystemTime.wYear = pTM->tm_year + 1900;
1540 SystemTime.wMonth = pTM->tm_mon + 1;
1541 SystemTime.wDay = pTM->tm_mday;
1542 SystemTime.wHour = pTM->tm_hour;
1543 SystemTime.wMinute = pTM->tm_min;
1544 SystemTime.wSecond = pTM->tm_sec;
1545 SystemTime.wMilliseconds = 0;
1547 return SystemTimeToFileTime(&SystemTime, &LocalTime) &&
1548 LocalFileTimeToFileTime(&LocalTime, pFileTime);
1552 win32_unlink(const char *filename)
1559 WCHAR wBuffer[MAX_PATH+1];
1562 A2WHELPER(filename, wBuffer, sizeof(wBuffer));
1563 pwBuffer = PerlDir_mapW(wBuffer);
1564 attrs = GetFileAttributesW(pwBuffer);
1565 if (attrs == 0xFFFFFFFF)
1567 if (attrs & FILE_ATTRIBUTE_READONLY) {
1568 (void)SetFileAttributesW(pwBuffer, attrs & ~FILE_ATTRIBUTE_READONLY);
1569 ret = _wunlink(pwBuffer);
1571 (void)SetFileAttributesW(pwBuffer, attrs);
1574 ret = _wunlink(pwBuffer);
1577 filename = PerlDir_mapA(filename);
1578 attrs = GetFileAttributesA(filename);
1579 if (attrs == 0xFFFFFFFF)
1581 if (attrs & FILE_ATTRIBUTE_READONLY) {
1582 (void)SetFileAttributesA(filename, attrs & ~FILE_ATTRIBUTE_READONLY);
1583 ret = unlink(filename);
1585 (void)SetFileAttributesA(filename, attrs);
1588 ret = unlink(filename);
1597 win32_utime(const char *filename, struct utimbuf *times)
1604 struct utimbuf TimeBuffer;
1605 WCHAR wbuffer[MAX_PATH+1];
1610 A2WHELPER(filename, wbuffer, sizeof(wbuffer));
1611 pwbuffer = PerlDir_mapW(wbuffer);
1612 rc = _wutime(pwbuffer, (struct _utimbuf*)times);
1615 filename = PerlDir_mapA(filename);
1616 rc = utime(filename, times);
1618 /* EACCES: path specifies directory or readonly file */
1619 if (rc == 0 || errno != EACCES /* || !IsWinNT() */)
1622 if (times == NULL) {
1623 times = &TimeBuffer;
1624 time(×->actime);
1625 times->modtime = times->actime;
1628 /* This will (and should) still fail on readonly files */
1630 handle = CreateFileW(pwbuffer, GENERIC_READ | GENERIC_WRITE,
1631 FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
1632 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1635 handle = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE,
1636 FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
1637 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1639 if (handle == INVALID_HANDLE_VALUE)
1642 if (GetFileTime(handle, &ftCreate, &ftAccess, &ftWrite) &&
1643 filetime_from_time(&ftAccess, times->actime) &&
1644 filetime_from_time(&ftWrite, times->modtime) &&
1645 SetFileTime(handle, &ftCreate, &ftAccess, &ftWrite))
1650 CloseHandle(handle);
1655 unsigned __int64 ft_i64;
1660 #define Const64(x) x##LL
1662 #define Const64(x) x##i64
1664 /* Number of 100 nanosecond units from 1/1/1601 to 1/1/1970 */
1665 #define EPOCH_BIAS Const64(116444736000000000)
1667 /* NOTE: This does not compute the timezone info (doing so can be expensive,
1668 * and appears to be unsupported even by glibc) */
1670 win32_gettimeofday(struct timeval *tp, void *not_used)
1674 /* this returns time in 100-nanosecond units (i.e. tens of usecs) */
1675 GetSystemTimeAsFileTime(&ft.ft_val);
1677 /* seconds since epoch */
1678 tp->tv_sec = (long)((ft.ft_i64 - EPOCH_BIAS) / Const64(10000000));
1680 /* microseconds remaining */
1681 tp->tv_usec = (long)((ft.ft_i64 / Const64(10)) % Const64(1000000));
1687 win32_uname(struct utsname *name)
1689 struct hostent *hep;
1690 STRLEN nodemax = sizeof(name->nodename)-1;
1691 OSVERSIONINFO osver;
1693 memset(&osver, 0, sizeof(OSVERSIONINFO));
1694 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1695 if (GetVersionEx(&osver)) {
1697 switch (osver.dwPlatformId) {
1698 case VER_PLATFORM_WIN32_WINDOWS:
1699 strcpy(name->sysname, "Windows");
1701 case VER_PLATFORM_WIN32_NT:
1702 strcpy(name->sysname, "Windows NT");
1704 case VER_PLATFORM_WIN32s:
1705 strcpy(name->sysname, "Win32s");
1708 strcpy(name->sysname, "Win32 Unknown");
1713 sprintf(name->release, "%d.%d",
1714 osver.dwMajorVersion, osver.dwMinorVersion);
1717 sprintf(name->version, "Build %d",
1718 osver.dwPlatformId == VER_PLATFORM_WIN32_NT
1719 ? osver.dwBuildNumber : (osver.dwBuildNumber & 0xffff));
1720 if (osver.szCSDVersion[0]) {
1721 char *buf = name->version + strlen(name->version);
1722 sprintf(buf, " (%s)", osver.szCSDVersion);
1726 *name->sysname = '\0';
1727 *name->version = '\0';
1728 *name->release = '\0';
1732 hep = win32_gethostbyname("localhost");
1734 STRLEN len = strlen(hep->h_name);
1735 if (len <= nodemax) {
1736 strcpy(name->nodename, hep->h_name);
1739 strncpy(name->nodename, hep->h_name, nodemax);
1740 name->nodename[nodemax] = '\0';
1745 if (!GetComputerName(name->nodename, &sz))
1746 *name->nodename = '\0';
1749 /* machine (architecture) */
1754 GetSystemInfo(&info);
1756 #if (defined(__BORLANDC__)&&(__BORLANDC__<=0x520)) \
1757 || (defined(__MINGW32__) && !defined(_ANONYMOUS_UNION))
1758 procarch = info.u.s.wProcessorArchitecture;
1760 procarch = info.wProcessorArchitecture;
1763 case PROCESSOR_ARCHITECTURE_INTEL:
1764 arch = "x86"; break;
1765 case PROCESSOR_ARCHITECTURE_MIPS:
1766 arch = "mips"; break;
1767 case PROCESSOR_ARCHITECTURE_ALPHA:
1768 arch = "alpha"; break;
1769 case PROCESSOR_ARCHITECTURE_PPC:
1770 arch = "ppc"; break;
1771 #ifdef PROCESSOR_ARCHITECTURE_SHX
1772 case PROCESSOR_ARCHITECTURE_SHX:
1773 arch = "shx"; break;
1775 #ifdef PROCESSOR_ARCHITECTURE_ARM
1776 case PROCESSOR_ARCHITECTURE_ARM:
1777 arch = "arm"; break;
1779 #ifdef PROCESSOR_ARCHITECTURE_IA64
1780 case PROCESSOR_ARCHITECTURE_IA64:
1781 arch = "ia64"; break;
1783 #ifdef PROCESSOR_ARCHITECTURE_ALPHA64
1784 case PROCESSOR_ARCHITECTURE_ALPHA64:
1785 arch = "alpha64"; break;
1787 #ifdef PROCESSOR_ARCHITECTURE_MSIL
1788 case PROCESSOR_ARCHITECTURE_MSIL:
1789 arch = "msil"; break;
1791 #ifdef PROCESSOR_ARCHITECTURE_AMD64
1792 case PROCESSOR_ARCHITECTURE_AMD64:
1793 arch = "amd64"; break;
1795 #ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
1796 case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
1797 arch = "ia32-64"; break;
1799 #ifdef PROCESSOR_ARCHITECTURE_UNKNOWN
1800 case PROCESSOR_ARCHITECTURE_UNKNOWN:
1801 arch = "unknown"; break;
1804 sprintf(name->machine, "unknown(0x%x)", procarch);
1805 arch = name->machine;
1808 if (name->machine != arch)
1809 strcpy(name->machine, arch);
1814 /* Timing related stuff */
1817 do_raise(pTHX_ int sig)
1819 if (sig < SIG_SIZE) {
1820 Sighandler_t handler = w32_sighandler[sig];
1821 if (handler == SIG_IGN) {
1824 else if (handler != SIG_DFL) {
1829 /* Choose correct default behaviour */
1845 /* Tell caller to exit thread/process as approriate */
1850 sig_terminate(pTHX_ int sig)
1852 Perl_warn(aTHX_ "Terminating on signal SIG%s(%d)\n",PL_sig_name[sig], sig);
1853 /* exit() seems to be safe, my_exit() or die() is a problem in ^C
1860 win32_async_check(pTHX)
1864 /* Passing PeekMessage -1 as HWND (2nd arg) only get PostThreadMessage() messages
1865 * and ignores window messages - should co-exist better with windows apps e.g. Tk
1867 while (PeekMessage(&msg, (HWND)-1, 0, 0, PM_REMOVE|PM_NOYIELD)) {
1869 switch(msg.message) {
1872 /* Perhaps some other messages could map to signals ? ... */
1875 /* Treat WM_QUIT like SIGHUP? */
1881 /* We use WM_USER to fake kill() with other signals */
1885 if (do_raise(aTHX_ sig)) {
1886 sig_terminate(aTHX_ sig);
1892 /* alarm() is a one-shot but SetTimer() repeats so kill it */
1894 KillTimer(NULL,w32_timerid);
1897 /* Now fake a call to signal handler */
1898 if (do_raise(aTHX_ 14)) {
1899 sig_terminate(aTHX_ 14);
1904 /* Otherwise do normal Win32 thing - in case it is useful */
1906 TranslateMessage(&msg);
1907 DispatchMessage(&msg);
1914 /* Above or other stuff may have set a signal flag */
1915 if (PL_sig_pending) {
1922 win32_msgwait(pTHX_ DWORD count, LPHANDLE handles, DWORD timeout, LPDWORD resultp)
1924 /* We may need several goes at this - so compute when we stop */
1926 if (timeout != INFINITE) {
1927 ticks = GetTickCount();
1931 DWORD result = MsgWaitForMultipleObjects(count,handles,FALSE,timeout-ticks, QS_ALLEVENTS);
1934 if (result == WAIT_TIMEOUT) {
1935 /* Ran out of time - explicit return of zero to avoid -ve if we
1936 have scheduling issues
1940 if (timeout != INFINITE) {
1941 ticks = GetTickCount();
1943 if (result == WAIT_OBJECT_0 + count) {
1944 /* Message has arrived - check it */
1945 if (win32_async_check(aTHX)) {
1946 /* was one of ours */
1951 /* Not timeout or message - one of handles is ready */
1955 /* compute time left to wait */
1956 ticks = timeout - ticks;
1957 /* If we are past the end say zero */
1958 return (ticks > 0) ? ticks : 0;
1962 win32_internal_wait(int *status, DWORD timeout)
1964 /* XXX this wait emulation only knows about processes
1965 * spawned via win32_spawnvp(P_NOWAIT, ...).
1969 DWORD exitcode, waitcode;
1972 if (w32_num_pseudo_children) {
1973 win32_msgwait(aTHX_ w32_num_pseudo_children, w32_pseudo_child_handles,
1974 timeout, &waitcode);
1975 /* Time out here if there are no other children to wait for. */
1976 if (waitcode == WAIT_TIMEOUT) {
1977 if (!w32_num_children) {
1981 else if (waitcode != WAIT_FAILED) {
1982 if (waitcode >= WAIT_ABANDONED_0
1983 && waitcode < WAIT_ABANDONED_0 + w32_num_pseudo_children)
1984 i = waitcode - WAIT_ABANDONED_0;
1986 i = waitcode - WAIT_OBJECT_0;
1987 if (GetExitCodeThread(w32_pseudo_child_handles[i], &exitcode)) {
1988 *status = (int)((exitcode & 0xff) << 8);
1989 retval = (int)w32_pseudo_child_pids[i];
1990 remove_dead_pseudo_process(i);
1997 if (!w32_num_children) {
2002 /* if a child exists, wait for it to die */
2003 win32_msgwait(aTHX_ w32_num_children, w32_child_handles, timeout, &waitcode);
2004 if (waitcode == WAIT_TIMEOUT) {
2007 if (waitcode != WAIT_FAILED) {
2008 if (waitcode >= WAIT_ABANDONED_0
2009 && waitcode < WAIT_ABANDONED_0 + w32_num_children)
2010 i = waitcode - WAIT_ABANDONED_0;
2012 i = waitcode - WAIT_OBJECT_0;
2013 if (GetExitCodeProcess(w32_child_handles[i], &exitcode) ) {
2014 *status = (int)((exitcode & 0xff) << 8);
2015 retval = (int)w32_child_pids[i];
2016 remove_dead_process(i);
2021 errno = GetLastError();
2026 win32_waitpid(int pid, int *status, int flags)
2029 DWORD timeout = (flags & WNOHANG) ? 0 : INFINITE;
2032 if (pid == -1) /* XXX threadid == 1 ? */
2033 return win32_internal_wait(status, timeout);
2036 child = find_pseudo_pid(-pid);
2038 HANDLE hThread = w32_pseudo_child_handles[child];
2040 win32_msgwait(aTHX_ 1, &hThread, timeout, &waitcode);
2041 if (waitcode == WAIT_TIMEOUT) {
2044 else if (waitcode == WAIT_OBJECT_0) {
2045 if (GetExitCodeThread(hThread, &waitcode)) {
2046 *status = (int)((waitcode & 0xff) << 8);
2047 retval = (int)w32_pseudo_child_pids[child];
2048 remove_dead_pseudo_process(child);
2055 else if (IsWin95()) {
2064 child = find_pid(pid);
2066 hProcess = w32_child_handles[child];
2067 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
2068 if (waitcode == WAIT_TIMEOUT) {
2071 else if (waitcode == WAIT_OBJECT_0) {
2072 if (GetExitCodeProcess(hProcess, &waitcode)) {
2073 *status = (int)((waitcode & 0xff) << 8);
2074 retval = (int)w32_child_pids[child];
2075 remove_dead_process(child);
2084 hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE,
2085 (IsWin95() ? -pid : pid));
2087 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
2088 if (waitcode == WAIT_TIMEOUT) {
2091 else if (waitcode == WAIT_OBJECT_0) {
2092 if (GetExitCodeProcess(hProcess, &waitcode)) {
2093 *status = (int)((waitcode & 0xff) << 8);
2094 CloseHandle(hProcess);
2098 CloseHandle(hProcess);
2104 return retval >= 0 ? pid : retval;
2108 win32_wait(int *status)
2110 return win32_internal_wait(status, INFINITE);
2113 DllExport unsigned int
2114 win32_sleep(unsigned int t)
2117 /* Win32 times are in ms so *1000 in and /1000 out */
2118 return win32_msgwait(aTHX_ 0, NULL, t*1000, NULL)/1000;
2121 DllExport unsigned int
2122 win32_alarm(unsigned int sec)
2125 * the 'obvious' implentation is SetTimer() with a callback
2126 * which does whatever receiving SIGALRM would do
2127 * we cannot use SIGALRM even via raise() as it is not
2128 * one of the supported codes in <signal.h>
2132 w32_timerid = SetTimer(NULL,w32_timerid,sec*1000,NULL);
2136 KillTimer(NULL,w32_timerid);
2143 #ifdef HAVE_DES_FCRYPT
2144 extern char * des_fcrypt(const char *txt, const char *salt, char *cbuf);
2148 win32_crypt(const char *txt, const char *salt)
2151 #ifdef HAVE_DES_FCRYPT
2152 return des_fcrypt(txt, salt, w32_crypt_buffer);
2154 Perl_croak(aTHX_ "The crypt() function is unimplemented due to excessive paranoia.");
2159 #ifdef USE_FIXED_OSFHANDLE
2161 #define FOPEN 0x01 /* file handle open */
2162 #define FNOINHERIT 0x10 /* file handle opened O_NOINHERIT */
2163 #define FAPPEND 0x20 /* file handle opened O_APPEND */
2164 #define FDEV 0x40 /* file handle refers to device */
2165 #define FTEXT 0x80 /* file handle is in text mode */
2168 *int my_open_osfhandle(intptr_t osfhandle, int flags) - open C Runtime file handle
2171 * This function allocates a free C Runtime file handle and associates
2172 * it with the Win32 HANDLE specified by the first parameter. This is a
2173 * temperary fix for WIN95's brain damage GetFileType() error on socket
2174 * we just bypass that call for socket
2176 * This works with MSVC++ 4.0+ or GCC/Mingw32
2179 * intptr_t osfhandle - Win32 HANDLE to associate with C Runtime file handle.
2180 * int flags - flags to associate with C Runtime file handle.
2183 * returns index of entry in fh, if successful
2184 * return -1, if no free entry is found
2188 *******************************************************************************/
2191 * we fake up some parts of the CRT that aren't exported by MSVCRT.dll
2192 * this lets sockets work on Win9X with GCC and should fix the problems
2197 /* create an ioinfo entry, kill its handle, and steal the entry */
2202 HANDLE hF = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
2203 int fh = _open_osfhandle((intptr_t)hF, 0);
2207 EnterCriticalSection(&(_pioinfo(fh)->lock));
2212 my_open_osfhandle(intptr_t osfhandle, int flags)
2215 char fileflags; /* _osfile flags */
2217 /* copy relevant flags from second parameter */
2220 if (flags & O_APPEND)
2221 fileflags |= FAPPEND;
2226 if (flags & O_NOINHERIT)
2227 fileflags |= FNOINHERIT;
2229 /* attempt to allocate a C Runtime file handle */
2230 if ((fh = _alloc_osfhnd()) == -1) {
2231 errno = EMFILE; /* too many open files */
2232 _doserrno = 0L; /* not an OS error */
2233 return -1; /* return error to caller */
2236 /* the file is open. now, set the info in _osfhnd array */
2237 _set_osfhnd(fh, osfhandle);
2239 fileflags |= FOPEN; /* mark as open */
2241 _osfile(fh) = fileflags; /* set osfile entry */
2242 LeaveCriticalSection(&_pioinfo(fh)->lock);
2244 return fh; /* return handle */
2247 #endif /* USE_FIXED_OSFHANDLE */
2249 /* simulate flock by locking a range on the file */
2251 #define LK_ERR(f,i) ((f) ? (i = 0) : (errno = GetLastError()))
2252 #define LK_LEN 0xffff0000
2255 win32_flock(int fd, int oper)
2263 Perl_croak_nocontext("flock() unimplemented on this platform");
2266 fh = (HANDLE)_get_osfhandle(fd);
2267 memset(&o, 0, sizeof(o));
2270 case LOCK_SH: /* shared lock */
2271 LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, 0, &o),i);
2273 case LOCK_EX: /* exclusive lock */
2274 LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o),i);
2276 case LOCK_SH|LOCK_NB: /* non-blocking shared lock */
2277 LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o),i);
2279 case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */
2280 LK_ERR(LockFileEx(fh,
2281 LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
2282 0, LK_LEN, 0, &o),i);
2284 case LOCK_UN: /* unlock lock */
2285 LK_ERR(UnlockFileEx(fh, 0, LK_LEN, 0, &o),i);
2287 default: /* unknown */
2298 * redirected io subsystem for all XS modules
2311 return (&(_environ));
2314 /* the rest are the remapped stdio routines */
2334 win32_ferror(FILE *fp)
2336 return (ferror(fp));
2341 win32_feof(FILE *fp)
2347 * Since the errors returned by the socket error function
2348 * WSAGetLastError() are not known by the library routine strerror
2349 * we have to roll our own.
2353 win32_strerror(int e)
2355 #if !defined __BORLANDC__ && !defined __MINGW32__ /* compiler intolerance */
2356 extern int sys_nerr;
2360 if (e < 0 || e > sys_nerr) {
2365 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0,
2366 w32_strerror_buffer,
2367 sizeof(w32_strerror_buffer), NULL) == 0)
2368 strcpy(w32_strerror_buffer, "Unknown Error");
2370 return w32_strerror_buffer;
2376 win32_str_os_error(void *sv, DWORD dwErr)
2380 dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
2381 |FORMAT_MESSAGE_IGNORE_INSERTS
2382 |FORMAT_MESSAGE_FROM_SYSTEM, NULL,
2383 dwErr, 0, (char *)&sMsg, 1, NULL);
2384 /* strip trailing whitespace and period */
2387 --dwLen; /* dwLen doesn't include trailing null */
2388 } while (0 < dwLen && isSPACE(sMsg[dwLen]));
2389 if ('.' != sMsg[dwLen])
2394 sMsg = (char*)LocalAlloc(0, 64/**sizeof(TCHAR)*/);
2396 dwLen = sprintf(sMsg,
2397 "Unknown error #0x%lX (lookup 0x%lX)",
2398 dwErr, GetLastError());
2402 sv_setpvn((SV*)sv, sMsg, dwLen);
2408 win32_fprintf(FILE *fp, const char *format, ...)
2411 va_start(marker, format); /* Initialize variable arguments. */
2413 return (vfprintf(fp, format, marker));
2417 win32_printf(const char *format, ...)
2420 va_start(marker, format); /* Initialize variable arguments. */
2422 return (vprintf(format, marker));
2426 win32_vfprintf(FILE *fp, const char *format, va_list args)
2428 return (vfprintf(fp, format, args));
2432 win32_vprintf(const char *format, va_list args)
2434 return (vprintf(format, args));
2438 win32_fread(void *buf, size_t size, size_t count, FILE *fp)
2440 return fread(buf, size, count, fp);
2444 win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
2446 return fwrite(buf, size, count, fp);
2449 #define MODE_SIZE 10
2452 win32_fopen(const char *filename, const char *mode)
2455 WCHAR wMode[MODE_SIZE], wBuffer[MAX_PATH+1];
2461 if (stricmp(filename, "/dev/null")==0)
2465 A2WHELPER(mode, wMode, sizeof(wMode));
2466 A2WHELPER(filename, wBuffer, sizeof(wBuffer));
2467 f = _wfopen(PerlDir_mapW(wBuffer), wMode);
2470 f = fopen(PerlDir_mapA(filename), mode);
2471 /* avoid buffering headaches for child processes */
2472 if (f && *mode == 'a')
2473 win32_fseek(f, 0, SEEK_END);
2477 #ifndef USE_SOCKETS_AS_HANDLES
2479 #define fdopen my_fdopen
2483 win32_fdopen(int handle, const char *mode)
2486 WCHAR wMode[MODE_SIZE];
2489 A2WHELPER(mode, wMode, sizeof(wMode));
2490 f = _wfdopen(handle, wMode);
2493 f = fdopen(handle, (char *) mode);
2494 /* avoid buffering headaches for child processes */
2495 if (f && *mode == 'a')
2496 win32_fseek(f, 0, SEEK_END);
2501 win32_freopen(const char *path, const char *mode, FILE *stream)
2504 WCHAR wMode[MODE_SIZE], wBuffer[MAX_PATH+1];
2505 if (stricmp(path, "/dev/null")==0)
2509 A2WHELPER(mode, wMode, sizeof(wMode));
2510 A2WHELPER(path, wBuffer, sizeof(wBuffer));
2511 return _wfreopen(PerlDir_mapW(wBuffer), wMode, stream);
2513 return freopen(PerlDir_mapA(path), mode, stream);
2517 win32_fclose(FILE *pf)
2519 return my_fclose(pf); /* defined in win32sck.c */
2523 win32_fputs(const char *s,FILE *pf)
2525 return fputs(s, pf);
2529 win32_fputc(int c,FILE *pf)
2535 win32_ungetc(int c,FILE *pf)
2537 return ungetc(c,pf);
2541 win32_getc(FILE *pf)
2547 win32_fileno(FILE *pf)
2553 win32_clearerr(FILE *pf)
2560 win32_fflush(FILE *pf)
2566 win32_ftell(FILE *pf)
2568 #if defined(WIN64) || defined(USE_LARGE_FILES)
2570 if (fgetpos(pf, &pos))
2579 win32_fseek(FILE *pf, Off_t offset,int origin)
2581 #if defined(WIN64) || defined(USE_LARGE_FILES)
2585 if (fgetpos(pf, &pos))
2590 fseek(pf, 0, SEEK_END);
2591 pos = _telli64(fileno(pf));
2600 return fsetpos(pf, &offset);
2602 return fseek(pf, offset, origin);
2607 win32_fgetpos(FILE *pf,fpos_t *p)
2609 return fgetpos(pf, p);
2613 win32_fsetpos(FILE *pf,const fpos_t *p)
2615 return fsetpos(pf, p);
2619 win32_rewind(FILE *pf)
2629 char prefix[MAX_PATH+1];
2630 char filename[MAX_PATH+1];
2631 DWORD len = GetTempPath(MAX_PATH, prefix);
2632 if (len && len < MAX_PATH) {
2633 if (GetTempFileName(prefix, "plx", 0, filename)) {
2634 HANDLE fh = CreateFile(filename,
2635 DELETE | GENERIC_READ | GENERIC_WRITE,
2639 FILE_ATTRIBUTE_NORMAL
2640 | FILE_FLAG_DELETE_ON_CLOSE,
2642 if (fh != INVALID_HANDLE_VALUE) {
2643 int fd = win32_open_osfhandle((intptr_t)fh, 0);
2645 #if defined(__BORLANDC__)
2646 setmode(fd,O_BINARY);
2648 DEBUG_p(PerlIO_printf(Perl_debug_log,
2649 "Created tmpfile=%s\n",filename));
2650 return fdopen(fd, "w+b");
2666 win32_fstat(int fd, Stat_t *sbufptr)
2669 /* A file designated by filehandle is not shown as accessible
2670 * for write operations, probably because it is opened for reading.
2673 int rc = fstat(fd,sbufptr);
2674 BY_HANDLE_FILE_INFORMATION bhfi;
2675 if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &bhfi)) {
2676 sbufptr->st_mode &= 0xFE00;
2677 if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
2678 sbufptr->st_mode |= (S_IREAD + (S_IREAD >> 3) + (S_IREAD >> 6));
2680 sbufptr->st_mode |= ((S_IREAD|S_IWRITE) + ((S_IREAD|S_IWRITE) >> 3)
2681 + ((S_IREAD|S_IWRITE) >> 6));
2685 return my_fstat(fd,sbufptr);
2690 win32_pipe(int *pfd, unsigned int size, int mode)
2692 return _pipe(pfd, size, mode);
2696 win32_popenlist(const char *mode, IV narg, SV **args)
2699 Perl_croak(aTHX_ "List form of pipe open not implemented");
2704 * a popen() clone that respects PERL5SHELL
2706 * changed to return PerlIO* rather than FILE * by BKS, 11-11-2000
2710 win32_popen(const char *command, const char *mode)
2712 #ifdef USE_RTL_POPEN
2713 return _popen(command, mode);
2725 /* establish which ends read and write */
2726 if (strchr(mode,'w')) {
2727 stdfd = 0; /* stdin */
2730 nhandle = STD_INPUT_HANDLE;
2732 else if (strchr(mode,'r')) {
2733 stdfd = 1; /* stdout */
2736 nhandle = STD_OUTPUT_HANDLE;
2741 /* set the correct mode */
2742 if (strchr(mode,'b'))
2744 else if (strchr(mode,'t'))
2747 ourmode = _fmode & (O_TEXT | O_BINARY);
2749 /* the child doesn't inherit handles */
2750 ourmode |= O_NOINHERIT;
2752 if (win32_pipe(p, 512, ourmode) == -1)
2755 /* save current stdfd */
2756 if ((oldfd = win32_dup(stdfd)) == -1)
2759 /* make stdfd go to child end of pipe (implicitly closes stdfd) */
2760 /* stdfd will be inherited by the child */
2761 if (win32_dup2(p[child], stdfd) == -1)
2764 /* close the child end in parent */
2765 win32_close(p[child]);
2767 /* save the old std handle, and set the std handle */
2770 old_h = GetStdHandle(nhandle);
2771 SetStdHandle(nhandle, (HANDLE)_get_osfhandle(stdfd));
2773 /* start the child */
2776 if ((childpid = do_spawn_nowait((char*)command)) == -1)
2779 /* restore the old std handle */
2781 SetStdHandle(nhandle, old_h);
2786 /* revert stdfd to whatever it was before */
2787 if (win32_dup2(oldfd, stdfd) == -1)
2790 /* close saved handle */
2794 sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid);
2797 /* set process id so that it can be returned by perl's open() */
2798 PL_forkprocess = childpid;
2801 /* we have an fd, return a file stream */
2802 return (PerlIO_fdopen(p[parent], (char *)mode));
2805 /* we don't need to check for errors here */
2809 SetStdHandle(nhandle, old_h);
2814 win32_dup2(oldfd, stdfd);
2819 #endif /* USE_RTL_POPEN */
2827 win32_pclose(PerlIO *pf)
2829 #ifdef USE_RTL_POPEN
2833 int childpid, status;
2837 sv = *av_fetch(w32_fdpid, PerlIO_fileno(pf), TRUE);
2840 childpid = SvIVX(sv);
2857 if (win32_waitpid(childpid, &status, 0) == -1)
2862 #endif /* USE_RTL_POPEN */
2868 LPCWSTR lpExistingFileName,
2869 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
2872 WCHAR wFullName[MAX_PATH+1];
2873 LPVOID lpContext = NULL;
2874 WIN32_STREAM_ID StreamId;
2875 DWORD dwSize = (char*)&StreamId.cStreamName - (char*)&StreamId;
2880 BOOL (__stdcall *pfnBackupWrite)(HANDLE, LPBYTE, DWORD, LPDWORD,
2881 BOOL, BOOL, LPVOID*) =
2882 (BOOL (__stdcall *)(HANDLE, LPBYTE, DWORD, LPDWORD,
2883 BOOL, BOOL, LPVOID*))
2884 GetProcAddress(GetModuleHandle("kernel32.dll"), "BackupWrite");
2885 if (pfnBackupWrite == NULL)
2888 dwLen = GetFullPathNameW(lpFileName, MAX_PATH, wFullName, NULL);
2891 dwLen = (dwLen+1)*sizeof(WCHAR);
2893 handle = CreateFileW(lpExistingFileName, FILE_WRITE_ATTRIBUTES,
2894 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2895 NULL, OPEN_EXISTING, 0, NULL);
2896 if (handle == INVALID_HANDLE_VALUE)
2899 StreamId.dwStreamId = BACKUP_LINK;
2900 StreamId.dwStreamAttributes = 0;
2901 StreamId.dwStreamNameSize = 0;
2902 #if defined(__BORLANDC__) \
2903 ||(defined(__MINGW32__) && !defined(_ANONYMOUS_UNION))
2904 StreamId.Size.u.HighPart = 0;
2905 StreamId.Size.u.LowPart = dwLen;
2907 StreamId.Size.HighPart = 0;
2908 StreamId.Size.LowPart = dwLen;
2911 bSuccess = pfnBackupWrite(handle, (LPBYTE)&StreamId, dwSize, &dwWritten,
2912 FALSE, FALSE, &lpContext);
2914 bSuccess = pfnBackupWrite(handle, (LPBYTE)wFullName, dwLen, &dwWritten,
2915 FALSE, FALSE, &lpContext);
2916 pfnBackupWrite(handle, NULL, 0, &dwWritten, TRUE, FALSE, &lpContext);
2919 CloseHandle(handle);
2924 win32_link(const char *oldname, const char *newname)
2927 BOOL (__stdcall *pfnCreateHardLinkW)(LPCWSTR,LPCWSTR,LPSECURITY_ATTRIBUTES);
2928 WCHAR wOldName[MAX_PATH+1];
2929 WCHAR wNewName[MAX_PATH+1];
2932 Perl_croak(aTHX_ PL_no_func, "link");
2934 pfnCreateHardLinkW =
2935 (BOOL (__stdcall *)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES))
2936 GetProcAddress(GetModuleHandle("kernel32.dll"), "CreateHardLinkW");
2937 if (pfnCreateHardLinkW == NULL)
2938 pfnCreateHardLinkW = Nt4CreateHardLinkW;
2940 if ((A2WHELPER(oldname, wOldName, sizeof(wOldName))) &&
2941 (A2WHELPER(newname, wNewName, sizeof(wNewName))) &&
2942 (wcscpy(wOldName, PerlDir_mapW(wOldName)),
2943 pfnCreateHardLinkW(PerlDir_mapW(wNewName), wOldName, NULL)))
2947 errno = (GetLastError() == ERROR_FILE_NOT_FOUND) ? ENOENT : EINVAL;
2952 win32_rename(const char *oname, const char *newname)
2954 WCHAR wOldName[MAX_PATH+1];
2955 WCHAR wNewName[MAX_PATH+1];
2956 char szOldName[MAX_PATH+1];
2957 char szNewName[MAX_PATH+1];
2961 /* XXX despite what the documentation says about MoveFileEx(),
2962 * it doesn't work under Windows95!
2965 DWORD dwFlags = MOVEFILE_COPY_ALLOWED;
2967 A2WHELPER(oname, wOldName, sizeof(wOldName));
2968 A2WHELPER(newname, wNewName, sizeof(wNewName));
2969 if (wcsicmp(wNewName, wOldName))
2970 dwFlags |= MOVEFILE_REPLACE_EXISTING;
2971 wcscpy(wOldName, PerlDir_mapW(wOldName));
2972 bResult = MoveFileExW(wOldName,PerlDir_mapW(wNewName), dwFlags);
2975 if (stricmp(newname, oname))
2976 dwFlags |= MOVEFILE_REPLACE_EXISTING;
2977 strcpy(szOldName, PerlDir_mapA(oname));
2978 bResult = MoveFileExA(szOldName,PerlDir_mapA(newname), dwFlags);
2981 DWORD err = GetLastError();
2983 case ERROR_BAD_NET_NAME:
2984 case ERROR_BAD_NETPATH:
2985 case ERROR_BAD_PATHNAME:
2986 case ERROR_FILE_NOT_FOUND:
2987 case ERROR_FILENAME_EXCED_RANGE:
2988 case ERROR_INVALID_DRIVE:
2989 case ERROR_NO_MORE_FILES:
2990 case ERROR_PATH_NOT_FOUND:
3003 char szTmpName[MAX_PATH+1];
3004 char dname[MAX_PATH+1];
3005 char *endname = Nullch;
3007 DWORD from_attr, to_attr;
3009 strcpy(szOldName, PerlDir_mapA(oname));
3010 strcpy(szNewName, PerlDir_mapA(newname));
3012 /* if oname doesn't exist, do nothing */
3013 from_attr = GetFileAttributes(szOldName);
3014 if (from_attr == 0xFFFFFFFF) {
3019 /* if newname exists, rename it to a temporary name so that we
3020 * don't delete it in case oname happens to be the same file
3021 * (but perhaps accessed via a different path)
3023 to_attr = GetFileAttributes(szNewName);
3024 if (to_attr != 0xFFFFFFFF) {
3025 /* if newname is a directory, we fail
3026 * XXX could overcome this with yet more convoluted logic */
3027 if (to_attr & FILE_ATTRIBUTE_DIRECTORY) {
3031 tmplen = strlen(szNewName);
3032 strcpy(szTmpName,szNewName);
3033 endname = szTmpName+tmplen;
3034 for (; endname > szTmpName ; --endname) {
3035 if (*endname == '/' || *endname == '\\') {
3040 if (endname > szTmpName)
3041 endname = strcpy(dname,szTmpName);
3045 /* get a temporary filename in same directory
3046 * XXX is this really the best we can do? */
3047 if (!GetTempFileName((LPCTSTR)endname, "plr", 0, szTmpName)) {
3051 DeleteFile(szTmpName);
3053 retval = rename(szNewName, szTmpName);
3060 /* rename oname to newname */
3061 retval = rename(szOldName, szNewName);
3063 /* if we created a temporary file before ... */
3064 if (endname != Nullch) {
3065 /* ...and rename succeeded, delete temporary file/directory */
3067 DeleteFile(szTmpName);
3068 /* else restore it to what it was */
3070 (void)rename(szTmpName, szNewName);
3077 win32_setmode(int fd, int mode)
3079 return setmode(fd, mode);
3083 win32_lseek(int fd, Off_t offset, int origin)
3085 #if defined(WIN64) || defined(USE_LARGE_FILES)
3086 return _lseeki64(fd, offset, origin);
3088 return lseek(fd, offset, origin);
3095 #if defined(WIN64) || defined(USE_LARGE_FILES)
3096 return _telli64(fd);
3103 win32_open(const char *path, int flag, ...)
3108 WCHAR wBuffer[MAX_PATH+1];
3111 pmode = va_arg(ap, int);
3114 if (stricmp(path, "/dev/null")==0)
3118 A2WHELPER(path, wBuffer, sizeof(wBuffer));
3119 return _wopen(PerlDir_mapW(wBuffer), flag, pmode);
3121 return open(PerlDir_mapA(path), flag, pmode);
3124 /* close() that understands socket */
3125 extern int my_close(int); /* in win32sck.c */
3130 return my_close(fd);
3146 win32_dup2(int fd1,int fd2)
3148 return dup2(fd1,fd2);
3151 #ifdef PERL_MSVCRT_READFIX
3153 #define LF 10 /* line feed */
3154 #define CR 13 /* carriage return */
3155 #define CTRLZ 26 /* ctrl-z means eof for text */
3156 #define FOPEN 0x01 /* file handle open */
3157 #define FEOFLAG 0x02 /* end of file has been encountered */
3158 #define FCRLF 0x04 /* CR-LF across read buffer (in text mode) */
3159 #define FPIPE 0x08 /* file handle refers to a pipe */
3160 #define FAPPEND 0x20 /* file handle opened O_APPEND */
3161 #define FDEV 0x40 /* file handle refers to device */
3162 #define FTEXT 0x80 /* file handle is in text mode */
3163 #define MAX_DESCRIPTOR_COUNT (64*32) /* this is the maximun that MSVCRT can handle */
3166 _fixed_read(int fh, void *buf, unsigned cnt)
3168 int bytes_read; /* number of bytes read */
3169 char *buffer; /* buffer to read to */
3170 int os_read; /* bytes read on OS call */
3171 char *p, *q; /* pointers into buffer */
3172 char peekchr; /* peek-ahead character */
3173 ULONG filepos; /* file position after seek */
3174 ULONG dosretval; /* o.s. return value */
3176 /* validate handle */
3177 if (((unsigned)fh >= (unsigned)MAX_DESCRIPTOR_COUNT) ||
3178 !(_osfile(fh) & FOPEN))
3180 /* out of range -- return error */
3182 _doserrno = 0; /* not o.s. error */
3187 * If lockinitflag is FALSE, assume fd is device
3188 * lockinitflag is set to TRUE by open.
3190 if (_pioinfo(fh)->lockinitflag)
3191 EnterCriticalSection(&(_pioinfo(fh)->lock)); /* lock file */
3193 bytes_read = 0; /* nothing read yet */
3194 buffer = (char*)buf;
3196 if (cnt == 0 || (_osfile(fh) & FEOFLAG)) {
3197 /* nothing to read or at EOF, so return 0 read */
3201 if ((_osfile(fh) & (FPIPE|FDEV)) && _pipech(fh) != LF) {
3202 /* a pipe/device and pipe lookahead non-empty: read the lookahead
3204 *buffer++ = _pipech(fh);
3207 _pipech(fh) = LF; /* mark as empty */
3212 if (!ReadFile((HANDLE)_osfhnd(fh), buffer, cnt, (LPDWORD)&os_read, NULL))
3214 /* ReadFile has reported an error. recognize two special cases.
3216 * 1. map ERROR_ACCESS_DENIED to EBADF
3218 * 2. just return 0 if ERROR_BROKEN_PIPE has occurred. it
3219 * means the handle is a read-handle on a pipe for which
3220 * all write-handles have been closed and all data has been
3223 if ((dosretval = GetLastError()) == ERROR_ACCESS_DENIED) {
3224 /* wrong read/write mode should return EBADF, not EACCES */
3226 _doserrno = dosretval;
3230 else if (dosretval == ERROR_BROKEN_PIPE) {
3240 bytes_read += os_read; /* update bytes read */
3242 if (_osfile(fh) & FTEXT) {
3243 /* now must translate CR-LFs to LFs in the buffer */
3245 /* set CRLF flag to indicate LF at beginning of buffer */
3246 /* if ((os_read != 0) && (*(char *)buf == LF)) */
3247 /* _osfile(fh) |= FCRLF; */
3249 /* _osfile(fh) &= ~FCRLF; */
3251 _osfile(fh) &= ~FCRLF;
3253 /* convert chars in the buffer: p is src, q is dest */
3255 while (p < (char *)buf + bytes_read) {
3257 /* if fh is not a device, set ctrl-z flag */
3258 if (!(_osfile(fh) & FDEV))
3259 _osfile(fh) |= FEOFLAG;
3260 break; /* stop translating */
3265 /* *p is CR, so must check next char for LF */
3266 if (p < (char *)buf + bytes_read - 1) {
3269 *q++ = LF; /* convert CR-LF to LF */
3272 *q++ = *p++; /* store char normally */
3275 /* This is the hard part. We found a CR at end of
3276 buffer. We must peek ahead to see if next char
3281 if (!ReadFile((HANDLE)_osfhnd(fh), &peekchr, 1,
3282 (LPDWORD)&os_read, NULL))
3283 dosretval = GetLastError();
3285 if (dosretval != 0 || os_read == 0) {
3286 /* couldn't read ahead, store CR */
3290 /* peekchr now has the extra character -- we now
3291 have several possibilities:
3292 1. disk file and char is not LF; just seek back
3294 2. disk file and char is LF; store LF, don't seek back
3295 3. pipe/device and char is LF; store LF.
3296 4. pipe/device and char isn't LF, store CR and
3297 put char in pipe lookahead buffer. */
3298 if (_osfile(fh) & (FDEV|FPIPE)) {
3299 /* non-seekable device */
3304 _pipech(fh) = peekchr;
3309 if (peekchr == LF) {
3310 /* nothing read yet; must make some
3313 /* turn on this flag for tell routine */
3314 _osfile(fh) |= FCRLF;
3317 HANDLE osHandle; /* o.s. handle value */
3319 if ((osHandle = (HANDLE)_get_osfhandle(fh)) != (HANDLE)-1)
3321 if ((filepos = SetFilePointer(osHandle, -1, NULL, FILE_CURRENT)) == -1)
3322 dosretval = GetLastError();
3333 /* we now change bytes_read to reflect the true number of chars
3335 bytes_read = q - (char *)buf;
3339 if (_pioinfo(fh)->lockinitflag)
3340 LeaveCriticalSection(&(_pioinfo(fh)->lock)); /* unlock file */
3345 #endif /* PERL_MSVCRT_READFIX */
3348 win32_read(int fd, void *buf, unsigned int cnt)
3350 #ifdef PERL_MSVCRT_READFIX
3351 return _fixed_read(fd, buf, cnt);
3353 return read(fd, buf, cnt);
3358 win32_write(int fd, const void *buf, unsigned int cnt)
3360 return write(fd, buf, cnt);
3364 win32_mkdir(const char *dir, int mode)
3368 WCHAR wBuffer[MAX_PATH+1];
3369 A2WHELPER(dir, wBuffer, sizeof(wBuffer));
3370 return _wmkdir(PerlDir_mapW(wBuffer));
3372 return mkdir(PerlDir_mapA(dir)); /* just ignore mode */
3376 win32_rmdir(const char *dir)
3380 WCHAR wBuffer[MAX_PATH+1];
3381 A2WHELPER(dir, wBuffer, sizeof(wBuffer));
3382 return _wrmdir(PerlDir_mapW(wBuffer));
3384 return rmdir(PerlDir_mapA(dir));
3388 win32_chdir(const char *dir)
3396 WCHAR wBuffer[MAX_PATH+1];
3397 A2WHELPER(dir, wBuffer, sizeof(wBuffer));
3398 return _wchdir(wBuffer);
3404 win32_access(const char *path, int mode)
3408 WCHAR wBuffer[MAX_PATH+1];
3409 A2WHELPER(path, wBuffer, sizeof(wBuffer));
3410 return _waccess(PerlDir_mapW(wBuffer), mode);
3412 return access(PerlDir_mapA(path), mode);
3416 win32_chmod(const char *path, int mode)
3420 WCHAR wBuffer[MAX_PATH+1];
3421 A2WHELPER(path, wBuffer, sizeof(wBuffer));
3422 return _wchmod(PerlDir_mapW(wBuffer), mode);
3424 return chmod(PerlDir_mapA(path), mode);
3429 create_command_line(char *cname, STRLEN clen, const char * const *args)
3436 bool bat_file = FALSE;
3437 bool cmd_shell = FALSE;
3438 bool dumb_shell = FALSE;
3439 bool extra_quotes = FALSE;
3440 bool quote_next = FALSE;
3443 cname = (char*)args[0];
3445 /* The NT cmd.exe shell has the following peculiarity that needs to be
3446 * worked around. It strips a leading and trailing dquote when any
3447 * of the following is true:
3448 * 1. the /S switch was used
3449 * 2. there are more than two dquotes
3450 * 3. there is a special character from this set: &<>()@^|
3451 * 4. no whitespace characters within the two dquotes
3452 * 5. string between two dquotes isn't an executable file
3453 * To work around this, we always add a leading and trailing dquote
3454 * to the string, if the first argument is either "cmd.exe" or "cmd",
3455 * and there were at least two or more arguments passed to cmd.exe
3456 * (not including switches).
3457 * XXX the above rules (from "cmd /?") don't seem to be applied
3458 * always, making for the convolutions below :-(
3462 clen = strlen(cname);
3465 && (stricmp(&cname[clen-4], ".bat") == 0
3466 || (IsWinNT() && stricmp(&cname[clen-4], ".cmd") == 0)))
3472 char *exe = strrchr(cname, '/');
3473 char *exe2 = strrchr(cname, '\\');
3480 if (stricmp(exe, "cmd.exe") == 0 || stricmp(exe, "cmd") == 0) {
3484 else if (stricmp(exe, "command.com") == 0
3485 || stricmp(exe, "command") == 0)
3492 DEBUG_p(PerlIO_printf(Perl_debug_log, "Args "));
3493 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3494 STRLEN curlen = strlen(arg);
3495 if (!(arg[0] == '"' && arg[curlen-1] == '"'))
3496 len += 2; /* assume quoting needed (worst case) */
3498 DEBUG_p(PerlIO_printf(Perl_debug_log, "[%s]",arg));
3500 DEBUG_p(PerlIO_printf(Perl_debug_log, "\n"));
3503 New(1310, cmd, len, char);
3508 extra_quotes = TRUE;
3511 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3513 STRLEN curlen = strlen(arg);
3515 /* we want to protect empty arguments and ones with spaces with
3516 * dquotes, but only if they aren't already there */
3521 else if (quote_next) {
3522 /* see if it really is multiple arguments pretending to
3523 * be one and force a set of quotes around it */
3524 if (*find_next_space(arg))
3527 else if (!(arg[0] == '"' && curlen > 1 && arg[curlen-1] == '"')) {
3529 while (i < curlen) {
3530 if (isSPACE(arg[i])) {
3533 else if (arg[i] == '"') {
3556 && (stricmp(arg, "/x/c") == 0 || stricmp(arg, "/c") == 0))
3558 /* is there a next argument? */
3559 if (args[index+1]) {
3560 /* are there two or more next arguments? */
3561 if (args[index+2]) {
3563 extra_quotes = TRUE;
3566 /* single argument, force quoting if it has spaces */
3582 qualified_path(const char *cmd)
3586 char *fullcmd, *curfullcmd;
3592 fullcmd = (char*)cmd;
3594 if (*fullcmd == '/' || *fullcmd == '\\')
3601 pathstr = PerlEnv_getenv("PATH");
3602 New(0, fullcmd, MAX_PATH+1, char);
3603 curfullcmd = fullcmd;
3608 /* start by appending the name to the current prefix */
3609 strcpy(curfullcmd, cmd);
3610 curfullcmd += cmdlen;
3612 /* if it doesn't end with '.', or has no extension, try adding
3613 * a trailing .exe first */
3614 if (cmd[cmdlen-1] != '.'
3615 && (cmdlen < 4 || cmd[cmdlen-4] != '.'))
3617 strcpy(curfullcmd, ".exe");
3618 res = GetFileAttributes(fullcmd);
3619 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3624 /* that failed, try the bare name */
3625 res = GetFileAttributes(fullcmd);
3626 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3629 /* quit if no other path exists, or if cmd already has path */
3630 if (!pathstr || !*pathstr || has_slash)
3633 /* skip leading semis */
3634 while (*pathstr == ';')
3637 /* build a new prefix from scratch */
3638 curfullcmd = fullcmd;
3639 while (*pathstr && *pathstr != ';') {
3640 if (*pathstr == '"') { /* foo;"baz;etc";bar */
3641 pathstr++; /* skip initial '"' */
3642 while (*pathstr && *pathstr != '"') {
3643 if ((STRLEN)(curfullcmd-fullcmd) < MAX_PATH-cmdlen-5)
3644 *curfullcmd++ = *pathstr;
3648 pathstr++; /* skip trailing '"' */
3651 if ((STRLEN)(curfullcmd-fullcmd) < MAX_PATH-cmdlen-5)
3652 *curfullcmd++ = *pathstr;
3657 pathstr++; /* skip trailing semi */
3658 if (curfullcmd > fullcmd /* append a dir separator */
3659 && curfullcmd[-1] != '/' && curfullcmd[-1] != '\\')
3661 *curfullcmd++ = '\\';
3669 /* The following are just place holders.
3670 * Some hosts may provide and environment that the OS is
3671 * not tracking, therefore, these host must provide that
3672 * environment and the current directory to CreateProcess
3676 win32_get_childenv(void)
3682 win32_free_childenv(void* d)
3687 win32_clearenv(void)
3689 char *envv = GetEnvironmentStrings();
3693 char *end = strchr(cur,'=');
3694 if (end && end != cur) {
3696 SetEnvironmentVariable(cur, NULL);
3698 cur = end + strlen(end+1)+2;
3700 else if ((len = strlen(cur)))
3703 FreeEnvironmentStrings(envv);
3707 win32_get_childdir(void)
3711 char szfilename[(MAX_PATH+1)*2];
3713 WCHAR wfilename[MAX_PATH+1];
3714 GetCurrentDirectoryW(MAX_PATH+1, wfilename);
3715 W2AHELPER(wfilename, szfilename, sizeof(szfilename));
3718 GetCurrentDirectoryA(MAX_PATH+1, szfilename);
3721 New(0, ptr, strlen(szfilename)+1, char);
3722 strcpy(ptr, szfilename);
3727 win32_free_childdir(char* d)
3734 /* XXX this needs to be made more compatible with the spawnvp()
3735 * provided by the various RTLs. In particular, searching for
3736 * *.{com,bat,cmd} files (as done by the RTLs) is unimplemented.
3737 * This doesn't significantly affect perl itself, because we
3738 * always invoke things using PERL5SHELL if a direct attempt to
3739 * spawn the executable fails.
3741 * XXX splitting and rejoining the commandline between do_aspawn()
3742 * and win32_spawnvp() could also be avoided.
3746 win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
3748 #ifdef USE_RTL_SPAWNVP
3749 return spawnvp(mode, cmdname, (char * const *)argv);
3756 STARTUPINFO StartupInfo;
3757 PROCESS_INFORMATION ProcessInformation;
3760 char *fullcmd = Nullch;
3761 char *cname = (char *)cmdname;
3765 clen = strlen(cname);
3766 /* if command name contains dquotes, must remove them */
3767 if (strchr(cname, '"')) {
3769 New(0,cname,clen+1,char);
3782 cmd = create_command_line(cname, clen, argv);
3784 env = PerlEnv_get_childenv();
3785 dir = PerlEnv_get_childdir();
3788 case P_NOWAIT: /* asynch + remember result */
3789 if (w32_num_children >= MAXIMUM_WAIT_OBJECTS) {
3794 /* Create a new process group so we can use GenerateConsoleCtrlEvent()
3797 create |= CREATE_NEW_PROCESS_GROUP;
3800 case P_WAIT: /* synchronous execution */
3802 default: /* invalid mode */
3807 memset(&StartupInfo,0,sizeof(StartupInfo));
3808 StartupInfo.cb = sizeof(StartupInfo);
3809 memset(&tbl,0,sizeof(tbl));
3810 PerlEnv_get_child_IO(&tbl);
3811 StartupInfo.dwFlags = tbl.dwFlags;
3812 StartupInfo.dwX = tbl.dwX;
3813 StartupInfo.dwY = tbl.dwY;
3814 StartupInfo.dwXSize = tbl.dwXSize;
3815 StartupInfo.dwYSize = tbl.dwYSize;
3816 StartupInfo.dwXCountChars = tbl.dwXCountChars;
3817 StartupInfo.dwYCountChars = tbl.dwYCountChars;
3818 StartupInfo.dwFillAttribute = tbl.dwFillAttribute;
3819 StartupInfo.wShowWindow = tbl.wShowWindow;
3820 StartupInfo.hStdInput = tbl.childStdIn;
3821 StartupInfo.hStdOutput = tbl.childStdOut;
3822 StartupInfo.hStdError = tbl.childStdErr;
3823 if (StartupInfo.hStdInput == INVALID_HANDLE_VALUE &&
3824 StartupInfo.hStdOutput == INVALID_HANDLE_VALUE &&
3825 StartupInfo.hStdError == INVALID_HANDLE_VALUE)
3827 create |= CREATE_NEW_CONSOLE;
3830 StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
3832 if (w32_use_showwindow) {
3833 StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
3834 StartupInfo.wShowWindow = w32_showwindow;
3837 DEBUG_p(PerlIO_printf(Perl_debug_log, "Spawning [%s] with [%s]\n",
3840 if (!CreateProcess(cname, /* search PATH to find executable */
3841 cmd, /* executable, and its arguments */
3842 NULL, /* process attributes */
3843 NULL, /* thread attributes */
3844 TRUE, /* inherit handles */
3845 create, /* creation flags */
3846 (LPVOID)env, /* inherit environment */
3847 dir, /* inherit cwd */
3849 &ProcessInformation))
3851 /* initial NULL argument to CreateProcess() does a PATH
3852 * search, but it always first looks in the directory
3853 * where the current process was started, which behavior
3854 * is undesirable for backward compatibility. So we
3855 * jump through our own hoops by picking out the path
3856 * we really want it to use. */
3858 fullcmd = qualified_path(cname);
3860 if (cname != cmdname)
3863 DEBUG_p(PerlIO_printf(Perl_debug_log,
3864 "Retrying [%s] with same args\n",
3874 if (mode == P_NOWAIT) {
3875 /* asynchronous spawn -- store handle, return PID */
3876 ret = (int)ProcessInformation.dwProcessId;
3877 if (IsWin95() && ret < 0)
3880 w32_child_handles[w32_num_children] = ProcessInformation.hProcess;
3881 w32_child_pids[w32_num_children] = (DWORD)ret;
3886 win32_msgwait(aTHX_ 1, &ProcessInformation.hProcess, INFINITE, NULL);
3887 /* FIXME: if msgwait returned due to message perhaps forward the
3888 "signal" to the process
3890 GetExitCodeProcess(ProcessInformation.hProcess, &status);
3892 CloseHandle(ProcessInformation.hProcess);
3895 CloseHandle(ProcessInformation.hThread);
3898 PerlEnv_free_childenv(env);
3899 PerlEnv_free_childdir(dir);
3901 if (cname != cmdname)
3908 win32_execv(const char *cmdname, const char *const *argv)
3912 /* if this is a pseudo-forked child, we just want to spawn
3913 * the new program, and return */
3915 return spawnv(P_WAIT, cmdname, (char *const *)argv);
3917 return execv(cmdname, (char *const *)argv);
3921 win32_execvp(const char *cmdname, const char *const *argv)
3925 /* if this is a pseudo-forked child, we just want to spawn
3926 * the new program, and return */
3927 if (w32_pseudo_id) {
3928 int status = win32_spawnvp(P_WAIT, cmdname, (char *const *)argv);
3937 return execvp(cmdname, (char *const *)argv);
3941 win32_perror(const char *str)
3947 win32_setbuf(FILE *pf, char *buf)
3953 win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
3955 return setvbuf(pf, buf, type, size);
3959 win32_flushall(void)
3965 win32_fcloseall(void)
3971 win32_fgets(char *s, int n, FILE *pf)
3973 return fgets(s, n, pf);
3983 win32_fgetc(FILE *pf)
3989 win32_putc(int c, FILE *pf)
3995 win32_puts(const char *s)
4007 win32_putchar(int c)
4014 #ifndef USE_PERL_SBRK
4016 static char *committed = NULL; /* XXX threadead */
4017 static char *base = NULL; /* XXX threadead */
4018 static char *reserved = NULL; /* XXX threadead */
4019 static char *brk = NULL; /* XXX threadead */
4020 static DWORD pagesize = 0; /* XXX threadead */
4021 static DWORD allocsize = 0; /* XXX threadead */
4024 sbrk(ptrdiff_t need)
4029 GetSystemInfo(&info);
4030 /* Pretend page size is larger so we don't perpetually
4031 * call the OS to commit just one page ...
4033 pagesize = info.dwPageSize << 3;
4034 allocsize = info.dwAllocationGranularity;
4036 /* This scheme fails eventually if request for contiguous
4037 * block is denied so reserve big blocks - this is only
4038 * address space not memory ...
4040 if (brk+need >= reserved)
4042 DWORD size = 64*1024*1024;
4044 if (committed && reserved && committed < reserved)
4046 /* Commit last of previous chunk cannot span allocations */
4047 addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
4049 committed = reserved;
4051 /* Reserve some (more) space
4052 * Note this is a little sneaky, 1st call passes NULL as reserved
4053 * so lets system choose where we start, subsequent calls pass
4054 * the old end address so ask for a contiguous block
4056 addr = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
4059 reserved = addr+size;
4074 if (brk > committed)
4076 DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
4077 char *addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
4092 win32_malloc(size_t size)
4094 return malloc(size);
4098 win32_calloc(size_t numitems, size_t size)
4100 return calloc(numitems,size);
4104 win32_realloc(void *block, size_t size)
4106 return realloc(block,size);
4110 win32_free(void *block)
4117 win32_open_osfhandle(intptr_t handle, int flags)
4119 #ifdef USE_FIXED_OSFHANDLE
4121 return my_open_osfhandle(handle, flags);
4123 return _open_osfhandle(handle, flags);
4127 win32_get_osfhandle(int fd)
4129 return (intptr_t)_get_osfhandle(fd);
4133 win32_fdupopen(FILE *pf)
4138 int fileno = win32_dup(win32_fileno(pf));
4140 /* open the file in the same mode */
4142 if((pf)->flags & _F_READ) {
4146 else if((pf)->flags & _F_WRIT) {
4150 else if((pf)->flags & _F_RDWR) {
4156 if((pf)->_flag & _IOREAD) {
4160 else if((pf)->_flag & _IOWRT) {
4164 else if((pf)->_flag & _IORW) {
4171 /* it appears that the binmode is attached to the
4172 * file descriptor so binmode files will be handled
4175 pfdup = win32_fdopen(fileno, mode);
4177 /* move the file pointer to the same position */
4178 if (!fgetpos(pf, &pos)) {
4179 fsetpos(pfdup, &pos);
4185 win32_dynaload(const char* filename)
4189 char buf[MAX_PATH+1];
4192 /* LoadLibrary() doesn't recognize forward slashes correctly,
4193 * so turn 'em back. */
4194 first = strchr(filename, '/');
4196 STRLEN len = strlen(filename);
4197 if (len <= MAX_PATH) {
4198 strcpy(buf, filename);
4199 filename = &buf[first - filename];
4201 if (*filename == '/')
4202 *(char*)filename = '\\';
4209 WCHAR wfilename[MAX_PATH+1];
4210 A2WHELPER(filename, wfilename, sizeof(wfilename));
4211 hModule = LoadLibraryExW(PerlDir_mapW(wfilename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
4214 hModule = LoadLibraryExA(PerlDir_mapA(filename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
4224 XS(w32_SetChildShowWindow)
4227 BOOL use_showwindow = w32_use_showwindow;
4228 /* use "unsigned short" because Perl has redefined "WORD" */
4229 unsigned short showwindow = w32_showwindow;
4232 Perl_croak(aTHX_ "usage: Win32::SetChildShowWindow($showwindow)");
4234 if (items == 0 || !SvOK(ST(0)))
4235 w32_use_showwindow = FALSE;
4237 w32_use_showwindow = TRUE;
4238 w32_showwindow = (unsigned short)SvIV(ST(0));
4243 ST(0) = sv_2mortal(newSViv(showwindow));
4245 ST(0) = &PL_sv_undef;
4253 /* Make the host for current directory */
4254 char* ptr = PerlEnv_get_childdir();
4257 * then it worked, set PV valid,
4258 * else return 'undef'
4261 SV *sv = sv_newmortal();
4263 PerlEnv_free_childdir(ptr);
4265 #ifndef INCOMPLETE_TAINTS
4282 Perl_croak(aTHX_ "usage: Win32::SetCurrentDirectory($cwd)");
4283 if (!PerlDir_chdir(SvPV_nolen(ST(0))))
4290 XS(w32_GetNextAvailDrive)
4294 char root[] = "_:\\";
4299 if (GetDriveType(root) == 1) {
4308 XS(w32_GetLastError)
4312 XSRETURN_IV(GetLastError());
4316 XS(w32_SetLastError)
4320 Perl_croak(aTHX_ "usage: Win32::SetLastError($error)");
4321 SetLastError(SvIV(ST(0)));
4329 char *name = w32_getlogin_buffer;
4330 DWORD size = sizeof(w32_getlogin_buffer);
4332 if (GetUserName(name,&size)) {
4333 /* size includes NULL */
4334 ST(0) = sv_2mortal(newSVpvn(name,size-1));
4344 char name[MAX_COMPUTERNAME_LENGTH+1];
4345 DWORD size = sizeof(name);
4347 if (GetComputerName(name,&size)) {
4348 /* size does NOT include NULL :-( */
4349 ST(0) = sv_2mortal(newSVpvn(name,size));
4360 HINSTANCE hNetApi32 = LoadLibrary("netapi32.dll");
4361 DWORD (__stdcall *pfnNetApiBufferFree)(LPVOID Buffer);
4362 DWORD (__stdcall *pfnNetWkstaGetInfo)(LPWSTR servername, DWORD level,
4366 pfnNetApiBufferFree = (DWORD (__stdcall *)(void *))
4367 GetProcAddress(hNetApi32, "NetApiBufferFree");
4368 pfnNetWkstaGetInfo = (DWORD (__stdcall *)(LPWSTR, DWORD, void *))
4369 GetProcAddress(hNetApi32, "NetWkstaGetInfo");
4372 if (hNetApi32 && pfnNetWkstaGetInfo && pfnNetApiBufferFree) {
4373 /* this way is more reliable, in case user has a local account. */
4375 DWORD dnamelen = sizeof(dname);
4377 DWORD wki100_platform_id;
4378 LPWSTR wki100_computername;
4379 LPWSTR wki100_langroup;
4380 DWORD wki100_ver_major;
4381 DWORD wki100_ver_minor;
4383 /* NERR_Success *is* 0*/
4384 if (0 == pfnNetWkstaGetInfo(NULL, 100, &pwi)) {
4385 if (pwi->wki100_langroup && *(pwi->wki100_langroup)) {
4386 WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_langroup,
4387 -1, (LPSTR)dname, dnamelen, NULL, NULL);
4390 WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_computername,
4391 -1, (LPSTR)dname, dnamelen, NULL, NULL);
4393 pfnNetApiBufferFree(pwi);
4394 FreeLibrary(hNetApi32);
4397 FreeLibrary(hNetApi32);
4400 /* Win95 doesn't have NetWksta*(), so do it the old way */
4402 DWORD size = sizeof(name);
4404 FreeLibrary(hNetApi32);
4405 if (GetUserName(name,&size)) {
4406 char sid[ONE_K_BUFSIZE];
4407 DWORD sidlen = sizeof(sid);
4409 DWORD dnamelen = sizeof(dname);
4411 if (LookupAccountName(NULL, name, (PSID)&sid, &sidlen,
4412 dname, &dnamelen, &snu)) {
4413 XSRETURN_PV(dname); /* all that for this */
4425 DWORD flags, filecomplen;
4426 if (GetVolumeInformation(NULL, NULL, 0, NULL, &filecomplen,
4427 &flags, fsname, sizeof(fsname))) {
4428 if (GIMME_V == G_ARRAY) {
4429 XPUSHs(sv_2mortal(newSVpvn(fsname,strlen(fsname))));
4430 XPUSHs(sv_2mortal(newSViv(flags)));
4431 XPUSHs(sv_2mortal(newSViv(filecomplen)));
4436 XSRETURN_PV(fsname);
4442 XS(w32_GetOSVersion)
4445 OSVERSIONINFOA osver;
4448 OSVERSIONINFOW osverw;
4449 char szCSDVersion[sizeof(osverw.szCSDVersion)];
4450 osverw.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
4451 if (!GetVersionExW(&osverw)) {
4454 W2AHELPER(osverw.szCSDVersion, szCSDVersion, sizeof(szCSDVersion));
4455 XPUSHs(newSVpvn(szCSDVersion, strlen(szCSDVersion)));
4456 osver.dwMajorVersion = osverw.dwMajorVersion;
4457 osver.dwMinorVersion = osverw.dwMinorVersion;
4458 osver.dwBuildNumber = osverw.dwBuildNumber;
4459 osver.dwPlatformId = osverw.dwPlatformId;
4462 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
4463 if (!GetVersionExA(&osver)) {
4466 XPUSHs(newSVpvn(osver.szCSDVersion, strlen(osver.szCSDVersion)));
4468 XPUSHs(newSViv(osver.dwMajorVersion));
4469 XPUSHs(newSViv(osver.dwMinorVersion));
4470 XPUSHs(newSViv(osver.dwBuildNumber));
4471 XPUSHs(newSViv(osver.dwPlatformId));
4480 XSRETURN_IV(IsWinNT());
4488 XSRETURN_IV(IsWin95());
4492 XS(w32_FormatMessage)
4496 char msgbuf[ONE_K_BUFSIZE];
4499 Perl_croak(aTHX_ "usage: Win32::FormatMessage($errno)");
4502 WCHAR wmsgbuf[ONE_K_BUFSIZE];
4503 if (FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
4504 &source, SvIV(ST(0)), 0,
4505 wmsgbuf, ONE_K_BUFSIZE-1, NULL))
4507 W2AHELPER(wmsgbuf, msgbuf, sizeof(msgbuf));
4508 XSRETURN_PV(msgbuf);
4512 if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,
4513 &source, SvIV(ST(0)), 0,
4514 msgbuf, sizeof(msgbuf)-1, NULL))
4515 XSRETURN_PV(msgbuf);
4528 PROCESS_INFORMATION stProcInfo;
4529 STARTUPINFO stStartInfo;
4530 BOOL bSuccess = FALSE;
4533 Perl_croak(aTHX_ "usage: Win32::Spawn($cmdName, $args, $PID)");
4535 cmd = SvPV_nolen(ST(0));
4536 args = SvPV_nolen(ST(1));
4538 env = PerlEnv_get_childenv();
4539 dir = PerlEnv_get_childdir();
4541 memset(&stStartInfo, 0, sizeof(stStartInfo)); /* Clear the block */
4542 stStartInfo.cb = sizeof(stStartInfo); /* Set the structure size */
4543 stStartInfo.dwFlags = STARTF_USESHOWWINDOW; /* Enable wShowWindow control */
4544 stStartInfo.wShowWindow = SW_SHOWMINNOACTIVE; /* Start min (normal) */
4547 cmd, /* Image path */
4548 args, /* Arguments for command line */
4549 NULL, /* Default process security */
4550 NULL, /* Default thread security */
4551 FALSE, /* Must be TRUE to use std handles */
4552 NORMAL_PRIORITY_CLASS, /* No special scheduling */
4553 env, /* Inherit our environment block */
4554 dir, /* Inherit our currrent directory */
4555 &stStartInfo, /* -> Startup info */
4556 &stProcInfo)) /* <- Process info (if OK) */
4558 int pid = (int)stProcInfo.dwProcessId;
4559 if (IsWin95() && pid < 0)
4561 sv_setiv(ST(2), pid);
4562 CloseHandle(stProcInfo.hThread);/* library source code does this. */
4565 PerlEnv_free_childenv(env);
4566 PerlEnv_free_childdir(dir);
4567 XSRETURN_IV(bSuccess);
4571 XS(w32_GetTickCount)
4574 DWORD msec = GetTickCount();
4582 XS(w32_GetShortPathName)
4589 Perl_croak(aTHX_ "usage: Win32::GetShortPathName($longPathName)");
4591 shortpath = sv_mortalcopy(ST(0));
4592 SvUPGRADE(shortpath, SVt_PV);
4593 if (!SvPVX(shortpath) || !SvLEN(shortpath))
4596 /* src == target is allowed */
4598 len = GetShortPathName(SvPVX(shortpath),
4601 } while (len >= SvLEN(shortpath) && sv_grow(shortpath,len+1));
4603 SvCUR_set(shortpath,len);
4611 XS(w32_GetFullPathName)
4620 Perl_croak(aTHX_ "usage: Win32::GetFullPathName($filename)");
4623 fullpath = sv_mortalcopy(filename);
4624 SvUPGRADE(fullpath, SVt_PV);
4625 if (!SvPVX(fullpath) || !SvLEN(fullpath))
4629 len = GetFullPathName(SvPVX(filename),
4633 } while (len >= SvLEN(fullpath) && sv_grow(fullpath,len+1));
4635 if (GIMME_V == G_ARRAY) {
4637 XST_mPV(1,filepart);
4638 len = filepart - SvPVX(fullpath);
4641 SvCUR_set(fullpath,len);
4649 XS(w32_GetLongPathName)
4653 char tmpbuf[MAX_PATH+1];
4658 Perl_croak(aTHX_ "usage: Win32::GetLongPathName($pathname)");
4661 pathstr = SvPV(path,len);
4662 strcpy(tmpbuf, pathstr);
4663 pathstr = win32_longpath(tmpbuf);
4665 ST(0) = sv_2mortal(newSVpvn(pathstr, strlen(pathstr)));
4676 Perl_croak(aTHX_ "usage: Win32::Sleep($milliseconds)");
4687 Perl_croak(aTHX_ "usage: Win32::CopyFile($from, $to, $overwrite)");
4689 WCHAR wSourceFile[MAX_PATH+1];
4690 WCHAR wDestFile[MAX_PATH+1];
4691 A2WHELPER(SvPV_nolen(ST(0)), wSourceFile, sizeof(wSourceFile));
4692 wcscpy(wSourceFile, PerlDir_mapW(wSourceFile));
4693 A2WHELPER(SvPV_nolen(ST(1)), wDestFile, sizeof(wDestFile));
4694 bResult = CopyFileW(wSourceFile, PerlDir_mapW(wDestFile), !SvTRUE(ST(2)));
4697 char szSourceFile[MAX_PATH+1];
4698 strcpy(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(0))));
4699 bResult = CopyFileA(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(1))), !SvTRUE(ST(2)));
4708 Perl_init_os_extras(void)
4711 char *file = __FILE__;
4714 /* these names are Activeware compatible */
4715 newXS("Win32::GetCwd", w32_GetCwd, file);
4716 newXS("Win32::SetCwd", w32_SetCwd, file);
4717 newXS("Win32::GetNextAvailDrive", w32_GetNextAvailDrive, file);
4718 newXS("Win32::GetLastError", w32_GetLastError, file);
4719 newXS("Win32::SetLastError", w32_SetLastError, file);
4720 newXS("Win32::LoginName", w32_LoginName, file);
4721 newXS("Win32::NodeName", w32_NodeName, file);
4722 newXS("Win32::DomainName", w32_DomainName, file);
4723 newXS("Win32::FsType", w32_FsType, file);
4724 newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
4725 newXS("Win32::IsWinNT", w32_IsWinNT, file);
4726 newXS("Win32::IsWin95", w32_IsWin95, file);
4727 newXS("Win32::FormatMessage", w32_FormatMessage, file);
4728 newXS("Win32::Spawn", w32_Spawn, file);
4729 newXS("Win32::GetTickCount", w32_GetTickCount, file);
4730 newXS("Win32::GetShortPathName", w32_GetShortPathName, file);
4731 newXS("Win32::GetFullPathName", w32_GetFullPathName, file);
4732 newXS("Win32::GetLongPathName", w32_GetLongPathName, file);
4733 newXS("Win32::CopyFile", w32_CopyFile, file);
4734 newXS("Win32::Sleep", w32_Sleep, file);
4735 newXS("Win32::SetChildShowWindow", w32_SetChildShowWindow, file);
4737 /* XXX Bloat Alert! The following Activeware preloads really
4738 * ought to be part of Win32::Sys::*, so they're not included
4741 /* LookupAccountName
4743 * InitiateSystemShutdown
4744 * AbortSystemShutdown
4745 * ExpandEnvrironmentStrings
4750 win32_signal_context(void)
4755 my_perl = PL_curinterp;
4756 PERL_SET_THX(my_perl);
4760 #ifdef USE_5005THREADS
4763 return PL_curinterp;
4770 win32_ctrlhandler(DWORD dwCtrlType)
4773 dTHXa(PERL_GET_SIG_CONTEXT);
4778 #ifdef USE_5005THREADS
4783 switch(dwCtrlType) {
4784 case CTRL_CLOSE_EVENT:
4785 /* A signal that the system sends to all processes attached to a console when
4786 the user closes the console (either by choosing the Close command from the
4787 console window's System menu, or by choosing the End Task command from the
4790 if (do_raise(aTHX_ 1)) /* SIGHUP */
4791 sig_terminate(aTHX_ 1);
4795 /* A CTRL+c signal was received */
4796 if (do_raise(aTHX_ SIGINT))
4797 sig_terminate(aTHX_ SIGINT);
4800 case CTRL_BREAK_EVENT:
4801 /* A CTRL+BREAK signal was received */
4802 if (do_raise(aTHX_ SIGBREAK))
4803 sig_terminate(aTHX_ SIGBREAK);
4806 case CTRL_LOGOFF_EVENT:
4807 /* A signal that the system sends to all console processes when a user is logging
4808 off. This signal does not indicate which user is logging off, so no
4809 assumptions can be made.
4812 case CTRL_SHUTDOWN_EVENT:
4813 /* A signal that the system sends to all console processes when the system is
4816 if (do_raise(aTHX_ SIGTERM))
4817 sig_terminate(aTHX_ SIGTERM);
4827 Perl_win32_init(int *argcp, char ***argvp)
4829 /* Disable floating point errors, Perl will trap the ones we
4830 * care about. VC++ RTL defaults to switching these off
4831 * already, but the Borland RTL doesn't. Since we don't
4832 * want to be at the vendor's whim on the default, we set
4833 * it explicitly here.
4835 #if !defined(_ALPHA_) && !defined(__GNUC__)
4836 _control87(MCW_EM, MCW_EM);
4842 win32_get_child_IO(child_IO_table* ptbl)
4844 ptbl->childStdIn = GetStdHandle(STD_INPUT_HANDLE);
4845 ptbl->childStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
4846 ptbl->childStdErr = GetStdHandle(STD_ERROR_HANDLE);
4850 win32_signal(int sig, Sighandler_t subcode)
4853 if (sig < SIG_SIZE) {
4854 int save_errno = errno;
4855 Sighandler_t result = signal(sig, subcode);
4856 if (result == SIG_ERR) {
4857 result = w32_sighandler[sig];
4860 w32_sighandler[sig] = subcode;
4870 #ifdef HAVE_INTERP_INTERN
4874 win32_csighandler(int sig)
4877 dTHXa(PERL_GET_SIG_CONTEXT);
4878 Perl_warn(aTHX_ "Got signal %d",sig);
4884 Perl_sys_intern_init(pTHX)
4887 w32_perlshell_tokens = Nullch;
4888 w32_perlshell_vec = (char**)NULL;
4889 w32_perlshell_items = 0;
4890 w32_fdpid = newAV();
4891 New(1313, w32_children, 1, child_tab);
4892 w32_num_children = 0;
4893 # ifdef USE_ITHREADS
4895 New(1313, w32_pseudo_children, 1, child_tab);
4896 w32_num_pseudo_children = 0;
4898 w32_init_socktype = 0;
4901 for (i=0; i < SIG_SIZE; i++) {
4902 w32_sighandler[i] = SIG_DFL;
4905 if (my_perl == PL_curinterp) {
4909 /* Force C runtime signal stuff to set its console handler */
4910 signal(SIGINT,&win32_csighandler);
4911 signal(SIGBREAK,&win32_csighandler);
4912 /* Push our handler on top */
4913 SetConsoleCtrlHandler(win32_ctrlhandler,TRUE);
4918 Perl_sys_intern_clear(pTHX)
4920 Safefree(w32_perlshell_tokens);
4921 Safefree(w32_perlshell_vec);
4922 /* NOTE: w32_fdpid is freed by sv_clean_all() */
4923 Safefree(w32_children);
4925 KillTimer(NULL,w32_timerid);
4928 # ifdef MULTIPLICITY
4929 if (my_perl == PL_curinterp) {
4933 SetConsoleCtrlHandler(win32_ctrlhandler,FALSE);
4935 # ifdef USE_ITHREADS
4936 Safefree(w32_pseudo_children);
4940 # ifdef USE_ITHREADS
4943 Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
4945 dst->perlshell_tokens = Nullch;
4946 dst->perlshell_vec = (char**)NULL;
4947 dst->perlshell_items = 0;
4948 dst->fdpid = newAV();
4949 Newz(1313, dst->children, 1, child_tab);
4951 Newz(1313, dst->pseudo_children, 1, child_tab);
4952 dst->thr_intern.Winit_socktype = 0;
4954 dst->poll_count = 0;
4955 Copy(src->sigtable,dst->sigtable,SIG_SIZE,Sighandler_t);
4957 # endif /* USE_ITHREADS */
4958 #endif /* HAVE_INTERP_INTERN */
4961 win32_free_argvw(pTHX_ void *ptr)
4963 char** argv = (char**)ptr;
4971 win32_argv2utf8(int argc, char** argv)
4976 LPWSTR* lpwStr = CommandLineToArgvW(GetCommandLineW(), &wargc);
4977 if (lpwStr && argc) {
4979 length = WideCharToMultiByte(CP_UTF8, 0, lpwStr[--wargc], -1, NULL, 0, NULL, NULL);
4980 Newz(0, psz, length, char);
4981 WideCharToMultiByte(CP_UTF8, 0, lpwStr[wargc], -1, psz, length, NULL, NULL);
4984 call_atexit(win32_free_argvw, argv);
4986 GlobalFree((HGLOBAL)lpwStr);