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