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