various fixes for race conditions under threads: mutex locks based
[p5sagit/p5-mst-13.2.git] / win32 / win32.c
CommitLineData
68dc0745 1/* WIN32.C
2 *
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.
6 *
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.
9 */
0a753a76 10
11#define WIN32_LEAN_AND_MEAN
12#define WIN32IO_IS_STDIO
13#include <tchar.h>
a835ef8a 14#ifdef __GNUC__
15#define Win32_Winsock
16#endif
0a753a76 17#include <windows.h>
18
e56670dd 19#ifndef __MINGW32__
9404a519 20#include <lmcons.h>
21#include <lmerr.h>
22/* ugliness to work around a buggy struct definition in lmwksta.h */
23#undef LPTSTR
24#define LPTSTR LPWSTR
25#include <lmwksta.h>
26#undef LPTSTR
27#define LPTSTR LPSTR
e56670dd 28#include <lmapibuf.h>
29#endif /* __MINGW32__ */
9404a519 30
68dc0745 31/* #include "config.h" */
0a753a76 32
33#define PERLIO_NOT_STDIO 0
34#if !defined(PERLIO_IS_STDIO) && !defined(USE_SFIO)
35#define PerlIO FILE
36#endif
37
38#include "EXTERN.h"
39#include "perl.h"
c69f6586 40
dc9e4912 41#include "patchlevel.h"
42
c69f6586 43#define NO_XSLOCKS
44#ifdef PERL_OBJECT
45extern CPerlObj* pPerl;
46#endif
ad2e33dc 47#include "XSUB.h"
c69f6586 48
49#include "Win32iop.h"
0a753a76 50#include <fcntl.h>
51#include <sys/stat.h>
5b0d9cbe 52#ifndef __GNUC__
53/* assert.h conflicts with #define of assert in perl.h */
0a753a76 54#include <assert.h>
5b0d9cbe 55#endif
0a753a76 56#include <string.h>
57#include <stdarg.h>
ad2e33dc 58#include <float.h>
ad0751ec 59#include <time.h>
3730b96e 60#if defined(_MSC_VER) || defined(__MINGW32__)
ad0751ec 61#include <sys/utime.h>
62#else
63#include <utime.h>
64#endif
0a753a76 65
5b0d9cbe 66#ifdef __GNUC__
67/* Mingw32 defaults to globing command line
68 * So we turn it off like this:
69 */
70int _CRT_glob = 0;
71#endif
72
6890e559 73#define EXECF_EXEC 1
74#define EXECF_SPAWN 2
75#define EXECF_SPAWN_NOWAIT 3
76
c69f6586 77#if defined(PERL_OBJECT)
e5a95ffb 78#undef win32_get_privlib
79#define win32_get_privlib g_win32_get_privlib
00dc2f4f 80#undef win32_get_sitelib
81#define win32_get_sitelib g_win32_get_sitelib
c69f6586 82#undef do_aspawn
83#define do_aspawn g_do_aspawn
84#undef do_spawn
85#define do_spawn g_do_spawn
86#undef do_exec
87#define do_exec g_do_exec
c69f6586 88#undef getlogin
89#define getlogin g_getlogin
90#endif
91
2d7a9237 92static DWORD os_id(void);
ce1da67e 93static void get_shell(void);
94static long tokenize(char *str, char **dest, char ***destv);
c69f6586 95 int do_spawn2(char *cmd, int exectype);
e200fe59 96static BOOL has_shell_metachars(char *ptr);
2d7a9237 97static long filetime_to_clock(PFILETIME ft);
ad0751ec 98static BOOL filetime_from_time(PFILETIME ft, time_t t);
e5a95ffb 99static char * get_emd_part(char *leading, char *trailing, ...);
f55ee38a 100static void remove_dead_process(HANDLE deceased);
c69f6586 101
2d7a9237 102HANDLE w32_perldll_handle = INVALID_HANDLE_VALUE;
4b556e6c 103static DWORD w32_platform = (DWORD)-1;
50892819 104
26618a56 105#ifdef USE_THREADS
106# ifdef USE_DECLSPEC_THREAD
107__declspec(thread) char strerror_buffer[512];
e34ffe5a 108__declspec(thread) char getlogin_buffer[128];
4b556e6c 109__declspec(thread) char w32_perllib_root[MAX_PATH+1];
26618a56 110# ifdef HAVE_DES_FCRYPT
111__declspec(thread) char crypt_buffer[30];
112# endif
113# else
114# define strerror_buffer (thr->i.Wstrerror_buffer)
e34ffe5a 115# define getlogin_buffer (thr->i.Wgetlogin_buffer)
4b556e6c 116# define w32_perllib_root (thr->i.Ww32_perllib_root)
26618a56 117# define crypt_buffer (thr->i.Wcrypt_buffer)
118# endif
119#else
4b556e6c 120static char strerror_buffer[512];
121static char getlogin_buffer[128];
122static char w32_perllib_root[MAX_PATH+1];
26618a56 123# ifdef HAVE_DES_FCRYPT
4b556e6c 124static char crypt_buffer[30];
26618a56 125# endif
126#endif
127
3fe9a6f1 128int
129IsWin95(void) {
2d7a9237 130 return (os_id() == VER_PLATFORM_WIN32_WINDOWS);
3fe9a6f1 131}
132
133int
134IsWinNT(void) {
2d7a9237 135 return (os_id() == VER_PLATFORM_WIN32_NT);
3fe9a6f1 136}
0a753a76 137
00dc2f4f 138char*
139GetRegStrFromKey(HKEY hkey, const char *lpszValueName, char** ptr, DWORD* lpDataLen)
140{ /* Retrieve a REG_SZ or REG_EXPAND_SZ from the registry */
141 HKEY handle;
142 DWORD type;
143 const char *subkey = "Software\\Perl";
144 long retval;
145
146 retval = RegOpenKeyEx(hkey, subkey, 0, KEY_READ, &handle);
ba3eb2af 147 if (retval == ERROR_SUCCESS){
00dc2f4f 148 retval = RegQueryValueEx(handle, lpszValueName, 0, &type, NULL, lpDataLen);
ba3eb2af 149 if (retval == ERROR_SUCCESS && type == REG_SZ) {
c934e9d4 150 if (*ptr) {
00dc2f4f 151 Renew(*ptr, *lpDataLen, char);
152 }
153 else {
154 New(1312, *ptr, *lpDataLen, char);
155 }
156 retval = RegQueryValueEx(handle, lpszValueName, 0, NULL, (PBYTE)*ptr, lpDataLen);
ba3eb2af 157 if (retval != ERROR_SUCCESS) {
e5a95ffb 158 Safefree(*ptr);
c934e9d4 159 *ptr = Nullch;
00dc2f4f 160 }
161 }
162 RegCloseKey(handle);
163 }
164 return *ptr;
165}
166
167char*
168GetRegStr(const char *lpszValueName, char** ptr, DWORD* lpDataLen)
169{
170 *ptr = GetRegStrFromKey(HKEY_CURRENT_USER, lpszValueName, ptr, lpDataLen);
c934e9d4 171 if (*ptr == Nullch)
00dc2f4f 172 {
173 *ptr = GetRegStrFromKey(HKEY_LOCAL_MACHINE, lpszValueName, ptr, lpDataLen);
174 }
175 return *ptr;
176}
177
e5a95ffb 178static char *
179get_emd_part(char *prev_path, char *trailing_path, ...)
00dc2f4f 180{
dc9e4912 181 char base[10];
e5a95ffb 182 va_list ap;
e24c7c18 183 char mod_name[MAX_PATH+1];
00dc2f4f 184 char *ptr;
e5a95ffb 185 char *optr;
186 char *strip;
187 int oldsize, newsize;
188
189 va_start(ap, trailing_path);
190 strip = va_arg(ap, char *);
191
dc9e4912 192 sprintf(base, "%5.3f", (double) 5 + ((double) PATCHLEVEL / (double) 1000));
193
123cbbb4 194 GetModuleFileName((w32_perldll_handle == INVALID_HANDLE_VALUE)
195 ? GetModuleHandle(NULL)
196 : w32_perldll_handle, mod_name, sizeof(mod_name));
e5a95ffb 197 ptr = strrchr(mod_name, '\\');
198 while (ptr && strip) {
199 /* look for directories to skip back */
200 optr = ptr;
00dc2f4f 201 *ptr = '\0';
e5a95ffb 202 ptr = strrchr(mod_name, '\\');
203 if (!ptr || stricmp(ptr+1, strip) != 0) {
204 *optr = '\\';
205 ptr = optr;
00dc2f4f 206 }
e5a95ffb 207 strip = va_arg(ap, char *);
00dc2f4f 208 }
e5a95ffb 209 if (!ptr) {
210 ptr = mod_name;
211 *ptr++ = '.';
00dc2f4f 212 *ptr = '\\';
213 }
e5a95ffb 214 va_end(ap);
215 strcpy(++ptr, trailing_path);
216
dc9e4912 217 /* only add directory if it exists */
218 if(GetFileAttributes(mod_name) != (DWORD) -1) {
219 /* directory exists */
220 newsize = strlen(mod_name) + 1;
221 if (prev_path) {
222 oldsize = strlen(prev_path) + 1;
223 newsize += oldsize; /* includes plus 1 for ';' */
224 Renew(prev_path, newsize, char);
225 prev_path[oldsize-1] = ';';
226 strcpy(&prev_path[oldsize], mod_name);
227 }
228 else {
229 New(1311, prev_path, newsize, char);
230 strcpy(prev_path, mod_name);
231 }
00dc2f4f 232 }
00dc2f4f 233
e5a95ffb 234 return prev_path;
00dc2f4f 235}
236
237char *
e5a95ffb 238win32_get_privlib(char *pl)
00dc2f4f 239{
e5a95ffb 240 char *stdlib = "lib";
241 char buffer[MAX_PATH+1];
242 char *path = Nullch;
243 DWORD datalen;
00dc2f4f 244
e5a95ffb 245 /* $stdlib = $HKCU{"lib-$]"} || $HKLM{"lib-$]"} || $HKCU{"lib"} || $HKLM{"lib"} || ""; */
246 sprintf(buffer, "%s-%s", stdlib, pl);
247 path = GetRegStr(buffer, &path, &datalen);
c934e9d4 248 if (!path)
e5a95ffb 249 path = GetRegStr(stdlib, &path, &datalen);
00dc2f4f 250
e5a95ffb 251 /* $stdlib .= ";$EMD/../../lib" */
252 return get_emd_part(path, stdlib, ARCHNAME, "bin", Nullch);
00dc2f4f 253}
254
68dc0745 255char *
00dc2f4f 256win32_get_sitelib(char *pl)
257{
e5a95ffb 258 char *sitelib = "sitelib";
259 char regstr[40];
e24c7c18 260 char pathstr[MAX_PATH+1];
e5a95ffb 261 DWORD datalen;
262 char *path1 = Nullch;
263 char *path2 = Nullch;
264 int len, newsize;
00dc2f4f 265
266 /* $HKCU{"sitelib-$]"} || $HKLM{"sitelib-$]"} . ---; */
e5a95ffb 267 sprintf(regstr, "%s-%s", sitelib, pl);
268 path1 = GetRegStr(regstr, &path1, &datalen);
269
270 /* $sitelib .=
271 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/site/$]/lib"; */
272 sprintf(pathstr, "site\\%s\\lib", pl);
273 path1 = get_emd_part(path1, pathstr, ARCHNAME, "bin", pl, Nullch);
00dc2f4f 274
275 /* $HKCU{'sitelib'} || $HKLM{'sitelib'} . ---; */
e5a95ffb 276 path2 = GetRegStr(sitelib, &path2, &datalen);
00dc2f4f 277
e5a95ffb 278 /* $sitelib .=
279 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/site/lib"; */
280 path2 = get_emd_part(path2, "site\\lib", ARCHNAME, "bin", pl, Nullch);
00dc2f4f 281
e5a95ffb 282 if (!path1)
283 return path2;
00dc2f4f 284
e5a95ffb 285 if (!path2)
286 return path1;
287
288 len = strlen(path1);
289 newsize = len + strlen(path2) + 2; /* plus one for ';' */
290
291 Renew(path1, newsize, char);
292 path1[len++] = ';';
293 strcpy(&path1[len], path2);
294
295 Safefree(path2);
296 return path1;
68dc0745 297}
0a753a76 298
b4793f7f 299
2d7a9237 300static BOOL
e200fe59 301has_shell_metachars(char *ptr)
68dc0745 302{
303 int inquote = 0;
304 char quote = '\0';
305
306 /*
307 * Scan string looking for redirection (< or >) or pipe
e200fe59 308 * characters (|) that are not in a quoted string.
309 * Shell variable interpolation (%VAR%) can also happen inside strings.
68dc0745 310 */
9404a519 311 while (*ptr) {
68dc0745 312 switch(*ptr) {
e200fe59 313 case '%':
314 return TRUE;
68dc0745 315 case '\'':
316 case '\"':
9404a519 317 if (inquote) {
318 if (quote == *ptr) {
68dc0745 319 inquote = 0;
320 quote = '\0';
0a753a76 321 }
68dc0745 322 }
323 else {
324 quote = *ptr;
325 inquote++;
326 }
327 break;
328 case '>':
329 case '<':
330 case '|':
9404a519 331 if (!inquote)
68dc0745 332 return TRUE;
333 default:
334 break;
0a753a76 335 }
68dc0745 336 ++ptr;
337 }
338 return FALSE;
0a753a76 339}
340
c69f6586 341#if !defined(PERL_OBJECT)
68dc0745 342/* since the current process environment is being updated in util.c
343 * the library functions will get the correct environment
344 */
345PerlIO *
346my_popen(char *cmd, char *mode)
0a753a76 347{
348#ifdef FIXCMD
68dc0745 349#define fixcmd(x) { \
350 char *pspace = strchr((x),' '); \
351 if (pspace) { \
352 char *p = (x); \
353 while (p < pspace) { \
354 if (*p == '/') \
355 *p = '\\'; \
356 p++; \
357 } \
358 } \
359 }
0a753a76 360#else
361#define fixcmd(x)
362#endif
68dc0745 363 fixcmd(cmd);
3e3baf6d 364 win32_fflush(stdout);
365 win32_fflush(stderr);
0a753a76 366 return win32_popen(cmd, mode);
0a753a76 367}
368
68dc0745 369long
370my_pclose(PerlIO *fp)
0a753a76 371{
372 return win32_pclose(fp);
373}
c69f6586 374#endif
0a753a76 375
8b10511d 376static DWORD
2d7a9237 377os_id(void)
0a753a76 378{
8b10511d 379 static OSVERSIONINFO osver;
0a753a76 380
2d7a9237 381 if (osver.dwPlatformId != w32_platform) {
8b10511d 382 memset(&osver, 0, sizeof(OSVERSIONINFO));
383 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
384 GetVersionEx(&osver);
2d7a9237 385 w32_platform = osver.dwPlatformId;
8b10511d 386 }
2d7a9237 387 return (w32_platform);
0a753a76 388}
389
ce1da67e 390/* Tokenize a string. Words are null-separated, and the list
391 * ends with a doubled null. Any character (except null and
392 * including backslash) may be escaped by preceding it with a
393 * backslash (the backslash will be stripped).
394 * Returns number of words in result buffer.
395 */
396static long
397tokenize(char *str, char **dest, char ***destv)
398{
399 char *retstart = Nullch;
400 char **retvstart = 0;
401 int items = -1;
402 if (str) {
403 int slen = strlen(str);
404 register char *ret;
405 register char **retv;
406 New(1307, ret, slen+2, char);
407 New(1308, retv, (slen+3)/2, char*);
408
409 retstart = ret;
410 retvstart = retv;
411 *retv = ret;
412 items = 0;
413 while (*str) {
414 *ret = *str++;
415 if (*ret == '\\' && *str)
416 *ret = *str++;
417 else if (*ret == ' ') {
418 while (*str == ' ')
419 str++;
420 if (ret == retstart)
421 ret--;
422 else {
423 *ret = '\0';
424 ++items;
425 if (*str)
426 *++retv = ret+1;
427 }
428 }
429 else if (!*str)
430 ++items;
431 ret++;
432 }
433 retvstart[items] = Nullch;
434 *ret++ = '\0';
435 *ret = '\0';
436 }
437 *dest = retstart;
438 *destv = retvstart;
439 return items;
440}
441
442static void
2d7a9237 443get_shell(void)
0a753a76 444{
ce1da67e 445 if (!w32_perlshell_tokens) {
174c211a 446 /* we don't use COMSPEC here for two reasons:
447 * 1. the same reason perl on UNIX doesn't use SHELL--rampant and
448 * uncontrolled unportability of the ensuing scripts.
449 * 2. PERL5SHELL could be set to a shell that may not be fit for
450 * interactive use (which is what most programs look in COMSPEC
451 * for).
452 */
ce1da67e 453 char* defaultshell = (IsWinNT() ? "cmd.exe /x/c" : "command.com /c");
454 char *usershell = getenv("PERL5SHELL");
455 w32_perlshell_items = tokenize(usershell ? usershell : defaultshell,
456 &w32_perlshell_tokens,
457 &w32_perlshell_vec);
68dc0745 458 }
0a753a76 459}
460
68dc0745 461int
2d7a9237 462do_aspawn(void *vreally, void **vmark, void **vsp)
0a753a76 463{
2d7a9237 464 SV *really = (SV*)vreally;
465 SV **mark = (SV**)vmark;
466 SV **sp = (SV**)vsp;
68dc0745 467 char **argv;
2d7a9237 468 char *str;
68dc0745 469 int status;
2d7a9237 470 int flag = P_WAIT;
68dc0745 471 int index = 0;
68dc0745 472
2d7a9237 473 if (sp <= mark)
474 return -1;
68dc0745 475
ce1da67e 476 get_shell();
477 New(1306, argv, (sp - mark) + w32_perlshell_items + 2, char*);
2d7a9237 478
479 if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
480 ++mark;
481 flag = SvIVx(*mark);
68dc0745 482 }
483
9404a519 484 while (++mark <= sp) {
6b88bc9c 485 if (*mark && (str = SvPV(*mark, PL_na)))
2d7a9237 486 argv[index++] = str;
487 else
488 argv[index++] = "";
68dc0745 489 }
490 argv[index++] = 0;
491
2d7a9237 492 status = win32_spawnvp(flag,
6b88bc9c 493 (const char*)(really ? SvPV(really,PL_na) : argv[0]),
2d7a9237 494 (const char* const*)argv);
495
496 if (status < 0 && errno == ENOEXEC) {
497 /* possible shell-builtin, invoke with shell */
ce1da67e 498 int sh_items;
499 sh_items = w32_perlshell_items;
2d7a9237 500 while (--index >= 0)
501 argv[index+sh_items] = argv[index];
ce1da67e 502 while (--sh_items >= 0)
503 argv[sh_items] = w32_perlshell_vec[sh_items];
2d7a9237 504
505 status = win32_spawnvp(flag,
6b88bc9c 506 (const char*)(really ? SvPV(really,PL_na) : argv[0]),
2d7a9237 507 (const char* const*)argv);
508 }
68dc0745 509
50892819 510 if (flag != P_NOWAIT) {
511 if (status < 0) {
b28d0864 512 if (PL_dowarn)
50892819 513 warn("Can't spawn \"%s\": %s", argv[0], strerror(errno));
514 status = 255 * 256;
515 }
516 else
517 status *= 256;
b28d0864 518 PL_statusvalue = status;
5aabfad6 519 }
ce1da67e 520 Safefree(argv);
50892819 521 return (status);
68dc0745 522}
523
c69f6586 524int
6890e559 525do_spawn2(char *cmd, int exectype)
68dc0745 526{
527 char **a;
528 char *s;
529 char **argv;
530 int status = -1;
531 BOOL needToTry = TRUE;
2d7a9237 532 char *cmd2;
68dc0745 533
2d7a9237 534 /* Save an extra exec if possible. See if there are shell
535 * metacharacters in it */
e200fe59 536 if (!has_shell_metachars(cmd)) {
fc36a67e 537 New(1301,argv, strlen(cmd) / 2 + 2, char*);
538 New(1302,cmd2, strlen(cmd) + 1, char);
68dc0745 539 strcpy(cmd2, cmd);
540 a = argv;
541 for (s = cmd2; *s;) {
542 while (*s && isspace(*s))
543 s++;
544 if (*s)
545 *(a++) = s;
9404a519 546 while (*s && !isspace(*s))
68dc0745 547 s++;
9404a519 548 if (*s)
68dc0745 549 *s++ = '\0';
0a753a76 550 }
68dc0745 551 *a = Nullch;
ce1da67e 552 if (argv[0]) {
6890e559 553 switch (exectype) {
554 case EXECF_SPAWN:
555 status = win32_spawnvp(P_WAIT, argv[0],
556 (const char* const*)argv);
557 break;
558 case EXECF_SPAWN_NOWAIT:
559 status = win32_spawnvp(P_NOWAIT, argv[0],
560 (const char* const*)argv);
561 break;
562 case EXECF_EXEC:
563 status = win32_execvp(argv[0], (const char* const*)argv);
564 break;
565 }
2d7a9237 566 if (status != -1 || errno == 0)
68dc0745 567 needToTry = FALSE;
0a753a76 568 }
0a753a76 569 Safefree(argv);
68dc0745 570 Safefree(cmd2);
571 }
2d7a9237 572 if (needToTry) {
ce1da67e 573 char **argv;
574 int i = -1;
575 get_shell();
576 New(1306, argv, w32_perlshell_items + 2, char*);
577 while (++i < w32_perlshell_items)
578 argv[i] = w32_perlshell_vec[i];
2d7a9237 579 argv[i++] = cmd;
580 argv[i] = Nullch;
6890e559 581 switch (exectype) {
582 case EXECF_SPAWN:
583 status = win32_spawnvp(P_WAIT, argv[0],
584 (const char* const*)argv);
585 break;
586 case EXECF_SPAWN_NOWAIT:
587 status = win32_spawnvp(P_NOWAIT, argv[0],
588 (const char* const*)argv);
589 break;
590 case EXECF_EXEC:
591 status = win32_execvp(argv[0], (const char* const*)argv);
592 break;
593 }
ce1da67e 594 cmd = argv[0];
595 Safefree(argv);
68dc0745 596 }
50892819 597 if (exectype != EXECF_SPAWN_NOWAIT) {
598 if (status < 0) {
b28d0864 599 if (PL_dowarn)
50892819 600 warn("Can't %s \"%s\": %s",
601 (exectype == EXECF_EXEC ? "exec" : "spawn"),
602 cmd, strerror(errno));
603 status = 255 * 256;
604 }
605 else
606 status *= 256;
b28d0864 607 PL_statusvalue = status;
5aabfad6 608 }
50892819 609 return (status);
0a753a76 610}
611
6890e559 612int
613do_spawn(char *cmd)
614{
615 return do_spawn2(cmd, EXECF_SPAWN);
616}
617
2d7a9237 618int
619do_spawn_nowait(char *cmd)
620{
621 return do_spawn2(cmd, EXECF_SPAWN_NOWAIT);
622}
623
6890e559 624bool
625do_exec(char *cmd)
626{
627 do_spawn2(cmd, EXECF_EXEC);
628 return FALSE;
629}
630
68dc0745 631/* The idea here is to read all the directory names into a string table
632 * (separated by nulls) and when one of the other dir functions is called
633 * return the pointer to the current file name.
634 */
635DIR *
ce2e26e5 636win32_opendir(char *filename)
0a753a76 637{
9404a519 638 DIR *p;
639 long len;
640 long idx;
641 char scanname[MAX_PATH+3];
642 struct stat sbuf;
643 WIN32_FIND_DATA FindData;
644 HANDLE fh;
645
646 len = strlen(filename);
647 if (len > MAX_PATH)
648 return NULL;
68dc0745 649
650 /* check to see if filename is a directory */
69d3ab13 651 if (win32_stat(filename, &sbuf) < 0 || !S_ISDIR(sbuf.st_mode))
24caa93f 652 return NULL;
68dc0745 653
68dc0745 654 /* Get us a DIR structure */
fc36a67e 655 Newz(1303, p, 1, DIR);
9404a519 656 if (p == NULL)
68dc0745 657 return NULL;
658
659 /* Create the search pattern */
660 strcpy(scanname, filename);
9404a519 661 if (scanname[len-1] != '/' && scanname[len-1] != '\\')
662 scanname[len++] = '/';
663 scanname[len++] = '*';
664 scanname[len] = '\0';
68dc0745 665
666 /* do the FindFirstFile call */
667 fh = FindFirstFile(scanname, &FindData);
9404a519 668 if (fh == INVALID_HANDLE_VALUE) {
21e72512 669 /* FindFirstFile() fails on empty drives! */
670 if (GetLastError() == ERROR_FILE_NOT_FOUND)
671 return p;
672 Safefree( p);
68dc0745 673 return NULL;
674 }
675
676 /* now allocate the first part of the string table for
677 * the filenames that we find.
678 */
679 idx = strlen(FindData.cFileName)+1;
fc36a67e 680 New(1304, p->start, idx, char);
9404a519 681 if (p->start == NULL)
65e48ea9 682 croak("opendir: malloc failed!\n");
68dc0745 683 strcpy(p->start, FindData.cFileName);
68dc0745 684 p->nfiles++;
685
686 /* loop finding all the files that match the wildcard
687 * (which should be all of them in this directory!).
688 * the variable idx should point one past the null terminator
689 * of the previous string found.
690 */
691 while (FindNextFile(fh, &FindData)) {
692 len = strlen(FindData.cFileName);
693 /* bump the string table size by enough for the
694 * new name and it's null terminator
695 */
696 Renew(p->start, idx+len+1, char);
9404a519 697 if (p->start == NULL)
65e48ea9 698 croak("opendir: malloc failed!\n");
68dc0745 699 strcpy(&p->start[idx], FindData.cFileName);
9404a519 700 p->nfiles++;
701 idx += len+1;
702 }
703 FindClose(fh);
704 p->size = idx;
705 p->curr = p->start;
706 return p;
0a753a76 707}
708
709
68dc0745 710/* Readdir just returns the current string pointer and bumps the
711 * string pointer to the nDllExport entry.
712 */
713struct direct *
ce2e26e5 714win32_readdir(DIR *dirp)
0a753a76 715{
68dc0745 716 int len;
717 static int dummy = 0;
0a753a76 718
68dc0745 719 if (dirp->curr) {
720 /* first set up the structure to return */
721 len = strlen(dirp->curr);
722 strcpy(dirp->dirstr.d_name, dirp->curr);
723 dirp->dirstr.d_namlen = len;
0a753a76 724
68dc0745 725 /* Fake an inode */
726 dirp->dirstr.d_ino = dummy++;
0a753a76 727
68dc0745 728 /* Now set up for the nDllExport call to readdir */
729 dirp->curr += len + 1;
730 if (dirp->curr >= (dirp->start + dirp->size)) {
731 dirp->curr = NULL;
732 }
0a753a76 733
68dc0745 734 return &(dirp->dirstr);
735 }
736 else
737 return NULL;
0a753a76 738}
739
68dc0745 740/* Telldir returns the current string pointer position */
741long
ce2e26e5 742win32_telldir(DIR *dirp)
0a753a76 743{
744 return (long) dirp->curr;
745}
746
747
68dc0745 748/* Seekdir moves the string pointer to a previously saved position
749 *(Saved by telldir).
750 */
751void
ce2e26e5 752win32_seekdir(DIR *dirp, long loc)
0a753a76 753{
754 dirp->curr = (char *)loc;
755}
756
68dc0745 757/* Rewinddir resets the string pointer to the start */
758void
ce2e26e5 759win32_rewinddir(DIR *dirp)
0a753a76 760{
761 dirp->curr = dirp->start;
762}
763
68dc0745 764/* free the memory allocated by opendir */
765int
ce2e26e5 766win32_closedir(DIR *dirp)
0a753a76 767{
768 Safefree(dirp->start);
769 Safefree(dirp);
68dc0745 770 return 1;
0a753a76 771}
772
773
68dc0745 774/*
775 * various stubs
776 */
0a753a76 777
778
68dc0745 779/* Ownership
780 *
781 * Just pretend that everyone is a superuser. NT will let us know if
782 * we don\'t really have permission to do something.
783 */
0a753a76 784
785#define ROOT_UID ((uid_t)0)
786#define ROOT_GID ((gid_t)0)
787
68dc0745 788uid_t
789getuid(void)
0a753a76 790{
68dc0745 791 return ROOT_UID;
0a753a76 792}
793
68dc0745 794uid_t
795geteuid(void)
0a753a76 796{
68dc0745 797 return ROOT_UID;
0a753a76 798}
799
68dc0745 800gid_t
801getgid(void)
0a753a76 802{
68dc0745 803 return ROOT_GID;
0a753a76 804}
805
68dc0745 806gid_t
807getegid(void)
0a753a76 808{
68dc0745 809 return ROOT_GID;
0a753a76 810}
811
68dc0745 812int
22239a37 813setuid(uid_t auid)
0a753a76 814{
22239a37 815 return (auid == ROOT_UID ? 0 : -1);
0a753a76 816}
817
68dc0745 818int
22239a37 819setgid(gid_t agid)
0a753a76 820{
22239a37 821 return (agid == ROOT_GID ? 0 : -1);
0a753a76 822}
823
e34ffe5a 824char *
825getlogin(void)
826{
827 dTHR;
828 char *buf = getlogin_buffer;
829 DWORD size = sizeof(getlogin_buffer);
830 if (GetUserName(buf,&size))
831 return buf;
832 return (char*)NULL;
833}
834
b990f8c8 835int
836chown(const char *path, uid_t owner, gid_t group)
837{
838 /* XXX noop */
1c1c7f20 839 return 0;
b990f8c8 840}
841
f55ee38a 842static void
843remove_dead_process(HANDLE deceased)
0a753a76 844{
f55ee38a 845#ifndef USE_RTL_WAIT
846 int child;
847 for (child = 0 ; child < w32_num_children ; ++child) {
848 if (w32_child_pids[child] == deceased) {
849 Copy(&w32_child_pids[child+1], &w32_child_pids[child],
850 (w32_num_children-child-1), HANDLE);
851 w32_num_children--;
852 break;
853 }
854 }
855#endif
856}
857
858DllExport int
859win32_kill(int pid, int sig)
860{
861#ifdef USE_RTL_WAIT
68dc0745 862 HANDLE hProcess= OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
f55ee38a 863#else
864 HANDLE hProcess = (HANDLE) pid;
865#endif
0a753a76 866
867 if (hProcess == NULL) {
65e48ea9 868 croak("kill process failed!\n");
68dc0745 869 }
870 else {
871 if (!TerminateProcess(hProcess, sig))
65e48ea9 872 croak("kill process failed!\n");
68dc0745 873 CloseHandle(hProcess);
f55ee38a 874
875 /* WaitForMultipleObjects() on a pid that was killed returns error
876 * so if we know the pid is gone we remove it from process list */
877 remove_dead_process(hProcess);
68dc0745 878 }
879 return 0;
0a753a76 880}
fbbbcc48 881
68dc0745 882/*
883 * File system stuff
884 */
0a753a76 885
f3986ebb 886DllExport unsigned int
887win32_sleep(unsigned int t)
0a753a76 888{
68dc0745 889 Sleep(t*1000);
890 return 0;
0a753a76 891}
892
68dc0745 893DllExport int
894win32_stat(const char *path, struct stat *buffer)
0a753a76 895{
24caa93f 896 char t[MAX_PATH+1];
68dc0745 897 const char *p = path;
898 int l = strlen(path);
67fbe06e 899 int res;
0a753a76 900
68dc0745 901 if (l > 1) {
902 switch(path[l - 1]) {
903 case '\\':
904 case '/':
905 if (path[l - 2] != ':') {
906 strncpy(t, path, l - 1);
907 t[l - 1] = 0;
908 p = t;
909 };
910 }
911 }
390b85e7 912 res = stat(p,buffer);
24caa93f 913 if (res < 0) {
914 /* CRT is buggy on sharenames, so make sure it really isn't.
915 * XXX using GetFileAttributesEx() will enable us to set
916 * buffer->st_*time (but note that's not available on the
917 * Windows of 1995) */
918 DWORD r = GetFileAttributes(p);
919 if (r != 0xffffffff && (r & FILE_ATTRIBUTE_DIRECTORY)) {
920 buffer->st_mode |= S_IFDIR | S_IREAD;
921 errno = 0;
922 if (!(r & FILE_ATTRIBUTE_READONLY))
923 buffer->st_mode |= S_IWRITE | S_IEXEC;
924 return 0;
925 }
926 }
24caa93f 927 else {
2293b0e9 928 if (l == 3 && path[l-2] == ':'
929 && (path[l-1] == '\\' || path[l-1] == '/'))
930 {
931 /* The drive can be inaccessible, some _stat()s are buggy */
932 if (!GetVolumeInformation(path,NULL,0,NULL,NULL,NULL,NULL,0)) {
933 errno = ENOENT;
934 return -1;
935 }
936 }
937#ifdef __BORLANDC__
67fbe06e 938 if (S_ISDIR(buffer->st_mode))
939 buffer->st_mode |= S_IWRITE | S_IEXEC;
940 else if (S_ISREG(buffer->st_mode)) {
941 if (l >= 4 && path[l-4] == '.') {
942 const char *e = path + l - 3;
943 if (strnicmp(e,"exe",3)
944 && strnicmp(e,"bat",3)
945 && strnicmp(e,"com",3)
946 && (IsWin95() || strnicmp(e,"cmd",3)))
947 buffer->st_mode &= ~S_IEXEC;
948 else
949 buffer->st_mode |= S_IEXEC;
950 }
951 else
952 buffer->st_mode &= ~S_IEXEC;
953 }
67fbe06e 954#endif
2293b0e9 955 }
67fbe06e 956 return res;
0a753a76 957}
958
0551aaa8 959#ifndef USE_WIN32_RTL_ENV
960
961DllExport char *
962win32_getenv(const char *name)
963{
c934e9d4 964 static char *curitem = Nullch; /* XXX threadead */
46124e9e 965 static DWORD curlen = 0; /* XXX threadead */
0551aaa8 966 DWORD needlen;
46124e9e 967 if (!curitem) {
968 curlen = 512;
0551aaa8 969 New(1305,curitem,curlen,char);
46124e9e 970 }
58a50f62 971
972 needlen = GetEnvironmentVariable(name,curitem,curlen);
973 if (needlen != 0) {
974 while (needlen > curlen) {
975 Renew(curitem,needlen,char);
976 curlen = needlen;
977 needlen = GetEnvironmentVariable(name,curitem,curlen);
978 }
0551aaa8 979 }
c934e9d4 980 else {
7a5f8e82 981 /* allow any environment variables that begin with 'PERL'
c934e9d4 982 to be stored in the registry */
983 if (curitem)
58a50f62 984 *curitem = '\0';
985
7a5f8e82 986 if (strncmp(name, "PERL", 4) == 0) {
c934e9d4 987 if (curitem) {
58a50f62 988 Safefree(curitem);
c934e9d4 989 curitem = Nullch;
46124e9e 990 curlen = 0;
58a50f62 991 }
00dc2f4f 992 curitem = GetRegStr(name, &curitem, &curlen);
58a50f62 993 }
c69f6586 994 }
c934e9d4 995 if (curitem && *curitem == '\0')
58a50f62 996 return Nullch;
997
0551aaa8 998 return curitem;
999}
1000
1001#endif
1002
d55594ae 1003static long
2d7a9237 1004filetime_to_clock(PFILETIME ft)
d55594ae 1005{
1006 __int64 qw = ft->dwHighDateTime;
1007 qw <<= 32;
1008 qw |= ft->dwLowDateTime;
1009 qw /= 10000; /* File time ticks at 0.1uS, clock at 1mS */
1010 return (long) qw;
1011}
1012
f3986ebb 1013DllExport int
1014win32_times(struct tms *timebuf)
0a753a76 1015{
d55594ae 1016 FILETIME user;
1017 FILETIME kernel;
1018 FILETIME dummy;
1019 if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy,
1020 &kernel,&user)) {
2d7a9237 1021 timebuf->tms_utime = filetime_to_clock(&user);
1022 timebuf->tms_stime = filetime_to_clock(&kernel);
d55594ae 1023 timebuf->tms_cutime = 0;
1024 timebuf->tms_cstime = 0;
1025
1026 } else {
1027 /* That failed - e.g. Win95 fallback to clock() */
1028 clock_t t = clock();
1029 timebuf->tms_utime = t;
1030 timebuf->tms_stime = 0;
1031 timebuf->tms_cutime = 0;
1032 timebuf->tms_cstime = 0;
1033 }
68dc0745 1034 return 0;
0a753a76 1035}
1036
ad0751ec 1037/* fix utime() so it works on directories in NT
1038 * thanks to Jan Dubois <jan.dubois@ibm.net>
1039 */
1040static BOOL
1041filetime_from_time(PFILETIME pFileTime, time_t Time)
1042{
1043 struct tm *pTM = gmtime(&Time);
1044 SYSTEMTIME SystemTime;
1045
1046 if (pTM == NULL)
1047 return FALSE;
1048
1049 SystemTime.wYear = pTM->tm_year + 1900;
1050 SystemTime.wMonth = pTM->tm_mon + 1;
1051 SystemTime.wDay = pTM->tm_mday;
1052 SystemTime.wHour = pTM->tm_hour;
1053 SystemTime.wMinute = pTM->tm_min;
1054 SystemTime.wSecond = pTM->tm_sec;
1055 SystemTime.wMilliseconds = 0;
1056
1057 return SystemTimeToFileTime(&SystemTime, pFileTime);
1058}
1059
1060DllExport int
3b405fc5 1061win32_utime(const char *filename, struct utimbuf *times)
ad0751ec 1062{
1063 HANDLE handle;
1064 FILETIME ftCreate;
1065 FILETIME ftAccess;
1066 FILETIME ftWrite;
1067 struct utimbuf TimeBuffer;
1068
1069 int rc = utime(filename,times);
1070 /* EACCES: path specifies directory or readonly file */
1071 if (rc == 0 || errno != EACCES /* || !IsWinNT() */)
1072 return rc;
1073
1074 if (times == NULL) {
1075 times = &TimeBuffer;
1076 time(&times->actime);
1077 times->modtime = times->actime;
1078 }
1079
1080 /* This will (and should) still fail on readonly files */
1081 handle = CreateFile(filename, GENERIC_READ | GENERIC_WRITE,
1082 FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
1083 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1084 if (handle == INVALID_HANDLE_VALUE)
1085 return rc;
1086
1087 if (GetFileTime(handle, &ftCreate, &ftAccess, &ftWrite) &&
1088 filetime_from_time(&ftAccess, times->actime) &&
1089 filetime_from_time(&ftWrite, times->modtime) &&
1090 SetFileTime(handle, &ftCreate, &ftAccess, &ftWrite))
1091 {
1092 rc = 0;
1093 }
1094
1095 CloseHandle(handle);
1096 return rc;
1097}
1098
2d7a9237 1099DllExport int
f55ee38a 1100win32_waitpid(int pid, int *status, int flags)
1101{
1102 int rc;
1103 if (pid == -1)
1104 return win32_wait(status);
1105 else {
1106 rc = cwait(status, pid, WAIT_CHILD);
8f1e745d 1107 /* cwait() returns "correctly" on Borland */
1108#ifndef __BORLANDC__
f55ee38a 1109 if (status)
8f1e745d 1110 *status *= 256;
f55ee38a 1111#endif
1112 remove_dead_process((HANDLE)pid);
1113 }
1114 return rc >= 0 ? pid : rc;
1115}
1116
1117DllExport int
2d7a9237 1118win32_wait(int *status)
1119{
4b556e6c 1120#ifdef USE_RTL_WAIT
2d7a9237 1121 return wait(status);
1122#else
1123 /* XXX this wait emulation only knows about processes
1124 * spawned via win32_spawnvp(P_NOWAIT, ...).
1125 */
1126 int i, retval;
1127 DWORD exitcode, waitcode;
1128
1129 if (!w32_num_children) {
1130 errno = ECHILD;
1131 return -1;
1132 }
1133
1134 /* if a child exists, wait for it to die */
1135 waitcode = WaitForMultipleObjects(w32_num_children,
1136 w32_child_pids,
1137 FALSE,
1138 INFINITE);
1139 if (waitcode != WAIT_FAILED) {
1140 if (waitcode >= WAIT_ABANDONED_0
1141 && waitcode < WAIT_ABANDONED_0 + w32_num_children)
1142 i = waitcode - WAIT_ABANDONED_0;
1143 else
1144 i = waitcode - WAIT_OBJECT_0;
1145 if (GetExitCodeProcess(w32_child_pids[i], &exitcode) ) {
1146 CloseHandle(w32_child_pids[i]);
1147 *status = (int)((exitcode & 0xff) << 8);
1148 retval = (int)w32_child_pids[i];
1149 Copy(&w32_child_pids[i+1], &w32_child_pids[i],
1150 (w32_num_children-i-1), HANDLE);
1151 w32_num_children--;
1152 return retval;
1153 }
1154 }
1155
1156FAILED:
1157 errno = GetLastError();
1158 return -1;
1159
1160#endif
1161}
d55594ae 1162
2d7a9237 1163static UINT timerid = 0;
d55594ae 1164
1165static VOID CALLBACK TimerProc(HWND win, UINT msg, UINT id, DWORD time)
1166{
1167 KillTimer(NULL,timerid);
1168 timerid=0;
1169 sighandler(14);
1170}
1171
f3986ebb 1172DllExport unsigned int
1173win32_alarm(unsigned int sec)
0a753a76 1174{
d55594ae 1175 /*
1176 * the 'obvious' implentation is SetTimer() with a callback
1177 * which does whatever receiving SIGALRM would do
1178 * we cannot use SIGALRM even via raise() as it is not
1179 * one of the supported codes in <signal.h>
1180 *
1181 * Snag is unless something is looking at the message queue
1182 * nothing happens :-(
1183 */
1184 if (sec)
1185 {
1186 timerid = SetTimer(NULL,timerid,sec*1000,(TIMERPROC)TimerProc);
1187 if (!timerid)
1188 croak("Cannot set timer");
1189 }
1190 else
1191 {
1192 if (timerid)
1193 {
1194 KillTimer(NULL,timerid);
1195 timerid=0;
1196 }
1197 }
68dc0745 1198 return 0;
0a753a76 1199}
1200
ff95b63e 1201#if defined(HAVE_DES_FCRYPT) || defined(PERL_OBJECT)
26618a56 1202#ifdef HAVE_DES_FCRYPT
2d77217b 1203extern char * des_fcrypt(const char *txt, const char *salt, char *cbuf);
ff95b63e 1204#endif
26618a56 1205
1206DllExport char *
1207win32_crypt(const char *txt, const char *salt)
1208{
ff95b63e 1209#ifdef HAVE_DES_FCRYPT
26618a56 1210 dTHR;
2d77217b 1211 return des_fcrypt(txt, salt, crypt_buffer);
ff95b63e 1212#else
1213 die("The crypt() function is unimplemented due to excessive paranoia.");
b8957cf1 1214 return Nullch;
ff95b63e 1215#endif
26618a56 1216}
1217#endif
1218
f3986ebb 1219#ifdef USE_FIXED_OSFHANDLE
390b85e7 1220
1221EXTERN_C int __cdecl _alloc_osfhnd(void);
1222EXTERN_C int __cdecl _set_osfhnd(int fh, long value);
1223EXTERN_C void __cdecl _lock_fhandle(int);
1224EXTERN_C void __cdecl _unlock_fhandle(int);
1225EXTERN_C void __cdecl _unlock(int);
1226
1227#if (_MSC_VER >= 1000)
1228typedef struct {
1229 long osfhnd; /* underlying OS file HANDLE */
1230 char osfile; /* attributes of file (e.g., open in text mode?) */
1231 char pipech; /* one char buffer for handles opened on pipes */
1232#if defined (_MT) && !defined (DLL_FOR_WIN32S)
1233 int lockinitflag;
1234 CRITICAL_SECTION lock;
1235#endif /* defined (_MT) && !defined (DLL_FOR_WIN32S) */
1236} ioinfo;
1237
1238EXTERN_C ioinfo * __pioinfo[];
1239
1240#define IOINFO_L2E 5
1241#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
1242#define _pioinfo(i) (__pioinfo[i >> IOINFO_L2E] + (i & (IOINFO_ARRAY_ELTS - 1)))
1243#define _osfile(i) (_pioinfo(i)->osfile)
1244
1245#else /* (_MSC_VER >= 1000) */
1246extern char _osfile[];
1247#endif /* (_MSC_VER >= 1000) */
1248
1249#define FOPEN 0x01 /* file handle open */
1250#define FAPPEND 0x20 /* file handle opened O_APPEND */
1251#define FDEV 0x40 /* file handle refers to device */
1252#define FTEXT 0x80 /* file handle is in text mode */
1253
1254#define _STREAM_LOCKS 26 /* Table of stream locks */
1255#define _LAST_STREAM_LOCK (_STREAM_LOCKS+_NSTREAM_-1) /* Last stream lock */
1256#define _FH_LOCKS (_LAST_STREAM_LOCK+1) /* Table of fh locks */
1257
1258/***
1259*int my_open_osfhandle(long osfhandle, int flags) - open C Runtime file handle
1260*
1261*Purpose:
1262* This function allocates a free C Runtime file handle and associates
1263* it with the Win32 HANDLE specified by the first parameter. This is a
1264* temperary fix for WIN95's brain damage GetFileType() error on socket
1265* we just bypass that call for socket
1266*
1267*Entry:
1268* long osfhandle - Win32 HANDLE to associate with C Runtime file handle.
1269* int flags - flags to associate with C Runtime file handle.
1270*
1271*Exit:
1272* returns index of entry in fh, if successful
1273* return -1, if no free entry is found
1274*
1275*Exceptions:
1276*
1277*******************************************************************************/
1278
1279static int
1280my_open_osfhandle(long osfhandle, int flags)
1281{
1282 int fh;
1283 char fileflags; /* _osfile flags */
1284
1285 /* copy relevant flags from second parameter */
1286 fileflags = FDEV;
1287
9404a519 1288 if (flags & O_APPEND)
390b85e7 1289 fileflags |= FAPPEND;
1290
9404a519 1291 if (flags & O_TEXT)
390b85e7 1292 fileflags |= FTEXT;
1293
1294 /* attempt to allocate a C Runtime file handle */
9404a519 1295 if ((fh = _alloc_osfhnd()) == -1) {
390b85e7 1296 errno = EMFILE; /* too many open files */
1297 _doserrno = 0L; /* not an OS error */
1298 return -1; /* return error to caller */
1299 }
1300
1301 /* the file is open. now, set the info in _osfhnd array */
1302 _set_osfhnd(fh, osfhandle);
1303
1304 fileflags |= FOPEN; /* mark as open */
1305
1306#if (_MSC_VER >= 1000)
1307 _osfile(fh) = fileflags; /* set osfile entry */
1308 _unlock_fhandle(fh);
1309#else
1310 _osfile[fh] = fileflags; /* set osfile entry */
1311 _unlock(fh+_FH_LOCKS); /* unlock handle */
1312#endif
1313
1314 return fh; /* return handle */
1315}
1316
1317#define _open_osfhandle my_open_osfhandle
f3986ebb 1318#endif /* USE_FIXED_OSFHANDLE */
390b85e7 1319
1320/* simulate flock by locking a range on the file */
1321
1322#define LK_ERR(f,i) ((f) ? (i = 0) : (errno = GetLastError()))
1323#define LK_LEN 0xffff0000
1324
f3986ebb 1325DllExport int
1326win32_flock(int fd, int oper)
390b85e7 1327{
1328 OVERLAPPED o;
1329 int i = -1;
1330 HANDLE fh;
1331
f3986ebb 1332 if (!IsWinNT()) {
1333 croak("flock() unimplemented on this platform");
1334 return -1;
1335 }
390b85e7 1336 fh = (HANDLE)_get_osfhandle(fd);
1337 memset(&o, 0, sizeof(o));
1338
1339 switch(oper) {
1340 case LOCK_SH: /* shared lock */
1341 LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, 0, &o),i);
1342 break;
1343 case LOCK_EX: /* exclusive lock */
1344 LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o),i);
1345 break;
1346 case LOCK_SH|LOCK_NB: /* non-blocking shared lock */
1347 LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o),i);
1348 break;
1349 case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */
1350 LK_ERR(LockFileEx(fh,
1351 LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
1352 0, LK_LEN, 0, &o),i);
1353 break;
1354 case LOCK_UN: /* unlock lock */
1355 LK_ERR(UnlockFileEx(fh, 0, LK_LEN, 0, &o),i);
1356 break;
1357 default: /* unknown */
1358 errno = EINVAL;
1359 break;
1360 }
1361 return i;
1362}
1363
1364#undef LK_ERR
1365#undef LK_LEN
1366
68dc0745 1367/*
1368 * redirected io subsystem for all XS modules
1369 *
1370 */
0a753a76 1371
68dc0745 1372DllExport int *
1373win32_errno(void)
0a753a76 1374{
390b85e7 1375 return (&errno);
0a753a76 1376}
1377
dcb2879a 1378DllExport char ***
1379win32_environ(void)
1380{
390b85e7 1381 return (&(_environ));
dcb2879a 1382}
1383
68dc0745 1384/* the rest are the remapped stdio routines */
1385DllExport FILE *
1386win32_stderr(void)
0a753a76 1387{
390b85e7 1388 return (stderr);
0a753a76 1389}
1390
68dc0745 1391DllExport FILE *
1392win32_stdin(void)
0a753a76 1393{
390b85e7 1394 return (stdin);
0a753a76 1395}
1396
68dc0745 1397DllExport FILE *
1398win32_stdout()
0a753a76 1399{
390b85e7 1400 return (stdout);
0a753a76 1401}
1402
68dc0745 1403DllExport int
1404win32_ferror(FILE *fp)
0a753a76 1405{
390b85e7 1406 return (ferror(fp));
0a753a76 1407}
1408
1409
68dc0745 1410DllExport int
1411win32_feof(FILE *fp)
0a753a76 1412{
390b85e7 1413 return (feof(fp));
0a753a76 1414}
1415
68dc0745 1416/*
1417 * Since the errors returned by the socket error function
1418 * WSAGetLastError() are not known by the library routine strerror
1419 * we have to roll our own.
1420 */
0a753a76 1421
68dc0745 1422DllExport char *
1423win32_strerror(int e)
0a753a76 1424{
3e3baf6d 1425#ifndef __BORLANDC__ /* Borland intolerance */
68dc0745 1426 extern int sys_nerr;
3e3baf6d 1427#endif
68dc0745 1428 DWORD source = 0;
0a753a76 1429
9404a519 1430 if (e < 0 || e > sys_nerr) {
c53bd28a 1431 dTHR;
9404a519 1432 if (e < 0)
68dc0745 1433 e = GetLastError();
0a753a76 1434
9404a519 1435 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0,
68dc0745 1436 strerror_buffer, sizeof(strerror_buffer), NULL) == 0)
1437 strcpy(strerror_buffer, "Unknown Error");
0a753a76 1438
68dc0745 1439 return strerror_buffer;
1440 }
390b85e7 1441 return strerror(e);
0a753a76 1442}
1443
22fae026 1444DllExport void
3730b96e 1445win32_str_os_error(void *sv, DWORD dwErr)
22fae026 1446{
1447 DWORD dwLen;
1448 char *sMsg;
1449 dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
1450 |FORMAT_MESSAGE_IGNORE_INSERTS
1451 |FORMAT_MESSAGE_FROM_SYSTEM, NULL,
1452 dwErr, 0, (char *)&sMsg, 1, NULL);
1453 if (0 < dwLen) {
1454 while (0 < dwLen && isspace(sMsg[--dwLen]))
1455 ;
1456 if ('.' != sMsg[dwLen])
1457 dwLen++;
1458 sMsg[dwLen]= '\0';
1459 }
1460 if (0 == dwLen) {
c69f6586 1461 sMsg = (char*)LocalAlloc(0, 64/**sizeof(TCHAR)*/);
22fae026 1462 dwLen = sprintf(sMsg,
1463 "Unknown error #0x%lX (lookup 0x%lX)",
1464 dwErr, GetLastError());
1465 }
3730b96e 1466 sv_setpvn((SV*)sv, sMsg, dwLen);
22fae026 1467 LocalFree(sMsg);
1468}
1469
1470
68dc0745 1471DllExport int
1472win32_fprintf(FILE *fp, const char *format, ...)
0a753a76 1473{
68dc0745 1474 va_list marker;
1475 va_start(marker, format); /* Initialize variable arguments. */
0a753a76 1476
390b85e7 1477 return (vfprintf(fp, format, marker));
0a753a76 1478}
1479
68dc0745 1480DllExport int
1481win32_printf(const char *format, ...)
0a753a76 1482{
68dc0745 1483 va_list marker;
1484 va_start(marker, format); /* Initialize variable arguments. */
0a753a76 1485
390b85e7 1486 return (vprintf(format, marker));
0a753a76 1487}
1488
68dc0745 1489DllExport int
1490win32_vfprintf(FILE *fp, const char *format, va_list args)
0a753a76 1491{
390b85e7 1492 return (vfprintf(fp, format, args));
0a753a76 1493}
1494
96e4d5b1 1495DllExport int
1496win32_vprintf(const char *format, va_list args)
1497{
390b85e7 1498 return (vprintf(format, args));
96e4d5b1 1499}
1500
68dc0745 1501DllExport size_t
1502win32_fread(void *buf, size_t size, size_t count, FILE *fp)
0a753a76 1503{
390b85e7 1504 return fread(buf, size, count, fp);
0a753a76 1505}
1506
68dc0745 1507DllExport size_t
1508win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
0a753a76 1509{
390b85e7 1510 return fwrite(buf, size, count, fp);
0a753a76 1511}
1512
68dc0745 1513DllExport FILE *
1514win32_fopen(const char *filename, const char *mode)
0a753a76 1515{
68dc0745 1516 if (stricmp(filename, "/dev/null")==0)
390b85e7 1517 return fopen("NUL", mode);
1518 return fopen(filename, mode);
0a753a76 1519}
1520
f3986ebb 1521#ifndef USE_SOCKETS_AS_HANDLES
1522#undef fdopen
1523#define fdopen my_fdopen
1524#endif
1525
68dc0745 1526DllExport FILE *
1527win32_fdopen( int handle, const char *mode)
0a753a76 1528{
390b85e7 1529 return fdopen(handle, (char *) mode);
0a753a76 1530}
1531
68dc0745 1532DllExport FILE *
1533win32_freopen( const char *path, const char *mode, FILE *stream)
0a753a76 1534{
68dc0745 1535 if (stricmp(path, "/dev/null")==0)
390b85e7 1536 return freopen("NUL", mode, stream);
1537 return freopen(path, mode, stream);
0a753a76 1538}
1539
68dc0745 1540DllExport int
1541win32_fclose(FILE *pf)
0a753a76 1542{
f3986ebb 1543 return my_fclose(pf); /* defined in win32sck.c */
0a753a76 1544}
1545
68dc0745 1546DllExport int
1547win32_fputs(const char *s,FILE *pf)
0a753a76 1548{
390b85e7 1549 return fputs(s, pf);
0a753a76 1550}
1551
68dc0745 1552DllExport int
1553win32_fputc(int c,FILE *pf)
0a753a76 1554{
390b85e7 1555 return fputc(c,pf);
0a753a76 1556}
1557
68dc0745 1558DllExport int
1559win32_ungetc(int c,FILE *pf)
0a753a76 1560{
390b85e7 1561 return ungetc(c,pf);
0a753a76 1562}
1563
68dc0745 1564DllExport int
1565win32_getc(FILE *pf)
0a753a76 1566{
390b85e7 1567 return getc(pf);
0a753a76 1568}
1569
68dc0745 1570DllExport int
1571win32_fileno(FILE *pf)
0a753a76 1572{
390b85e7 1573 return fileno(pf);
0a753a76 1574}
1575
68dc0745 1576DllExport void
1577win32_clearerr(FILE *pf)
0a753a76 1578{
390b85e7 1579 clearerr(pf);
68dc0745 1580 return;
0a753a76 1581}
1582
68dc0745 1583DllExport int
1584win32_fflush(FILE *pf)
0a753a76 1585{
390b85e7 1586 return fflush(pf);
0a753a76 1587}
1588
68dc0745 1589DllExport long
1590win32_ftell(FILE *pf)
0a753a76 1591{
390b85e7 1592 return ftell(pf);
0a753a76 1593}
1594
68dc0745 1595DllExport int
1596win32_fseek(FILE *pf,long offset,int origin)
0a753a76 1597{
390b85e7 1598 return fseek(pf, offset, origin);
0a753a76 1599}
1600
68dc0745 1601DllExport int
1602win32_fgetpos(FILE *pf,fpos_t *p)
0a753a76 1603{
390b85e7 1604 return fgetpos(pf, p);
0a753a76 1605}
1606
68dc0745 1607DllExport int
1608win32_fsetpos(FILE *pf,const fpos_t *p)
0a753a76 1609{
390b85e7 1610 return fsetpos(pf, p);
0a753a76 1611}
1612
68dc0745 1613DllExport void
1614win32_rewind(FILE *pf)
0a753a76 1615{
390b85e7 1616 rewind(pf);
68dc0745 1617 return;
0a753a76 1618}
1619
68dc0745 1620DllExport FILE*
1621win32_tmpfile(void)
0a753a76 1622{
390b85e7 1623 return tmpfile();
0a753a76 1624}
1625
68dc0745 1626DllExport void
1627win32_abort(void)
0a753a76 1628{
390b85e7 1629 abort();
68dc0745 1630 return;
0a753a76 1631}
1632
68dc0745 1633DllExport int
22239a37 1634win32_fstat(int fd,struct stat *sbufptr)
0a753a76 1635{
22239a37 1636 return fstat(fd,sbufptr);
0a753a76 1637}
1638
68dc0745 1639DllExport int
1640win32_pipe(int *pfd, unsigned int size, int mode)
0a753a76 1641{
390b85e7 1642 return _pipe(pfd, size, mode);
0a753a76 1643}
1644
50892819 1645/*
1646 * a popen() clone that respects PERL5SHELL
1647 */
1648
68dc0745 1649DllExport FILE*
1650win32_popen(const char *command, const char *mode)
0a753a76 1651{
4b556e6c 1652#ifdef USE_RTL_POPEN
390b85e7 1653 return _popen(command, mode);
50892819 1654#else
1655 int p[2];
1656 int parent, child;
1657 int stdfd, oldfd;
1658 int ourmode;
1659 int childpid;
1660
1661 /* establish which ends read and write */
1662 if (strchr(mode,'w')) {
1663 stdfd = 0; /* stdin */
1664 parent = 1;
1665 child = 0;
1666 }
1667 else if (strchr(mode,'r')) {
1668 stdfd = 1; /* stdout */
1669 parent = 0;
1670 child = 1;
1671 }
1672 else
1673 return NULL;
1674
1675 /* set the correct mode */
1676 if (strchr(mode,'b'))
1677 ourmode = O_BINARY;
1678 else if (strchr(mode,'t'))
1679 ourmode = O_TEXT;
1680 else
1681 ourmode = _fmode & (O_TEXT | O_BINARY);
1682
1683 /* the child doesn't inherit handles */
1684 ourmode |= O_NOINHERIT;
1685
1686 if (win32_pipe( p, 512, ourmode) == -1)
1687 return NULL;
1688
1689 /* save current stdfd */
1690 if ((oldfd = win32_dup(stdfd)) == -1)
1691 goto cleanup;
1692
1693 /* make stdfd go to child end of pipe (implicitly closes stdfd) */
1694 /* stdfd will be inherited by the child */
1695 if (win32_dup2(p[child], stdfd) == -1)
1696 goto cleanup;
1697
1698 /* close the child end in parent */
1699 win32_close(p[child]);
1700
1701 /* start the child */
1702 if ((childpid = do_spawn_nowait((char*)command)) == -1)
1703 goto cleanup;
1704
1705 /* revert stdfd to whatever it was before */
1706 if (win32_dup2(oldfd, stdfd) == -1)
1707 goto cleanup;
1708
1709 /* close saved handle */
1710 win32_close(oldfd);
1711
4b556e6c 1712 sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid);
50892819 1713
1714 /* we have an fd, return a file stream */
1715 return (win32_fdopen(p[parent], (char *)mode));
1716
1717cleanup:
1718 /* we don't need to check for errors here */
1719 win32_close(p[0]);
1720 win32_close(p[1]);
1721 if (oldfd != -1) {
1722 win32_dup2(oldfd, stdfd);
1723 win32_close(oldfd);
1724 }
1725 return (NULL);
1726
4b556e6c 1727#endif /* USE_RTL_POPEN */
0a753a76 1728}
1729
50892819 1730/*
1731 * pclose() clone
1732 */
1733
68dc0745 1734DllExport int
1735win32_pclose(FILE *pf)
0a753a76 1736{
4b556e6c 1737#ifdef USE_RTL_POPEN
390b85e7 1738 return _pclose(pf);
50892819 1739#else
50892819 1740
e17cb2a9 1741 int childpid, status;
1742 SV *sv;
1743
4b556e6c 1744 sv = *av_fetch(w32_fdpid, win32_fileno(pf), TRUE);
e17cb2a9 1745 if (SvIOK(sv))
1746 childpid = SvIVX(sv);
1747 else
1748 childpid = 0;
50892819 1749
1750 if (!childpid) {
1751 errno = EBADF;
1752 return -1;
1753 }
1754
1755 win32_fclose(pf);
e17cb2a9 1756 SvIVX(sv) = 0;
1757
f55ee38a 1758 remove_dead_process((HANDLE)childpid);
50892819 1759
1760 /* wait for the child */
1761 if (cwait(&status, childpid, WAIT_CHILD) == -1)
1762 return (-1);
8f1e745d 1763 /* cwait() returns "correctly" on Borland */
1764#ifndef __BORLANDC__
1765 status *= 256;
50892819 1766#endif
8f1e745d 1767 return (status);
50892819 1768
4b556e6c 1769#endif /* USE_RTL_POPEN */
0a753a76 1770}
1771
68dc0745 1772DllExport int
8d9b2e3c 1773win32_rename(const char *oname, const char *newname)
e24c7c18 1774{
1775 char szNewWorkName[MAX_PATH+1];
1776 WIN32_FIND_DATA fdOldFile, fdNewFile;
1777 HANDLE handle;
1778 char *ptr;
1779
8d9b2e3c 1780 if ((strchr(oname, '\\') || strchr(oname, '/'))
e24c7c18 1781 && strchr(newname, '\\') == NULL
1782 && strchr(newname, '/') == NULL)
1783 {
8d9b2e3c 1784 strcpy(szNewWorkName, oname);
e24c7c18 1785 if ((ptr = strrchr(szNewWorkName, '\\')) == NULL)
1786 ptr = strrchr(szNewWorkName, '/');
1787 strcpy(++ptr, newname);
1788 }
1789 else
1790 strcpy(szNewWorkName, newname);
1791
8d9b2e3c 1792 if (stricmp(oname, szNewWorkName) != 0) {
e24c7c18 1793 // check that we're not being fooled by relative paths
1794 // and only delete the new file
1795 // 1) if it exists
1796 // 2) it is not the same file as the old file
1797 // 3) old file exist
1798 // GetFullPathName does not return the long file name on some systems
8d9b2e3c 1799 handle = FindFirstFile(oname, &fdOldFile);
e24c7c18 1800 if (handle != INVALID_HANDLE_VALUE) {
1801 FindClose(handle);
1802
1803 handle = FindFirstFile(szNewWorkName, &fdNewFile);
1804
1805 if (handle != INVALID_HANDLE_VALUE)
1806 FindClose(handle);
1807 else
1808 fdNewFile.cFileName[0] = '\0';
1809
1810 if (strcmp(fdOldFile.cAlternateFileName,
1811 fdNewFile.cAlternateFileName) != 0
1812 && strcmp(fdOldFile.cFileName, fdNewFile.cFileName) != 0)
1813 {
1814 // file exists and not same file
1815 DeleteFile(szNewWorkName);
1816 }
1817 }
1818 }
8d9b2e3c 1819 return rename(oname, newname);
e24c7c18 1820}
1821
1822DllExport int
68dc0745 1823win32_setmode(int fd, int mode)
0a753a76 1824{
390b85e7 1825 return setmode(fd, mode);
0a753a76 1826}
1827
96e4d5b1 1828DllExport long
1829win32_lseek(int fd, long offset, int origin)
1830{
390b85e7 1831 return lseek(fd, offset, origin);
96e4d5b1 1832}
1833
1834DllExport long
1835win32_tell(int fd)
1836{
390b85e7 1837 return tell(fd);
96e4d5b1 1838}
1839
68dc0745 1840DllExport int
1841win32_open(const char *path, int flag, ...)
0a753a76 1842{
68dc0745 1843 va_list ap;
1844 int pmode;
0a753a76 1845
1846 va_start(ap, flag);
1847 pmode = va_arg(ap, int);
1848 va_end(ap);
1849
68dc0745 1850 if (stricmp(path, "/dev/null")==0)
390b85e7 1851 return open("NUL", flag, pmode);
1852 return open(path,flag,pmode);
0a753a76 1853}
1854
68dc0745 1855DllExport int
1856win32_close(int fd)
0a753a76 1857{
390b85e7 1858 return close(fd);
0a753a76 1859}
1860
68dc0745 1861DllExport int
96e4d5b1 1862win32_eof(int fd)
1863{
390b85e7 1864 return eof(fd);
96e4d5b1 1865}
1866
1867DllExport int
68dc0745 1868win32_dup(int fd)
0a753a76 1869{
390b85e7 1870 return dup(fd);
0a753a76 1871}
1872
68dc0745 1873DllExport int
1874win32_dup2(int fd1,int fd2)
0a753a76 1875{
390b85e7 1876 return dup2(fd1,fd2);
0a753a76 1877}
1878
68dc0745 1879DllExport int
3e3baf6d 1880win32_read(int fd, void *buf, unsigned int cnt)
0a753a76 1881{
390b85e7 1882 return read(fd, buf, cnt);
0a753a76 1883}
1884
68dc0745 1885DllExport int
3e3baf6d 1886win32_write(int fd, const void *buf, unsigned int cnt)
0a753a76 1887{
390b85e7 1888 return write(fd, buf, cnt);
0a753a76 1889}
1890
68dc0745 1891DllExport int
5aabfad6 1892win32_mkdir(const char *dir, int mode)
1893{
390b85e7 1894 return mkdir(dir); /* just ignore mode */
5aabfad6 1895}
96e4d5b1 1896
5aabfad6 1897DllExport int
1898win32_rmdir(const char *dir)
1899{
390b85e7 1900 return rmdir(dir);
5aabfad6 1901}
96e4d5b1 1902
5aabfad6 1903DllExport int
1904win32_chdir(const char *dir)
1905{
390b85e7 1906 return chdir(dir);
5aabfad6 1907}
96e4d5b1 1908
5aabfad6 1909DllExport int
3e3baf6d 1910win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
0a753a76 1911{
2d7a9237 1912 int status;
1913
4b556e6c 1914#ifndef USE_RTL_WAIT
e17cb2a9 1915 if (mode == P_NOWAIT && w32_num_children >= MAXIMUM_WAIT_OBJECTS)
1916 return -1;
1917#endif
1918
2d7a9237 1919 status = spawnvp(mode, cmdname, (char * const *) argv);
4b556e6c 1920#ifndef USE_RTL_WAIT
2d7a9237 1921 /* XXX For the P_NOWAIT case, Borland RTL returns pinfo.dwProcessId
1922 * while VC RTL returns pinfo.hProcess. For purposes of the custom
1923 * implementation of win32_wait(), we assume the latter.
1924 */
1925 if (mode == P_NOWAIT && status >= 0)
1926 w32_child_pids[w32_num_children++] = (HANDLE)status;
1927#endif
1928 return status;
0a753a76 1929}
1930
6890e559 1931DllExport int
eb62e965 1932win32_execv(const char *cmdname, const char *const *argv)
1933{
1934 return execv(cmdname, (char *const *)argv);
1935}
1936
1937DllExport int
6890e559 1938win32_execvp(const char *cmdname, const char *const *argv)
1939{
390b85e7 1940 return execvp(cmdname, (char *const *)argv);
6890e559 1941}
1942
84902520 1943DllExport void
1944win32_perror(const char *str)
1945{
390b85e7 1946 perror(str);
84902520 1947}
1948
1949DllExport void
1950win32_setbuf(FILE *pf, char *buf)
1951{
390b85e7 1952 setbuf(pf, buf);
84902520 1953}
1954
1955DllExport int
1956win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
1957{
390b85e7 1958 return setvbuf(pf, buf, type, size);
84902520 1959}
1960
1961DllExport int
1962win32_flushall(void)
1963{
390b85e7 1964 return flushall();
84902520 1965}
1966
1967DllExport int
1968win32_fcloseall(void)
1969{
390b85e7 1970 return fcloseall();
84902520 1971}
1972
1973DllExport char*
1974win32_fgets(char *s, int n, FILE *pf)
1975{
390b85e7 1976 return fgets(s, n, pf);
84902520 1977}
1978
1979DllExport char*
1980win32_gets(char *s)
1981{
390b85e7 1982 return gets(s);
84902520 1983}
1984
1985DllExport int
1986win32_fgetc(FILE *pf)
1987{
390b85e7 1988 return fgetc(pf);
84902520 1989}
1990
1991DllExport int
1992win32_putc(int c, FILE *pf)
1993{
390b85e7 1994 return putc(c,pf);
84902520 1995}
1996
1997DllExport int
1998win32_puts(const char *s)
1999{
390b85e7 2000 return puts(s);
84902520 2001}
2002
2003DllExport int
2004win32_getchar(void)
2005{
390b85e7 2006 return getchar();
84902520 2007}
2008
2009DllExport int
2010win32_putchar(int c)
2011{
390b85e7 2012 return putchar(c);
84902520 2013}
2014
bbc8f9de 2015#ifdef MYMALLOC
2016
2017#ifndef USE_PERL_SBRK
2018
2019static char *committed = NULL;
2020static char *base = NULL;
2021static char *reserved = NULL;
2022static char *brk = NULL;
2023static DWORD pagesize = 0;
2024static DWORD allocsize = 0;
2025
2026void *
2027sbrk(int need)
2028{
2029 void *result;
2030 if (!pagesize)
2031 {SYSTEM_INFO info;
2032 GetSystemInfo(&info);
2033 /* Pretend page size is larger so we don't perpetually
2034 * call the OS to commit just one page ...
2035 */
2036 pagesize = info.dwPageSize << 3;
2037 allocsize = info.dwAllocationGranularity;
2038 }
2039 /* This scheme fails eventually if request for contiguous
2040 * block is denied so reserve big blocks - this is only
2041 * address space not memory ...
2042 */
2043 if (brk+need >= reserved)
2044 {
2045 DWORD size = 64*1024*1024;
2046 char *addr;
2047 if (committed && reserved && committed < reserved)
2048 {
2049 /* Commit last of previous chunk cannot span allocations */
161b471a 2050 addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
bbc8f9de 2051 if (addr)
2052 committed = reserved;
2053 }
2054 /* Reserve some (more) space
2055 * Note this is a little sneaky, 1st call passes NULL as reserved
2056 * so lets system choose where we start, subsequent calls pass
2057 * the old end address so ask for a contiguous block
2058 */
161b471a 2059 addr = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
bbc8f9de 2060 if (addr)
2061 {
2062 reserved = addr+size;
2063 if (!base)
2064 base = addr;
2065 if (!committed)
2066 committed = base;
2067 if (!brk)
2068 brk = committed;
2069 }
2070 else
2071 {
2072 return (void *) -1;
2073 }
2074 }
2075 result = brk;
2076 brk += need;
2077 if (brk > committed)
2078 {
2079 DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
161b471a 2080 char *addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
bbc8f9de 2081 if (addr)
2082 {
2083 committed += size;
2084 }
2085 else
2086 return (void *) -1;
2087 }
2088 return result;
2089}
2090
2091#endif
2092#endif
2093
84902520 2094DllExport void*
2095win32_malloc(size_t size)
2096{
390b85e7 2097 return malloc(size);
84902520 2098}
2099
2100DllExport void*
2101win32_calloc(size_t numitems, size_t size)
2102{
390b85e7 2103 return calloc(numitems,size);
84902520 2104}
2105
2106DllExport void*
2107win32_realloc(void *block, size_t size)
2108{
390b85e7 2109 return realloc(block,size);
84902520 2110}
2111
2112DllExport void
2113win32_free(void *block)
2114{
390b85e7 2115 free(block);
84902520 2116}
2117
bbc8f9de 2118
68dc0745 2119int
65e48ea9 2120win32_open_osfhandle(long handle, int flags)
0a753a76 2121{
390b85e7 2122 return _open_osfhandle(handle, flags);
0a753a76 2123}
2124
68dc0745 2125long
65e48ea9 2126win32_get_osfhandle(int fd)
0a753a76 2127{
390b85e7 2128 return _get_osfhandle(fd);
0a753a76 2129}
7bac28a0 2130
7bac28a0 2131/*
2132 * Extras.
2133 */
2134
ad2e33dc 2135static
2136XS(w32_GetCwd)
2137{
2138 dXSARGS;
2139 SV *sv = sv_newmortal();
2140 /* Make one call with zero size - return value is required size */
2141 DWORD len = GetCurrentDirectory((DWORD)0,NULL);
2142 SvUPGRADE(sv,SVt_PV);
2143 SvGROW(sv,len);
2144 SvCUR(sv) = GetCurrentDirectory((DWORD) SvLEN(sv), SvPVX(sv));
2145 /*
2146 * If result != 0
2147 * then it worked, set PV valid,
2148 * else leave it 'undef'
2149 */
2150 if (SvCUR(sv))
2151 SvPOK_on(sv);
50892819 2152 EXTEND(SP,1);
ad2e33dc 2153 ST(0) = sv;
2154 XSRETURN(1);
2155}
2156
2157static
2158XS(w32_SetCwd)
2159{
2160 dXSARGS;
2161 if (items != 1)
2162 croak("usage: Win32::SetCurrentDirectory($cwd)");
6b88bc9c 2163 if (SetCurrentDirectory(SvPV(ST(0),PL_na)))
ad2e33dc 2164 XSRETURN_YES;
2165
2166 XSRETURN_NO;
2167}
2168
2169static
2170XS(w32_GetNextAvailDrive)
2171{
2172 dXSARGS;
2173 char ix = 'C';
2174 char root[] = "_:\\";
2175 while (ix <= 'Z') {
2176 root[0] = ix++;
2177 if (GetDriveType(root) == 1) {
2178 root[2] = '\0';
2179 XSRETURN_PV(root);
2180 }
2181 }
2182 XSRETURN_UNDEF;
2183}
2184
2185static
2186XS(w32_GetLastError)
2187{
2188 dXSARGS;
2189 XSRETURN_IV(GetLastError());
2190}
2191
2192static
2193XS(w32_LoginName)
2194{
2195 dXSARGS;
e34ffe5a 2196 char *name = getlogin_buffer;
2197 DWORD size = sizeof(getlogin_buffer);
ad2e33dc 2198 if (GetUserName(name,&size)) {
2199 /* size includes NULL */
2200 ST(0) = sv_2mortal(newSVpv(name,size-1));
2201 XSRETURN(1);
2202 }
2203 XSRETURN_UNDEF;
2204}
2205
2206static
2207XS(w32_NodeName)
2208{
2209 dXSARGS;
2210 char name[MAX_COMPUTERNAME_LENGTH+1];
2211 DWORD size = sizeof(name);
2212 if (GetComputerName(name,&size)) {
2213 /* size does NOT include NULL :-( */
2214 ST(0) = sv_2mortal(newSVpv(name,size));
2215 XSRETURN(1);
2216 }
2217 XSRETURN_UNDEF;
2218}
2219
2220
2221static
2222XS(w32_DomainName)
2223{
2224 dXSARGS;
8c9208bc 2225#ifndef HAS_NETWKSTAGETINFO
2226 /* mingw32 (and Win95) don't have NetWksta*(), so do it the old way */
ad2e33dc 2227 char name[256];
2228 DWORD size = sizeof(name);
2229 if (GetUserName(name,&size)) {
2230 char sid[1024];
2231 DWORD sidlen = sizeof(sid);
2232 char dname[256];
2233 DWORD dnamelen = sizeof(dname);
2234 SID_NAME_USE snu;
db15561c 2235 if (LookupAccountName(NULL, name, (PSID)&sid, &sidlen,
ad2e33dc 2236 dname, &dnamelen, &snu)) {
2237 XSRETURN_PV(dname); /* all that for this */
2238 }
2239 }
e56670dd 2240#else
8c9208bc 2241 /* this way is more reliable, in case user has a local account.
2242 * XXX need dynamic binding of netapi32.dll symbols or this will fail on
2243 * Win95. Probably makes more sense to move it into libwin32. */
9404a519 2244 char dname[256];
2245 DWORD dnamelen = sizeof(dname);
0a2408cf 2246 PWKSTA_INFO_100 pwi;
2247 if (NERR_Success == NetWkstaGetInfo(NULL, 100, (LPBYTE*)&pwi)) {
2248 if (pwi->wki100_langroup && *(pwi->wki100_langroup)) {
2249 WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_langroup,
2250 -1, (LPSTR)dname, dnamelen, NULL, NULL);
2251 }
2252 else {
2253 WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_computername,
2254 -1, (LPSTR)dname, dnamelen, NULL, NULL);
2255 }
2256 NetApiBufferFree(pwi);
9404a519 2257 XSRETURN_PV(dname);
2258 }
e56670dd 2259#endif
ad2e33dc 2260 XSRETURN_UNDEF;
2261}
2262
2263static
2264XS(w32_FsType)
2265{
2266 dXSARGS;
2267 char fsname[256];
2268 DWORD flags, filecomplen;
2269 if (GetVolumeInformation(NULL, NULL, 0, NULL, &filecomplen,
2270 &flags, fsname, sizeof(fsname))) {
2271 if (GIMME == G_ARRAY) {
2272 XPUSHs(sv_2mortal(newSVpv(fsname,0)));
2273 XPUSHs(sv_2mortal(newSViv(flags)));
2274 XPUSHs(sv_2mortal(newSViv(filecomplen)));
2275 PUTBACK;
2276 return;
2277 }
2278 XSRETURN_PV(fsname);
2279 }
2280 XSRETURN_UNDEF;
2281}
2282
2283static
2284XS(w32_GetOSVersion)
2285{
2286 dXSARGS;
2287 OSVERSIONINFO osver;
2288
2289 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
2290 if (GetVersionEx(&osver)) {
2291 XPUSHs(newSVpv(osver.szCSDVersion, 0));
2292 XPUSHs(newSViv(osver.dwMajorVersion));
2293 XPUSHs(newSViv(osver.dwMinorVersion));
2294 XPUSHs(newSViv(osver.dwBuildNumber));
2295 XPUSHs(newSViv(osver.dwPlatformId));
2296 PUTBACK;
2297 return;
2298 }
2299 XSRETURN_UNDEF;
2300}
2301
2302static
2303XS(w32_IsWinNT)
2304{
2305 dXSARGS;
2306 XSRETURN_IV(IsWinNT());
2307}
2308
2309static
2310XS(w32_IsWin95)
2311{
2312 dXSARGS;
2313 XSRETURN_IV(IsWin95());
2314}
2315
2316static
2317XS(w32_FormatMessage)
2318{
2319 dXSARGS;
2320 DWORD source = 0;
2321 char msgbuf[1024];
2322
2323 if (items != 1)
2324 croak("usage: Win32::FormatMessage($errno)");
2325
2326 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
2327 &source, SvIV(ST(0)), 0,
2328 msgbuf, sizeof(msgbuf)-1, NULL))
2329 XSRETURN_PV(msgbuf);
2330
2331 XSRETURN_UNDEF;
2332}
2333
2334static
2335XS(w32_Spawn)
2336{
2337 dXSARGS;
2338 char *cmd, *args;
2339 PROCESS_INFORMATION stProcInfo;
2340 STARTUPINFO stStartInfo;
2341 BOOL bSuccess = FALSE;
2342
9404a519 2343 if (items != 3)
ad2e33dc 2344 croak("usage: Win32::Spawn($cmdName, $args, $PID)");
2345
6b88bc9c 2346 cmd = SvPV(ST(0),PL_na);
2347 args = SvPV(ST(1), PL_na);
ad2e33dc 2348
2349 memset(&stStartInfo, 0, sizeof(stStartInfo)); /* Clear the block */
2350 stStartInfo.cb = sizeof(stStartInfo); /* Set the structure size */
2351 stStartInfo.dwFlags = STARTF_USESHOWWINDOW; /* Enable wShowWindow control */
2352 stStartInfo.wShowWindow = SW_SHOWMINNOACTIVE; /* Start min (normal) */
2353
9404a519 2354 if (CreateProcess(
ad2e33dc 2355 cmd, /* Image path */
2356 args, /* Arguments for command line */
2357 NULL, /* Default process security */
2358 NULL, /* Default thread security */
2359 FALSE, /* Must be TRUE to use std handles */
2360 NORMAL_PRIORITY_CLASS, /* No special scheduling */
2361 NULL, /* Inherit our environment block */
2362 NULL, /* Inherit our currrent directory */
2363 &stStartInfo, /* -> Startup info */
2364 &stProcInfo)) /* <- Process info (if OK) */
2365 {
2366 CloseHandle(stProcInfo.hThread);/* library source code does this. */
2367 sv_setiv(ST(2), stProcInfo.dwProcessId);
2368 bSuccess = TRUE;
2369 }
2370 XSRETURN_IV(bSuccess);
2371}
2372
2373static
2374XS(w32_GetTickCount)
2375{
2376 dXSARGS;
2377 XSRETURN_IV(GetTickCount());
2378}
2379
2380static
2381XS(w32_GetShortPathName)
2382{
2383 dXSARGS;
2384 SV *shortpath;
e8bab181 2385 DWORD len;
ad2e33dc 2386
9404a519 2387 if (items != 1)
ad2e33dc 2388 croak("usage: Win32::GetShortPathName($longPathName)");
2389
2390 shortpath = sv_mortalcopy(ST(0));
2391 SvUPGRADE(shortpath, SVt_PV);
2392 /* src == target is allowed */
e8bab181 2393 do {
2394 len = GetShortPathName(SvPVX(shortpath),
2395 SvPVX(shortpath),
2396 SvLEN(shortpath));
2397 } while (len >= SvLEN(shortpath) && sv_grow(shortpath,len+1));
2398 if (len) {
2399 SvCUR_set(shortpath,len);
ad2e33dc 2400 ST(0) = shortpath;
e8bab181 2401 }
ad2e33dc 2402 else
6b88bc9c 2403 ST(0) = &PL_sv_undef;
ad2e33dc 2404 XSRETURN(1);
2405}
2406
ad0751ec 2407static
2408XS(w32_Sleep)
2409{
2410 dXSARGS;
2411 if (items != 1)
2412 croak("usage: Win32::Sleep($milliseconds)");
2413 Sleep(SvIV(ST(0)));
2414 XSRETURN_YES;
2415}
2416
ad2e33dc 2417void
f3986ebb 2418Perl_init_os_extras()
ad2e33dc 2419{
2420 char *file = __FILE__;
2421 dXSUB_SYS;
2422
4b556e6c 2423 w32_perlshell_tokens = Nullch;
2424 w32_perlshell_items = -1;
2425 w32_fdpid = newAV(); /* XXX needs to be in Perl_win32_init()? */
2426#ifndef USE_RTL_WAIT
2427 w32_num_children = 0;
2428#endif
2429
ad2e33dc 2430 /* these names are Activeware compatible */
2431 newXS("Win32::GetCwd", w32_GetCwd, file);
2432 newXS("Win32::SetCwd", w32_SetCwd, file);
2433 newXS("Win32::GetNextAvailDrive", w32_GetNextAvailDrive, file);
2434 newXS("Win32::GetLastError", w32_GetLastError, file);
2435 newXS("Win32::LoginName", w32_LoginName, file);
2436 newXS("Win32::NodeName", w32_NodeName, file);
2437 newXS("Win32::DomainName", w32_DomainName, file);
2438 newXS("Win32::FsType", w32_FsType, file);
2439 newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
2440 newXS("Win32::IsWinNT", w32_IsWinNT, file);
2441 newXS("Win32::IsWin95", w32_IsWin95, file);
2442 newXS("Win32::FormatMessage", w32_FormatMessage, file);
2443 newXS("Win32::Spawn", w32_Spawn, file);
2444 newXS("Win32::GetTickCount", w32_GetTickCount, file);
2445 newXS("Win32::GetShortPathName", w32_GetShortPathName, file);
ad0751ec 2446 newXS("Win32::Sleep", w32_Sleep, file);
ad2e33dc 2447
2448 /* XXX Bloat Alert! The following Activeware preloads really
2449 * ought to be part of Win32::Sys::*, so they're not included
2450 * here.
2451 */
2452 /* LookupAccountName
2453 * LookupAccountSID
2454 * InitiateSystemShutdown
2455 * AbortSystemShutdown
2456 * ExpandEnvrironmentStrings
2457 */
2458}
2459
2460void
2461Perl_win32_init(int *argcp, char ***argvp)
2462{
2463 /* Disable floating point errors, Perl will trap the ones we
2464 * care about. VC++ RTL defaults to switching these off
2465 * already, but the Borland RTL doesn't. Since we don't
2466 * want to be at the vendor's whim on the default, we set
2467 * it explicitly here.
2468 */
a835ef8a 2469#if !defined(_ALPHA_) && !defined(__GNUC__)
ad2e33dc 2470 _control87(MCW_EM, MCW_EM);
3dc9191e 2471#endif
4b556e6c 2472 MALLOC_INIT;
ad2e33dc 2473}
d55594ae 2474
a868473f 2475#ifdef USE_BINMODE_SCRIPTS
2476
2477void
2478win32_strip_return(SV *sv)
2479{
2480 char *s = SvPVX(sv);
2481 char *e = s+SvCUR(sv);
2482 char *d = s;
2483 while (s < e)
2484 {
2485 if (*s == '\r' && s[1] == '\n')
2486 {
2487 *d++ = '\n';
2488 s += 2;
2489 }
2490 else
2491 {
2492 *d++ = *s++;
2493 }
2494 }
2495 SvCUR_set(sv,d-SvPVX(sv));
2496}
2497
2498#endif