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);
1654 /* NOTE: This does not compute the timezone info (doing so can be expensive,
1655 * and appears to be unsupported even by glibc) */
1657 win32_gettimeofday(struct timeval *tp, void *not_used)
1659 return PerlProc_gettimeofday(tp, not_used); // Implemented in Time::HiRes.
1663 win32_uname(struct utsname *name)
1665 struct hostent *hep;
1666 STRLEN nodemax = sizeof(name->nodename)-1;
1667 OSVERSIONINFO osver;
1669 memset(&osver, 0, sizeof(OSVERSIONINFO));
1670 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1671 if (GetVersionEx(&osver)) {
1673 switch (osver.dwPlatformId) {
1674 case VER_PLATFORM_WIN32_WINDOWS:
1675 strcpy(name->sysname, "Windows");
1677 case VER_PLATFORM_WIN32_NT:
1678 strcpy(name->sysname, "Windows NT");
1680 case VER_PLATFORM_WIN32s:
1681 strcpy(name->sysname, "Win32s");
1684 strcpy(name->sysname, "Win32 Unknown");
1689 sprintf(name->release, "%d.%d",
1690 osver.dwMajorVersion, osver.dwMinorVersion);
1693 sprintf(name->version, "Build %d",
1694 osver.dwPlatformId == VER_PLATFORM_WIN32_NT
1695 ? osver.dwBuildNumber : (osver.dwBuildNumber & 0xffff));
1696 if (osver.szCSDVersion[0]) {
1697 char *buf = name->version + strlen(name->version);
1698 sprintf(buf, " (%s)", osver.szCSDVersion);
1702 *name->sysname = '\0';
1703 *name->version = '\0';
1704 *name->release = '\0';
1708 hep = win32_gethostbyname("localhost");
1710 STRLEN len = strlen(hep->h_name);
1711 if (len <= nodemax) {
1712 strcpy(name->nodename, hep->h_name);
1715 strncpy(name->nodename, hep->h_name, nodemax);
1716 name->nodename[nodemax] = '\0';
1721 if (!GetComputerName(name->nodename, &sz))
1722 *name->nodename = '\0';
1725 /* machine (architecture) */
1729 GetSystemInfo(&info);
1731 #if (defined(__BORLANDC__)&&(__BORLANDC__<=0x520)) \
1732 || (defined(__MINGW32__) && !defined(_ANONYMOUS_UNION))
1733 switch (info.u.s.wProcessorArchitecture) {
1735 switch (info.wProcessorArchitecture) {
1737 case PROCESSOR_ARCHITECTURE_INTEL:
1738 arch = "x86"; break;
1739 case PROCESSOR_ARCHITECTURE_MIPS:
1740 arch = "mips"; break;
1741 case PROCESSOR_ARCHITECTURE_ALPHA:
1742 arch = "alpha"; break;
1743 case PROCESSOR_ARCHITECTURE_PPC:
1744 arch = "ppc"; break;
1746 arch = "unknown"; break;
1748 strcpy(name->machine, arch);
1753 /* Timing related stuff */
1756 do_raise(pTHX_ int sig)
1758 if (sig < SIG_SIZE) {
1759 Sighandler_t handler = w32_sighandler[sig];
1760 if (handler == SIG_IGN) {
1763 else if (handler != SIG_DFL) {
1768 /* Choose correct default behaviour */
1784 /* Tell caller to exit thread/process as approriate */
1789 sig_terminate(pTHX_ int sig)
1791 Perl_warn(aTHX_ "Terminating on signal SIG%s(%d)\n",PL_sig_name[sig], sig);
1792 /* exit() seems to be safe, my_exit() or die() is a problem in ^C
1799 win32_async_check(pTHX)
1803 /* Passing PeekMessage -1 as HWND (2nd arg) only get PostThreadMessage() messages
1804 * and ignores window messages - should co-exist better with windows apps e.g. Tk
1806 while (PeekMessage(&msg, (HWND)-1, 0, 0, PM_REMOVE|PM_NOYIELD)) {
1808 switch(msg.message) {
1811 /* Perhaps some other messages could map to signals ? ... */
1814 /* Treat WM_QUIT like SIGHUP? */
1820 /* We use WM_USER to fake kill() with other signals */
1824 if (do_raise(aTHX_ sig)) {
1825 sig_terminate(aTHX_ sig);
1831 /* alarm() is a one-shot but SetTimer() repeats so kill it */
1833 KillTimer(NULL,w32_timerid);
1836 /* Now fake a call to signal handler */
1837 if (do_raise(aTHX_ 14)) {
1838 sig_terminate(aTHX_ 14);
1843 /* Otherwise do normal Win32 thing - in case it is useful */
1845 TranslateMessage(&msg);
1846 DispatchMessage(&msg);
1853 /* Above or other stuff may have set a signal flag */
1854 if (PL_sig_pending) {
1861 win32_msgwait(pTHX_ DWORD count, LPHANDLE handles, DWORD timeout, LPDWORD resultp)
1863 /* We may need several goes at this - so compute when we stop */
1865 if (timeout != INFINITE) {
1866 ticks = GetTickCount();
1870 DWORD result = MsgWaitForMultipleObjects(count,handles,FALSE,timeout-ticks, QS_ALLEVENTS);
1873 if (result == WAIT_TIMEOUT) {
1874 /* Ran out of time - explicit return of zero to avoid -ve if we
1875 have scheduling issues
1879 if (timeout != INFINITE) {
1880 ticks = GetTickCount();
1882 if (result == WAIT_OBJECT_0 + count) {
1883 /* Message has arrived - check it */
1884 if (win32_async_check(aTHX)) {
1885 /* was one of ours */
1890 /* Not timeout or message - one of handles is ready */
1894 /* compute time left to wait */
1895 ticks = timeout - ticks;
1896 /* If we are past the end say zero */
1897 return (ticks > 0) ? ticks : 0;
1901 win32_internal_wait(int *status, DWORD timeout)
1903 /* XXX this wait emulation only knows about processes
1904 * spawned via win32_spawnvp(P_NOWAIT, ...).
1908 DWORD exitcode, waitcode;
1911 if (w32_num_pseudo_children) {
1912 win32_msgwait(aTHX_ w32_num_pseudo_children, w32_pseudo_child_handles,
1913 timeout, &waitcode);
1914 /* Time out here if there are no other children to wait for. */
1915 if (waitcode == WAIT_TIMEOUT) {
1916 if (!w32_num_children) {
1920 else if (waitcode != WAIT_FAILED) {
1921 if (waitcode >= WAIT_ABANDONED_0
1922 && waitcode < WAIT_ABANDONED_0 + w32_num_pseudo_children)
1923 i = waitcode - WAIT_ABANDONED_0;
1925 i = waitcode - WAIT_OBJECT_0;
1926 if (GetExitCodeThread(w32_pseudo_child_handles[i], &exitcode)) {
1927 *status = (int)((exitcode & 0xff) << 8);
1928 retval = (int)w32_pseudo_child_pids[i];
1929 remove_dead_pseudo_process(i);
1936 if (!w32_num_children) {
1941 /* if a child exists, wait for it to die */
1942 win32_msgwait(aTHX_ w32_num_children, w32_child_handles, timeout, &waitcode);
1943 if (waitcode == WAIT_TIMEOUT) {
1946 if (waitcode != WAIT_FAILED) {
1947 if (waitcode >= WAIT_ABANDONED_0
1948 && waitcode < WAIT_ABANDONED_0 + w32_num_children)
1949 i = waitcode - WAIT_ABANDONED_0;
1951 i = waitcode - WAIT_OBJECT_0;
1952 if (GetExitCodeProcess(w32_child_handles[i], &exitcode) ) {
1953 *status = (int)((exitcode & 0xff) << 8);
1954 retval = (int)w32_child_pids[i];
1955 remove_dead_process(i);
1960 errno = GetLastError();
1965 win32_waitpid(int pid, int *status, int flags)
1968 DWORD timeout = (flags & WNOHANG) ? 0 : INFINITE;
1971 if (pid == -1) /* XXX threadid == 1 ? */
1972 return win32_internal_wait(status, timeout);
1975 child = find_pseudo_pid(-pid);
1977 HANDLE hThread = w32_pseudo_child_handles[child];
1979 win32_msgwait(aTHX_ 1, &hThread, timeout, &waitcode);
1980 if (waitcode == WAIT_TIMEOUT) {
1983 else if (waitcode == WAIT_OBJECT_0) {
1984 if (GetExitCodeThread(hThread, &waitcode)) {
1985 *status = (int)((waitcode & 0xff) << 8);
1986 retval = (int)w32_pseudo_child_pids[child];
1987 remove_dead_pseudo_process(child);
1994 else if (IsWin95()) {
2003 child = find_pid(pid);
2005 hProcess = w32_child_handles[child];
2006 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
2007 if (waitcode == WAIT_TIMEOUT) {
2010 else if (waitcode == WAIT_OBJECT_0) {
2011 if (GetExitCodeProcess(hProcess, &waitcode)) {
2012 *status = (int)((waitcode & 0xff) << 8);
2013 retval = (int)w32_child_pids[child];
2014 remove_dead_process(child);
2023 hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE,
2024 (IsWin95() ? -pid : pid));
2026 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
2027 if (waitcode == WAIT_TIMEOUT) {
2030 else if (waitcode == WAIT_OBJECT_0) {
2031 if (GetExitCodeProcess(hProcess, &waitcode)) {
2032 *status = (int)((waitcode & 0xff) << 8);
2033 CloseHandle(hProcess);
2037 CloseHandle(hProcess);
2043 return retval >= 0 ? pid : retval;
2047 win32_wait(int *status)
2049 return win32_internal_wait(status, INFINITE);
2052 DllExport unsigned int
2053 win32_sleep(unsigned int t)
2056 /* Win32 times are in ms so *1000 in and /1000 out */
2057 return win32_msgwait(aTHX_ 0, NULL, t*1000, NULL)/1000;
2060 DllExport unsigned int
2061 win32_alarm(unsigned int sec)
2064 * the 'obvious' implentation is SetTimer() with a callback
2065 * which does whatever receiving SIGALRM would do
2066 * we cannot use SIGALRM even via raise() as it is not
2067 * one of the supported codes in <signal.h>
2071 w32_timerid = SetTimer(NULL,w32_timerid,sec*1000,NULL);
2075 KillTimer(NULL,w32_timerid);
2082 #ifdef HAVE_DES_FCRYPT
2083 extern char * des_fcrypt(const char *txt, const char *salt, char *cbuf);
2087 win32_crypt(const char *txt, const char *salt)
2090 #ifdef HAVE_DES_FCRYPT
2091 return des_fcrypt(txt, salt, w32_crypt_buffer);
2093 Perl_croak(aTHX_ "The crypt() function is unimplemented due to excessive paranoia.");
2098 #ifdef USE_FIXED_OSFHANDLE
2100 #define FOPEN 0x01 /* file handle open */
2101 #define FNOINHERIT 0x10 /* file handle opened O_NOINHERIT */
2102 #define FAPPEND 0x20 /* file handle opened O_APPEND */
2103 #define FDEV 0x40 /* file handle refers to device */
2104 #define FTEXT 0x80 /* file handle is in text mode */
2107 *int my_open_osfhandle(intptr_t osfhandle, int flags) - open C Runtime file handle
2110 * This function allocates a free C Runtime file handle and associates
2111 * it with the Win32 HANDLE specified by the first parameter. This is a
2112 * temperary fix for WIN95's brain damage GetFileType() error on socket
2113 * we just bypass that call for socket
2115 * This works with MSVC++ 4.0+ or GCC/Mingw32
2118 * intptr_t osfhandle - Win32 HANDLE to associate with C Runtime file handle.
2119 * int flags - flags to associate with C Runtime file handle.
2122 * returns index of entry in fh, if successful
2123 * return -1, if no free entry is found
2127 *******************************************************************************/
2130 * we fake up some parts of the CRT that aren't exported by MSVCRT.dll
2131 * this lets sockets work on Win9X with GCC and should fix the problems
2136 /* create an ioinfo entry, kill its handle, and steal the entry */
2141 HANDLE hF = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
2142 int fh = _open_osfhandle((intptr_t)hF, 0);
2146 EnterCriticalSection(&(_pioinfo(fh)->lock));
2151 my_open_osfhandle(intptr_t osfhandle, int flags)
2154 char fileflags; /* _osfile flags */
2156 /* copy relevant flags from second parameter */
2159 if (flags & O_APPEND)
2160 fileflags |= FAPPEND;
2165 if (flags & O_NOINHERIT)
2166 fileflags |= FNOINHERIT;
2168 /* attempt to allocate a C Runtime file handle */
2169 if ((fh = _alloc_osfhnd()) == -1) {
2170 errno = EMFILE; /* too many open files */
2171 _doserrno = 0L; /* not an OS error */
2172 return -1; /* return error to caller */
2175 /* the file is open. now, set the info in _osfhnd array */
2176 _set_osfhnd(fh, osfhandle);
2178 fileflags |= FOPEN; /* mark as open */
2180 _osfile(fh) = fileflags; /* set osfile entry */
2181 LeaveCriticalSection(&_pioinfo(fh)->lock);
2183 return fh; /* return handle */
2186 #endif /* USE_FIXED_OSFHANDLE */
2188 /* simulate flock by locking a range on the file */
2190 #define LK_ERR(f,i) ((f) ? (i = 0) : (errno = GetLastError()))
2191 #define LK_LEN 0xffff0000
2194 win32_flock(int fd, int oper)
2202 Perl_croak_nocontext("flock() unimplemented on this platform");
2205 fh = (HANDLE)_get_osfhandle(fd);
2206 memset(&o, 0, sizeof(o));
2209 case LOCK_SH: /* shared lock */
2210 LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, 0, &o),i);
2212 case LOCK_EX: /* exclusive lock */
2213 LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o),i);
2215 case LOCK_SH|LOCK_NB: /* non-blocking shared lock */
2216 LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o),i);
2218 case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */
2219 LK_ERR(LockFileEx(fh,
2220 LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
2221 0, LK_LEN, 0, &o),i);
2223 case LOCK_UN: /* unlock lock */
2224 LK_ERR(UnlockFileEx(fh, 0, LK_LEN, 0, &o),i);
2226 default: /* unknown */
2237 * redirected io subsystem for all XS modules
2250 return (&(_environ));
2253 /* the rest are the remapped stdio routines */
2273 win32_ferror(FILE *fp)
2275 return (ferror(fp));
2280 win32_feof(FILE *fp)
2286 * Since the errors returned by the socket error function
2287 * WSAGetLastError() are not known by the library routine strerror
2288 * we have to roll our own.
2292 win32_strerror(int e)
2294 #if !defined __BORLANDC__ && !defined __MINGW32__ /* compiler intolerance */
2295 extern int sys_nerr;
2299 if (e < 0 || e > sys_nerr) {
2304 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0,
2305 w32_strerror_buffer,
2306 sizeof(w32_strerror_buffer), NULL) == 0)
2307 strcpy(w32_strerror_buffer, "Unknown Error");
2309 return w32_strerror_buffer;
2315 win32_str_os_error(void *sv, DWORD dwErr)
2319 dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
2320 |FORMAT_MESSAGE_IGNORE_INSERTS
2321 |FORMAT_MESSAGE_FROM_SYSTEM, NULL,
2322 dwErr, 0, (char *)&sMsg, 1, NULL);
2323 /* strip trailing whitespace and period */
2326 --dwLen; /* dwLen doesn't include trailing null */
2327 } while (0 < dwLen && isSPACE(sMsg[dwLen]));
2328 if ('.' != sMsg[dwLen])
2333 sMsg = (char*)LocalAlloc(0, 64/**sizeof(TCHAR)*/);
2335 dwLen = sprintf(sMsg,
2336 "Unknown error #0x%lX (lookup 0x%lX)",
2337 dwErr, GetLastError());
2341 sv_setpvn((SV*)sv, sMsg, dwLen);
2347 win32_fprintf(FILE *fp, const char *format, ...)
2350 va_start(marker, format); /* Initialize variable arguments. */
2352 return (vfprintf(fp, format, marker));
2356 win32_printf(const char *format, ...)
2359 va_start(marker, format); /* Initialize variable arguments. */
2361 return (vprintf(format, marker));
2365 win32_vfprintf(FILE *fp, const char *format, va_list args)
2367 return (vfprintf(fp, format, args));
2371 win32_vprintf(const char *format, va_list args)
2373 return (vprintf(format, args));
2377 win32_fread(void *buf, size_t size, size_t count, FILE *fp)
2379 return fread(buf, size, count, fp);
2383 win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
2385 return fwrite(buf, size, count, fp);
2388 #define MODE_SIZE 10
2391 win32_fopen(const char *filename, const char *mode)
2394 WCHAR wMode[MODE_SIZE], wBuffer[MAX_PATH+1];
2400 if (stricmp(filename, "/dev/null")==0)
2404 A2WHELPER(mode, wMode, sizeof(wMode));
2405 A2WHELPER(filename, wBuffer, sizeof(wBuffer));
2406 f = _wfopen(PerlDir_mapW(wBuffer), wMode);
2409 f = fopen(PerlDir_mapA(filename), mode);
2410 /* avoid buffering headaches for child processes */
2411 if (f && *mode == 'a')
2412 win32_fseek(f, 0, SEEK_END);
2416 #ifndef USE_SOCKETS_AS_HANDLES
2418 #define fdopen my_fdopen
2422 win32_fdopen(int handle, const char *mode)
2425 WCHAR wMode[MODE_SIZE];
2428 A2WHELPER(mode, wMode, sizeof(wMode));
2429 f = _wfdopen(handle, wMode);
2432 f = fdopen(handle, (char *) mode);
2433 /* avoid buffering headaches for child processes */
2434 if (f && *mode == 'a')
2435 win32_fseek(f, 0, SEEK_END);
2440 win32_freopen(const char *path, const char *mode, FILE *stream)
2443 WCHAR wMode[MODE_SIZE], wBuffer[MAX_PATH+1];
2444 if (stricmp(path, "/dev/null")==0)
2448 A2WHELPER(mode, wMode, sizeof(wMode));
2449 A2WHELPER(path, wBuffer, sizeof(wBuffer));
2450 return _wfreopen(PerlDir_mapW(wBuffer), wMode, stream);
2452 return freopen(PerlDir_mapA(path), mode, stream);
2456 win32_fclose(FILE *pf)
2458 return my_fclose(pf); /* defined in win32sck.c */
2462 win32_fputs(const char *s,FILE *pf)
2464 return fputs(s, pf);
2468 win32_fputc(int c,FILE *pf)
2474 win32_ungetc(int c,FILE *pf)
2476 return ungetc(c,pf);
2480 win32_getc(FILE *pf)
2486 win32_fileno(FILE *pf)
2492 win32_clearerr(FILE *pf)
2499 win32_fflush(FILE *pf)
2505 win32_ftell(FILE *pf)
2507 #if defined(WIN64) || defined(USE_LARGE_FILES)
2509 if (fgetpos(pf, &pos))
2518 win32_fseek(FILE *pf, Off_t offset,int origin)
2520 #if defined(WIN64) || defined(USE_LARGE_FILES)
2524 if (fgetpos(pf, &pos))
2529 fseek(pf, 0, SEEK_END);
2530 pos = _telli64(fileno(pf));
2539 return fsetpos(pf, &offset);
2541 return fseek(pf, offset, origin);
2546 win32_fgetpos(FILE *pf,fpos_t *p)
2548 return fgetpos(pf, p);
2552 win32_fsetpos(FILE *pf,const fpos_t *p)
2554 return fsetpos(pf, p);
2558 win32_rewind(FILE *pf)
2568 char prefix[MAX_PATH+1];
2569 char filename[MAX_PATH+1];
2570 DWORD len = GetTempPath(MAX_PATH, prefix);
2571 if (len && len < MAX_PATH) {
2572 if (GetTempFileName(prefix, "plx", 0, filename)) {
2573 HANDLE fh = CreateFile(filename,
2574 DELETE | GENERIC_READ | GENERIC_WRITE,
2578 FILE_ATTRIBUTE_NORMAL
2579 | FILE_FLAG_DELETE_ON_CLOSE,
2581 if (fh != INVALID_HANDLE_VALUE) {
2582 int fd = win32_open_osfhandle((intptr_t)fh, 0);
2584 #if defined(__BORLANDC__)
2585 setmode(fd,O_BINARY);
2587 DEBUG_p(PerlIO_printf(Perl_debug_log,
2588 "Created tmpfile=%s\n",filename));
2589 return fdopen(fd, "w+b");
2605 win32_fstat(int fd, Stat_t *sbufptr)
2608 /* A file designated by filehandle is not shown as accessible
2609 * for write operations, probably because it is opened for reading.
2612 int rc = fstat(fd,sbufptr);
2613 BY_HANDLE_FILE_INFORMATION bhfi;
2614 if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &bhfi)) {
2615 sbufptr->st_mode &= 0xFE00;
2616 if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
2617 sbufptr->st_mode |= (S_IREAD + (S_IREAD >> 3) + (S_IREAD >> 6));
2619 sbufptr->st_mode |= ((S_IREAD|S_IWRITE) + ((S_IREAD|S_IWRITE) >> 3)
2620 + ((S_IREAD|S_IWRITE) >> 6));
2624 return my_fstat(fd,sbufptr);
2629 win32_pipe(int *pfd, unsigned int size, int mode)
2631 return _pipe(pfd, size, mode);
2635 win32_popenlist(const char *mode, IV narg, SV **args)
2638 Perl_croak(aTHX_ "List form of pipe open not implemented");
2643 * a popen() clone that respects PERL5SHELL
2645 * changed to return PerlIO* rather than FILE * by BKS, 11-11-2000
2649 win32_popen(const char *command, const char *mode)
2651 #ifdef USE_RTL_POPEN
2652 return _popen(command, mode);
2661 /* establish which ends read and write */
2662 if (strchr(mode,'w')) {
2663 stdfd = 0; /* stdin */
2667 else if (strchr(mode,'r')) {
2668 stdfd = 1; /* stdout */
2675 /* set the correct mode */
2676 if (strchr(mode,'b'))
2678 else if (strchr(mode,'t'))
2681 ourmode = _fmode & (O_TEXT | O_BINARY);
2683 /* the child doesn't inherit handles */
2684 ourmode |= O_NOINHERIT;
2686 if (win32_pipe( p, 512, ourmode) == -1)
2689 /* save current stdfd */
2690 if ((oldfd = win32_dup(stdfd)) == -1)
2693 /* make stdfd go to child end of pipe (implicitly closes stdfd) */
2694 /* stdfd will be inherited by the child */
2695 if (win32_dup2(p[child], stdfd) == -1)
2698 /* close the child end in parent */
2699 win32_close(p[child]);
2701 /* start the child */
2704 if ((childpid = do_spawn_nowait((char*)command)) == -1)
2707 /* revert stdfd to whatever it was before */
2708 if (win32_dup2(oldfd, stdfd) == -1)
2711 /* close saved handle */
2715 sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid);
2718 /* set process id so that it can be returned by perl's open() */
2719 PL_forkprocess = childpid;
2722 /* we have an fd, return a file stream */
2723 return (PerlIO_fdopen(p[parent], (char *)mode));
2726 /* we don't need to check for errors here */
2730 win32_dup2(oldfd, stdfd);
2735 #endif /* USE_RTL_POPEN */
2743 win32_pclose(PerlIO *pf)
2745 #ifdef USE_RTL_POPEN
2749 int childpid, status;
2753 sv = *av_fetch(w32_fdpid, PerlIO_fileno(pf), TRUE);
2756 childpid = SvIVX(sv);
2773 if (win32_waitpid(childpid, &status, 0) == -1)
2778 #endif /* USE_RTL_POPEN */
2784 LPCWSTR lpExistingFileName,
2785 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
2788 WCHAR wFullName[MAX_PATH+1];
2789 LPVOID lpContext = NULL;
2790 WIN32_STREAM_ID StreamId;
2791 DWORD dwSize = (char*)&StreamId.cStreamName - (char*)&StreamId;
2796 BOOL (__stdcall *pfnBackupWrite)(HANDLE, LPBYTE, DWORD, LPDWORD,
2797 BOOL, BOOL, LPVOID*) =
2798 (BOOL (__stdcall *)(HANDLE, LPBYTE, DWORD, LPDWORD,
2799 BOOL, BOOL, LPVOID*))
2800 GetProcAddress(GetModuleHandle("kernel32.dll"), "BackupWrite");
2801 if (pfnBackupWrite == NULL)
2804 dwLen = GetFullPathNameW(lpFileName, MAX_PATH, wFullName, NULL);
2807 dwLen = (dwLen+1)*sizeof(WCHAR);
2809 handle = CreateFileW(lpExistingFileName, FILE_WRITE_ATTRIBUTES,
2810 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2811 NULL, OPEN_EXISTING, 0, NULL);
2812 if (handle == INVALID_HANDLE_VALUE)
2815 StreamId.dwStreamId = BACKUP_LINK;
2816 StreamId.dwStreamAttributes = 0;
2817 StreamId.dwStreamNameSize = 0;
2818 #if defined(__BORLANDC__) \
2819 ||(defined(__MINGW32__) && !defined(_ANONYMOUS_UNION))
2820 StreamId.Size.u.HighPart = 0;
2821 StreamId.Size.u.LowPart = dwLen;
2823 StreamId.Size.HighPart = 0;
2824 StreamId.Size.LowPart = dwLen;
2827 bSuccess = pfnBackupWrite(handle, (LPBYTE)&StreamId, dwSize, &dwWritten,
2828 FALSE, FALSE, &lpContext);
2830 bSuccess = pfnBackupWrite(handle, (LPBYTE)wFullName, dwLen, &dwWritten,
2831 FALSE, FALSE, &lpContext);
2832 pfnBackupWrite(handle, NULL, 0, &dwWritten, TRUE, FALSE, &lpContext);
2835 CloseHandle(handle);
2840 win32_link(const char *oldname, const char *newname)
2843 BOOL (__stdcall *pfnCreateHardLinkW)(LPCWSTR,LPCWSTR,LPSECURITY_ATTRIBUTES);
2844 WCHAR wOldName[MAX_PATH+1];
2845 WCHAR wNewName[MAX_PATH+1];
2848 Perl_croak(aTHX_ PL_no_func, "link");
2850 pfnCreateHardLinkW =
2851 (BOOL (__stdcall *)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES))
2852 GetProcAddress(GetModuleHandle("kernel32.dll"), "CreateHardLinkW");
2853 if (pfnCreateHardLinkW == NULL)
2854 pfnCreateHardLinkW = Nt4CreateHardLinkW;
2856 if ((A2WHELPER(oldname, wOldName, sizeof(wOldName))) &&
2857 (A2WHELPER(newname, wNewName, sizeof(wNewName))) &&
2858 (wcscpy(wOldName, PerlDir_mapW(wOldName)),
2859 pfnCreateHardLinkW(PerlDir_mapW(wNewName), wOldName, NULL)))
2863 errno = (GetLastError() == ERROR_FILE_NOT_FOUND) ? ENOENT : EINVAL;
2868 win32_rename(const char *oname, const char *newname)
2870 WCHAR wOldName[MAX_PATH+1];
2871 WCHAR wNewName[MAX_PATH+1];
2872 char szOldName[MAX_PATH+1];
2873 char szNewName[MAX_PATH+1];
2877 /* XXX despite what the documentation says about MoveFileEx(),
2878 * it doesn't work under Windows95!
2881 DWORD dwFlags = MOVEFILE_COPY_ALLOWED;
2883 A2WHELPER(oname, wOldName, sizeof(wOldName));
2884 A2WHELPER(newname, wNewName, sizeof(wNewName));
2885 if (wcsicmp(wNewName, wOldName))
2886 dwFlags |= MOVEFILE_REPLACE_EXISTING;
2887 wcscpy(wOldName, PerlDir_mapW(wOldName));
2888 bResult = MoveFileExW(wOldName,PerlDir_mapW(wNewName), dwFlags);
2891 if (stricmp(newname, oname))
2892 dwFlags |= MOVEFILE_REPLACE_EXISTING;
2893 strcpy(szOldName, PerlDir_mapA(oname));
2894 bResult = MoveFileExA(szOldName,PerlDir_mapA(newname), dwFlags);
2897 DWORD err = GetLastError();
2899 case ERROR_BAD_NET_NAME:
2900 case ERROR_BAD_NETPATH:
2901 case ERROR_BAD_PATHNAME:
2902 case ERROR_FILE_NOT_FOUND:
2903 case ERROR_FILENAME_EXCED_RANGE:
2904 case ERROR_INVALID_DRIVE:
2905 case ERROR_NO_MORE_FILES:
2906 case ERROR_PATH_NOT_FOUND:
2919 char szTmpName[MAX_PATH+1];
2920 char dname[MAX_PATH+1];
2921 char *endname = Nullch;
2923 DWORD from_attr, to_attr;
2925 strcpy(szOldName, PerlDir_mapA(oname));
2926 strcpy(szNewName, PerlDir_mapA(newname));
2928 /* if oname doesn't exist, do nothing */
2929 from_attr = GetFileAttributes(szOldName);
2930 if (from_attr == 0xFFFFFFFF) {
2935 /* if newname exists, rename it to a temporary name so that we
2936 * don't delete it in case oname happens to be the same file
2937 * (but perhaps accessed via a different path)
2939 to_attr = GetFileAttributes(szNewName);
2940 if (to_attr != 0xFFFFFFFF) {
2941 /* if newname is a directory, we fail
2942 * XXX could overcome this with yet more convoluted logic */
2943 if (to_attr & FILE_ATTRIBUTE_DIRECTORY) {
2947 tmplen = strlen(szNewName);
2948 strcpy(szTmpName,szNewName);
2949 endname = szTmpName+tmplen;
2950 for (; endname > szTmpName ; --endname) {
2951 if (*endname == '/' || *endname == '\\') {
2956 if (endname > szTmpName)
2957 endname = strcpy(dname,szTmpName);
2961 /* get a temporary filename in same directory
2962 * XXX is this really the best we can do? */
2963 if (!GetTempFileName((LPCTSTR)endname, "plr", 0, szTmpName)) {
2967 DeleteFile(szTmpName);
2969 retval = rename(szNewName, szTmpName);
2976 /* rename oname to newname */
2977 retval = rename(szOldName, szNewName);
2979 /* if we created a temporary file before ... */
2980 if (endname != Nullch) {
2981 /* ...and rename succeeded, delete temporary file/directory */
2983 DeleteFile(szTmpName);
2984 /* else restore it to what it was */
2986 (void)rename(szTmpName, szNewName);
2993 win32_setmode(int fd, int mode)
2995 return setmode(fd, mode);
2999 win32_lseek(int fd, Off_t offset, int origin)
3001 #if defined(WIN64) || defined(USE_LARGE_FILES)
3002 return _lseeki64(fd, offset, origin);
3004 return lseek(fd, offset, origin);
3011 #if defined(WIN64) || defined(USE_LARGE_FILES)
3012 return _telli64(fd);
3019 win32_open(const char *path, int flag, ...)
3024 WCHAR wBuffer[MAX_PATH+1];
3027 pmode = va_arg(ap, int);
3030 if (stricmp(path, "/dev/null")==0)
3034 A2WHELPER(path, wBuffer, sizeof(wBuffer));
3035 return _wopen(PerlDir_mapW(wBuffer), flag, pmode);
3037 return open(PerlDir_mapA(path), flag, pmode);
3040 /* close() that understands socket */
3041 extern int my_close(int); /* in win32sck.c */
3046 return my_close(fd);
3062 win32_dup2(int fd1,int fd2)
3064 return dup2(fd1,fd2);
3067 #ifdef PERL_MSVCRT_READFIX
3069 #define LF 10 /* line feed */
3070 #define CR 13 /* carriage return */
3071 #define CTRLZ 26 /* ctrl-z means eof for text */
3072 #define FOPEN 0x01 /* file handle open */
3073 #define FEOFLAG 0x02 /* end of file has been encountered */
3074 #define FCRLF 0x04 /* CR-LF across read buffer (in text mode) */
3075 #define FPIPE 0x08 /* file handle refers to a pipe */
3076 #define FAPPEND 0x20 /* file handle opened O_APPEND */
3077 #define FDEV 0x40 /* file handle refers to device */
3078 #define FTEXT 0x80 /* file handle is in text mode */
3079 #define MAX_DESCRIPTOR_COUNT (64*32) /* this is the maximun that MSVCRT can handle */
3082 _fixed_read(int fh, void *buf, unsigned cnt)
3084 int bytes_read; /* number of bytes read */
3085 char *buffer; /* buffer to read to */
3086 int os_read; /* bytes read on OS call */
3087 char *p, *q; /* pointers into buffer */
3088 char peekchr; /* peek-ahead character */
3089 ULONG filepos; /* file position after seek */
3090 ULONG dosretval; /* o.s. return value */
3092 /* validate handle */
3093 if (((unsigned)fh >= (unsigned)MAX_DESCRIPTOR_COUNT) ||
3094 !(_osfile(fh) & FOPEN))
3096 /* out of range -- return error */
3098 _doserrno = 0; /* not o.s. error */
3103 * If lockinitflag is FALSE, assume fd is device
3104 * lockinitflag is set to TRUE by open.
3106 if (_pioinfo(fh)->lockinitflag)
3107 EnterCriticalSection(&(_pioinfo(fh)->lock)); /* lock file */
3109 bytes_read = 0; /* nothing read yet */
3110 buffer = (char*)buf;
3112 if (cnt == 0 || (_osfile(fh) & FEOFLAG)) {
3113 /* nothing to read or at EOF, so return 0 read */
3117 if ((_osfile(fh) & (FPIPE|FDEV)) && _pipech(fh) != LF) {
3118 /* a pipe/device and pipe lookahead non-empty: read the lookahead
3120 *buffer++ = _pipech(fh);
3123 _pipech(fh) = LF; /* mark as empty */
3128 if (!ReadFile((HANDLE)_osfhnd(fh), buffer, cnt, (LPDWORD)&os_read, NULL))
3130 /* ReadFile has reported an error. recognize two special cases.
3132 * 1. map ERROR_ACCESS_DENIED to EBADF
3134 * 2. just return 0 if ERROR_BROKEN_PIPE has occurred. it
3135 * means the handle is a read-handle on a pipe for which
3136 * all write-handles have been closed and all data has been
3139 if ((dosretval = GetLastError()) == ERROR_ACCESS_DENIED) {
3140 /* wrong read/write mode should return EBADF, not EACCES */
3142 _doserrno = dosretval;
3146 else if (dosretval == ERROR_BROKEN_PIPE) {
3156 bytes_read += os_read; /* update bytes read */
3158 if (_osfile(fh) & FTEXT) {
3159 /* now must translate CR-LFs to LFs in the buffer */
3161 /* set CRLF flag to indicate LF at beginning of buffer */
3162 /* if ((os_read != 0) && (*(char *)buf == LF)) */
3163 /* _osfile(fh) |= FCRLF; */
3165 /* _osfile(fh) &= ~FCRLF; */
3167 _osfile(fh) &= ~FCRLF;
3169 /* convert chars in the buffer: p is src, q is dest */
3171 while (p < (char *)buf + bytes_read) {
3173 /* if fh is not a device, set ctrl-z flag */
3174 if (!(_osfile(fh) & FDEV))
3175 _osfile(fh) |= FEOFLAG;
3176 break; /* stop translating */
3181 /* *p is CR, so must check next char for LF */
3182 if (p < (char *)buf + bytes_read - 1) {
3185 *q++ = LF; /* convert CR-LF to LF */
3188 *q++ = *p++; /* store char normally */
3191 /* This is the hard part. We found a CR at end of
3192 buffer. We must peek ahead to see if next char
3197 if (!ReadFile((HANDLE)_osfhnd(fh), &peekchr, 1,
3198 (LPDWORD)&os_read, NULL))
3199 dosretval = GetLastError();
3201 if (dosretval != 0 || os_read == 0) {
3202 /* couldn't read ahead, store CR */
3206 /* peekchr now has the extra character -- we now
3207 have several possibilities:
3208 1. disk file and char is not LF; just seek back
3210 2. disk file and char is LF; store LF, don't seek back
3211 3. pipe/device and char is LF; store LF.
3212 4. pipe/device and char isn't LF, store CR and
3213 put char in pipe lookahead buffer. */
3214 if (_osfile(fh) & (FDEV|FPIPE)) {
3215 /* non-seekable device */
3220 _pipech(fh) = peekchr;
3225 if (peekchr == LF) {
3226 /* nothing read yet; must make some
3229 /* turn on this flag for tell routine */
3230 _osfile(fh) |= FCRLF;
3233 HANDLE osHandle; /* o.s. handle value */
3235 if ((osHandle = (HANDLE)_get_osfhandle(fh)) != (HANDLE)-1)
3237 if ((filepos = SetFilePointer(osHandle, -1, NULL, FILE_CURRENT)) == -1)
3238 dosretval = GetLastError();
3249 /* we now change bytes_read to reflect the true number of chars
3251 bytes_read = q - (char *)buf;
3255 if (_pioinfo(fh)->lockinitflag)
3256 LeaveCriticalSection(&(_pioinfo(fh)->lock)); /* unlock file */
3261 #endif /* PERL_MSVCRT_READFIX */
3264 win32_read(int fd, void *buf, unsigned int cnt)
3266 #ifdef PERL_MSVCRT_READFIX
3267 return _fixed_read(fd, buf, cnt);
3269 return read(fd, buf, cnt);
3274 win32_write(int fd, const void *buf, unsigned int cnt)
3276 return write(fd, buf, cnt);
3280 win32_mkdir(const char *dir, int mode)
3284 WCHAR wBuffer[MAX_PATH+1];
3285 A2WHELPER(dir, wBuffer, sizeof(wBuffer));
3286 return _wmkdir(PerlDir_mapW(wBuffer));
3288 return mkdir(PerlDir_mapA(dir)); /* just ignore mode */
3292 win32_rmdir(const char *dir)
3296 WCHAR wBuffer[MAX_PATH+1];
3297 A2WHELPER(dir, wBuffer, sizeof(wBuffer));
3298 return _wrmdir(PerlDir_mapW(wBuffer));
3300 return rmdir(PerlDir_mapA(dir));
3304 win32_chdir(const char *dir)
3312 WCHAR wBuffer[MAX_PATH+1];
3313 A2WHELPER(dir, wBuffer, sizeof(wBuffer));
3314 return _wchdir(wBuffer);
3320 win32_access(const char *path, int mode)
3324 WCHAR wBuffer[MAX_PATH+1];
3325 A2WHELPER(path, wBuffer, sizeof(wBuffer));
3326 return _waccess(PerlDir_mapW(wBuffer), mode);
3328 return access(PerlDir_mapA(path), mode);
3332 win32_chmod(const char *path, int mode)
3336 WCHAR wBuffer[MAX_PATH+1];
3337 A2WHELPER(path, wBuffer, sizeof(wBuffer));
3338 return _wchmod(PerlDir_mapW(wBuffer), mode);
3340 return chmod(PerlDir_mapA(path), mode);
3345 create_command_line(char *cname, STRLEN clen, const char * const *args)
3352 bool bat_file = FALSE;
3353 bool cmd_shell = FALSE;
3354 bool dumb_shell = FALSE;
3355 bool extra_quotes = FALSE;
3356 bool quote_next = FALSE;
3359 cname = (char*)args[0];
3361 /* The NT cmd.exe shell has the following peculiarity that needs to be
3362 * worked around. It strips a leading and trailing dquote when any
3363 * of the following is true:
3364 * 1. the /S switch was used
3365 * 2. there are more than two dquotes
3366 * 3. there is a special character from this set: &<>()@^|
3367 * 4. no whitespace characters within the two dquotes
3368 * 5. string between two dquotes isn't an executable file
3369 * To work around this, we always add a leading and trailing dquote
3370 * to the string, if the first argument is either "cmd.exe" or "cmd",
3371 * and there were at least two or more arguments passed to cmd.exe
3372 * (not including switches).
3373 * XXX the above rules (from "cmd /?") don't seem to be applied
3374 * always, making for the convolutions below :-(
3378 clen = strlen(cname);
3381 && (stricmp(&cname[clen-4], ".bat") == 0
3382 || (IsWinNT() && stricmp(&cname[clen-4], ".cmd") == 0)))
3388 char *exe = strrchr(cname, '/');
3389 char *exe2 = strrchr(cname, '\\');
3396 if (stricmp(exe, "cmd.exe") == 0 || stricmp(exe, "cmd") == 0) {
3400 else if (stricmp(exe, "command.com") == 0
3401 || stricmp(exe, "command") == 0)
3408 DEBUG_p(PerlIO_printf(Perl_debug_log, "Args "));
3409 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3410 STRLEN curlen = strlen(arg);
3411 if (!(arg[0] == '"' && arg[curlen-1] == '"'))
3412 len += 2; /* assume quoting needed (worst case) */
3414 DEBUG_p(PerlIO_printf(Perl_debug_log, "[%s]",arg));
3416 DEBUG_p(PerlIO_printf(Perl_debug_log, "\n"));
3419 New(1310, cmd, len, char);
3424 extra_quotes = TRUE;
3427 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3429 STRLEN curlen = strlen(arg);
3431 /* we want to protect empty arguments and ones with spaces with
3432 * dquotes, but only if they aren't already there */
3437 else if (quote_next) {
3438 /* see if it really is multiple arguments pretending to
3439 * be one and force a set of quotes around it */
3440 if (*find_next_space(arg))
3443 else if (!(arg[0] == '"' && curlen > 1 && arg[curlen-1] == '"')) {
3445 while (i < curlen) {
3446 if (isSPACE(arg[i])) {
3449 else if (arg[i] == '"') {
3472 && (stricmp(arg, "/x/c") == 0 || stricmp(arg, "/c") == 0))
3474 /* is there a next argument? */
3475 if (args[index+1]) {
3476 /* are there two or more next arguments? */
3477 if (args[index+2]) {
3479 extra_quotes = TRUE;
3482 /* single argument, force quoting if it has spaces */
3498 qualified_path(const char *cmd)
3502 char *fullcmd, *curfullcmd;
3508 fullcmd = (char*)cmd;
3510 if (*fullcmd == '/' || *fullcmd == '\\')
3517 pathstr = PerlEnv_getenv("PATH");
3518 New(0, fullcmd, MAX_PATH+1, char);
3519 curfullcmd = fullcmd;
3524 /* start by appending the name to the current prefix */
3525 strcpy(curfullcmd, cmd);
3526 curfullcmd += cmdlen;
3528 /* if it doesn't end with '.', or has no extension, try adding
3529 * a trailing .exe first */
3530 if (cmd[cmdlen-1] != '.'
3531 && (cmdlen < 4 || cmd[cmdlen-4] != '.'))
3533 strcpy(curfullcmd, ".exe");
3534 res = GetFileAttributes(fullcmd);
3535 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3540 /* that failed, try the bare name */
3541 res = GetFileAttributes(fullcmd);
3542 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3545 /* quit if no other path exists, or if cmd already has path */
3546 if (!pathstr || !*pathstr || has_slash)
3549 /* skip leading semis */
3550 while (*pathstr == ';')
3553 /* build a new prefix from scratch */
3554 curfullcmd = fullcmd;
3555 while (*pathstr && *pathstr != ';') {
3556 if (*pathstr == '"') { /* foo;"baz;etc";bar */
3557 pathstr++; /* skip initial '"' */
3558 while (*pathstr && *pathstr != '"') {
3559 if ((STRLEN)(curfullcmd-fullcmd) < MAX_PATH-cmdlen-5)
3560 *curfullcmd++ = *pathstr;
3564 pathstr++; /* skip trailing '"' */
3567 if ((STRLEN)(curfullcmd-fullcmd) < MAX_PATH-cmdlen-5)
3568 *curfullcmd++ = *pathstr;
3573 pathstr++; /* skip trailing semi */
3574 if (curfullcmd > fullcmd /* append a dir separator */
3575 && curfullcmd[-1] != '/' && curfullcmd[-1] != '\\')
3577 *curfullcmd++ = '\\';
3585 /* The following are just place holders.
3586 * Some hosts may provide and environment that the OS is
3587 * not tracking, therefore, these host must provide that
3588 * environment and the current directory to CreateProcess
3592 win32_get_childenv(void)
3598 win32_free_childenv(void* d)
3603 win32_clearenv(void)
3605 char *envv = GetEnvironmentStrings();
3609 char *end = strchr(cur,'=');
3610 if (end && end != cur) {
3612 SetEnvironmentVariable(cur, NULL);
3614 cur = end + strlen(end+1)+2;
3616 else if ((len = strlen(cur)))
3619 FreeEnvironmentStrings(envv);
3623 win32_get_childdir(void)
3627 char szfilename[(MAX_PATH+1)*2];
3629 WCHAR wfilename[MAX_PATH+1];
3630 GetCurrentDirectoryW(MAX_PATH+1, wfilename);
3631 W2AHELPER(wfilename, szfilename, sizeof(szfilename));
3634 GetCurrentDirectoryA(MAX_PATH+1, szfilename);
3637 New(0, ptr, strlen(szfilename)+1, char);
3638 strcpy(ptr, szfilename);
3643 win32_free_childdir(char* d)
3650 /* XXX this needs to be made more compatible with the spawnvp()
3651 * provided by the various RTLs. In particular, searching for
3652 * *.{com,bat,cmd} files (as done by the RTLs) is unimplemented.
3653 * This doesn't significantly affect perl itself, because we
3654 * always invoke things using PERL5SHELL if a direct attempt to
3655 * spawn the executable fails.
3657 * XXX splitting and rejoining the commandline between do_aspawn()
3658 * and win32_spawnvp() could also be avoided.
3662 win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
3664 #ifdef USE_RTL_SPAWNVP
3665 return spawnvp(mode, cmdname, (char * const *)argv);
3672 STARTUPINFO StartupInfo;
3673 PROCESS_INFORMATION ProcessInformation;
3676 char *fullcmd = Nullch;
3677 char *cname = (char *)cmdname;
3681 clen = strlen(cname);
3682 /* if command name contains dquotes, must remove them */
3683 if (strchr(cname, '"')) {
3685 New(0,cname,clen+1,char);
3698 cmd = create_command_line(cname, clen, argv);
3700 env = PerlEnv_get_childenv();
3701 dir = PerlEnv_get_childdir();
3704 case P_NOWAIT: /* asynch + remember result */
3705 if (w32_num_children >= MAXIMUM_WAIT_OBJECTS) {
3710 /* Create a new process group so we can use GenerateConsoleCtrlEvent()
3713 create |= CREATE_NEW_PROCESS_GROUP;
3716 case P_WAIT: /* synchronous execution */
3718 default: /* invalid mode */
3723 memset(&StartupInfo,0,sizeof(StartupInfo));
3724 StartupInfo.cb = sizeof(StartupInfo);
3725 memset(&tbl,0,sizeof(tbl));
3726 PerlEnv_get_child_IO(&tbl);
3727 StartupInfo.dwFlags = tbl.dwFlags;
3728 StartupInfo.dwX = tbl.dwX;
3729 StartupInfo.dwY = tbl.dwY;
3730 StartupInfo.dwXSize = tbl.dwXSize;
3731 StartupInfo.dwYSize = tbl.dwYSize;
3732 StartupInfo.dwXCountChars = tbl.dwXCountChars;
3733 StartupInfo.dwYCountChars = tbl.dwYCountChars;
3734 StartupInfo.dwFillAttribute = tbl.dwFillAttribute;
3735 StartupInfo.wShowWindow = tbl.wShowWindow;
3736 StartupInfo.hStdInput = tbl.childStdIn;
3737 StartupInfo.hStdOutput = tbl.childStdOut;
3738 StartupInfo.hStdError = tbl.childStdErr;
3739 if (StartupInfo.hStdInput == INVALID_HANDLE_VALUE &&
3740 StartupInfo.hStdOutput == INVALID_HANDLE_VALUE &&
3741 StartupInfo.hStdError == INVALID_HANDLE_VALUE)
3743 create |= CREATE_NEW_CONSOLE;
3746 StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
3748 if (w32_use_showwindow) {
3749 StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
3750 StartupInfo.wShowWindow = w32_showwindow;
3753 DEBUG_p(PerlIO_printf(Perl_debug_log, "Spawning [%s] with [%s]\n",
3756 if (!CreateProcess(cname, /* search PATH to find executable */
3757 cmd, /* executable, and its arguments */
3758 NULL, /* process attributes */
3759 NULL, /* thread attributes */
3760 TRUE, /* inherit handles */
3761 create, /* creation flags */
3762 (LPVOID)env, /* inherit environment */
3763 dir, /* inherit cwd */
3765 &ProcessInformation))
3767 /* initial NULL argument to CreateProcess() does a PATH
3768 * search, but it always first looks in the directory
3769 * where the current process was started, which behavior
3770 * is undesirable for backward compatibility. So we
3771 * jump through our own hoops by picking out the path
3772 * we really want it to use. */
3774 fullcmd = qualified_path(cname);
3776 if (cname != cmdname)
3779 DEBUG_p(PerlIO_printf(Perl_debug_log,
3780 "Retrying [%s] with same args\n",
3790 if (mode == P_NOWAIT) {
3791 /* asynchronous spawn -- store handle, return PID */
3792 ret = (int)ProcessInformation.dwProcessId;
3793 if (IsWin95() && ret < 0)
3796 w32_child_handles[w32_num_children] = ProcessInformation.hProcess;
3797 w32_child_pids[w32_num_children] = (DWORD)ret;
3802 win32_msgwait(aTHX_ 1, &ProcessInformation.hProcess, INFINITE, NULL);
3803 /* FIXME: if msgwait returned due to message perhaps forward the
3804 "signal" to the process
3806 GetExitCodeProcess(ProcessInformation.hProcess, &status);
3808 CloseHandle(ProcessInformation.hProcess);
3811 CloseHandle(ProcessInformation.hThread);
3814 PerlEnv_free_childenv(env);
3815 PerlEnv_free_childdir(dir);
3817 if (cname != cmdname)
3824 win32_execv(const char *cmdname, const char *const *argv)
3828 /* if this is a pseudo-forked child, we just want to spawn
3829 * the new program, and return */
3831 return spawnv(P_WAIT, cmdname, (char *const *)argv);
3833 return execv(cmdname, (char *const *)argv);
3837 win32_execvp(const char *cmdname, const char *const *argv)
3841 /* if this is a pseudo-forked child, we just want to spawn
3842 * the new program, and return */
3843 if (w32_pseudo_id) {
3844 int status = win32_spawnvp(P_WAIT, cmdname, (char *const *)argv);
3853 return execvp(cmdname, (char *const *)argv);
3857 win32_perror(const char *str)
3863 win32_setbuf(FILE *pf, char *buf)
3869 win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
3871 return setvbuf(pf, buf, type, size);
3875 win32_flushall(void)
3881 win32_fcloseall(void)
3887 win32_fgets(char *s, int n, FILE *pf)
3889 return fgets(s, n, pf);
3899 win32_fgetc(FILE *pf)
3905 win32_putc(int c, FILE *pf)
3911 win32_puts(const char *s)
3923 win32_putchar(int c)
3930 #ifndef USE_PERL_SBRK
3932 static char *committed = NULL; /* XXX threadead */
3933 static char *base = NULL; /* XXX threadead */
3934 static char *reserved = NULL; /* XXX threadead */
3935 static char *brk = NULL; /* XXX threadead */
3936 static DWORD pagesize = 0; /* XXX threadead */
3937 static DWORD allocsize = 0; /* XXX threadead */
3940 sbrk(ptrdiff_t need)
3945 GetSystemInfo(&info);
3946 /* Pretend page size is larger so we don't perpetually
3947 * call the OS to commit just one page ...
3949 pagesize = info.dwPageSize << 3;
3950 allocsize = info.dwAllocationGranularity;
3952 /* This scheme fails eventually if request for contiguous
3953 * block is denied so reserve big blocks - this is only
3954 * address space not memory ...
3956 if (brk+need >= reserved)
3958 DWORD size = 64*1024*1024;
3960 if (committed && reserved && committed < reserved)
3962 /* Commit last of previous chunk cannot span allocations */
3963 addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
3965 committed = reserved;
3967 /* Reserve some (more) space
3968 * Note this is a little sneaky, 1st call passes NULL as reserved
3969 * so lets system choose where we start, subsequent calls pass
3970 * the old end address so ask for a contiguous block
3972 addr = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
3975 reserved = addr+size;
3990 if (brk > committed)
3992 DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
3993 char *addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
4008 win32_malloc(size_t size)
4010 return malloc(size);
4014 win32_calloc(size_t numitems, size_t size)
4016 return calloc(numitems,size);
4020 win32_realloc(void *block, size_t size)
4022 return realloc(block,size);
4026 win32_free(void *block)
4033 win32_open_osfhandle(intptr_t handle, int flags)
4035 #ifdef USE_FIXED_OSFHANDLE
4037 return my_open_osfhandle(handle, flags);
4039 return _open_osfhandle(handle, flags);
4043 win32_get_osfhandle(int fd)
4045 return (intptr_t)_get_osfhandle(fd);
4049 win32_fdupopen(FILE *pf)
4054 int fileno = win32_dup(win32_fileno(pf));
4056 /* open the file in the same mode */
4058 if((pf)->flags & _F_READ) {
4062 else if((pf)->flags & _F_WRIT) {
4066 else if((pf)->flags & _F_RDWR) {
4072 if((pf)->_flag & _IOREAD) {
4076 else if((pf)->_flag & _IOWRT) {
4080 else if((pf)->_flag & _IORW) {
4087 /* it appears that the binmode is attached to the
4088 * file descriptor so binmode files will be handled
4091 pfdup = win32_fdopen(fileno, mode);
4093 /* move the file pointer to the same position */
4094 if (!fgetpos(pf, &pos)) {
4095 fsetpos(pfdup, &pos);
4101 win32_dynaload(const char* filename)
4105 char buf[MAX_PATH+1];
4108 /* LoadLibrary() doesn't recognize forward slashes correctly,
4109 * so turn 'em back. */
4110 first = strchr(filename, '/');
4112 STRLEN len = strlen(filename);
4113 if (len <= MAX_PATH) {
4114 strcpy(buf, filename);
4115 filename = &buf[first - filename];
4117 if (*filename == '/')
4118 *(char*)filename = '\\';
4125 WCHAR wfilename[MAX_PATH+1];
4126 A2WHELPER(filename, wfilename, sizeof(wfilename));
4127 hModule = LoadLibraryExW(PerlDir_mapW(wfilename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
4130 hModule = LoadLibraryExA(PerlDir_mapA(filename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
4140 XS(w32_SetChildShowWindow)
4143 BOOL use_showwindow = w32_use_showwindow;
4144 /* use "unsigned short" because Perl has redefined "WORD" */
4145 unsigned short showwindow = w32_showwindow;
4148 Perl_croak(aTHX_ "usage: Win32::SetChildShowWindow($showwindow)");
4150 if (items == 0 || !SvOK(ST(0)))
4151 w32_use_showwindow = FALSE;
4153 w32_use_showwindow = TRUE;
4154 w32_showwindow = (unsigned short)SvIV(ST(0));
4159 ST(0) = sv_2mortal(newSViv(showwindow));
4161 ST(0) = &PL_sv_undef;
4169 /* Make the host for current directory */
4170 char* ptr = PerlEnv_get_childdir();
4173 * then it worked, set PV valid,
4174 * else return 'undef'
4177 SV *sv = sv_newmortal();
4179 PerlEnv_free_childdir(ptr);
4181 #ifndef INCOMPLETE_TAINTS
4198 Perl_croak(aTHX_ "usage: Win32::SetCurrentDirectory($cwd)");
4199 if (!PerlDir_chdir(SvPV_nolen(ST(0))))
4206 XS(w32_GetNextAvailDrive)
4210 char root[] = "_:\\";
4215 if (GetDriveType(root) == 1) {
4224 XS(w32_GetLastError)
4228 XSRETURN_IV(GetLastError());
4232 XS(w32_SetLastError)
4236 Perl_croak(aTHX_ "usage: Win32::SetLastError($error)");
4237 SetLastError(SvIV(ST(0)));
4245 char *name = w32_getlogin_buffer;
4246 DWORD size = sizeof(w32_getlogin_buffer);
4248 if (GetUserName(name,&size)) {
4249 /* size includes NULL */
4250 ST(0) = sv_2mortal(newSVpvn(name,size-1));
4260 char name[MAX_COMPUTERNAME_LENGTH+1];
4261 DWORD size = sizeof(name);
4263 if (GetComputerName(name,&size)) {
4264 /* size does NOT include NULL :-( */
4265 ST(0) = sv_2mortal(newSVpvn(name,size));
4276 HINSTANCE hNetApi32 = LoadLibrary("netapi32.dll");
4277 DWORD (__stdcall *pfnNetApiBufferFree)(LPVOID Buffer);
4278 DWORD (__stdcall *pfnNetWkstaGetInfo)(LPWSTR servername, DWORD level,
4282 pfnNetApiBufferFree = (DWORD (__stdcall *)(void *))
4283 GetProcAddress(hNetApi32, "NetApiBufferFree");
4284 pfnNetWkstaGetInfo = (DWORD (__stdcall *)(LPWSTR, DWORD, void *))
4285 GetProcAddress(hNetApi32, "NetWkstaGetInfo");
4288 if (hNetApi32 && pfnNetWkstaGetInfo && pfnNetApiBufferFree) {
4289 /* this way is more reliable, in case user has a local account. */
4291 DWORD dnamelen = sizeof(dname);
4293 DWORD wki100_platform_id;
4294 LPWSTR wki100_computername;
4295 LPWSTR wki100_langroup;
4296 DWORD wki100_ver_major;
4297 DWORD wki100_ver_minor;
4299 /* NERR_Success *is* 0*/
4300 if (0 == pfnNetWkstaGetInfo(NULL, 100, &pwi)) {
4301 if (pwi->wki100_langroup && *(pwi->wki100_langroup)) {
4302 WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_langroup,
4303 -1, (LPSTR)dname, dnamelen, NULL, NULL);
4306 WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_computername,
4307 -1, (LPSTR)dname, dnamelen, NULL, NULL);
4309 pfnNetApiBufferFree(pwi);
4310 FreeLibrary(hNetApi32);
4313 FreeLibrary(hNetApi32);
4316 /* Win95 doesn't have NetWksta*(), so do it the old way */
4318 DWORD size = sizeof(name);
4320 FreeLibrary(hNetApi32);
4321 if (GetUserName(name,&size)) {
4322 char sid[ONE_K_BUFSIZE];
4323 DWORD sidlen = sizeof(sid);
4325 DWORD dnamelen = sizeof(dname);
4327 if (LookupAccountName(NULL, name, (PSID)&sid, &sidlen,
4328 dname, &dnamelen, &snu)) {
4329 XSRETURN_PV(dname); /* all that for this */
4341 DWORD flags, filecomplen;
4342 if (GetVolumeInformation(NULL, NULL, 0, NULL, &filecomplen,
4343 &flags, fsname, sizeof(fsname))) {
4344 if (GIMME_V == G_ARRAY) {
4345 XPUSHs(sv_2mortal(newSVpvn(fsname,strlen(fsname))));
4346 XPUSHs(sv_2mortal(newSViv(flags)));
4347 XPUSHs(sv_2mortal(newSViv(filecomplen)));
4352 XSRETURN_PV(fsname);
4358 XS(w32_GetOSVersion)
4361 OSVERSIONINFOA osver;
4364 OSVERSIONINFOW osverw;
4365 char szCSDVersion[sizeof(osverw.szCSDVersion)];
4366 osverw.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
4367 if (!GetVersionExW(&osverw)) {
4370 W2AHELPER(osverw.szCSDVersion, szCSDVersion, sizeof(szCSDVersion));
4371 XPUSHs(newSVpvn(szCSDVersion, strlen(szCSDVersion)));
4372 osver.dwMajorVersion = osverw.dwMajorVersion;
4373 osver.dwMinorVersion = osverw.dwMinorVersion;
4374 osver.dwBuildNumber = osverw.dwBuildNumber;
4375 osver.dwPlatformId = osverw.dwPlatformId;
4378 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
4379 if (!GetVersionExA(&osver)) {
4382 XPUSHs(newSVpvn(osver.szCSDVersion, strlen(osver.szCSDVersion)));
4384 XPUSHs(newSViv(osver.dwMajorVersion));
4385 XPUSHs(newSViv(osver.dwMinorVersion));
4386 XPUSHs(newSViv(osver.dwBuildNumber));
4387 XPUSHs(newSViv(osver.dwPlatformId));
4396 XSRETURN_IV(IsWinNT());
4404 XSRETURN_IV(IsWin95());
4408 XS(w32_FormatMessage)
4412 char msgbuf[ONE_K_BUFSIZE];
4415 Perl_croak(aTHX_ "usage: Win32::FormatMessage($errno)");
4418 WCHAR wmsgbuf[ONE_K_BUFSIZE];
4419 if (FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
4420 &source, SvIV(ST(0)), 0,
4421 wmsgbuf, ONE_K_BUFSIZE-1, NULL))
4423 W2AHELPER(wmsgbuf, msgbuf, sizeof(msgbuf));
4424 XSRETURN_PV(msgbuf);
4428 if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,
4429 &source, SvIV(ST(0)), 0,
4430 msgbuf, sizeof(msgbuf)-1, NULL))
4431 XSRETURN_PV(msgbuf);
4444 PROCESS_INFORMATION stProcInfo;
4445 STARTUPINFO stStartInfo;
4446 BOOL bSuccess = FALSE;
4449 Perl_croak(aTHX_ "usage: Win32::Spawn($cmdName, $args, $PID)");
4451 cmd = SvPV_nolen(ST(0));
4452 args = SvPV_nolen(ST(1));
4454 env = PerlEnv_get_childenv();
4455 dir = PerlEnv_get_childdir();
4457 memset(&stStartInfo, 0, sizeof(stStartInfo)); /* Clear the block */
4458 stStartInfo.cb = sizeof(stStartInfo); /* Set the structure size */
4459 stStartInfo.dwFlags = STARTF_USESHOWWINDOW; /* Enable wShowWindow control */
4460 stStartInfo.wShowWindow = SW_SHOWMINNOACTIVE; /* Start min (normal) */
4463 cmd, /* Image path */
4464 args, /* Arguments for command line */
4465 NULL, /* Default process security */
4466 NULL, /* Default thread security */
4467 FALSE, /* Must be TRUE to use std handles */
4468 NORMAL_PRIORITY_CLASS, /* No special scheduling */
4469 env, /* Inherit our environment block */
4470 dir, /* Inherit our currrent directory */
4471 &stStartInfo, /* -> Startup info */
4472 &stProcInfo)) /* <- Process info (if OK) */
4474 int pid = (int)stProcInfo.dwProcessId;
4475 if (IsWin95() && pid < 0)
4477 sv_setiv(ST(2), pid);
4478 CloseHandle(stProcInfo.hThread);/* library source code does this. */
4481 PerlEnv_free_childenv(env);
4482 PerlEnv_free_childdir(dir);
4483 XSRETURN_IV(bSuccess);
4487 XS(w32_GetTickCount)
4490 DWORD msec = GetTickCount();
4498 XS(w32_GetShortPathName)
4505 Perl_croak(aTHX_ "usage: Win32::GetShortPathName($longPathName)");
4507 shortpath = sv_mortalcopy(ST(0));
4508 SvUPGRADE(shortpath, SVt_PV);
4509 if (!SvPVX(shortpath) || !SvLEN(shortpath))
4512 /* src == target is allowed */
4514 len = GetShortPathName(SvPVX(shortpath),
4517 } while (len >= SvLEN(shortpath) && sv_grow(shortpath,len+1));
4519 SvCUR_set(shortpath,len);
4527 XS(w32_GetFullPathName)
4536 Perl_croak(aTHX_ "usage: Win32::GetFullPathName($filename)");
4539 fullpath = sv_mortalcopy(filename);
4540 SvUPGRADE(fullpath, SVt_PV);
4541 if (!SvPVX(fullpath) || !SvLEN(fullpath))
4545 len = GetFullPathName(SvPVX(filename),
4549 } while (len >= SvLEN(fullpath) && sv_grow(fullpath,len+1));
4551 if (GIMME_V == G_ARRAY) {
4553 XST_mPV(1,filepart);
4554 len = filepart - SvPVX(fullpath);
4557 SvCUR_set(fullpath,len);
4565 XS(w32_GetLongPathName)
4569 char tmpbuf[MAX_PATH+1];
4574 Perl_croak(aTHX_ "usage: Win32::GetLongPathName($pathname)");
4577 pathstr = SvPV(path,len);
4578 strcpy(tmpbuf, pathstr);
4579 pathstr = win32_longpath(tmpbuf);
4581 ST(0) = sv_2mortal(newSVpvn(pathstr, strlen(pathstr)));
4592 Perl_croak(aTHX_ "usage: Win32::Sleep($milliseconds)");
4603 Perl_croak(aTHX_ "usage: Win32::CopyFile($from, $to, $overwrite)");
4605 WCHAR wSourceFile[MAX_PATH+1];
4606 WCHAR wDestFile[MAX_PATH+1];
4607 A2WHELPER(SvPV_nolen(ST(0)), wSourceFile, sizeof(wSourceFile));
4608 wcscpy(wSourceFile, PerlDir_mapW(wSourceFile));
4609 A2WHELPER(SvPV_nolen(ST(1)), wDestFile, sizeof(wDestFile));
4610 bResult = CopyFileW(wSourceFile, PerlDir_mapW(wDestFile), !SvTRUE(ST(2)));
4613 char szSourceFile[MAX_PATH+1];
4614 strcpy(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(0))));
4615 bResult = CopyFileA(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(1))), !SvTRUE(ST(2)));
4624 Perl_init_os_extras(void)
4627 char *file = __FILE__;
4630 /* these names are Activeware compatible */
4631 newXS("Win32::GetCwd", w32_GetCwd, file);
4632 newXS("Win32::SetCwd", w32_SetCwd, file);
4633 newXS("Win32::GetNextAvailDrive", w32_GetNextAvailDrive, file);
4634 newXS("Win32::GetLastError", w32_GetLastError, file);
4635 newXS("Win32::SetLastError", w32_SetLastError, file);
4636 newXS("Win32::LoginName", w32_LoginName, file);
4637 newXS("Win32::NodeName", w32_NodeName, file);
4638 newXS("Win32::DomainName", w32_DomainName, file);
4639 newXS("Win32::FsType", w32_FsType, file);
4640 newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
4641 newXS("Win32::IsWinNT", w32_IsWinNT, file);
4642 newXS("Win32::IsWin95", w32_IsWin95, file);
4643 newXS("Win32::FormatMessage", w32_FormatMessage, file);
4644 newXS("Win32::Spawn", w32_Spawn, file);
4645 newXS("Win32::GetTickCount", w32_GetTickCount, file);
4646 newXS("Win32::GetShortPathName", w32_GetShortPathName, file);
4647 newXS("Win32::GetFullPathName", w32_GetFullPathName, file);
4648 newXS("Win32::GetLongPathName", w32_GetLongPathName, file);
4649 newXS("Win32::CopyFile", w32_CopyFile, file);
4650 newXS("Win32::Sleep", w32_Sleep, file);
4651 newXS("Win32::SetChildShowWindow", w32_SetChildShowWindow, file);
4653 /* XXX Bloat Alert! The following Activeware preloads really
4654 * ought to be part of Win32::Sys::*, so they're not included
4657 /* LookupAccountName
4659 * InitiateSystemShutdown
4660 * AbortSystemShutdown
4661 * ExpandEnvrironmentStrings
4666 win32_signal_context(void)
4671 my_perl = PL_curinterp;
4672 PERL_SET_THX(my_perl);
4676 #ifdef USE_5005THREADS
4679 return PL_curinterp;
4686 win32_ctrlhandler(DWORD dwCtrlType)
4689 dTHXa(PERL_GET_SIG_CONTEXT);
4694 #ifdef USE_5005THREADS
4699 switch(dwCtrlType) {
4700 case CTRL_CLOSE_EVENT:
4701 /* A signal that the system sends to all processes attached to a console when
4702 the user closes the console (either by choosing the Close command from the
4703 console window's System menu, or by choosing the End Task command from the
4706 if (do_raise(aTHX_ 1)) /* SIGHUP */
4707 sig_terminate(aTHX_ 1);
4711 /* A CTRL+c signal was received */
4712 if (do_raise(aTHX_ SIGINT))
4713 sig_terminate(aTHX_ SIGINT);
4716 case CTRL_BREAK_EVENT:
4717 /* A CTRL+BREAK signal was received */
4718 if (do_raise(aTHX_ SIGBREAK))
4719 sig_terminate(aTHX_ SIGBREAK);
4722 case CTRL_LOGOFF_EVENT:
4723 /* A signal that the system sends to all console processes when a user is logging
4724 off. This signal does not indicate which user is logging off, so no
4725 assumptions can be made.
4728 case CTRL_SHUTDOWN_EVENT:
4729 /* A signal that the system sends to all console processes when the system is
4732 if (do_raise(aTHX_ SIGTERM))
4733 sig_terminate(aTHX_ SIGTERM);
4743 Perl_win32_init(int *argcp, char ***argvp)
4745 /* Disable floating point errors, Perl will trap the ones we
4746 * care about. VC++ RTL defaults to switching these off
4747 * already, but the Borland RTL doesn't. Since we don't
4748 * want to be at the vendor's whim on the default, we set
4749 * it explicitly here.
4751 #if !defined(_ALPHA_) && !defined(__GNUC__)
4752 _control87(MCW_EM, MCW_EM);
4758 win32_get_child_IO(child_IO_table* ptbl)
4760 ptbl->childStdIn = GetStdHandle(STD_INPUT_HANDLE);
4761 ptbl->childStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
4762 ptbl->childStdErr = GetStdHandle(STD_ERROR_HANDLE);
4766 win32_signal(int sig, Sighandler_t subcode)
4769 if (sig < SIG_SIZE) {
4770 int save_errno = errno;
4771 Sighandler_t result = signal(sig, subcode);
4772 if (result == SIG_ERR) {
4773 result = w32_sighandler[sig];
4776 w32_sighandler[sig] = subcode;
4786 #ifdef HAVE_INTERP_INTERN
4790 win32_csighandler(int sig)
4793 dTHXa(PERL_GET_SIG_CONTEXT);
4794 Perl_warn(aTHX_ "Got signal %d",sig);
4800 Perl_sys_intern_init(pTHX)
4803 w32_perlshell_tokens = Nullch;
4804 w32_perlshell_vec = (char**)NULL;
4805 w32_perlshell_items = 0;
4806 w32_fdpid = newAV();
4807 New(1313, w32_children, 1, child_tab);
4808 w32_num_children = 0;
4809 # ifdef USE_ITHREADS
4811 New(1313, w32_pseudo_children, 1, child_tab);
4812 w32_num_pseudo_children = 0;
4814 w32_init_socktype = 0;
4817 for (i=0; i < SIG_SIZE; i++) {
4818 w32_sighandler[i] = SIG_DFL;
4821 if (my_perl == PL_curinterp) {
4825 /* Force C runtime signal stuff to set its console handler */
4826 signal(SIGINT,&win32_csighandler);
4827 signal(SIGBREAK,&win32_csighandler);
4828 /* Push our handler on top */
4829 SetConsoleCtrlHandler(win32_ctrlhandler,TRUE);
4834 Perl_sys_intern_clear(pTHX)
4836 Safefree(w32_perlshell_tokens);
4837 Safefree(w32_perlshell_vec);
4838 /* NOTE: w32_fdpid is freed by sv_clean_all() */
4839 Safefree(w32_children);
4841 KillTimer(NULL,w32_timerid);
4844 # ifdef MULTIPLICITY
4845 if (my_perl == PL_curinterp) {
4849 SetConsoleCtrlHandler(win32_ctrlhandler,FALSE);
4851 # ifdef USE_ITHREADS
4852 Safefree(w32_pseudo_children);
4856 # ifdef USE_ITHREADS
4859 Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
4861 dst->perlshell_tokens = Nullch;
4862 dst->perlshell_vec = (char**)NULL;
4863 dst->perlshell_items = 0;
4864 dst->fdpid = newAV();
4865 Newz(1313, dst->children, 1, child_tab);
4867 Newz(1313, dst->pseudo_children, 1, child_tab);
4868 dst->thr_intern.Winit_socktype = 0;
4870 dst->poll_count = 0;
4871 Copy(src->sigtable,dst->sigtable,SIG_SIZE,Sighandler_t);
4873 # endif /* USE_ITHREADS */
4874 #endif /* HAVE_INTERP_INTERN */
4877 win32_free_argvw(pTHX_ void *ptr)
4879 char** argv = (char**)ptr;
4887 win32_argv2utf8(int argc, char** argv)
4892 LPWSTR* lpwStr = CommandLineToArgvW(GetCommandLineW(), &wargc);
4893 if (lpwStr && argc) {
4895 length = WideCharToMultiByte(CP_UTF8, 0, lpwStr[--wargc], -1, NULL, 0, NULL, NULL);
4896 Newz(0, psz, length, char);
4897 WideCharToMultiByte(CP_UTF8, 0, lpwStr[wargc], -1, psz, length, NULL, NULL);
4900 call_atexit(win32_free_argvw, argv);
4902 GlobalFree((HGLOBAL)lpwStr);