DEFINITIONS
This source file includes following functions.
- CreateSignal
- SetSignal
- ResetSignal
- CreateSignal
- SetSignal
- ResetSignal
- IdOS
- IsWin95
- IsWinNT
- IsWinNT
- IsWin95
- GetCurrentThreadHandle
- flock_winnt
- flock_win95
- flock
- NtInitialize
- getlogin
- FindFirstChildSlot
- FindChildSlot
- CloseChildHandle
- FindFreeChildSlot
- SafeFree
- isInternalCmd
- rb_w32_get_osfhandle
- pipe_exec
- do_spawn
- CreateChild
- NtFreeCmdLine
- insert
- NtCmdGlob
- NtHasRedirection
- NtMakeCmdVector
- rb_w32_opendir
- rb_w32_readdir
- rb_w32_telldir
- rb_w32_seekdir
- rb_w32_rewinddir
- rb_w32_closedir
- valid_filename
- MTHREAD_ONLY
- STHREAD_ONLY
- MTHREAD_ONLY
- STHREAD_ONLY
- MTHREAD_ONLY
- STHREAD_ONLY
- rb_w32_open_osfhandle
- is_socket
- rb_w32_fddup
- rb_w32_fdclose
- rb_w32_strerror
- getuid
- geteuid
- getgid
- getegid
- setuid
- setgid
- ioctl
- rb_w32_fdset
- rb_w32_fdclr
- rb_w32_fdisset
- extract_file_fd
- rb_w32_select
- StartSockets
- rb_w32_accept
- rb_w32_bind
- rb_w32_connect
- rb_w32_getpeername
- rb_w32_getsockname
- rb_w32_getsockopt
- rb_w32_ioctlsocket
- rb_w32_listen
- rb_w32_recv
- rb_w32_recvfrom
- rb_w32_send
- rb_w32_sendto
- rb_w32_setsockopt
- rb_w32_shutdown
- rb_w32_socket
- rb_w32_gethostbyaddr
- rb_w32_gethostbyname
- rb_w32_gethostname
- rb_w32_getprotobyname
- rb_w32_getprotobynumber
- rb_w32_getservbyname
- rb_w32_getservbyport
- endhostent
- endnetent
- endprotoent
- endservent
- getnetent
- getnetbyaddr
- getnetbyname
- getprotoent
- getservent
- sethostent
- setnetent
- setprotoent
- setservent
- poll_child_status
- waitpid
- gettimeofday
- rb_w32_getcwd
- str_grow
- chown
- kill
- link
- wait
- rb_w32_getenv
- rb_w32_rename
- isUNCRoot
- rb_w32_stat
- filetime_to_clock
- rb_w32_times
- wait_events
- system_state
- rb_w32_enter_critical
- rb_w32_leave_critical
- rb_w32_call_handler
- setup_handler
- setup_call
- rb_w32_main_context
- rb_w32_sleep
- catch_interrupt
- rb_w32_getc
- rb_w32_putc
- call_asynchronous
- rb_w32_asynchronize
- rb_w32_get_environ
- rb_w32_free_environ
- rb_w32_getpid
1
2
3
4
5
6
7
8
9
10
11
12
13 #include "ruby.h"
14 #include "rubysig.h"
15 #include <fcntl.h>
16 #include <process.h>
17 #include <sys/stat.h>
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <errno.h>
22 #include <assert.h>
23
24 #include <windows.h>
25 #include <winbase.h>
26 #include <wincon.h>
27 #ifdef __MINGW32__
28 #include <mswsock.h>
29 #endif
30 #include "win32.h"
31 #include "win32/dir.h"
32 #ifndef index
33 #define index(x, y) strchr((x), (y))
34 #endif
35 #define isdirsep(x) ((x) == '/' || (x) == '\\')
36 #undef stat
37
38 #ifndef bool
39 #define bool int
40 #endif
41
42 #ifdef _M_IX86
43 # define WIN95 1
44 #else
45 # undef WIN95
46 #endif
47
48 #ifdef __BORLANDC__
49 # define _filbuf _fgetc
50 # define _flsbuf fputc
51 #endif
52
53 #if HAVE_WSAWAITFORMULTIPLEEVENTS
54 # define USE_INTERRUPT_WINSOCK
55 #endif
56
57 #if USE_INTERRUPT_WINSOCK
58 # define WaitForMultipleEvents WSAWaitForMultipleEvents
59 # define CreateSignal() (HANDLE)WSACreateEvent()
60 # define SetSignal(ev) WSASetEvent(ev)
61 # define ResetSignal(ev) WSAResetEvent(ev)
62 #else
63 # define WaitForMultipleEvents WaitForMultipleObjectsEx
64 # define CreateSignal() CreateEvent(NULL, FALSE, FALSE, NULL);
65 # define SetSignal(ev) SetEvent(ev)
66 # define ResetSignal(ev) (void)0
67 #endif
68
69 #ifdef WIN32_DEBUG
70 #define Debug(something) something
71 #else
72 #define Debug(something)
73 #endif
74
75 #define TO_SOCKET(x) _get_osfhandle(x)
76
77 bool NtSyncProcess = TRUE;
78
79 static struct ChildRecord *CreateChild(char *, SECURITY_ATTRIBUTES *, HANDLE, HANDLE, HANDLE);
80 static bool NtHasRedirection (char *);
81 static int valid_filename(char *s);
82 static void StartSockets ();
83 static char *str_grow(struct RString *str, size_t new_size);
84 static DWORD wait_events(HANDLE event, DWORD timeout);
85 #ifndef __BORLANDC__
86 static int rb_w32_open_osfhandle(long osfhandle, int flags);
87 #endif
88
89 char *NTLoginName;
90
91 #ifdef WIN95
92 DWORD Win32System = (DWORD)-1;
93
94 static DWORD
95 IdOS(void)
96 {
97 static OSVERSIONINFO osver;
98
99 if (osver.dwPlatformId != Win32System) {
100 memset(&osver, 0, sizeof(OSVERSIONINFO));
101 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
102 GetVersionEx(&osver);
103 Win32System = osver.dwPlatformId;
104 }
105 return (Win32System);
106 }
107
108 static int
109 IsWin95(void) {
110 return (IdOS() == VER_PLATFORM_WIN32_WINDOWS);
111 }
112
113 static int
114 IsWinNT(void) {
115 return (IdOS() == VER_PLATFORM_WIN32_NT);
116 }
117 #else
118 # define IsWinNT() TRUE
119 # define IsWin95() FALSE
120 #endif
121
122
123 static struct {
124 HANDLE handle;
125 DWORD id;
126 } main_thread;
127
128
129 static HANDLE interrupted_event;
130
131 HANDLE GetCurrentThreadHandle(void)
132 {
133 static HANDLE current_process_handle = NULL;
134 HANDLE h;
135
136 if (!current_process_handle)
137 current_process_handle = GetCurrentProcess();
138 if (!DuplicateHandle(current_process_handle, GetCurrentThread(),
139 current_process_handle, &h,
140 0, FALSE, DUPLICATE_SAME_ACCESS))
141 return NULL;
142 return h;
143 }
144
145
146
147
148 #define LK_ERR(f,i) ((f) ? (i = 0) : (errno = GetLastError()))
149 #define LK_LEN 0xffff0000
150
151 static VALUE
152 flock_winnt(VALUE self, int argc, VALUE* argv)
153 {
154 OVERLAPPED o;
155 int i = -1;
156 const HANDLE fh = (HANDLE)self;
157 const int oper = argc;
158
159 memset(&o, 0, sizeof(o));
160
161 switch(oper) {
162 case LOCK_SH:
163 LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, 0, &o), i);
164 break;
165 case LOCK_EX:
166 LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o), i);
167 break;
168 case LOCK_SH|LOCK_NB:
169 LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o), i);
170 break;
171 case LOCK_EX|LOCK_NB:
172 LK_ERR(LockFileEx(fh,
173 LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
174 0, LK_LEN, 0, &o), i);
175 if (errno == EDOM)
176 errno = EWOULDBLOCK;
177 break;
178 case LOCK_UN:
179 if (UnlockFileEx(fh, 0, LK_LEN, 0, &o)) {
180 i = 0;
181 if (errno == EDOM)
182 errno = EWOULDBLOCK;
183 }
184 else {
185
186 errno = EWOULDBLOCK;
187 }
188 break;
189 default:
190 errno = EINVAL;
191 break;
192 }
193 return i;
194 }
195
196 #ifdef WIN95
197 static VALUE
198 flock_win95(VALUE self, int argc, VALUE* argv)
199 {
200 int i = -1;
201 const HANDLE fh = (HANDLE)self;
202 const int oper = argc;
203
204 switch(oper) {
205 case LOCK_EX:
206 while(i == -1) {
207 LK_ERR(LockFile(fh, 0, 0, LK_LEN, 0), i);
208 if (errno != EDOM && i == -1) break;
209 }
210 break;
211 case LOCK_EX | LOCK_NB:
212 LK_ERR(LockFile(fh, 0, 0, LK_LEN, 0), i);
213 if (errno == EDOM)
214 errno = EWOULDBLOCK;
215 break;
216 case LOCK_UN:
217 LK_ERR(UnlockFile(fh, 0, 0, LK_LEN, 0), i);
218 if (errno == EDOM)
219 errno = EWOULDBLOCK;
220 break;
221 default:
222 errno = EINVAL;
223 break;
224 }
225 return i;
226 }
227 #endif
228
229 #undef LK_ERR
230 #undef LK_LEN
231
232 int
233 flock(int fd, int oper)
234 {
235 #ifdef WIN95
236 static asynchronous_func_t locker = NULL;
237
238 if (!locker) {
239 if (IsWinNT())
240 locker = flock_winnt;
241 else
242 locker = flock_win95;
243 }
244 #else
245 const asynchronous_func_t locker = flock_winnt;
246 #endif
247
248 return rb_w32_asynchronize(locker,
249 (VALUE)_get_osfhandle(fd), oper, NULL,
250 (DWORD)-1);
251 }
252
253
254
255
256
257
258
259 void
260 NtInitialize(int *argc, char ***argv)
261 {
262
263 WORD version;
264 int ret;
265
266
267
268
269 *argc = NtMakeCmdVector((char *)GetCommandLine(), argv, TRUE);
270
271
272
273
274
275 tzset();
276
277
278 StartSockets();
279 }
280
281 char *getlogin()
282 {
283 char buffer[200];
284 DWORD len = 200;
285 extern char *NTLoginName;
286
287 if (NTLoginName == NULL) {
288 if (GetUserName(buffer, &len)) {
289 NTLoginName = ALLOC_N(char, len+1);
290 strncpy(NTLoginName, buffer, len);
291 NTLoginName[len] = '\0';
292 }
293 else {
294 NTLoginName = "<Unknown>";
295 }
296 }
297 return NTLoginName;
298 }
299
300 #define MAXCHILDNUM 256
301
302 struct ChildRecord {
303 HANDLE hProcess;
304 pid_t pid;
305 } ChildRecord[MAXCHILDNUM];
306
307 #define FOREACH_CHILD(v) do { \
308 struct ChildRecord* v; \
309 for (v = ChildRecord; v < ChildRecord + sizeof(ChildRecord) / sizeof(ChildRecord[0]); ++v)
310 #define END_FOREACH_CHILD } while (0)
311
312 static struct ChildRecord *
313 FindFirstChildSlot(void)
314 {
315 FOREACH_CHILD(child) {
316 if (child->pid) return child;
317 } END_FOREACH_CHILD;
318 return NULL;
319 }
320
321 static struct ChildRecord *
322 FindChildSlot(pid_t pid)
323 {
324
325 FOREACH_CHILD(child) {
326 if (child->pid == pid) {
327 return child;
328 }
329 } END_FOREACH_CHILD;
330 return NULL;
331 }
332
333 static void
334 CloseChildHandle(struct ChildRecord *child)
335 {
336 HANDLE h = child->hProcess;
337 child->hProcess = NULL;
338 child->pid = 0;
339 CloseHandle(h);
340 }
341
342 static struct ChildRecord *
343 FindFreeChildSlot(void)
344 {
345 FOREACH_CHILD(child) {
346 if (!child->pid) {
347 child->pid = -1;
348 child->hProcess = NULL;
349 return child;
350 }
351 } END_FOREACH_CHILD;
352 return NULL;
353 }
354
355
356 int SafeFree(char **vec, int vecc)
357 {
358
359
360
361
362
363
364
365
366 char *p;
367
368 p = (char *)vec;
369 free(p);
370
371 return 0;
372 }
373
374
375 static char *szInternalCmds[] = {
376 "append",
377 "break",
378 "call",
379 "cd",
380 "chdir",
381 "cls",
382 "copy",
383 "date",
384 "del",
385 "dir",
386 "echo",
387 "erase",
388 "label",
389 "md",
390 "mkdir",
391 "path",
392 "pause",
393 "rd",
394 "rem",
395 "ren",
396 "rename",
397 "rmdir",
398 "set",
399 "start",
400 "time",
401 "type",
402 "ver",
403 "vol",
404 NULL
405 };
406
407 int
408 isInternalCmd(char *cmd)
409 {
410 int i, fRet=0;
411 char **vec;
412 int vecc = NtMakeCmdVector(cmd, &vec, FALSE);
413
414 if (vecc == 0)
415 return 0;
416 for( i = 0; szInternalCmds[i] ; i++){
417 if(!strcasecmp(szInternalCmds[i], vec[0])){
418 fRet = 1;
419 break;
420 }
421 }
422
423 SafeFree(vec, vecc);
424
425 return fRet;
426 }
427
428
429 SOCKET
430 rb_w32_get_osfhandle(int fh)
431 {
432 return _get_osfhandle(fh);
433
434 }
435
436 pid_t
437 pipe_exec(char *cmd, int mode, FILE **fpr, FILE **fpw)
438 {
439 struct ChildRecord* child;
440 HANDLE hReadIn, hReadOut;
441 HANDLE hWriteIn, hWriteOut;
442 HANDLE hSavedStdIn, hSavedStdOut;
443 HANDLE hDupInFile, hDupOutFile;
444 HANDLE hCurProc;
445 SECURITY_ATTRIBUTES sa;
446 BOOL fRet;
447 BOOL reading, writing;
448 int fdin, fdout;
449 int pipemode;
450 char modes[3];
451 int ret;
452
453
454 writing = (mode & (O_WRONLY | O_RDWR)) ? TRUE : FALSE;
455 reading = ((mode & O_RDWR) || !writing) ? TRUE : FALSE;
456 pipemode = (mode & O_BINARY) ? O_BINARY : O_TEXT;
457
458 sa.nLength = sizeof (SECURITY_ATTRIBUTES);
459 sa.lpSecurityDescriptor = NULL;
460 sa.bInheritHandle = TRUE;
461
462
463 RUBY_CRITICAL(do {
464 ret = -1;
465 hCurProc = GetCurrentProcess();
466 if (reading) {
467 fRet = CreatePipe(&hReadIn, &hReadOut, &sa, 2048L);
468 if (!fRet) {
469 errno = GetLastError();
470 break;
471 }
472 hSavedStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
473 if (!SetStdHandle(STD_OUTPUT_HANDLE, hReadOut) ||
474 !DuplicateHandle(hCurProc, hReadIn, hCurProc, &hDupInFile, 0,
475 FALSE, DUPLICATE_SAME_ACCESS)) {
476 errno = GetLastError();
477 CloseHandle(hReadIn);
478 CloseHandle(hReadOut);
479 CloseHandle(hCurProc);
480 break;
481 }
482 CloseHandle(hReadIn);
483 }
484 if (writing) {
485 fRet = CreatePipe(&hWriteIn, &hWriteOut, &sa, 2048L);
486 if (!fRet) {
487 errno = GetLastError();
488 if (reading) {
489 CloseHandle(hDupInFile);
490 CloseHandle(hReadOut);
491 }
492 break;
493 }
494 hSavedStdIn = GetStdHandle(STD_INPUT_HANDLE);
495 if (!SetStdHandle(STD_INPUT_HANDLE, hWriteIn) ||
496 !DuplicateHandle(hCurProc, hWriteOut, hCurProc, &hDupOutFile, 0,
497 FALSE, DUPLICATE_SAME_ACCESS)) {
498 errno = GetLastError();
499 CloseHandle(hWriteIn);
500 CloseHandle(hWriteOut);
501 CloseHandle(hCurProc);
502 if (reading) {
503 CloseHandle(hDupInFile);
504 CloseHandle(hReadOut);
505 }
506 break;
507 }
508 CloseHandle(hWriteOut);
509 }
510 CloseHandle(hCurProc);
511 ret = 0;
512 } while (0));
513 if (ret != 0) {
514 return ret;
515 }
516
517
518 child = CreateChild(cmd, &sa, NULL, NULL, NULL);
519 if (!child) {
520 RUBY_CRITICAL({
521 if (reading) {
522 SetStdHandle(STD_OUTPUT_HANDLE, hSavedStdOut);
523 CloseHandle(hReadOut);
524 CloseHandle(hDupInFile);
525 }
526 if (writing) {
527 SetStdHandle(STD_INPUT_HANDLE, hSavedStdIn);
528 CloseHandle(hWriteIn);
529 CloseHandle(hDupOutFile);
530 }
531 });
532 return -1;
533 }
534
535
536 RUBY_CRITICAL(do {
537 ret = -1;
538 if (reading) {
539 if (!SetStdHandle(STD_OUTPUT_HANDLE, hSavedStdOut)) {
540 errno = GetLastError();
541 CloseChildHandle(child);
542 CloseHandle(hReadOut);
543 CloseHandle(hDupInFile);
544 if (writing) {
545 CloseHandle(hWriteIn);
546 CloseHandle(hDupOutFile);
547 }
548 break;
549 }
550 }
551 if (writing) {
552 if (!SetStdHandle(STD_INPUT_HANDLE, hSavedStdIn)) {
553 errno = GetLastError();
554 CloseChildHandle(child);
555 CloseHandle(hWriteIn);
556 CloseHandle(hDupOutFile);
557 if (reading) {
558 CloseHandle(hReadOut);
559 CloseHandle(hDupInFile);
560 }
561 break;
562 }
563 }
564 ret = 0;
565 } while (0));
566 if (ret != 0) {
567 return ret;
568 }
569
570 if (reading) {
571 #ifdef __BORLANDC__
572 fdin = _open_osfhandle((long)hDupInFile, (_O_RDONLY | pipemode));
573 #else
574 fdin = rb_w32_open_osfhandle((long)hDupInFile, (_O_RDONLY | pipemode));
575 #endif
576 CloseHandle(hReadOut);
577 if (fdin == -1) {
578 CloseHandle(hDupInFile);
579 if (writing) {
580 CloseHandle(hWriteIn);
581 CloseHandle(hDupOutFile);
582 }
583 CloseChildHandle(child);
584 return -1;
585 }
586 }
587 if (writing) {
588 #ifdef __BORLANDC__
589 fdout = _open_osfhandle((long)hDupOutFile, (_O_WRONLY | pipemode));
590 #else
591 fdout = rb_w32_open_osfhandle((long)hDupOutFile,
592 (_O_WRONLY | pipemode));
593 #endif
594 CloseHandle(hWriteIn);
595 if (fdout == -1) {
596 CloseHandle(hDupOutFile);
597 if (reading) {
598 _close(fdin);
599 }
600 CloseChildHandle(child);
601 return -1;
602 }
603 }
604
605 if (reading) {
606 sprintf(modes, "r%s", pipemode == O_BINARY ? "b" : "");
607 if ((*fpr = (FILE *)fdopen(fdin, modes)) == NULL) {
608 _close(fdin);
609 if (writing) {
610 _close(fdout);
611 }
612 CloseChildHandle(child);
613 return -1;
614 }
615 }
616 if (writing) {
617 sprintf(modes, "w%s", pipemode == O_BINARY ? "b" : "");
618 if ((*fpw = (FILE *)fdopen(fdout, modes)) == NULL) {
619 _close(fdout);
620 if (reading) {
621 fclose(*fpr);
622 }
623 CloseChildHandle(child);
624 return -1;
625 }
626 }
627
628 return child->pid;
629 }
630
631 extern VALUE rb_last_status;
632
633 int
634 do_spawn(cmd)
635 char *cmd;
636 {
637 struct ChildRecord *child = CreateChild(cmd, NULL, NULL, NULL, NULL);
638 if (!child) {
639 return -1;
640 }
641 rb_syswait(child->pid);
642 return NUM2INT(rb_last_status);
643 }
644
645 static struct ChildRecord *
646 CreateChild(char *cmd, SECURITY_ATTRIBUTES *psa, HANDLE hInput, HANDLE hOutput, HANDLE hError)
647 {
648 BOOL fRet;
649 DWORD dwCreationFlags;
650 STARTUPINFO aStartupInfo;
651 PROCESS_INFORMATION aProcessInformation;
652 SECURITY_ATTRIBUTES sa;
653 char *shell;
654 struct ChildRecord *child;
655
656 child = FindFreeChildSlot();
657 if (!child) {
658 errno = EAGAIN;
659 return NULL;
660 }
661
662 if (!psa) {
663 sa.nLength = sizeof (SECURITY_ATTRIBUTES);
664 sa.lpSecurityDescriptor = NULL;
665 sa.bInheritHandle = TRUE;
666 psa = &sa;
667 }
668
669 memset(&aStartupInfo, 0, sizeof (STARTUPINFO));
670 memset(&aProcessInformation, 0, sizeof (PROCESS_INFORMATION));
671 aStartupInfo.cb = sizeof (STARTUPINFO);
672 if (hInput || hOutput || hError) {
673 aStartupInfo.dwFlags = STARTF_USESTDHANDLES;
674 if (hInput) {
675 aStartupInfo.hStdInput = hInput;
676 }
677 else {
678 aStartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
679 }
680 if (hOutput) {
681 aStartupInfo.hStdOutput = hOutput;
682 }
683 else {
684 aStartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
685 }
686 if (hError) {
687 aStartupInfo.hStdError = hError;
688 }
689 else {
690 aStartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
691 }
692 }
693
694 dwCreationFlags = (NORMAL_PRIORITY_CLASS);
695
696 if ((shell = getenv("RUBYSHELL")) && NtHasRedirection(cmd)) {
697 char *tmp = ALLOCA_N(char, strlen(shell) + strlen(cmd) + sizeof (" -c "));
698 sprintf(tmp, "%s -c %s", shell, cmd);
699 cmd = tmp;
700 }
701 else if ((shell = getenv("COMSPEC")) &&
702 (NtHasRedirection(cmd) || isInternalCmd(cmd))) {
703 char *tmp = ALLOCA_N(char, strlen(shell) + strlen(cmd) + sizeof (" /c "));
704 sprintf(tmp, "%s /c %s", shell, cmd);
705 cmd = tmp;
706 }
707 else {
708 shell = NULL;
709 }
710
711 RUBY_CRITICAL({
712 fRet = CreateProcess(shell, cmd, psa, psa,
713 psa->bInheritHandle, dwCreationFlags, NULL, NULL,
714 &aStartupInfo, &aProcessInformation);
715 errno = GetLastError();
716 });
717
718 if (!fRet) {
719 child->pid = 0;
720 return NULL;
721 }
722
723 CloseHandle(aProcessInformation.hThread);
724
725 child->hProcess = aProcessInformation.hProcess;
726 child->pid = (pid_t)aProcessInformation.dwProcessId;
727
728 if (!IsWinNT()) {
729
730 child->pid = -child->pid;
731 }
732
733 return child;
734 }
735
736 typedef struct _NtCmdLineElement {
737 struct _NtCmdLineElement *next, *prev;
738 char *str;
739 int len;
740 int flags;
741 } NtCmdLineElement;
742
743
744
745
746
747 #define NTGLOB 0x1
748 #define NTMALLOC 0x2
749 #define NTSTRING 0x4
750
751 NtCmdLineElement *NtCmdHead = NULL, *NtCmdTail = NULL;
752
753 void
754 NtFreeCmdLine(void)
755 {
756 NtCmdLineElement *ptr;
757
758 while(NtCmdHead) {
759 ptr = NtCmdHead;
760 NtCmdHead = NtCmdHead->next;
761 free(ptr);
762 }
763 NtCmdHead = NtCmdTail = NULL;
764 }
765
766
767
768
769
770
771
772
773 typedef struct {
774 NtCmdLineElement *head;
775 NtCmdLineElement *tail;
776 } ListInfo;
777
778 static void
779 insert(const char *path, VALUE vinfo)
780 {
781 NtCmdLineElement *tmpcurr;
782 ListInfo *listinfo = (ListInfo *)vinfo;
783
784 tmpcurr = ALLOC(NtCmdLineElement);
785 MEMZERO(tmpcurr, NtCmdLineElement, 1);
786 tmpcurr->len = strlen(path);
787 tmpcurr->str = ALLOC_N(char, tmpcurr->len + 1);
788 tmpcurr->flags |= NTMALLOC;
789 strcpy(tmpcurr->str, path);
790 if (listinfo->tail) {
791 listinfo->tail->next = tmpcurr;
792 tmpcurr->prev = listinfo->tail;
793 listinfo->tail = tmpcurr;
794 }
795 else {
796 listinfo->tail = listinfo->head = tmpcurr;
797 }
798 }
799
800 #ifdef HAVE_SYS_PARAM_H
801 # include <sys/param.h>
802 #else
803 # define MAXPATHLEN 512
804 #endif
805
806 void
807 NtCmdGlob (NtCmdLineElement *patt)
808 {
809 ListInfo listinfo;
810 char buffer[MAXPATHLEN], *buf = buffer;
811 char *p;
812
813 listinfo.head = listinfo.tail = 0;
814
815 if (patt->len >= MAXPATHLEN)
816 buf = ruby_xmalloc(patt->len + 1);
817
818 strncpy (buf, patt->str, patt->len);
819 buf[patt->len] = '\0';
820 for (p = buf; *p; p = CharNext(p))
821 if (*p == '\\')
822 *p = '/';
823 rb_globi(buf, insert, (VALUE)&listinfo);
824 if (buf != buffer)
825 free(buf);
826
827 if (listinfo.head && listinfo.tail) {
828 listinfo.head->prev = patt->prev;
829 listinfo.tail->next = patt->next;
830 if (listinfo.head->prev)
831 listinfo.head->prev->next = listinfo.head;
832 if (listinfo.tail->next)
833 listinfo.tail->next->prev = listinfo.tail;
834 }
835 if (patt->flags & NTMALLOC)
836 free(patt->str);
837
838 }
839
840
841
842
843
844
845 static bool
846 NtHasRedirection (char *cmd)
847 {
848 int inquote = 0;
849 char quote = '\0';
850 char *ptr ;
851
852
853
854
855
856
857 for (ptr = cmd; *ptr; ptr++) {
858
859 switch (*ptr) {
860
861 case '\'':
862 case '\"':
863 if (inquote) {
864 if (quote == *ptr) {
865 inquote = 0;
866 quote = '\0';
867 }
868 }
869 else {
870 quote = *ptr;
871 inquote++;
872 }
873 break;
874
875 case '>':
876 case '<':
877 case '|':
878
879 if (!inquote)
880 return TRUE;
881 }
882 }
883 return FALSE;
884 }
885
886
887 int
888 NtMakeCmdVector (char *cmdline, char ***vec, int InputCmd)
889 {
890 int cmdlen = strlen(cmdline);
891 int done, instring, globbing, quoted, len;
892 int newline, need_free = 0, i;
893 int elements, strsz;
894 int slashes = 0;
895 char *ptr, *base, *buffer;
896 char **vptr;
897 char quote;
898 NtCmdLineElement *curr;
899
900
901
902
903
904 if (cmdlen == 0) {
905 *vec = NULL;
906 return 0;
907 }
908
909 cmdline = strdup(cmdline);
910
911
912
913
914
915 ptr = cmdline+(cmdlen - 1);
916 while(ptr >= cmdline && ISSPACE(*ptr))
917 --ptr;
918 *++ptr = '\0';
919
920
921
922
923
924
925
926
927
928
929
930 for (done = 0, ptr = cmdline; *ptr;) {
931
932
933
934
935
936 while(ISSPACE(*ptr))
937 ptr++;
938 base = ptr;
939
940 for (done = newline = globbing = instring = quoted = 0;
941 *ptr && !done; ptr++) {
942
943
944
945
946
947
948
949 switch (*ptr) {
950 case '\\':
951 if (ptr[1] == '"') ptr++;
952 break;
953 case ' ':
954 case '\t':
955 #if 0
956 case '/':
957
958
959
960
961
962 if (*ptr == '/' && base == ptr)
963 continue;
964 #endif
965
966
967
968
969
970 if (!instring)
971 done++;
972 break;
973
974 case '*':
975 case '?':
976
977
978
979
980
981
982 if (!(instring && quote == '\''))
983 globbing++;
984 break;
985
986 case '\n':
987
988
989
990
991
992
993
994 newline++;
995 break;
996
997 case '\'':
998 case '\"':
999
1000
1001
1002
1003
1004
1005
1006
1007 if (instring) {
1008 if (quote == *ptr) {
1009 instring = 0;
1010 quote = '\0';
1011 }
1012 }
1013 else {
1014 instring++;
1015 quote = *ptr;
1016 quoted++;
1017 }
1018 break;
1019 }
1020 }
1021
1022
1023
1024
1025
1026
1027 if (*ptr)
1028 ptr--;
1029
1030
1031
1032
1033
1034
1035
1036 curr = ALLOC(NtCmdLineElement);
1037 memset (curr, 0, sizeof(*curr));
1038
1039 len = ptr - base;
1040
1041
1042
1043
1044
1045
1046 if (InputCmd && (base[0] == '\"' && base[len-1] == '\"')) {
1047 char *p;
1048 base++;
1049 len -= 2;
1050 base[len] = 0;
1051 for (p = base; p < base + len; p++) {
1052 if ((p[0] == '\\' || p[0] == '\"') && p[1] == '"') {
1053 strcpy(p, p + 1);
1054 len--;
1055 }
1056 }
1057 }
1058 else if (InputCmd && (base[0] == '\'' && base[len-1] == '\'')) {
1059 base++;
1060 len -= 2;
1061 }
1062
1063 curr->str = base;
1064 curr->len = len;
1065 curr->flags |= (globbing ? NTGLOB : 0);
1066
1067
1068
1069
1070 if (NtCmdTail) {
1071 NtCmdTail->next = curr;
1072 curr->prev = NtCmdTail;
1073 NtCmdTail = curr;
1074 }
1075 else {
1076 NtCmdHead = NtCmdTail = curr;
1077 }
1078 }
1079
1080 if (InputCmd) {
1081
1082
1083
1084
1085
1086
1087 for(curr = NtCmdHead; curr; curr = curr->next) {
1088 if (curr->flags & NTGLOB) {
1089 NtCmdGlob(curr);
1090 }
1091 }
1092 }
1093
1094
1095
1096
1097
1098
1099
1100 for (elements = 0, strsz = 0, curr = NtCmdHead; curr; curr = curr->next) {
1101 elements++;
1102 strsz += (curr->len + 1);
1103 }
1104
1105 len = (elements+1)*sizeof(char *) + strsz;
1106 buffer = ALLOC_N(char, len);
1107
1108 memset (buffer, 0, len);
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122 vptr = (char **) buffer;
1123
1124 ptr = buffer + (elements+1) * sizeof(char *);
1125
1126 for (curr = NtCmdHead; curr; curr = curr->next) {
1127 strncpy (ptr, curr->str, curr->len);
1128 ptr[curr->len] = '\0';
1129 *vptr++ = ptr;
1130 ptr += curr->len + 1;
1131 }
1132 NtFreeCmdLine();
1133 *vec = (char **) buffer;
1134 free(cmdline);
1135 return elements;
1136 }
1137
1138
1139
1140
1141
1142 #define PATHLEN 1024
1143
1144
1145
1146
1147
1148
1149
1150 DIR *
1151 rb_w32_opendir(const char *filename)
1152 {
1153 DIR *p;
1154 long len;
1155 long idx;
1156 char scannamespc[PATHLEN];
1157 char *scanname = scannamespc;
1158 struct stat sbuf;
1159 WIN32_FIND_DATA FindData;
1160 HANDLE fh;
1161
1162
1163
1164
1165
1166 if ((rb_w32_stat (filename, &sbuf) < 0 ||
1167 #ifdef __BORLANDC__
1168 (unsigned short)(sbuf.st_mode) & _S_IFDIR == 0) &&
1169 #else
1170 sbuf.st_mode & _S_IFDIR == 0) &&
1171 #endif
1172 (!ISALPHA(filename[0]) || filename[1] != ':' || filename[2] != '\0' ||
1173 ((1 << (filename[0] & 0x5f) - 'A') & GetLogicalDrives()) == 0)) {
1174 return NULL;
1175 }
1176
1177
1178
1179
1180
1181 p = xcalloc(sizeof(DIR), 1);
1182 if (p == NULL)
1183 return NULL;
1184
1185
1186
1187
1188
1189 strcpy(scanname, filename);
1190
1191 if (index("/\\:", *CharPrev(scanname, scanname + strlen(scanname))) == NULL)
1192 strcat(scanname, "/*");
1193 else
1194 strcat(scanname, "*");
1195
1196
1197
1198
1199
1200 fh = FindFirstFile (scanname, &FindData);
1201 if (fh == INVALID_HANDLE_VALUE) {
1202 return NULL;
1203 }
1204
1205
1206
1207
1208
1209
1210 idx = strlen(FindData.cFileName)+1;
1211 p->start = ALLOC_N(char, idx);
1212 strcpy (p->start, FindData.cFileName);
1213 p->nfiles++;
1214
1215
1216
1217
1218
1219
1220
1221 while (FindNextFile(fh, &FindData)) {
1222 len = strlen (FindData.cFileName);
1223
1224
1225
1226
1227
1228
1229 #define Renew(x, y, z) (x = (z *)realloc(x, y))
1230
1231 Renew (p->start, idx+len+1, char);
1232 if (p->start == NULL) {
1233 rb_fatal ("opendir: malloc failed!\n");
1234 }
1235 strcpy(&p->start[idx], FindData.cFileName);
1236 p->nfiles++;
1237 idx += len+1;
1238 }
1239 FindClose(fh);
1240 p->size = idx;
1241 p->curr = p->start;
1242 return p;
1243 }
1244
1245
1246
1247
1248
1249
1250
1251 struct direct *
1252 rb_w32_readdir(DIR *dirp)
1253 {
1254 int len;
1255 static int dummy = 0;
1256
1257 if (dirp->curr) {
1258
1259
1260
1261
1262
1263 len = strlen(dirp->curr);
1264 strcpy(dirp->dirstr.d_name, dirp->curr);
1265 dirp->dirstr.d_namlen = len;
1266
1267
1268
1269
1270 dirp->dirstr.d_ino = dummy++;
1271
1272
1273
1274
1275
1276 dirp->curr += len + 1;
1277 if (dirp->curr >= (dirp->start + dirp->size)) {
1278 dirp->curr = NULL;
1279 }
1280
1281 return &(dirp->dirstr);
1282
1283 } else
1284 return NULL;
1285 }
1286
1287
1288
1289
1290
1291 long
1292 rb_w32_telldir(DIR *dirp)
1293 {
1294 return (long) dirp->curr;
1295 }
1296
1297
1298
1299
1300
1301 void
1302 rb_w32_seekdir(DIR *dirp, long loc)
1303 {
1304 dirp->curr = (char *) loc;
1305 }
1306
1307
1308
1309
1310
1311 void
1312 rb_w32_rewinddir(DIR *dirp)
1313 {
1314 dirp->curr = dirp->start;
1315 }
1316
1317
1318
1319
1320
1321 void
1322 rb_w32_closedir(DIR *dirp)
1323 {
1324 free(dirp->start);
1325 free(dirp);
1326 }
1327
1328 static int
1329 valid_filename(char *s)
1330 {
1331 int fd;
1332
1333
1334
1335
1336
1337 if (_access(s, 0) == 0) {
1338 return 1;
1339 }
1340
1341
1342
1343
1344
1345 if ((fd = _open(s, _O_CREAT, 0666)) >= 0) {
1346 close(fd);
1347 _unlink (s);
1348 return 1;
1349 }
1350 return 0;
1351 }
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366 EXTERN_C void __cdecl _lock_fhandle(int);
1367 EXTERN_C void __cdecl _unlock_fhandle(int);
1368 EXTERN_C void __cdecl _unlock(int);
1369
1370 #if (defined _MT || defined __MSVCRT__) && !defined __BORLANDC__
1371 #define MSVCRT_THREADS
1372 #endif
1373 #ifdef MSVCRT_THREADS
1374 # define MTHREAD_ONLY(x) x
1375 # define STHREAD_ONLY(x)
1376 #elif defined(__BORLANDC__)
1377 # define MTHREAD_ONLY(x)
1378 # define STHREAD_ONLY(x)
1379 #else
1380 # define MTHREAD_ONLY(x)
1381 # define STHREAD_ONLY(x) x
1382 #endif
1383
1384 typedef struct {
1385 long osfhnd;
1386 char osfile;
1387 char pipech;
1388 #ifdef MSVCRT_THREADS
1389 int lockinitflag;
1390 CRITICAL_SECTION lock;
1391 #endif
1392 } ioinfo;
1393
1394 #if !defined _CRTIMP
1395 #define _CRTIMP __declspec(dllimport)
1396 #endif
1397
1398 #ifndef __BORLANDC__
1399 EXTERN_C _CRTIMP ioinfo * __pioinfo[];
1400
1401 #define IOINFO_L2E 5
1402 #define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
1403 #define _pioinfo(i) (__pioinfo[i >> IOINFO_L2E] + (i & (IOINFO_ARRAY_ELTS - 1)))
1404 #define _osfhnd(i) (_pioinfo(i)->osfhnd)
1405 #define _osfile(i) (_pioinfo(i)->osfile)
1406 #define _pipech(i) (_pioinfo(i)->pipech)
1407
1408 #define _set_osfhnd(fh, osfh) (void)(_osfhnd(fh) = osfh)
1409 #define _set_osflags(fh, flags) (_osfile(fh) = (flags))
1410
1411 #else
1412
1413 #define _set_osfhnd(fh, osfh) (void)((fh), (osfh))
1414 #define _set_osflags(fh, flags) (void)((fh), (flags))
1415
1416 #endif
1417
1418 #define FOPEN 0x01
1419 #define FNOINHERIT 0x10
1420 #define FAPPEND 0x20
1421 #define FDEV 0x40
1422 #define FTEXT 0x80
1423
1424 static int
1425 rb_w32_open_osfhandle(long osfhandle, int flags)
1426 {
1427 int fh;
1428 char fileflags;
1429
1430
1431 fileflags = FDEV;
1432
1433 if (flags & O_APPEND)
1434 fileflags |= FAPPEND;
1435
1436 if (flags & O_TEXT)
1437 fileflags |= FTEXT;
1438
1439 if (flags & O_NOINHERIT)
1440 fileflags |= FNOINHERIT;
1441
1442 RUBY_CRITICAL({
1443
1444 HANDLE hF = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
1445 fh = _open_osfhandle((long)hF, 0);
1446 CloseHandle(hF);
1447 if (fh == -1) {
1448 errno = EMFILE;
1449 _doserrno = 0L;
1450 }
1451 else {
1452
1453 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fh)->lock)));
1454
1455 _set_osfhnd(fh, osfhandle);
1456
1457 fileflags |= FOPEN;
1458
1459 _set_osflags(fh, fileflags);
1460 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fh)->lock));
1461 }
1462 });
1463 return fh;
1464 }
1465
1466 #undef getsockopt
1467
1468 static int
1469 is_socket(SOCKET fd)
1470 {
1471 char sockbuf[80];
1472 int optlen;
1473 int retval;
1474
1475 optlen = sizeof(sockbuf);
1476 retval = getsockopt(fd, SOL_SOCKET, SO_TYPE, sockbuf, &optlen);
1477 if (retval == SOCKET_ERROR) {
1478 int iRet;
1479
1480 iRet = WSAGetLastError();
1481 if (iRet == WSAENOTSOCK || iRet == WSANOTINITIALISED)
1482 return FALSE;
1483 }
1484
1485
1486
1487
1488
1489 return TRUE;
1490 }
1491
1492 int
1493 rb_w32_fddup (int fd)
1494 {
1495 SOCKET s = TO_SOCKET(fd);
1496
1497 if (s == -1)
1498 return -1;
1499
1500 return rb_w32_open_osfhandle(s, O_RDWR|O_BINARY);
1501 }
1502
1503
1504 void
1505 rb_w32_fdclose(FILE *fp)
1506 {
1507 RUBY_CRITICAL({
1508 STHREAD_ONLY(_free_osfhnd(fileno(fp)));
1509 fclose(fp);
1510 });
1511 }
1512
1513
1514
1515
1516
1517
1518
1519 #undef strerror
1520
1521 char *
1522 rb_w32_strerror(int e)
1523 {
1524 static char buffer[512];
1525 #if !defined __MINGW32__
1526 extern int sys_nerr;
1527 #endif
1528 DWORD source = 0;
1529 char *p;
1530
1531 if (e < 0 || e > sys_nerr) {
1532 if (e < 0)
1533 e = GetLastError();
1534 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
1535 FORMAT_MESSAGE_IGNORE_INSERTS, &source, e, 0,
1536 buffer, 512, NULL) == 0) {
1537 strcpy(buffer, "Unknown Error");
1538 }
1539 for (p = buffer + strlen(buffer) - 1; buffer <= p; p--) {
1540 if (*p != '\r' && *p != '\n') break;
1541 *p = 0;
1542 }
1543 return buffer;
1544 }
1545 return strerror(e);
1546 }
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559 #define ROOT_UID 0
1560 #define ROOT_GID 0
1561
1562 UIDTYPE
1563 getuid(void)
1564 {
1565 return ROOT_UID;
1566 }
1567
1568 UIDTYPE
1569 geteuid(void)
1570 {
1571 return ROOT_UID;
1572 }
1573
1574 GIDTYPE
1575 getgid(void)
1576 {
1577 return ROOT_GID;
1578 }
1579
1580 GIDTYPE
1581 getegid(void)
1582 {
1583 return ROOT_GID;
1584 }
1585
1586 int
1587 setuid(int uid)
1588 {
1589 return (uid == ROOT_UID ? 0 : -1);
1590 }
1591
1592 int
1593 setgid(int gid)
1594 {
1595 return (gid == ROOT_GID ? 0 : -1);
1596 }
1597
1598
1599
1600
1601
1602 int
1603
1604 #ifdef __BORLANDC__
1605 ioctl(int i, int u, ...)
1606 #else
1607 ioctl(int i, unsigned int u, long data)
1608 #endif
1609 {
1610 return -1;
1611 }
1612
1613 #undef FD_SET
1614
1615 void
1616 rb_w32_fdset(int fd, fd_set *set)
1617 {
1618 unsigned int i;
1619 SOCKET s = TO_SOCKET(fd);
1620
1621 for (i = 0; i < set->fd_count; i++) {
1622 if (set->fd_array[i] == s) {
1623 return;
1624 }
1625 }
1626 if (i == set->fd_count) {
1627 if (set->fd_count < FD_SETSIZE) {
1628 set->fd_array[i] = s;
1629 set->fd_count++;
1630 }
1631 }
1632 }
1633
1634 #undef FD_CLR
1635
1636 void
1637 rb_w32_fdclr(int fd, fd_set *set)
1638 {
1639 unsigned int i;
1640 SOCKET s = TO_SOCKET(fd);
1641
1642 for (i = 0; i < set->fd_count; i++) {
1643 if (set->fd_array[i] == s) {
1644 while (i < set->fd_count - 1) {
1645 set->fd_array[i] = set->fd_array[i + 1];
1646 i++;
1647 }
1648 set->fd_count--;
1649 break;
1650 }
1651 }
1652 }
1653
1654 #undef FD_ISSET
1655
1656 int
1657 rb_w32_fdisset(int fd, fd_set *set)
1658 {
1659 return __WSAFDIsSet(TO_SOCKET(fd), set);
1660 }
1661
1662
1663
1664
1665
1666
1667
1668 #undef select
1669
1670 static int NtSocketsInitialized = 0;
1671
1672 static int
1673 extract_file_fd(fd_set *set, fd_set *fileset)
1674 {
1675 int idx;
1676
1677 fileset->fd_count = 0;
1678 if (!set)
1679 return 0;
1680 for (idx = 0; idx < set->fd_count; idx++) {
1681 SOCKET fd = set->fd_array[idx];
1682
1683 if (!is_socket(fd)) {
1684 int i;
1685
1686 for (i = 0; i < fileset->fd_count; i++) {
1687 if (fileset->fd_array[i] == fd) {
1688 break;
1689 }
1690 }
1691 if (i == fileset->fd_count) {
1692 if (fileset->fd_count < FD_SETSIZE) {
1693 fileset->fd_array[i] = fd;
1694 fileset->fd_count++;
1695 }
1696 }
1697 }
1698 }
1699 return fileset->fd_count;
1700 }
1701
1702 long
1703 rb_w32_select (int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
1704 struct timeval *timeout)
1705 {
1706 long r;
1707 fd_set file_rd;
1708 fd_set file_wr;
1709 #ifdef USE_INTERRUPT_WINSOCK
1710 fd_set trap;
1711 #endif
1712 int file_nfds;
1713
1714 if (!NtSocketsInitialized++) {
1715 StartSockets();
1716 }
1717 r = 0;
1718 if (rd && rd->fd_count > r) r = rd->fd_count;
1719 if (wr && wr->fd_count > r) r = wr->fd_count;
1720 if (ex && ex->fd_count > r) r = ex->fd_count;
1721 if (nfds > r) nfds = r;
1722 if (nfds == 0 && timeout) {
1723 Sleep(timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
1724 return 0;
1725 }
1726 file_nfds = extract_file_fd(rd, &file_rd);
1727 file_nfds += extract_file_fd(wr, &file_wr);
1728 if (file_nfds)
1729 {
1730
1731
1732 if (rd) *rd = file_rd;
1733 if (wr) *wr = file_wr;
1734 return file_nfds;
1735 }
1736
1737 #if USE_INTERRUPT_WINSOCK
1738 if (ex)
1739 trap = *ex;
1740 else
1741 trap.fd_count = 0;
1742 if (trap.fd_count < FD_SETSIZE)
1743 trap.fd_array[trap.fd_count++] = (SOCKET)interrupted_event;
1744
1745 ex = &trap;
1746 #endif
1747
1748 RUBY_CRITICAL(r = select (nfds, rd, wr, ex, timeout));
1749 if (r == SOCKET_ERROR) {
1750 errno = WSAGetLastError();
1751 switch (errno) {
1752 case WSAEINTR:
1753 errno = EINTR;
1754 break;
1755 }
1756 }
1757 return r;
1758 }
1759
1760 static void
1761 StartSockets ()
1762 {
1763 WORD version;
1764 WSADATA retdata;
1765 int ret;
1766 int iSockOpt;
1767
1768
1769
1770
1771
1772 version = MAKEWORD(1, 1);
1773 if (ret = WSAStartup(version, &retdata))
1774 rb_fatal ("Unable to locate winsock library!\n");
1775 if (LOBYTE(retdata.wVersion) != 1)
1776 rb_fatal("could not find version 1 of winsock dll\n");
1777
1778 if (HIBYTE(retdata.wVersion) != 1)
1779 rb_fatal("could not find version 1 of winsock dll\n");
1780
1781 atexit((void (*)(void)) WSACleanup);
1782
1783 #ifndef SO_SYNCHRONOUS_NONALERT
1784 #define SO_SYNCHRONOUS_NONALERT 0x20
1785 #endif
1786
1787 iSockOpt = SO_SYNCHRONOUS_NONALERT;
1788
1789
1790
1791 #ifndef SO_OPENTYPE
1792 #define SO_OPENTYPE 0x7008
1793 #endif
1794
1795 setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
1796 (char *)&iSockOpt, sizeof(iSockOpt));
1797
1798 main_thread.handle = GetCurrentThreadHandle();
1799 main_thread.id = GetCurrentThreadId();
1800
1801 interrupted_event = CreateSignal();
1802 if (!interrupted_event)
1803 rb_fatal("Unable to create interrupt event!\n");
1804 }
1805
1806 #undef accept
1807
1808 SOCKET
1809 rb_w32_accept (SOCKET s, struct sockaddr *addr, int *addrlen)
1810 {
1811 SOCKET r;
1812
1813 if (!NtSocketsInitialized++) {
1814 StartSockets();
1815 }
1816 RUBY_CRITICAL(r = accept (TO_SOCKET(s), addr, addrlen));
1817 if (r == INVALID_SOCKET)
1818 errno = WSAGetLastError();
1819 return rb_w32_open_osfhandle(r, O_RDWR|O_BINARY);
1820 }
1821
1822 #undef bind
1823
1824 int
1825 rb_w32_bind (SOCKET s, struct sockaddr *addr, int addrlen)
1826 {
1827 int r;
1828
1829 if (!NtSocketsInitialized++) {
1830 StartSockets();
1831 }
1832 RUBY_CRITICAL(r = bind (TO_SOCKET(s), addr, addrlen));
1833 if (r == SOCKET_ERROR)
1834 errno = WSAGetLastError();
1835 return r;
1836 }
1837
1838 #undef connect
1839
1840 int
1841 rb_w32_connect (SOCKET s, struct sockaddr *addr, int addrlen)
1842 {
1843 int r;
1844 if (!NtSocketsInitialized++) {
1845 StartSockets();
1846 }
1847 RUBY_CRITICAL(r = connect (TO_SOCKET(s), addr, addrlen));
1848 if (r == SOCKET_ERROR)
1849 errno = WSAGetLastError();
1850 return r;
1851 }
1852
1853
1854 #undef getpeername
1855
1856 int
1857 rb_w32_getpeername (SOCKET s, struct sockaddr *addr, int *addrlen)
1858 {
1859 int r;
1860 if (!NtSocketsInitialized++) {
1861 StartSockets();
1862 }
1863 RUBY_CRITICAL(r = getpeername (TO_SOCKET(s), addr, addrlen));
1864 if (r == SOCKET_ERROR)
1865 errno = WSAGetLastError();
1866 return r;
1867 }
1868
1869 #undef getsockname
1870
1871 int
1872 rb_w32_getsockname (SOCKET s, struct sockaddr *addr, int *addrlen)
1873 {
1874 int r;
1875 if (!NtSocketsInitialized++) {
1876 StartSockets();
1877 }
1878 RUBY_CRITICAL(r = getsockname (TO_SOCKET(s), addr, addrlen));
1879 if (r == SOCKET_ERROR)
1880 errno = WSAGetLastError();
1881 return r;
1882 }
1883
1884 int
1885 rb_w32_getsockopt (SOCKET s, int level, int optname, char *optval, int *optlen)
1886 {
1887 int r;
1888 if (!NtSocketsInitialized++) {
1889 StartSockets();
1890 }
1891 RUBY_CRITICAL(r = getsockopt (TO_SOCKET(s), level, optname, optval, optlen));
1892 if (r == SOCKET_ERROR)
1893 errno = WSAGetLastError();
1894 return r;
1895 }
1896
1897 #undef ioctlsocket
1898
1899 int
1900 rb_w32_ioctlsocket (SOCKET s, long cmd, u_long *argp)
1901 {
1902 int r;
1903 if (!NtSocketsInitialized++) {
1904 StartSockets();
1905 }
1906 RUBY_CRITICAL(r = ioctlsocket (TO_SOCKET(s), cmd, argp));
1907 if (r == SOCKET_ERROR)
1908 errno = WSAGetLastError();
1909 return r;
1910 }
1911
1912 #undef listen
1913
1914 int
1915 rb_w32_listen (SOCKET s, int backlog)
1916 {
1917 int r;
1918 if (!NtSocketsInitialized++) {
1919 StartSockets();
1920 }
1921 RUBY_CRITICAL(r = listen (TO_SOCKET(s), backlog));
1922 if (r == SOCKET_ERROR)
1923 errno = WSAGetLastError();
1924 return r;
1925 }
1926
1927 #undef recv
1928
1929 int
1930 rb_w32_recv (SOCKET s, char *buf, int len, int flags)
1931 {
1932 int r;
1933 if (!NtSocketsInitialized++) {
1934 StartSockets();
1935 }
1936 RUBY_CRITICAL(r = recv (TO_SOCKET(s), buf, len, flags));
1937 if (r == SOCKET_ERROR)
1938 errno = WSAGetLastError();
1939 return r;
1940 }
1941
1942 #undef recvfrom
1943
1944 int
1945 rb_w32_recvfrom (SOCKET s, char *buf, int len, int flags,
1946 struct sockaddr *from, int *fromlen)
1947 {
1948 int r;
1949 if (!NtSocketsInitialized++) {
1950 StartSockets();
1951 }
1952 RUBY_CRITICAL(r = recvfrom (TO_SOCKET(s), buf, len, flags, from, fromlen));
1953 if (r == SOCKET_ERROR)
1954 errno = WSAGetLastError();
1955 return r;
1956 }
1957
1958 #undef send
1959
1960 int
1961 rb_w32_send (SOCKET s, char *buf, int len, int flags)
1962 {
1963 int r;
1964 if (!NtSocketsInitialized++) {
1965 StartSockets();
1966 }
1967 RUBY_CRITICAL(r = send (TO_SOCKET(s), buf, len, flags));
1968 if (r == SOCKET_ERROR)
1969 errno = WSAGetLastError();
1970 return r;
1971 }
1972
1973 #undef sendto
1974
1975 int
1976 rb_w32_sendto (SOCKET s, char *buf, int len, int flags,
1977 struct sockaddr *to, int tolen)
1978 {
1979 int r;
1980 if (!NtSocketsInitialized++) {
1981 StartSockets();
1982 }
1983 RUBY_CRITICAL(r = sendto (TO_SOCKET(s), buf, len, flags, to, tolen));
1984 if (r == SOCKET_ERROR)
1985 errno = WSAGetLastError();
1986 return r;
1987 }
1988
1989 #undef setsockopt
1990
1991 int
1992 rb_w32_setsockopt (SOCKET s, int level, int optname, char *optval, int optlen)
1993 {
1994 int r;
1995 if (!NtSocketsInitialized++) {
1996 StartSockets();
1997 }
1998 RUBY_CRITICAL(r = setsockopt (TO_SOCKET(s), level, optname, optval, optlen));
1999 if (r == SOCKET_ERROR)
2000 errno = WSAGetLastError();
2001 return r;
2002 }
2003
2004 #undef shutdown
2005
2006 int
2007 rb_w32_shutdown (SOCKET s, int how)
2008 {
2009 int r;
2010 if (!NtSocketsInitialized++) {
2011 StartSockets();
2012 }
2013 RUBY_CRITICAL(r = shutdown (TO_SOCKET(s), how));
2014 if (r == SOCKET_ERROR)
2015 errno = WSAGetLastError();
2016 return r;
2017 }
2018
2019 #undef socket
2020
2021 SOCKET
2022 rb_w32_socket (int af, int type, int protocol)
2023 {
2024 SOCKET s;
2025 if (!NtSocketsInitialized++) {
2026 StartSockets();
2027 }
2028 RUBY_CRITICAL(s = socket (af, type, protocol));
2029 if (s == INVALID_SOCKET) {
2030 errno = WSAGetLastError();
2031
2032 }
2033 #ifdef __BORLANDC__
2034 return _open_osfhandle(s, O_RDWR|O_BINARY);
2035 #else
2036 return rb_w32_open_osfhandle(s, O_RDWR|O_BINARY);
2037 #endif
2038 }
2039
2040 #undef gethostbyaddr
2041
2042 struct hostent *
2043 rb_w32_gethostbyaddr (char *addr, int len, int type)
2044 {
2045 struct hostent *r;
2046 if (!NtSocketsInitialized++) {
2047 StartSockets();
2048 }
2049 RUBY_CRITICAL(r = gethostbyaddr (addr, len, type));
2050 if (r == NULL)
2051 errno = WSAGetLastError();
2052 return r;
2053 }
2054
2055 #undef gethostbyname
2056
2057 struct hostent *
2058 rb_w32_gethostbyname (char *name)
2059 {
2060 struct hostent *r;
2061 if (!NtSocketsInitialized++) {
2062 StartSockets();
2063 }
2064 RUBY_CRITICAL(r = gethostbyname (name));
2065 if (r == NULL)
2066 errno = WSAGetLastError();
2067 return r;
2068 }
2069
2070 #undef gethostname
2071
2072 int
2073 rb_w32_gethostname (char *name, int len)
2074 {
2075 int r;
2076 if (!NtSocketsInitialized++) {
2077 StartSockets();
2078 }
2079 RUBY_CRITICAL(r = gethostname (name, len));
2080 if (r == SOCKET_ERROR)
2081 errno = WSAGetLastError();
2082 return r;
2083 }
2084
2085 #undef getprotobyname
2086
2087 struct protoent *
2088 rb_w32_getprotobyname (char *name)
2089 {
2090 struct protoent *r;
2091 if (!NtSocketsInitialized++) {
2092 StartSockets();
2093 }
2094 RUBY_CRITICAL(r = getprotobyname (name));
2095 if (r == NULL)
2096 errno = WSAGetLastError();
2097 return r;
2098 }
2099
2100 #undef getprotobynumber
2101
2102 struct protoent *
2103 rb_w32_getprotobynumber (int num)
2104 {
2105 struct protoent *r;
2106 if (!NtSocketsInitialized++) {
2107 StartSockets();
2108 }
2109 RUBY_CRITICAL(r = getprotobynumber (num));
2110 if (r == NULL)
2111 errno = WSAGetLastError();
2112 return r;
2113 }
2114
2115 #undef getservbyname
2116
2117 struct servent *
2118 rb_w32_getservbyname (char *name, char *proto)
2119 {
2120 struct servent *r;
2121 if (!NtSocketsInitialized++) {
2122 StartSockets();
2123 }
2124 RUBY_CRITICAL(r = getservbyname (name, proto));
2125 if (r == NULL)
2126 errno = WSAGetLastError();
2127 return r;
2128 }
2129
2130 #undef getservbyport
2131
2132 struct servent *
2133 rb_w32_getservbyport (int port, char *proto)
2134 {
2135 struct servent *r;
2136 if (!NtSocketsInitialized++) {
2137 StartSockets();
2138 }
2139 RUBY_CRITICAL(r = getservbyport (port, proto));
2140 if (r == NULL)
2141 errno = WSAGetLastError();
2142 return r;
2143 }
2144
2145
2146
2147
2148
2149 void endhostent() {}
2150 void endnetent() {}
2151 void endprotoent() {}
2152 void endservent() {}
2153
2154 struct netent *getnetent (void) {return (struct netent *) NULL;}
2155
2156 struct netent *getnetbyaddr(char *name) {return (struct netent *)NULL;}
2157
2158 struct netent *getnetbyname(long net, int type) {return (struct netent *)NULL;}
2159
2160 struct protoent *getprotoent (void) {return (struct protoent *) NULL;}
2161
2162 struct servent *getservent (void) {return (struct servent *) NULL;}
2163
2164 void sethostent (int stayopen) {}
2165
2166 void setnetent (int stayopen) {}
2167
2168 void setprotoent (int stayopen) {}
2169
2170 void setservent (int stayopen) {}
2171
2172 #ifndef WNOHANG
2173 #define WNOHANG -1
2174 #endif
2175
2176 static pid_t
2177 poll_child_status(struct ChildRecord *child, int *stat_loc)
2178 {
2179 DWORD exitcode;
2180
2181 if (!GetExitCodeProcess(child->hProcess, &exitcode)) {
2182
2183 errno = GetLastError();
2184 if (errno == ERROR_INVALID_PARAMETER) {
2185 errno = ECHILD;
2186 }
2187 CloseChildHandle(child);
2188 return -1;
2189 }
2190 if (exitcode != STILL_ACTIVE) {
2191
2192 pid_t pid = child->pid;
2193 CloseChildHandle(child);
2194 if (stat_loc) *stat_loc = exitcode << 8;
2195 return pid;
2196 }
2197 return 0;
2198 }
2199
2200 pid_t
2201 waitpid (pid_t pid, int *stat_loc, int options)
2202 {
2203 DWORD timeout;
2204
2205 if (options == WNOHANG) {
2206 timeout = 0;
2207 } else {
2208 timeout = INFINITE;
2209 }
2210
2211 if (pid == -1) {
2212 int count = 0;
2213 DWORD ret;
2214 HANDLE events[MAXCHILDNUM + 1];
2215
2216 FOREACH_CHILD(child) {
2217 if (!child->pid || child->pid < 0) continue;
2218 if ((pid = poll_child_status(child, stat_loc))) return pid;
2219 events[count++] = child->hProcess;
2220 } END_FOREACH_CHILD;
2221 if (!count) {
2222 errno = ECHILD;
2223 return -1;
2224 }
2225 events[count] = interrupted_event;
2226
2227 ret = WaitForMultipleEvents(count + 1, events, FALSE, timeout, TRUE);
2228 if (ret == WAIT_TIMEOUT) return 0;
2229 if ((ret -= WAIT_OBJECT_0) == count) {
2230 ResetSignal(interrupted_event);
2231 errno = EINTR;
2232 return -1;
2233 }
2234 if (ret > count) {
2235 errno = GetLastError();
2236 return -1;
2237 }
2238
2239 return poll_child_status(ChildRecord + ret, stat_loc);
2240 }
2241 else {
2242 struct ChildRecord* child = FindChildSlot(pid);
2243 if (!child) {
2244 errno = ECHILD;
2245 return -1;
2246 }
2247
2248 while (!(pid = poll_child_status(child, stat_loc))) {
2249
2250 if (wait_events(child->hProcess, timeout) != WAIT_OBJECT_0) {
2251
2252 pid = 0;
2253 break;
2254 }
2255 }
2256 }
2257
2258 return pid;
2259 }
2260
2261 #include <sys/timeb.h>
2262
2263 int _cdecl
2264 gettimeofday(struct timeval *tv, struct timezone *tz)
2265 {
2266 SYSTEMTIME st;
2267 time_t t;
2268 struct tm tm;
2269
2270 GetLocalTime(&st);
2271 tm.tm_sec = st.wSecond;
2272 tm.tm_min = st.wMinute;
2273 tm.tm_hour = st.wHour;
2274 tm.tm_mday = st.wDay;
2275 tm.tm_mon = st.wMonth - 1;
2276 tm.tm_year = st.wYear - 1900;
2277 tm.tm_isdst = -1;
2278 t = mktime(&tm);
2279 tv->tv_sec = t;
2280 tv->tv_usec = st.wMilliseconds * 1000;
2281
2282 return 0;
2283 }
2284
2285 char *
2286 rb_w32_getcwd(buffer, size)
2287 char *buffer;
2288 int size;
2289 {
2290 int length;
2291 char *bp;
2292
2293 #ifdef __BORLANDC__
2294 #undef getcwd
2295 if (getcwd(buffer, size) == NULL) {
2296 #else
2297 if (_getcwd(buffer, size) == NULL) {
2298 #endif
2299 return NULL;
2300 }
2301 length = strlen(buffer);
2302 if (length >= size) {
2303 return NULL;
2304 }
2305
2306 for (bp = buffer; *bp != '\0'; bp = CharNext(bp)) {
2307 if (*bp == '\\') {
2308 *bp = '/';
2309 }
2310 }
2311 return buffer;
2312 }
2313
2314 static char *
2315 str_grow(struct RString *str, size_t new_size)
2316 {
2317 char *p;
2318
2319 p = realloc(str->ptr, new_size);
2320 if (p == NULL)
2321 rb_fatal("cannot grow string\n");
2322
2323 str->len = new_size;
2324 str->ptr = p;
2325
2326 return p;
2327 }
2328
2329 int
2330 chown(const char *path, int owner, int group)
2331 {
2332 return 0;
2333 }
2334
2335 int
2336 kill(int pid, int sig)
2337 {
2338 int ret = 0;
2339
2340 if (pid <= 0) {
2341 errno = EINVAL;
2342 return -1;
2343 }
2344
2345 if (IsWin95()) pid = -pid;
2346 if ((unsigned int)pid == GetCurrentProcessId() && sig != SIGKILL)
2347 return raise(sig);
2348
2349 switch (sig) {
2350 case SIGINT:
2351 RUBY_CRITICAL({
2352 if (!GenerateConsoleCtrlEvent(CTRL_C_EVENT, (DWORD)pid)) {
2353 if ((errno = GetLastError()) == 0) {
2354 errno = EPERM;
2355 }
2356 ret = -1;
2357 }
2358 });
2359 break;
2360
2361 case SIGKILL:
2362 RUBY_CRITICAL({
2363 HANDLE hProc = OpenProcess(PROCESS_TERMINATE, FALSE, (DWORD)pid);
2364 if (hProc == NULL || hProc == INVALID_HANDLE_VALUE) {
2365 if (GetLastError() == ERROR_INVALID_PARAMETER) {
2366 errno = ESRCH;
2367 }
2368 else {
2369 errno = EPERM;
2370 }
2371 ret = -1;
2372 }
2373 else if (!TerminateProcess(hProc, 0)) {
2374 errno = EPERM;
2375 ret = -1;
2376 }
2377 CloseHandle(hProc);
2378 });
2379 break;
2380
2381 define:
2382 errno = EINVAL;
2383 ret = -1;
2384 break;
2385 }
2386
2387 return ret;
2388 }
2389
2390 int
2391 link(char *from, char *to)
2392 {
2393 return -1;
2394 }
2395
2396 int
2397 wait()
2398 {
2399 return 0;
2400 }
2401
2402 char *
2403 rb_w32_getenv(const char *name)
2404 {
2405 static char *curitem = NULL;
2406 static DWORD curlen = 0;
2407 DWORD needlen;
2408
2409 if (curitem == NULL || curlen == 0) {
2410 curlen = 512;
2411 curitem = ALLOC_N(char, curlen);
2412 }
2413
2414 needlen = GetEnvironmentVariable(name, curitem, curlen);
2415 if (needlen != 0) {
2416 while (needlen > curlen) {
2417 REALLOC_N(curitem, char, needlen);
2418 curlen = needlen;
2419 needlen = GetEnvironmentVariable(name, curitem, curlen);
2420 }
2421 }
2422 else {
2423 return NULL;
2424 }
2425
2426 return curitem;
2427 }
2428
2429 int
2430 rb_w32_rename(const char *oldpath, const char *newpath)
2431 {
2432 int res = 0;
2433 int oldatts;
2434 int newatts;
2435
2436 oldatts = GetFileAttributes(oldpath);
2437 newatts = GetFileAttributes(newpath);
2438
2439 if (oldatts == -1) {
2440 errno = GetLastError();
2441 return -1;
2442 }
2443
2444 RUBY_CRITICAL({
2445 if (newatts != -1 && newatts & FILE_ATTRIBUTE_READONLY)
2446 SetFileAttributesA(newpath, newatts & ~ FILE_ATTRIBUTE_READONLY);
2447
2448 if (!MoveFile(oldpath, newpath))
2449 res = -1;
2450
2451 if (res) {
2452 switch (GetLastError()) {
2453 case ERROR_ALREADY_EXISTS:
2454 case ERROR_FILE_EXISTS:
2455 if (IsWinNT()) {
2456 if (MoveFileEx(oldpath, newpath, MOVEFILE_REPLACE_EXISTING))
2457 res = 0;
2458 } else {
2459 for (;;) {
2460 if (!DeleteFile(newpath) && GetLastError() != ERROR_FILE_NOT_FOUND)
2461 break;
2462 else if (MoveFile(oldpath, newpath)) {
2463 res = 0;
2464 break;
2465 }
2466 }
2467 }
2468 }
2469 }
2470
2471 if (res)
2472 errno = GetLastError();
2473 else
2474 SetFileAttributes(newpath, oldatts);
2475 });
2476
2477 return res;
2478 }
2479
2480 static int
2481 isUNCRoot(const char *path)
2482 {
2483 if (path[0] == '\\' && path[1] == '\\') {
2484 const char *p;
2485 for (p = path + 3; *p; p = CharNext(p)) {
2486 if (*p == '\\')
2487 break;
2488 }
2489 if (p[0] && p[1]) {
2490 for (p++; *p; p = CharNext(p)) {
2491 if (*p == '\\')
2492 break;
2493 }
2494 if (!p[0] || !p[1])
2495 return 1;
2496 }
2497 }
2498 return 0;
2499 }
2500
2501 int
2502 rb_w32_stat(const char *path, struct stat *st)
2503 {
2504 const char *p;
2505 char *buf1 = ALLOCA_N(char, strlen(path) + 2);
2506 char *buf2 = ALLOCA_N(char, MAXPATHLEN);
2507 char *s;
2508 int len;
2509 int ret;
2510
2511 for (p = path, s = buf1; *p; p++, s++) {
2512 if (*p == '/')
2513 *s = '\\';
2514 else
2515 *s = *p;
2516 }
2517 *s = '\0';
2518 len = strlen(buf1);
2519 p = CharPrev(buf1, buf1 + len);
2520 if (isUNCRoot(buf1)) {
2521 if (*p != '\\')
2522 strcat(buf1, "\\");
2523 } else if (*p == '\\' || *p == ':')
2524 strcat(buf1, ".");
2525 if (_fullpath(buf2, buf1, MAXPATHLEN)) {
2526 ret = stat(buf2, st);
2527 if (ret == 0) {
2528 st->st_mode &= ~(S_IWGRP | S_IWOTH);
2529 }
2530 return ret;
2531 }
2532 else
2533 return -1;
2534 }
2535
2536 static long
2537 filetime_to_clock(FILETIME *ft)
2538 {
2539 __int64 qw = ft->dwHighDateTime;
2540 qw <<= 32;
2541 qw |= ft->dwLowDateTime;
2542 qw /= 10000;
2543 return (long) qw;
2544 }
2545
2546 int
2547 rb_w32_times(struct tms *tmbuf)
2548 {
2549 FILETIME create, exit, kernel, user;
2550
2551 if (GetProcessTimes(GetCurrentProcess(),&create, &exit, &kernel, &user)) {
2552 tmbuf->tms_utime = filetime_to_clock(&user);
2553 tmbuf->tms_stime = filetime_to_clock(&kernel);
2554 tmbuf->tms_cutime = 0;
2555 tmbuf->tms_cstime = 0;
2556 }
2557 else {
2558 tmbuf->tms_utime = clock();
2559 tmbuf->tms_stime = 0;
2560 tmbuf->tms_cutime = 0;
2561 tmbuf->tms_cstime = 0;
2562 }
2563 return 0;
2564 }
2565
2566 #undef Sleep
2567 #define yield_once() Sleep(0)
2568 #define yield_until(condition) do yield_once(); while (!(condition))
2569
2570 static DWORD wait_events(HANDLE event, DWORD timeout)
2571 {
2572 HANDLE events[2];
2573 int count = 0;
2574 DWORD ret;
2575
2576 if (event) {
2577 events[count++] = event;
2578 }
2579 events[count++] = interrupted_event;
2580
2581 ret = WaitForMultipleEvents(count, events, FALSE, timeout, TRUE);
2582
2583 if (ret == WAIT_OBJECT_0 + count - 1) {
2584 ResetSignal(interrupted_event);
2585 errno = EINTR;
2586 }
2587
2588 return ret;
2589 }
2590
2591 static CRITICAL_SECTION* system_state(void)
2592 {
2593 static int initialized = 0;
2594 static CRITICAL_SECTION syssect;
2595
2596 if (!initialized) {
2597 InitializeCriticalSection(&syssect);
2598 initialized = 1;
2599 }
2600 return &syssect;
2601 }
2602
2603 static LONG flag_interrupt = -1;
2604 static volatile DWORD tlsi_interrupt = TLS_OUT_OF_INDEXES;
2605
2606 void rb_w32_enter_critical(void)
2607 {
2608 if (IsWinNT()) {
2609 EnterCriticalSection(system_state());
2610 return;
2611 }
2612
2613 if (tlsi_interrupt == TLS_OUT_OF_INDEXES) {
2614 tlsi_interrupt = TlsAlloc();
2615 }
2616
2617 {
2618 DWORD ti = (DWORD)TlsGetValue(tlsi_interrupt);
2619 while (InterlockedIncrement(&flag_interrupt) > 0 && !ti) {
2620 InterlockedDecrement(&flag_interrupt);
2621 Sleep(1);
2622 }
2623 TlsSetValue(tlsi_interrupt, (PVOID)++ti);
2624 }
2625 }
2626
2627 void rb_w32_leave_critical(void)
2628 {
2629 if (IsWinNT()) {
2630 LeaveCriticalSection(system_state());
2631 return;
2632 }
2633
2634 InterlockedDecrement(&flag_interrupt);
2635 TlsSetValue(tlsi_interrupt, (PVOID)((DWORD)TlsGetValue(tlsi_interrupt) - 1));
2636 }
2637
2638 struct handler_arg_t {
2639 void (*handler)(int);
2640 int arg;
2641 int status;
2642 int finished;
2643 HANDLE handshake;
2644 };
2645
2646 static void rb_w32_call_handler(struct handler_arg_t* h)
2647 {
2648 int status;
2649 RUBY_CRITICAL(rb_protect((VALUE (*)(VALUE))h->handler, (VALUE)h->arg, &h->status);
2650 status = h->status;
2651 SetEvent(h->handshake));
2652 if (status) {
2653 rb_jump_tag(status);
2654 }
2655 h->finished = 1;
2656 Sleep(INFINITE);
2657 }
2658
2659 static struct handler_arg_t* setup_handler(struct handler_arg_t *harg,
2660 int arg,
2661 void (*handler)(int),
2662 HANDLE handshake)
2663 {
2664 harg->handler = handler;
2665 harg->arg = arg;
2666 harg->status = 0;
2667 harg->finished = 0;
2668 harg->handshake = handshake;
2669 return harg;
2670 }
2671
2672 static void setup_call(CONTEXT* ctx, struct handler_arg_t *harg)
2673 {
2674 #ifdef _M_IX86
2675 DWORD *esp = (DWORD *)ctx->Esp;
2676 *--esp = (DWORD)harg;
2677 *--esp = ctx->Eip;
2678 ctx->Esp = (DWORD)esp;
2679 ctx->Eip = (DWORD)rb_w32_call_handler;
2680 #else
2681 #error unsupported processor
2682 #endif
2683 }
2684
2685 int rb_w32_main_context(int arg, void (*handler)(int))
2686 {
2687 static HANDLE interrupt_done = NULL;
2688 struct handler_arg_t harg;
2689 CONTEXT ctx_orig;
2690 HANDLE current_thread = GetCurrentThread();
2691 int old_priority = GetThreadPriority(current_thread);
2692
2693 if (GetCurrentThreadId() == main_thread.id) return FALSE;
2694
2695 SetSignal(interrupted_event);
2696
2697 RUBY_CRITICAL({
2698 CONTEXT ctx;
2699
2700 SuspendThread(main_thread.handle);
2701 SetThreadPriority(current_thread, GetThreadPriority(main_thread.handle));
2702
2703 ZeroMemory(&ctx, sizeof(CONTEXT));
2704 ctx.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT;
2705 GetThreadContext(main_thread.handle, &ctx);
2706 ctx_orig = ctx;
2707
2708
2709 if (!interrupt_done) {
2710 interrupt_done = CreateEvent(NULL, FALSE, FALSE, NULL);
2711
2712 }
2713 else {
2714 ResetEvent(interrupt_done);
2715 }
2716 setup_call(&ctx, setup_handler(&harg, arg, handler, interrupt_done));
2717
2718 ctx.ContextFlags = CONTEXT_CONTROL;
2719 SetThreadContext(main_thread.handle, &ctx);
2720 ResumeThread(main_thread.handle);
2721 });
2722
2723
2724 yield_once();
2725 WaitForSingleObject(interrupt_done, INFINITE);
2726
2727 if (!harg.status) {
2728
2729 RUBY_CRITICAL({
2730
2731 yield_until(harg.finished);
2732
2733 SuspendThread(main_thread.handle);
2734 ctx_orig.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT;
2735 SetThreadContext(main_thread.handle, &ctx_orig);
2736 ResumeThread(main_thread.handle);
2737 });
2738 }
2739
2740
2741 SetThreadPriority(current_thread, old_priority);
2742
2743 return TRUE;
2744 }
2745
2746 int rb_w32_sleep(unsigned long msec)
2747 {
2748 DWORD ret;
2749 RUBY_CRITICAL(ret = wait_events(NULL, msec));
2750 yield_once();
2751 CHECK_INTS;
2752 return ret != WAIT_TIMEOUT;
2753 }
2754
2755 static void catch_interrupt(void)
2756 {
2757 yield_once();
2758 RUBY_CRITICAL(wait_events(NULL, 0));
2759 CHECK_INTS;
2760 }
2761
2762 #undef fgetc
2763 int rb_w32_getc(FILE* stream)
2764 {
2765 int c, trap_immediate = rb_trap_immediate;
2766 if (--stream->FILE_COUNT >= 0) {
2767 c = (unsigned char)*stream->FILE_READPTR++;
2768 rb_trap_immediate = trap_immediate;
2769 }
2770 else {
2771 c = _filbuf(stream);
2772 #ifdef __BORLANDC__
2773 if( ( c == EOF )&&( errno == EPIPE ) )
2774 {
2775 clearerr(stream);
2776 }
2777 #endif
2778 rb_trap_immediate = trap_immediate;
2779 catch_interrupt();
2780 }
2781 return c;
2782 }
2783
2784 #undef fputc
2785 int rb_w32_putc(int c, FILE* stream)
2786 {
2787 int trap_immediate = rb_trap_immediate;
2788 if (--stream->FILE_COUNT >= 0) {
2789 c = (unsigned char)(*stream->FILE_READPTR++ = (char)c);
2790 rb_trap_immediate = trap_immediate;
2791 }
2792 else {
2793 c = _flsbuf(c, stream);
2794 rb_trap_immediate = trap_immediate;
2795 catch_interrupt();
2796 }
2797 return c;
2798 }
2799
2800 struct asynchronous_arg_t {
2801
2802 void* stackaddr;
2803
2804
2805 VALUE (*func)(VALUE self, int argc, VALUE* argv);
2806 VALUE self;
2807 int argc;
2808 VALUE* argv;
2809 };
2810
2811 static DWORD WINAPI
2812 call_asynchronous(PVOID argp)
2813 {
2814 struct asynchronous_arg_t *arg = argp;
2815 arg->stackaddr = &argp;
2816 return (DWORD)arg->func(arg->self, arg->argc, arg->argv);
2817 }
2818
2819 VALUE rb_w32_asynchronize(asynchronous_func_t func,
2820 VALUE self, int argc, VALUE* argv, VALUE intrval)
2821 {
2822 DWORD val;
2823 BOOL interrupted = FALSE;
2824 HANDLE thr;
2825
2826 RUBY_CRITICAL({
2827 struct asynchronous_arg_t arg;
2828
2829 arg.stackaddr = NULL;
2830 arg.func = func;
2831 arg.self = self;
2832 arg.argc = argc;
2833 arg.argv = argv;
2834
2835 thr = CreateThread(NULL, 0, call_asynchronous, &arg, 0, &val);
2836
2837 if (thr) {
2838 yield_until(arg.stackaddr);
2839
2840 if (wait_events(thr, INFINITE) != WAIT_OBJECT_0) {
2841 interrupted = TRUE;
2842
2843 if (TerminateThread(thr, intrval)) {
2844 yield_once();
2845 }
2846 }
2847
2848 GetExitCodeThread(thr, &val);
2849 CloseHandle(thr);
2850
2851 if (interrupted) {
2852
2853 MEMORY_BASIC_INFORMATION m;
2854
2855 memset(&m, 0, sizeof(m));
2856 if (!VirtualQuery(arg.stackaddr, &m, sizeof(m))) {
2857 Debug(fprintf(stderr, "couldn't get stack base:%p:%d\n",
2858 arg.stackaddr, GetLastError()));
2859 }
2860 else if (!VirtualFree(m.AllocationBase, 0, MEM_RELEASE)) {
2861 Debug(fprintf(stderr, "couldn't release stack:%p:%d\n",
2862 m.AllocationBase, GetLastError()));
2863 }
2864 }
2865 }
2866 });
2867
2868 if (!thr) {
2869 rb_fatal("failed to launch waiter thread:%d", GetLastError());
2870 }
2871
2872 if (interrupted) {
2873 errno = EINTR;
2874 CHECK_INTS;
2875 }
2876
2877 return val;
2878 }
2879
2880 char **rb_w32_get_environ(void)
2881 {
2882 char *envtop, *env;
2883 char **myenvtop, **myenv;
2884 int num;
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895 envtop = GetEnvironmentStrings();
2896 for (env = envtop, num = 0; *env; env += strlen(env) + 1)
2897 if (*env != '=') num++;
2898
2899 myenvtop = ALLOC_N(char*, num + 1);
2900 for (env = envtop, myenv = myenvtop; *env; env += strlen(env) + 1) {
2901 if (*env != '=') {
2902 *myenv = ALLOC_N(char, strlen(env) + 1);
2903 strcpy(*myenv, env);
2904 myenv++;
2905 }
2906 }
2907 *myenv = NULL;
2908 FreeEnvironmentStrings(envtop);
2909
2910 return myenvtop;
2911 }
2912
2913 void rb_w32_free_environ(char **env)
2914 {
2915 char **t = env;
2916
2917 while (*t) free(*t++);
2918 free(env);
2919 }
2920
2921 pid_t rb_w32_getpid(void)
2922 {
2923 pid_t pid;
2924
2925 pid = _getpid();
2926 if (IsWin95()) pid = -pid;
2927
2928 return pid;
2929 }