mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	* ext/socket/getaddrinfo.c: fix typo. fixed: [ruby-core:03947] * win32/win32.c: need to include dln.h. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@7531 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
		
			
				
	
	
		
			3369 lines
		
	
	
	
		
			68 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			3369 lines
		
	
	
	
		
			68 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 *  Copyright (c) 1993, Intergraph Corporation
 | 
						|
 *
 | 
						|
 *  You may distribute under the terms of either the GNU General Public
 | 
						|
 *  License or the Artistic License, as specified in the perl README file.
 | 
						|
 *
 | 
						|
 *  Various Unix compatibility functions and NT specific functions.
 | 
						|
 *
 | 
						|
 *  Some of this code was derived from the MSDOS port(s) and the OS/2 port.
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
#include "ruby.h"
 | 
						|
#include "rubysig.h"
 | 
						|
#include "dln.h"
 | 
						|
#include <fcntl.h>
 | 
						|
#include <process.h>
 | 
						|
#include <sys/stat.h>
 | 
						|
/* #include <sys/wait.h> */
 | 
						|
#include <stdio.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <errno.h>
 | 
						|
#include <assert.h>
 | 
						|
 | 
						|
#include <windows.h>
 | 
						|
#include <winbase.h>
 | 
						|
#include <wincon.h>
 | 
						|
#ifdef __MINGW32__
 | 
						|
#include <mswsock.h>
 | 
						|
#endif
 | 
						|
#include "win32.h"
 | 
						|
#include "win32/dir.h"
 | 
						|
#ifdef _WIN32_WCE
 | 
						|
#include "wince.h"
 | 
						|
#endif
 | 
						|
#ifndef index
 | 
						|
#define index(x, y) strchr((x), (y))
 | 
						|
#endif
 | 
						|
#define isdirsep(x) ((x) == '/' || (x) == '\\')
 | 
						|
 | 
						|
#undef stat
 | 
						|
#undef fclose
 | 
						|
#undef close
 | 
						|
#undef setsockopt
 | 
						|
 | 
						|
#ifndef bool
 | 
						|
#define bool int
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef _M_IX86
 | 
						|
# define WIN95 1
 | 
						|
#else
 | 
						|
# undef  WIN95
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined __BORLANDC__ || defined _WIN32_WCE
 | 
						|
#  define _filbuf _fgetc
 | 
						|
#  define _flsbuf _fputc
 | 
						|
#  define enough_to_get(n) (--(n) >= 0)
 | 
						|
#  define enough_to_put(n) (++(n) < 0)
 | 
						|
#else
 | 
						|
#  define enough_to_get(n) (--(n) >= 0)
 | 
						|
#  define enough_to_put(n) (--(n) >= 0)
 | 
						|
#endif
 | 
						|
 | 
						|
#if HAVE_WSAWAITFORMULTIPLEEVENTS
 | 
						|
# define USE_INTERRUPT_WINSOCK
 | 
						|
#endif
 | 
						|
 | 
						|
#if USE_INTERRUPT_WINSOCK
 | 
						|
# define WaitForMultipleEvents WSAWaitForMultipleEvents
 | 
						|
# define CreateSignal() (HANDLE)WSACreateEvent()
 | 
						|
# define SetSignal(ev) WSASetEvent(ev)
 | 
						|
# define ResetSignal(ev) WSAResetEvent(ev)
 | 
						|
#else  /* USE_INTERRUPT_WINSOCK */
 | 
						|
# define WaitForMultipleEvents WaitForMultipleObjectsEx
 | 
						|
# define CreateSignal() CreateEvent(NULL, FALSE, FALSE, NULL);
 | 
						|
# define SetSignal(ev) SetEvent(ev)
 | 
						|
# define ResetSignal(ev) (void)0
 | 
						|
#endif /* USE_INTERRUPT_WINSOCK */
 | 
						|
 | 
						|
#ifdef WIN32_DEBUG
 | 
						|
#define Debug(something) something
 | 
						|
#else
 | 
						|
#define Debug(something) /* nothing */
 | 
						|
#endif
 | 
						|
 | 
						|
#define TO_SOCKET(x)	_get_osfhandle(x)
 | 
						|
 | 
						|
bool NtSyncProcess = TRUE;
 | 
						|
 | 
						|
static struct ChildRecord *CreateChild(const char *, const char *, SECURITY_ATTRIBUTES *, HANDLE, HANDLE, HANDLE);
 | 
						|
static bool has_redirection(const char *);
 | 
						|
static void StartSockets ();
 | 
						|
static DWORD wait_events(HANDLE event, DWORD timeout);
 | 
						|
#if !defined(__BORLANDC__) && !defined(_WIN32_WCE)
 | 
						|
static int rb_w32_open_osfhandle(long osfhandle, int flags);
 | 
						|
#else
 | 
						|
#define rb_w32_open_osfhandle(osfhandle, flags) _open_osfhandle(osfhandle, flags)
 | 
						|
#endif
 | 
						|
 | 
						|
/* errno mapping */
 | 
						|
static struct {
 | 
						|
    DWORD winerr;
 | 
						|
    int err;
 | 
						|
} errmap[] = {
 | 
						|
    {	ERROR_INVALID_FUNCTION,		EINVAL		},
 | 
						|
    {	ERROR_FILE_NOT_FOUND,		ENOENT		},
 | 
						|
    {	ERROR_PATH_NOT_FOUND,		ENOENT		},
 | 
						|
    {	ERROR_TOO_MANY_OPEN_FILES,	EMFILE		},
 | 
						|
    {	ERROR_ACCESS_DENIED,		EACCES		},
 | 
						|
    {	ERROR_INVALID_HANDLE,		EBADF		},
 | 
						|
    {	ERROR_ARENA_TRASHED,		ENOMEM		},
 | 
						|
    {	ERROR_NOT_ENOUGH_MEMORY,	ENOMEM		},
 | 
						|
    {	ERROR_INVALID_BLOCK,		ENOMEM		},
 | 
						|
    {	ERROR_BAD_ENVIRONMENT,		E2BIG		},
 | 
						|
    {	ERROR_BAD_FORMAT,		ENOEXEC		},
 | 
						|
    {	ERROR_INVALID_ACCESS,		EINVAL		},
 | 
						|
    {	ERROR_INVALID_DATA,		EINVAL		},
 | 
						|
    {	ERROR_INVALID_DRIVE,		ENOENT		},
 | 
						|
    {	ERROR_CURRENT_DIRECTORY,	EACCES		},
 | 
						|
    {	ERROR_NOT_SAME_DEVICE,		EXDEV		},
 | 
						|
    {	ERROR_NO_MORE_FILES,		ENOENT		},
 | 
						|
    {	ERROR_WRITE_PROTECT,		EROFS		},
 | 
						|
    {	ERROR_BAD_UNIT,			ENODEV		},
 | 
						|
    {	ERROR_NOT_READY,		ENXIO		},
 | 
						|
    {	ERROR_BAD_COMMAND,		EACCES		},
 | 
						|
    {	ERROR_CRC,			EACCES		},
 | 
						|
    {	ERROR_BAD_LENGTH,		EACCES		},
 | 
						|
    {	ERROR_SEEK,			EIO		},
 | 
						|
    {	ERROR_NOT_DOS_DISK,		EACCES		},
 | 
						|
    {	ERROR_SECTOR_NOT_FOUND,		EACCES		},
 | 
						|
    {	ERROR_OUT_OF_PAPER,		EACCES		},
 | 
						|
    {	ERROR_WRITE_FAULT,		EIO		},
 | 
						|
    {	ERROR_READ_FAULT,		EIO		},
 | 
						|
    {	ERROR_GEN_FAILURE,		EACCES		},
 | 
						|
    {	ERROR_LOCK_VIOLATION,		EACCES		},
 | 
						|
    {	ERROR_SHARING_VIOLATION,	EACCES		},
 | 
						|
    {	ERROR_WRONG_DISK,		EACCES		},
 | 
						|
    {	ERROR_SHARING_BUFFER_EXCEEDED,	EACCES		},
 | 
						|
    {	ERROR_BAD_NETPATH,		ENOENT		},
 | 
						|
    {	ERROR_NETWORK_ACCESS_DENIED,	EACCES		},
 | 
						|
    {	ERROR_BAD_NET_NAME,		ENOENT		},
 | 
						|
    {	ERROR_FILE_EXISTS,		EEXIST		},
 | 
						|
    {	ERROR_CANNOT_MAKE,		EACCES		},
 | 
						|
    {	ERROR_FAIL_I24,			EACCES		},
 | 
						|
    {	ERROR_INVALID_PARAMETER,	EINVAL		},
 | 
						|
    {	ERROR_NO_PROC_SLOTS,		EAGAIN		},
 | 
						|
    {	ERROR_DRIVE_LOCKED,		EACCES		},
 | 
						|
    {	ERROR_BROKEN_PIPE,		EPIPE		},
 | 
						|
    {	ERROR_DISK_FULL,		ENOSPC		},
 | 
						|
    {	ERROR_INVALID_TARGET_HANDLE,	EBADF		},
 | 
						|
    {	ERROR_INVALID_HANDLE,		EINVAL		},
 | 
						|
    {	ERROR_WAIT_NO_CHILDREN,		ECHILD		},
 | 
						|
    {	ERROR_CHILD_NOT_COMPLETE,	ECHILD		},
 | 
						|
    {	ERROR_DIRECT_ACCESS_HANDLE,	EBADF		},
 | 
						|
    {	ERROR_NEGATIVE_SEEK,		EINVAL		},
 | 
						|
    {	ERROR_SEEK_ON_DEVICE,		EACCES		},
 | 
						|
    {	ERROR_DIR_NOT_EMPTY,		ENOTEMPTY	},
 | 
						|
    {	ERROR_NOT_LOCKED,		EACCES		},
 | 
						|
    {	ERROR_BAD_PATHNAME,		ENOENT		},
 | 
						|
    {	ERROR_MAX_THRDS_REACHED,	EAGAIN		},
 | 
						|
    {	ERROR_LOCK_FAILED,		EACCES		},
 | 
						|
    {	ERROR_ALREADY_EXISTS,		EEXIST		},
 | 
						|
    {	ERROR_INVALID_STARTING_CODESEG,	ENOEXEC		},
 | 
						|
    {	ERROR_INVALID_STACKSEG,		ENOEXEC		},
 | 
						|
    {	ERROR_INVALID_MODULETYPE,	ENOEXEC		},
 | 
						|
    {	ERROR_INVALID_EXE_SIGNATURE,	ENOEXEC		},
 | 
						|
    {	ERROR_EXE_MARKED_INVALID,	ENOEXEC		},
 | 
						|
    {	ERROR_BAD_EXE_FORMAT,		ENOEXEC		},
 | 
						|
    {	ERROR_ITERATED_DATA_EXCEEDS_64k,ENOEXEC		},
 | 
						|
    {	ERROR_INVALID_MINALLOCSIZE,	ENOEXEC		},
 | 
						|
    {	ERROR_DYNLINK_FROM_INVALID_RING,ENOEXEC		},
 | 
						|
    {	ERROR_IOPL_NOT_ENABLED,		ENOEXEC		},
 | 
						|
    {	ERROR_INVALID_SEGDPL,		ENOEXEC		},
 | 
						|
    {	ERROR_AUTODATASEG_EXCEEDS_64k,	ENOEXEC		},
 | 
						|
    {	ERROR_RING2SEG_MUST_BE_MOVABLE,	ENOEXEC		},
 | 
						|
    {	ERROR_RELOC_CHAIN_XEEDS_SEGLIM,	ENOEXEC		},
 | 
						|
    {	ERROR_INFLOOP_IN_RELOC_CHAIN,	ENOEXEC		},
 | 
						|
    {	ERROR_FILENAME_EXCED_RANGE,	ENOENT		},
 | 
						|
    {	ERROR_NESTING_NOT_ALLOWED,	EAGAIN		},
 | 
						|
    {	ERROR_NOT_ENOUGH_QUOTA,		ENOMEM		},
 | 
						|
    {	WSAENAMETOOLONG,		ENAMETOOLONG	},
 | 
						|
    {	WSAENOTEMPTY,			ENOTEMPTY	}
 | 
						|
};
 | 
						|
 | 
						|
static int
 | 
						|
map_errno(DWORD winerr)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
 | 
						|
    if (winerr == 0) {
 | 
						|
	return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    for (i = 0; i < sizeof(errmap) / sizeof(*errmap); i++) {
 | 
						|
	if (errmap[i].winerr == winerr) {
 | 
						|
	    return errmap[i].err;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
    if (winerr >= WSABASEERR) {
 | 
						|
	return winerr;
 | 
						|
    }
 | 
						|
    return EINVAL;
 | 
						|
}
 | 
						|
 | 
						|
static char *NTLoginName;
 | 
						|
 | 
						|
#ifdef WIN95
 | 
						|
DWORD Win32System = (DWORD)-1;
 | 
						|
 | 
						|
static DWORD
 | 
						|
IdOS(void)
 | 
						|
{
 | 
						|
    static OSVERSIONINFO osver;
 | 
						|
 | 
						|
    if (osver.dwPlatformId != Win32System) {
 | 
						|
	memset(&osver, 0, sizeof(OSVERSIONINFO));
 | 
						|
	osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
 | 
						|
	GetVersionEx(&osver);
 | 
						|
	Win32System = osver.dwPlatformId;
 | 
						|
    }
 | 
						|
    return (Win32System);
 | 
						|
}
 | 
						|
 | 
						|
static int 
 | 
						|
IsWin95(void) {
 | 
						|
    return (IdOS() == VER_PLATFORM_WIN32_WINDOWS);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
IsWinNT(void) {
 | 
						|
    return (IdOS() == VER_PLATFORM_WIN32_NT);
 | 
						|
}
 | 
						|
#else
 | 
						|
# define IsWinNT() TRUE
 | 
						|
# define IsWin95() FALSE
 | 
						|
#endif
 | 
						|
 | 
						|
/* main thread constants */
 | 
						|
static struct {
 | 
						|
    HANDLE handle;
 | 
						|
    DWORD id;
 | 
						|
} main_thread;
 | 
						|
 | 
						|
/* interrupt stuff */
 | 
						|
static HANDLE interrupted_event;
 | 
						|
 | 
						|
HANDLE GetCurrentThreadHandle(void)
 | 
						|
{
 | 
						|
    static HANDLE current_process_handle = NULL;
 | 
						|
    HANDLE h;
 | 
						|
 | 
						|
    if (!current_process_handle)
 | 
						|
	current_process_handle = GetCurrentProcess();
 | 
						|
    if (!DuplicateHandle(current_process_handle, GetCurrentThread(),
 | 
						|
			 current_process_handle, &h,
 | 
						|
			 0, FALSE, DUPLICATE_SAME_ACCESS))
 | 
						|
	return NULL;
 | 
						|
    return h;
 | 
						|
}
 | 
						|
 | 
						|
/* simulate flock by locking a range on the file */
 | 
						|
 | 
						|
 | 
						|
#define LK_ERR(f,i) ((f) ? (i = 0) : (errno = GetLastError() == ERROR_LOCK_VIOLATION ? EWOULDBLOCK : EACCES))
 | 
						|
#define LK_LEN      ULONG_MAX
 | 
						|
 | 
						|
static VALUE
 | 
						|
flock_winnt(VALUE self, int argc, VALUE* argv)
 | 
						|
{
 | 
						|
    OVERLAPPED o;
 | 
						|
    int i = -1;
 | 
						|
    const HANDLE fh = (HANDLE)self;
 | 
						|
    const int oper = argc;
 | 
						|
 | 
						|
    memset(&o, 0, sizeof(o));
 | 
						|
 | 
						|
    switch(oper) {
 | 
						|
      case LOCK_SH:		/* shared lock */
 | 
						|
	LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, LK_LEN, &o), i);
 | 
						|
	break;
 | 
						|
      case LOCK_EX:		/* exclusive lock */
 | 
						|
	LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, LK_LEN, &o), i);
 | 
						|
	break;
 | 
						|
      case LOCK_SH|LOCK_NB:	/* non-blocking shared lock */
 | 
						|
	LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, LK_LEN, &o), i);
 | 
						|
	break;
 | 
						|
      case LOCK_EX|LOCK_NB:	/* non-blocking exclusive lock */
 | 
						|
	LK_ERR(LockFileEx(fh,
 | 
						|
			  LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
 | 
						|
			  0, LK_LEN, LK_LEN, &o), i);
 | 
						|
	break;
 | 
						|
      case LOCK_UN:		/* unlock lock */
 | 
						|
	LK_ERR(UnlockFileEx(fh, 0, LK_LEN, LK_LEN, &o), i);
 | 
						|
	break;
 | 
						|
      default:            /* unknown */
 | 
						|
	errno = EINVAL;
 | 
						|
	break;
 | 
						|
    }
 | 
						|
    return i;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef WIN95
 | 
						|
static VALUE
 | 
						|
flock_win95(VALUE self, int argc, VALUE* argv)
 | 
						|
{
 | 
						|
    int i = -1;
 | 
						|
    const HANDLE fh = (HANDLE)self;
 | 
						|
    const int oper = argc;
 | 
						|
 | 
						|
    switch(oper) {
 | 
						|
      case LOCK_EX:
 | 
						|
	do {
 | 
						|
	    LK_ERR(LockFile(fh, 0, 0, LK_LEN, LK_LEN), i);
 | 
						|
	} while (i && errno == EWOULDBLOCK);
 | 
						|
	break;
 | 
						|
      case LOCK_EX|LOCK_NB:
 | 
						|
	LK_ERR(LockFile(fh, 0, 0, LK_LEN, LK_LEN), i);
 | 
						|
	break;
 | 
						|
      case LOCK_UN:
 | 
						|
	LK_ERR(UnlockFile(fh, 0, 0, LK_LEN, LK_LEN), i);
 | 
						|
	break;
 | 
						|
      default:
 | 
						|
	errno = EINVAL;
 | 
						|
	break;
 | 
						|
    }
 | 
						|
    return i;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#undef LK_ERR
 | 
						|
 | 
						|
int
 | 
						|
flock(int fd, int oper)
 | 
						|
{
 | 
						|
#ifdef WIN95
 | 
						|
    static asynchronous_func_t locker = NULL;
 | 
						|
 | 
						|
    if (!locker) {
 | 
						|
	if (IsWinNT())
 | 
						|
	    locker = flock_winnt;
 | 
						|
	else
 | 
						|
	    locker = flock_win95;
 | 
						|
    }
 | 
						|
#else
 | 
						|
    const asynchronous_func_t locker = flock_winnt;
 | 
						|
#endif
 | 
						|
 | 
						|
    return rb_w32_asynchronize(locker,
 | 
						|
			      (VALUE)_get_osfhandle(fd), oper, NULL,
 | 
						|
			      (DWORD)-1);
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// Initialization stuff
 | 
						|
//
 | 
						|
void
 | 
						|
NtInitialize(int *argc, char ***argv)
 | 
						|
{
 | 
						|
 | 
						|
    WORD version;
 | 
						|
    int ret;
 | 
						|
 | 
						|
#ifdef __BORLANDC__
 | 
						|
    _controlfp(0x5, 0x5);
 | 
						|
#endif
 | 
						|
 | 
						|
    //
 | 
						|
    // Now set up the correct time stuff
 | 
						|
    //
 | 
						|
 | 
						|
    tzset();
 | 
						|
 | 
						|
    // Initialize Winsock
 | 
						|
    StartSockets();
 | 
						|
}
 | 
						|
 | 
						|
char *getlogin()
 | 
						|
{
 | 
						|
    char buffer[200];
 | 
						|
    DWORD len = 200;
 | 
						|
    extern char *NTLoginName;
 | 
						|
 | 
						|
    if (NTLoginName == NULL) {
 | 
						|
	if (GetUserName(buffer, &len)) {
 | 
						|
	    NTLoginName = ALLOC_N(char, len+1);
 | 
						|
	    strncpy(NTLoginName, buffer, len);
 | 
						|
	    NTLoginName[len] = '\0';
 | 
						|
	}
 | 
						|
	else {
 | 
						|
	    NTLoginName = "<Unknown>";
 | 
						|
	}
 | 
						|
    }
 | 
						|
    return NTLoginName;
 | 
						|
}
 | 
						|
 | 
						|
#define MAXCHILDNUM 256	/* max num of child processes */
 | 
						|
 | 
						|
static struct ChildRecord {
 | 
						|
    HANDLE hProcess;	/* process handle */
 | 
						|
    pid_t pid;		/* process id */
 | 
						|
} ChildRecord[MAXCHILDNUM];
 | 
						|
 | 
						|
#define FOREACH_CHILD(v) do { \
 | 
						|
    struct ChildRecord* v; \
 | 
						|
    for (v = ChildRecord; v < ChildRecord + sizeof(ChildRecord) / sizeof(ChildRecord[0]); ++v)
 | 
						|
#define END_FOREACH_CHILD } while (0)
 | 
						|
 | 
						|
static struct ChildRecord *
 | 
						|
FindFirstChildSlot(void)
 | 
						|
{
 | 
						|
    FOREACH_CHILD(child) {
 | 
						|
	if (child->pid) return child;
 | 
						|
    } END_FOREACH_CHILD;
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
static struct ChildRecord *
 | 
						|
FindChildSlot(pid_t pid)
 | 
						|
{
 | 
						|
 | 
						|
    FOREACH_CHILD(child) {
 | 
						|
	if (child->pid == pid) {
 | 
						|
	    return child;
 | 
						|
	}
 | 
						|
    } END_FOREACH_CHILD;
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
CloseChildHandle(struct ChildRecord *child)
 | 
						|
{
 | 
						|
    HANDLE h = child->hProcess;
 | 
						|
    child->hProcess = NULL;
 | 
						|
    child->pid = 0;
 | 
						|
    CloseHandle(h);
 | 
						|
}
 | 
						|
 | 
						|
static struct ChildRecord *
 | 
						|
FindFreeChildSlot(void)
 | 
						|
{
 | 
						|
    FOREACH_CHILD(child) {
 | 
						|
	if (!child->pid) {
 | 
						|
	    child->pid = -1;	/* lock the slot */
 | 
						|
	    child->hProcess = NULL;
 | 
						|
	    return child;
 | 
						|
	}
 | 
						|
    } END_FOREACH_CHILD;
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int SafeFree(char **vec, int vecc)
 | 
						|
{
 | 
						|
    //   vec
 | 
						|
    //   |
 | 
						|
    //   V       ^---------------------V
 | 
						|
    //   +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
 | 
						|
    //   |   |       | ....  |  NULL |   | ..... |\0 |   | ..... |\0 |...
 | 
						|
    //   +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
 | 
						|
    //   |-  elements+1             -| ^ 1st element   ^ 2nd element
 | 
						|
 | 
						|
	char *p;
 | 
						|
 | 
						|
	p = (char *)vec;
 | 
						|
	free(p);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  ruby -lne 'BEGIN{$cmds = Hash.new(0); $mask = 1}'
 | 
						|
   -e '$cmds[$_.downcase] |= $mask' -e '$mask <<= 1 if ARGF.eof'
 | 
						|
   -e 'END{$cmds.sort.each{|n,f|puts "    \"\\#{f.to_s(8)}\" #{n.dump} + 1,"}}'
 | 
						|
   98cmd ntcmd
 | 
						|
 */
 | 
						|
static char *szInternalCmds[] = {
 | 
						|
    "\2" "assoc" + 1,
 | 
						|
    "\3" "break" + 1,
 | 
						|
    "\3" "call" + 1,
 | 
						|
    "\3" "cd" + 1,
 | 
						|
    "\1" "chcp" + 1,
 | 
						|
    "\3" "chdir" + 1,
 | 
						|
    "\3" "cls" + 1,
 | 
						|
    "\2" "color" + 1,
 | 
						|
    "\3" "copy" + 1,
 | 
						|
    "\1" "ctty" + 1,
 | 
						|
    "\3" "date" + 1,
 | 
						|
    "\3" "del" + 1,
 | 
						|
    "\3" "dir" + 1,
 | 
						|
    "\3" "echo" + 1,
 | 
						|
    "\2" "endlocal" + 1,
 | 
						|
    "\3" "erase" + 1,
 | 
						|
    "\3" "exit" + 1,
 | 
						|
    "\3" "for" + 1,
 | 
						|
    "\2" "ftype" + 1,
 | 
						|
    "\3" "goto" + 1,
 | 
						|
    "\3" "if" + 1,
 | 
						|
    "\1" "lfnfor" + 1,
 | 
						|
    "\1" "lh" + 1,
 | 
						|
    "\1" "lock" + 1,
 | 
						|
    "\3" "md" + 1,
 | 
						|
    "\3" "mkdir" + 1,
 | 
						|
    "\2" "move" + 1,
 | 
						|
    "\3" "path" + 1,
 | 
						|
    "\3" "pause" + 1,
 | 
						|
    "\2" "popd" + 1,
 | 
						|
    "\3" "prompt" + 1,
 | 
						|
    "\2" "pushd" + 1,
 | 
						|
    "\3" "rd" + 1,
 | 
						|
    "\3" "rem" + 1,
 | 
						|
    "\3" "ren" + 1,
 | 
						|
    "\3" "rename" + 1,
 | 
						|
    "\3" "rmdir" + 1,
 | 
						|
    "\3" "set" + 1,
 | 
						|
    "\2" "setlocal" + 1,
 | 
						|
    "\3" "shift" + 1,
 | 
						|
    "\2" "start" + 1,
 | 
						|
    "\3" "time" + 1,
 | 
						|
    "\2" "title" + 1,
 | 
						|
    "\1" "truename" + 1,
 | 
						|
    "\3" "type" + 1,
 | 
						|
    "\1" "unlock" + 1,
 | 
						|
    "\3" "ver" + 1,
 | 
						|
    "\3" "verify" + 1,
 | 
						|
    "\3" "vol" + 1,
 | 
						|
};
 | 
						|
 | 
						|
static int
 | 
						|
internal_match(const void *key, const void *elem)
 | 
						|
{
 | 
						|
    return strcmp(key, *(const char *const *)elem);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
isInternalCmd(const char *cmd, const char *interp)
 | 
						|
{
 | 
						|
    int i, nt = 1;
 | 
						|
    char cmdname[9], *b = cmdname, c, **nm;
 | 
						|
 | 
						|
    i = strlen(interp) - 11;
 | 
						|
    if ((i == 0 || i > 0 && isdirsep(interp[i-1])) &&
 | 
						|
	strcasecmp(interp+i, "command.com") == 0) {
 | 
						|
	nt = 0;
 | 
						|
    }
 | 
						|
    do {
 | 
						|
	if (!(c = *cmd++)) return 0;
 | 
						|
    } while (isspace(c));
 | 
						|
    while (isalpha(c)) {
 | 
						|
	*b++ = tolower(c);
 | 
						|
	if (b == cmdname + sizeof(cmdname)) return 0;
 | 
						|
	c = *cmd++;
 | 
						|
    }
 | 
						|
    if (c == '.') c = *cmd;
 | 
						|
    switch (c) {
 | 
						|
      case '<': case '>': case '|':
 | 
						|
	return 1;
 | 
						|
      case '\0': case ' ': case '\t': case '\n':
 | 
						|
	break;
 | 
						|
      default:
 | 
						|
	return 0;
 | 
						|
    }
 | 
						|
    *b = 0;
 | 
						|
    nm = bsearch(cmdname, szInternalCmds,
 | 
						|
		 sizeof(szInternalCmds) / sizeof(*szInternalCmds),
 | 
						|
		 sizeof(*szInternalCmds),
 | 
						|
		 internal_match);
 | 
						|
    if (!nm || !(nm[0][-1] & (nt ? 2 : 1)))
 | 
						|
	return 0;
 | 
						|
    return 1;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
SOCKET
 | 
						|
rb_w32_get_osfhandle(int fh)
 | 
						|
{
 | 
						|
    return _get_osfhandle(fh);
 | 
						|
}
 | 
						|
 | 
						|
pid_t
 | 
						|
pipe_exec(char *cmd, int mode, FILE **fpr, FILE **fpw)
 | 
						|
{
 | 
						|
    struct ChildRecord* child;
 | 
						|
    HANDLE hReadIn, hReadOut;
 | 
						|
    HANDLE hWriteIn, hWriteOut;
 | 
						|
    HANDLE hDupInFile, hDupOutFile;
 | 
						|
    HANDLE hCurProc;
 | 
						|
    SECURITY_ATTRIBUTES sa;
 | 
						|
    BOOL fRet;
 | 
						|
    BOOL reading, writing;
 | 
						|
    int fd;
 | 
						|
    int pipemode;
 | 
						|
    char modes[3];
 | 
						|
    int ret;
 | 
						|
 | 
						|
    /* Figure out what we're doing... */
 | 
						|
    writing = (mode & (O_WRONLY | O_RDWR)) ? TRUE : FALSE;
 | 
						|
    reading = ((mode & O_RDWR) || !writing) ? TRUE : FALSE;
 | 
						|
    if (mode & O_BINARY) {
 | 
						|
	pipemode = O_BINARY;
 | 
						|
	modes[1] = 'b';
 | 
						|
	modes[2] = '\0';
 | 
						|
    }
 | 
						|
    else {
 | 
						|
	pipemode = O_TEXT;
 | 
						|
	modes[1] = '\0';
 | 
						|
    }
 | 
						|
 | 
						|
    sa.nLength              = sizeof (SECURITY_ATTRIBUTES);
 | 
						|
    sa.lpSecurityDescriptor = NULL;
 | 
						|
    sa.bInheritHandle       = TRUE;
 | 
						|
    ret = -1;
 | 
						|
    hWriteIn = hReadOut = NULL;
 | 
						|
 | 
						|
    RUBY_CRITICAL(do {
 | 
						|
	/* create pipe */
 | 
						|
	hCurProc = GetCurrentProcess();
 | 
						|
	if (reading) {
 | 
						|
	    fRet = CreatePipe(&hReadIn, &hReadOut, &sa, 2048L);
 | 
						|
	    if (!fRet) {
 | 
						|
		errno = map_errno(GetLastError());
 | 
						|
		break;
 | 
						|
	    }
 | 
						|
	    if (!DuplicateHandle(hCurProc, hReadIn, hCurProc, &hDupInFile, 0,
 | 
						|
				 FALSE, DUPLICATE_SAME_ACCESS)) {
 | 
						|
		errno = map_errno(GetLastError());
 | 
						|
		CloseHandle(hReadIn);
 | 
						|
		CloseHandle(hReadOut);
 | 
						|
		CloseHandle(hCurProc);
 | 
						|
		break;
 | 
						|
	    }
 | 
						|
	    CloseHandle(hReadIn);
 | 
						|
	}
 | 
						|
	if (writing) {
 | 
						|
	    fRet = CreatePipe(&hWriteIn, &hWriteOut, &sa, 2048L);
 | 
						|
	    if (!fRet) {
 | 
						|
		errno = map_errno(GetLastError());
 | 
						|
	      write_pipe_failed:
 | 
						|
		if (reading) {
 | 
						|
		    CloseHandle(hDupInFile);
 | 
						|
		    CloseHandle(hReadOut);
 | 
						|
		}
 | 
						|
		break;
 | 
						|
	    }
 | 
						|
	    if (!DuplicateHandle(hCurProc, hWriteOut, hCurProc, &hDupOutFile, 0,
 | 
						|
				 FALSE, DUPLICATE_SAME_ACCESS)) {
 | 
						|
		errno = map_errno(GetLastError());
 | 
						|
		CloseHandle(hWriteIn);
 | 
						|
		CloseHandle(hWriteOut);
 | 
						|
		CloseHandle(hCurProc);
 | 
						|
		goto write_pipe_failed;
 | 
						|
	    }
 | 
						|
	    CloseHandle(hWriteOut);
 | 
						|
	}
 | 
						|
	CloseHandle(hCurProc);
 | 
						|
 | 
						|
	/* create child process */
 | 
						|
	child = CreateChild(cmd, NULL, &sa, hWriteIn, hReadOut, NULL);
 | 
						|
	if (!child) {
 | 
						|
	    if (reading) {
 | 
						|
		CloseHandle(hReadOut);
 | 
						|
		CloseHandle(hDupInFile);
 | 
						|
	    }
 | 
						|
	    if (writing) {
 | 
						|
		CloseHandle(hWriteIn);
 | 
						|
		CloseHandle(hDupOutFile);
 | 
						|
	    }
 | 
						|
	    break;
 | 
						|
	}
 | 
						|
 | 
						|
	/* associate handle to fp */
 | 
						|
	if (reading) {
 | 
						|
	    fd = rb_w32_open_osfhandle((long)hDupInFile,
 | 
						|
				       (_O_RDONLY | pipemode));
 | 
						|
	    CloseHandle(hReadOut);
 | 
						|
	    if (fd == -1) {
 | 
						|
		CloseHandle(hDupInFile);
 | 
						|
	      read_open_failed:
 | 
						|
		if (writing) {
 | 
						|
		    CloseHandle(hWriteIn);
 | 
						|
		    CloseHandle(hDupOutFile);
 | 
						|
		}
 | 
						|
		CloseChildHandle(child);
 | 
						|
		break;
 | 
						|
	    }
 | 
						|
	    modes[0] = 'r';
 | 
						|
	    if ((*fpr = (FILE *)fdopen(fd, modes)) == NULL) {
 | 
						|
		_close(fd);
 | 
						|
		goto read_open_failed;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	if (writing) {
 | 
						|
	    fd = rb_w32_open_osfhandle((long)hDupOutFile,
 | 
						|
				       (_O_WRONLY | pipemode));
 | 
						|
	    CloseHandle(hWriteIn);
 | 
						|
	    if (fd == -1) {
 | 
						|
		CloseHandle(hDupOutFile);
 | 
						|
	      write_open_failed:
 | 
						|
		if (reading) {
 | 
						|
		    fclose(*fpr);
 | 
						|
		}
 | 
						|
		CloseChildHandle(child);
 | 
						|
		break;
 | 
						|
	    }
 | 
						|
	    modes[0] = 'w';
 | 
						|
	    if ((*fpw = (FILE *)fdopen(fd, modes)) == NULL) {
 | 
						|
		_close(fd);
 | 
						|
		goto write_open_failed;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	ret = child->pid;
 | 
						|
    } while (0));
 | 
						|
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
extern VALUE rb_last_status;
 | 
						|
 | 
						|
int
 | 
						|
do_spawn(mode, cmd)
 | 
						|
int mode;
 | 
						|
char *cmd;
 | 
						|
{
 | 
						|
    struct ChildRecord *child;
 | 
						|
    DWORD exitcode;
 | 
						|
 | 
						|
    switch (mode) {
 | 
						|
      case P_WAIT:
 | 
						|
      case P_NOWAIT:
 | 
						|
      case P_OVERLAY:
 | 
						|
	break;
 | 
						|
      default:
 | 
						|
	errno = EINVAL;
 | 
						|
	return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    child = CreateChild(cmd, NULL, NULL, NULL, NULL, NULL);
 | 
						|
    if (!child) {
 | 
						|
	return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    switch (mode) {
 | 
						|
      case P_WAIT:
 | 
						|
	rb_syswait(child->pid);
 | 
						|
	return NUM2INT(rb_last_status);
 | 
						|
      case P_NOWAIT:
 | 
						|
	return child->pid;
 | 
						|
      case P_OVERLAY:
 | 
						|
	WaitForSingleObject(child->hProcess, INFINITE);
 | 
						|
	GetExitCodeProcess(child->hProcess, &exitcode);
 | 
						|
	CloseChildHandle(child);
 | 
						|
	_exit(exitcode);
 | 
						|
      default:
 | 
						|
	return -1;	/* not reached */
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
do_aspawn(mode, prog, argv)
 | 
						|
int mode;
 | 
						|
char *prog;
 | 
						|
char **argv;
 | 
						|
{
 | 
						|
    char *cmd, *p, *q, *s, **t;
 | 
						|
    int len, n, bs, quote;
 | 
						|
    struct ChildRecord *child;
 | 
						|
    DWORD exitcode;
 | 
						|
 | 
						|
    switch (mode) {
 | 
						|
      case P_WAIT:
 | 
						|
      case P_NOWAIT:
 | 
						|
      case P_OVERLAY:
 | 
						|
	break;
 | 
						|
      default:
 | 
						|
	errno = EINVAL;
 | 
						|
	return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    for (t = argv, len = 0; *t; t++) {
 | 
						|
	for (p = *t, n = quote = bs = 0; *p; ++p) {
 | 
						|
	    switch (*p) {
 | 
						|
	      case '\\':
 | 
						|
		++bs;
 | 
						|
		break;
 | 
						|
	      case '"':
 | 
						|
		n += bs + 1; bs = 0;
 | 
						|
		quote = 1;
 | 
						|
		break;
 | 
						|
	      case ' ': case '\t':
 | 
						|
		quote = 1;
 | 
						|
	      default:
 | 
						|
		bs = 0;
 | 
						|
		p = CharNext(p) - 1;
 | 
						|
		break;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	len += p - *t + n + 1;
 | 
						|
	if (quote) len += 2;
 | 
						|
    }
 | 
						|
    cmd = ALLOCA_N(char, len);
 | 
						|
    for (t = argv, q = cmd; p = *t; t++) {
 | 
						|
	quote = 0;
 | 
						|
	s = p;
 | 
						|
	if (!*p || strpbrk(p, " \t\"")) {
 | 
						|
	    quote = 1;
 | 
						|
	    *q++ = '"';
 | 
						|
	}
 | 
						|
	for (bs = 0; *p; ++p) {
 | 
						|
	    switch (*p) {
 | 
						|
	      case '\\':
 | 
						|
		++bs;
 | 
						|
		break;
 | 
						|
	      case '"':
 | 
						|
		memcpy(q, s, n = p - s); q += n; s = p;
 | 
						|
		memset(q, '\\', ++bs); q += bs; bs = 0;
 | 
						|
		break;
 | 
						|
	      default:
 | 
						|
		bs = 0;
 | 
						|
		p = CharNext(p) - 1;
 | 
						|
		break;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	memcpy(q, s, n = p - s);
 | 
						|
	q += n;
 | 
						|
	if (quote) *q++ = '"';
 | 
						|
	*q++ = ' ';
 | 
						|
    }
 | 
						|
    if (q > cmd) --q;
 | 
						|
    *q = '\0';
 | 
						|
 | 
						|
    child = CreateChild(cmd, prog, NULL, NULL, NULL, NULL);
 | 
						|
    if (!child) {
 | 
						|
	return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    switch (mode) {
 | 
						|
      case P_WAIT:
 | 
						|
	rb_syswait(child->pid);
 | 
						|
	return NUM2INT(rb_last_status);
 | 
						|
      case P_NOWAIT:
 | 
						|
	return child->pid;
 | 
						|
      case P_OVERLAY:
 | 
						|
	WaitForSingleObject(child->hProcess, INFINITE);
 | 
						|
	GetExitCodeProcess(child->hProcess, &exitcode);
 | 
						|
	CloseChildHandle(child);
 | 
						|
	_exit(exitcode);
 | 
						|
      default:
 | 
						|
	return -1;	/* not reached */
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static struct ChildRecord *
 | 
						|
CreateChild(const char *cmd, const char *prog, SECURITY_ATTRIBUTES *psa,
 | 
						|
	    HANDLE hInput, HANDLE hOutput, HANDLE hError)
 | 
						|
{
 | 
						|
    BOOL fRet;
 | 
						|
    DWORD  dwCreationFlags;
 | 
						|
    STARTUPINFO aStartupInfo;
 | 
						|
    PROCESS_INFORMATION aProcessInformation;
 | 
						|
    SECURITY_ATTRIBUTES sa;
 | 
						|
    const char *shell;
 | 
						|
    struct ChildRecord *child;
 | 
						|
    char *p = NULL;
 | 
						|
 | 
						|
    if (!cmd && !prog) {
 | 
						|
	errno = EFAULT;
 | 
						|
	return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    child = FindFreeChildSlot();
 | 
						|
    if (!child) {
 | 
						|
	errno = EAGAIN;
 | 
						|
	return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!psa) {
 | 
						|
	sa.nLength              = sizeof (SECURITY_ATTRIBUTES);
 | 
						|
	sa.lpSecurityDescriptor = NULL;
 | 
						|
	sa.bInheritHandle       = TRUE;
 | 
						|
	psa = &sa;
 | 
						|
    }
 | 
						|
 | 
						|
    memset(&aStartupInfo, 0, sizeof (STARTUPINFO));
 | 
						|
    memset(&aProcessInformation, 0, sizeof (PROCESS_INFORMATION));
 | 
						|
    aStartupInfo.cb = sizeof (STARTUPINFO);
 | 
						|
    if (hInput || hOutput || hError) {
 | 
						|
	aStartupInfo.dwFlags = STARTF_USESTDHANDLES;
 | 
						|
	if (hInput) {
 | 
						|
	    aStartupInfo.hStdInput  = hInput;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
	    aStartupInfo.hStdInput  = GetStdHandle(STD_INPUT_HANDLE);
 | 
						|
	}
 | 
						|
	if (hOutput) {
 | 
						|
	    aStartupInfo.hStdOutput = hOutput;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
	    aStartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
 | 
						|
	}
 | 
						|
	if (hError) {
 | 
						|
	    aStartupInfo.hStdError = hError;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
	    aStartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
    dwCreationFlags = (NORMAL_PRIORITY_CLASS);
 | 
						|
 | 
						|
    if (prog) {
 | 
						|
	if (!(p = dln_find_exe(prog, NULL))) {
 | 
						|
	    shell = prog;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    else {
 | 
						|
	int redir = -1;
 | 
						|
	int len = 0;
 | 
						|
	while (ISSPACE(*cmd)) cmd++;
 | 
						|
	for (prog = cmd; *prog; prog = CharNext(prog)) {
 | 
						|
	    if (ISSPACE(*prog)) {
 | 
						|
		len = prog - cmd;
 | 
						|
		do ++prog; while (ISSPACE(*prog));
 | 
						|
		if (!*prog--) break;
 | 
						|
	    }
 | 
						|
	    else {
 | 
						|
		len = 0;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	if (!len) len = strlen(cmd);
 | 
						|
	if ((shell = getenv("RUBYSHELL")) && (redir = has_redirection(cmd))) {
 | 
						|
	    char *tmp = ALLOCA_N(char, strlen(shell) + len + sizeof(" -c ") + 2);
 | 
						|
	    sprintf(tmp, "%s -c \"%.*s\"", shell, len, cmd);
 | 
						|
	    cmd = tmp;
 | 
						|
	}
 | 
						|
	else if ((shell = getenv("COMSPEC")) &&
 | 
						|
		 ((redir < 0 ? has_redirection(cmd) : redir) ||
 | 
						|
		  isInternalCmd(cmd, shell))) {
 | 
						|
	    char *tmp = ALLOCA_N(char, strlen(shell) + len + sizeof(" /c "));
 | 
						|
	    sprintf(tmp, "%s /c %.*s", shell, len, cmd);
 | 
						|
	    cmd = tmp;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
	    shell = NULL;
 | 
						|
	    prog = cmd;
 | 
						|
	    for (;;) {
 | 
						|
		if (!*prog) {
 | 
						|
		    p = dln_find_exe(cmd, NULL);
 | 
						|
		    break;
 | 
						|
		}
 | 
						|
		if (strchr(".:*?\"/\\", *prog)) {
 | 
						|
		    if (cmd[len]) {
 | 
						|
			char *tmp = ALLOCA_N(char, len + 1);
 | 
						|
			memcpy(tmp, cmd, len);
 | 
						|
			tmp[len] = 0;
 | 
						|
			cmd = tmp;
 | 
						|
		    }
 | 
						|
		    break;
 | 
						|
		}
 | 
						|
		if (ISSPACE(*prog) || strchr("<>|", *prog)) {
 | 
						|
		    len = prog - cmd;
 | 
						|
		    p = ALLOCA_N(char, len + 1);
 | 
						|
		    memcpy(p, cmd, len);
 | 
						|
		    p[len] = 0;
 | 
						|
		    p = dln_find_exe(p, NULL);
 | 
						|
		    break;
 | 
						|
		}
 | 
						|
		prog++;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
    if (p) {
 | 
						|
	shell = p;
 | 
						|
	while (*p) {
 | 
						|
	    if ((unsigned char)*p == '/')
 | 
						|
		*p = '\\';
 | 
						|
	    p = CharNext(p);
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	fRet = CreateProcess(shell, (char *)cmd, psa, psa,
 | 
						|
			     psa->bInheritHandle, dwCreationFlags, NULL, NULL,
 | 
						|
			     &aStartupInfo, &aProcessInformation);
 | 
						|
	errno = map_errno(GetLastError());
 | 
						|
    });
 | 
						|
 | 
						|
    if (!fRet) {
 | 
						|
	child->pid = 0;		/* release the slot */
 | 
						|
	return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    CloseHandle(aProcessInformation.hThread);
 | 
						|
 | 
						|
    child->hProcess = aProcessInformation.hProcess;
 | 
						|
    child->pid = (pid_t)aProcessInformation.dwProcessId;
 | 
						|
 | 
						|
    if (!IsWinNT()) {
 | 
						|
	/* On Win9x, make pid positive similarly to cygwin and perl */
 | 
						|
	child->pid = -child->pid;
 | 
						|
    }
 | 
						|
 | 
						|
    return child;
 | 
						|
}
 | 
						|
 | 
						|
typedef struct _NtCmdLineElement {
 | 
						|
    struct _NtCmdLineElement *next;
 | 
						|
    char *str;
 | 
						|
    int len;
 | 
						|
    int flags;
 | 
						|
} NtCmdLineElement;
 | 
						|
 | 
						|
//
 | 
						|
// Possible values for flags
 | 
						|
//
 | 
						|
 | 
						|
#define NTGLOB   0x1	// element contains a wildcard
 | 
						|
#define NTMALLOC 0x2	// string in element was malloc'ed
 | 
						|
#define NTSTRING 0x4	// element contains a quoted string
 | 
						|
 | 
						|
static void
 | 
						|
insert(const char *path, VALUE vinfo)
 | 
						|
{
 | 
						|
    NtCmdLineElement *tmpcurr;
 | 
						|
    NtCmdLineElement ***tail = (NtCmdLineElement ***)vinfo;
 | 
						|
 | 
						|
    tmpcurr = ALLOC(NtCmdLineElement);
 | 
						|
    MEMZERO(tmpcurr, NtCmdLineElement, 1);
 | 
						|
    tmpcurr->len = strlen(path);
 | 
						|
    tmpcurr->str = ALLOC_N(char, tmpcurr->len + 1);
 | 
						|
    tmpcurr->flags |= NTMALLOC;
 | 
						|
    strcpy(tmpcurr->str, path);
 | 
						|
    **tail = tmpcurr;
 | 
						|
    *tail = &tmpcurr->next;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef HAVE_SYS_PARAM_H
 | 
						|
# include <sys/param.h>
 | 
						|
#else
 | 
						|
# define MAXPATHLEN 512
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
static NtCmdLineElement **
 | 
						|
cmdglob(NtCmdLineElement *patt, NtCmdLineElement **tail)
 | 
						|
{
 | 
						|
    char buffer[MAXPATHLEN], *buf = buffer;
 | 
						|
    char *p;
 | 
						|
    NtCmdLineElement **last = tail;
 | 
						|
 | 
						|
    if (patt->len >= MAXPATHLEN)
 | 
						|
	buf = ruby_xmalloc(patt->len + 1);
 | 
						|
 | 
						|
    strncpy (buf, patt->str, patt->len);
 | 
						|
    buf[patt->len] = '\0';
 | 
						|
    for (p = buf; *p; p = CharNext(p))
 | 
						|
	if (*p == '\\')
 | 
						|
	    *p = '/';
 | 
						|
    rb_globi(buf, insert, (VALUE)&tail);
 | 
						|
    if (buf != buffer)
 | 
						|
	free(buf);
 | 
						|
 | 
						|
    if (last == tail) return 0;
 | 
						|
    if (patt->flags & NTMALLOC)
 | 
						|
	free(patt->str);
 | 
						|
    free(patt);
 | 
						|
    return tail;
 | 
						|
}
 | 
						|
 | 
						|
// 
 | 
						|
// Check a command string to determine if it has I/O redirection
 | 
						|
// characters that require it to be executed by a command interpreter
 | 
						|
//
 | 
						|
 | 
						|
static bool
 | 
						|
has_redirection(const char *cmd)
 | 
						|
{
 | 
						|
    char quote = '\0';
 | 
						|
    const char *ptr;
 | 
						|
 | 
						|
    //
 | 
						|
    // Scan the string, looking for redirection (< or >) or pipe 
 | 
						|
    // characters (|) that are not in a quoted string
 | 
						|
    //
 | 
						|
 | 
						|
    for (ptr = cmd; *ptr;) {
 | 
						|
	switch (*ptr) {
 | 
						|
	  case '\'':
 | 
						|
	  case '\"':
 | 
						|
	    if (!quote)
 | 
						|
		quote = *ptr;
 | 
						|
	    else if (quote == *ptr)
 | 
						|
		quote = '\0';
 | 
						|
	    ptr++;
 | 
						|
	    break;
 | 
						|
 | 
						|
	  case '>':
 | 
						|
	  case '<':
 | 
						|
	  case '|':
 | 
						|
	    if (!quote)
 | 
						|
		return TRUE;
 | 
						|
	    ptr++;
 | 
						|
	    break;
 | 
						|
 | 
						|
	  case '\\':
 | 
						|
	    ptr++;
 | 
						|
	  default:
 | 
						|
	    ptr = CharNext(ptr);
 | 
						|
	    break;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static inline char *
 | 
						|
skipspace(char *ptr)
 | 
						|
{
 | 
						|
    while (ISSPACE(*ptr))
 | 
						|
	ptr++;
 | 
						|
    return ptr;
 | 
						|
}
 | 
						|
 | 
						|
int 
 | 
						|
rb_w32_cmdvector(const char *cmd, char ***vec)
 | 
						|
{
 | 
						|
    int cmdlen, globbing, len, i;
 | 
						|
    int elements, strsz, done;
 | 
						|
    int slashes, escape;
 | 
						|
    char *ptr, *base, *buffer, *cmdline;
 | 
						|
    char **vptr;
 | 
						|
    char quote;
 | 
						|
    NtCmdLineElement *curr, **tail;
 | 
						|
    NtCmdLineElement *cmdhead = NULL, **cmdtail = &cmdhead;
 | 
						|
 | 
						|
    //
 | 
						|
    // just return if we don't have a command line
 | 
						|
    //
 | 
						|
 | 
						|
    while (ISSPACE(*cmd))
 | 
						|
	cmd++;
 | 
						|
    if (!*cmd) {
 | 
						|
	*vec = NULL;
 | 
						|
	return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    ptr = cmdline = strdup(cmd);
 | 
						|
 | 
						|
    //
 | 
						|
    // Ok, parse the command line, building a list of CmdLineElements.
 | 
						|
    // When we've finished, and it's an input command (meaning that it's
 | 
						|
    // the processes argv), we'll do globing and then build the argument 
 | 
						|
    // vector.
 | 
						|
    // The outer loop does one interation for each element seen. 
 | 
						|
    // The inner loop does one interation for each character in the element.
 | 
						|
    //
 | 
						|
 | 
						|
    while (*(ptr = skipspace(ptr))) {
 | 
						|
	base = ptr;
 | 
						|
	quote = slashes = globbing = escape = 0;
 | 
						|
	for (done = 0; !done && *ptr; ) {
 | 
						|
	    //
 | 
						|
	    // Switch on the current character. We only care about the
 | 
						|
	    // white-space characters, the  wild-card characters, and the
 | 
						|
	    // quote characters.
 | 
						|
	    //
 | 
						|
 | 
						|
	    switch (*ptr) {
 | 
						|
	      case '\\':
 | 
						|
		slashes++;
 | 
						|
	        break;
 | 
						|
 | 
						|
	      case ' ':
 | 
						|
	      case '\t':
 | 
						|
	      case '\n':
 | 
						|
		//
 | 
						|
		// if we're not in a string, then we're finished with this
 | 
						|
		// element
 | 
						|
		//
 | 
						|
 | 
						|
		if (!quote) {
 | 
						|
		    *ptr = 0;
 | 
						|
		    done = 1;
 | 
						|
		}
 | 
						|
		break;
 | 
						|
 | 
						|
	      case '*':
 | 
						|
	      case '?':
 | 
						|
	      case '[':
 | 
						|
	      case '{':
 | 
						|
		// 
 | 
						|
		// record the fact that this element has a wildcard character
 | 
						|
		// N.B. Don't glob if inside a single quoted string
 | 
						|
		//
 | 
						|
 | 
						|
		if (quote != '\'')
 | 
						|
		    globbing++;
 | 
						|
		slashes = 0;
 | 
						|
		break;
 | 
						|
 | 
						|
	      case '\'':
 | 
						|
	      case '\"':
 | 
						|
		//
 | 
						|
		// if we're already in a string, see if this is the
 | 
						|
		// terminating close-quote. If it is, we're finished with 
 | 
						|
		// the string, but not neccessarily with the element.
 | 
						|
		// If we're not already in a string, start one.
 | 
						|
		//
 | 
						|
 | 
						|
		if (!(slashes & 1)) {
 | 
						|
		    if (!quote)
 | 
						|
			quote = *ptr;
 | 
						|
		    else if (quote == *ptr)
 | 
						|
			quote = '\0';
 | 
						|
		    escape++;
 | 
						|
		}
 | 
						|
		slashes = 0;
 | 
						|
		break;
 | 
						|
 | 
						|
	      default:
 | 
						|
		ptr = CharNext(ptr);
 | 
						|
		slashes = 0;
 | 
						|
		continue;
 | 
						|
	    }
 | 
						|
	    ptr++;
 | 
						|
	}
 | 
						|
 | 
						|
	//
 | 
						|
	// when we get here, we've got a pair of pointers to the element,
 | 
						|
	// base and ptr. Base points to the start of the element while ptr
 | 
						|
	// points to the character following the element.
 | 
						|
	//
 | 
						|
 | 
						|
	len = ptr - base;
 | 
						|
	if (done) --len;
 | 
						|
 | 
						|
	//
 | 
						|
	// if it's an input vector element and it's enclosed by quotes, 
 | 
						|
	// we can remove them.
 | 
						|
	//
 | 
						|
 | 
						|
	if (escape) {
 | 
						|
	    char *p = base;
 | 
						|
	    slashes = quote = 0;
 | 
						|
	    while (p < base + len) {
 | 
						|
		switch (*p) {
 | 
						|
		  case '\\':
 | 
						|
		    p++;
 | 
						|
		    slashes++;
 | 
						|
		    break;
 | 
						|
 | 
						|
		  case '\'':
 | 
						|
		  case '"':
 | 
						|
		    if (!(slashes & 1)) {
 | 
						|
			if (!quote)
 | 
						|
			    quote = *p;
 | 
						|
			else if (quote == *p)
 | 
						|
			    quote = '\0';
 | 
						|
			else {
 | 
						|
			    p++;
 | 
						|
			    slashes = 0;
 | 
						|
			    break;
 | 
						|
			}
 | 
						|
		    }
 | 
						|
		    if (base + slashes == p) {
 | 
						|
			base += slashes >> 1;
 | 
						|
			len -= slashes >> 1;
 | 
						|
			slashes &= 1;
 | 
						|
		    }
 | 
						|
		    if (base == p) {
 | 
						|
			base = ++p;
 | 
						|
			--len;
 | 
						|
		    }
 | 
						|
		    else {
 | 
						|
			memcpy(p - ((slashes + 1) >> 1), p + (~slashes & 1), base + len - p);
 | 
						|
			slashes >>= 1;
 | 
						|
			p -= slashes;
 | 
						|
			len -= slashes + 1;
 | 
						|
			slashes = 0;
 | 
						|
		    }
 | 
						|
		    break;
 | 
						|
 | 
						|
		  default:
 | 
						|
		    p = CharNext(p);
 | 
						|
		    slashes = 0;
 | 
						|
		    break;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	}
 | 
						|
 | 
						|
	curr = ALLOC(NtCmdLineElement);
 | 
						|
	MEMZERO(curr, NtCmdLineElement, 1);
 | 
						|
	curr->str = base;
 | 
						|
	curr->len = len;
 | 
						|
 | 
						|
	if (globbing && (tail = cmdglob(curr, cmdtail))) {
 | 
						|
	    cmdtail = tail;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
	    *cmdtail = curr;
 | 
						|
	    cmdtail = &curr->next;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Almost done! 
 | 
						|
    // Count up the elements, then allocate space for a vector of pointers
 | 
						|
    // (argv) and a string table for the elements.
 | 
						|
    // 
 | 
						|
 | 
						|
    for (elements = 0, strsz = 0, curr = cmdhead; curr; curr = curr->next) {
 | 
						|
	elements++;
 | 
						|
	strsz += (curr->len + 1);
 | 
						|
    }
 | 
						|
 | 
						|
    len = (elements+1)*sizeof(char *) + strsz;
 | 
						|
    buffer = ALLOC_N(char, len);
 | 
						|
    
 | 
						|
    //
 | 
						|
    // make vptr point to the start of the buffer
 | 
						|
    // and ptr point to the area we'll consider the string table.
 | 
						|
    //
 | 
						|
    //   buffer (*vec)
 | 
						|
    //   |
 | 
						|
    //   V       ^---------------------V
 | 
						|
    //   +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
 | 
						|
    //   |   |       | ....  | NULL  |   | ..... |\0 |   | ..... |\0 |...
 | 
						|
    //   +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
 | 
						|
    //   |-  elements+1             -| ^ 1st element   ^ 2nd element
 | 
						|
 | 
						|
    vptr = (char **) buffer;
 | 
						|
 | 
						|
    ptr = buffer + (elements+1) * sizeof(char *);
 | 
						|
 | 
						|
    while (curr = cmdhead) {
 | 
						|
	strncpy (ptr, curr->str, curr->len);
 | 
						|
	ptr[curr->len] = '\0';
 | 
						|
	*vptr++ = ptr;
 | 
						|
	ptr += curr->len + 1;
 | 
						|
	cmdhead = curr->next;
 | 
						|
	if (curr->flags & NTMALLOC) free(curr->str);
 | 
						|
	free(curr);
 | 
						|
    }
 | 
						|
    *vptr = 0;
 | 
						|
 | 
						|
    *vec = (char **) buffer;
 | 
						|
    free(cmdline);
 | 
						|
    return elements;
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// UNIX compatible directory access functions for NT
 | 
						|
//
 | 
						|
 | 
						|
#define PATHLEN 1024
 | 
						|
 | 
						|
//
 | 
						|
// The idea here is to read all the directory names into a string table
 | 
						|
// (separated by nulls) and when one of the other dir functions is called
 | 
						|
// return the pointer to the current file name. 
 | 
						|
//
 | 
						|
 | 
						|
DIR *
 | 
						|
rb_w32_opendir(const char *filename)
 | 
						|
{
 | 
						|
    DIR               *p;
 | 
						|
    long               len;
 | 
						|
    long               idx;
 | 
						|
    char               scannamespc[PATHLEN];
 | 
						|
    char	      *scanname = scannamespc;
 | 
						|
    struct stat	       sbuf;
 | 
						|
    WIN32_FIND_DATA fd;
 | 
						|
    HANDLE          fh;
 | 
						|
 | 
						|
    //
 | 
						|
    // check to see if we've got a directory
 | 
						|
    //
 | 
						|
 | 
						|
    if (rb_w32_stat(filename, &sbuf) < 0)
 | 
						|
	return NULL;
 | 
						|
    if (!(sbuf.st_mode & S_IFDIR) &&
 | 
						|
	(!ISALPHA(filename[0]) || filename[1] != ':' || filename[2] != '\0' ||
 | 
						|
	((1 << (filename[0] & 0x5f) - 'A') & GetLogicalDrives()) == 0)) {
 | 
						|
	errno = ENOTDIR;
 | 
						|
	return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Get us a DIR structure
 | 
						|
    //
 | 
						|
 | 
						|
    p = xcalloc(sizeof(DIR), 1);
 | 
						|
    if (p == NULL)
 | 
						|
	return NULL;
 | 
						|
    
 | 
						|
    //
 | 
						|
    // Create the search pattern
 | 
						|
    //
 | 
						|
 | 
						|
    strcpy(scanname, filename);
 | 
						|
 | 
						|
    if (index("/\\:", *CharPrev(scanname, scanname + strlen(scanname))) == NULL)
 | 
						|
	strcat(scanname, "/*");
 | 
						|
    else
 | 
						|
	strcat(scanname, "*");
 | 
						|
 | 
						|
    //
 | 
						|
    // do the FindFirstFile call
 | 
						|
    //
 | 
						|
 | 
						|
    fh = FindFirstFile(scanname, &fd);
 | 
						|
    if (fh == INVALID_HANDLE_VALUE) {
 | 
						|
	errno = map_errno(GetLastError());
 | 
						|
	return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // now allocate the first part of the string table for the
 | 
						|
    // filenames that we find.
 | 
						|
    //
 | 
						|
 | 
						|
    idx = strlen(fd.cFileName)+1;
 | 
						|
    p->start = ALLOC_N(char, idx);
 | 
						|
    strcpy(p->start, fd.cFileName);
 | 
						|
    p->nfiles++;
 | 
						|
 | 
						|
    //
 | 
						|
    // loop finding all the files that match the wildcard
 | 
						|
    // (which should be all of them in this directory!).
 | 
						|
    // the variable idx should point one past the null terminator
 | 
						|
    // of the previous string found.
 | 
						|
    //
 | 
						|
    while (FindNextFile(fh, &fd)) {
 | 
						|
	len = strlen(fd.cFileName);
 | 
						|
 | 
						|
	//
 | 
						|
	// bump the string table size by enough for the
 | 
						|
	// new name and it's null terminator 
 | 
						|
	//
 | 
						|
 | 
						|
	#define Renew(x, y, z) (x = (z *)realloc(x, y))
 | 
						|
 | 
						|
	Renew (p->start, idx+len+1, char);
 | 
						|
	if (p->start == NULL) {
 | 
						|
            rb_fatal ("opendir: malloc failed!\n");
 | 
						|
	}
 | 
						|
	strcpy(&p->start[idx], fd.cFileName);
 | 
						|
	p->nfiles++;
 | 
						|
	idx += len+1;
 | 
						|
    }
 | 
						|
    FindClose(fh);
 | 
						|
    p->size = idx;
 | 
						|
    p->curr = p->start;
 | 
						|
    return p;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
//
 | 
						|
// Readdir just returns the current string pointer and bumps the
 | 
						|
// string pointer to the next entry.
 | 
						|
//
 | 
						|
 | 
						|
struct direct  *
 | 
						|
rb_w32_readdir(DIR *dirp)
 | 
						|
{
 | 
						|
    int         len;
 | 
						|
    static int  dummy = 0;
 | 
						|
 | 
						|
    if (dirp->curr) {
 | 
						|
 | 
						|
	//
 | 
						|
	// first set up the structure to return
 | 
						|
	//
 | 
						|
 | 
						|
	len = strlen(dirp->curr);
 | 
						|
	strcpy(dirp->dirstr.d_name, dirp->curr);
 | 
						|
	dirp->dirstr.d_namlen = len;
 | 
						|
 | 
						|
	//
 | 
						|
	// Fake inode
 | 
						|
	//
 | 
						|
	dirp->dirstr.d_ino = dummy++;
 | 
						|
 | 
						|
	//
 | 
						|
	// Now set up for the next call to readdir
 | 
						|
	//
 | 
						|
 | 
						|
	dirp->curr += len + 1;
 | 
						|
	if (dirp->curr >= (dirp->start + dirp->size)) {
 | 
						|
	    dirp->curr = NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	return &(dirp->dirstr);
 | 
						|
 | 
						|
    } else
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// Telldir returns the current string pointer position
 | 
						|
//
 | 
						|
 | 
						|
long
 | 
						|
rb_w32_telldir(DIR *dirp)
 | 
						|
{
 | 
						|
	return (long) dirp->curr;	/* ouch! pointer to long cast */
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// Seekdir moves the string pointer to a previously saved position
 | 
						|
// (Saved by telldir).
 | 
						|
 | 
						|
void
 | 
						|
rb_w32_seekdir(DIR *dirp, long loc)
 | 
						|
{
 | 
						|
	dirp->curr = (char *) loc;	/* ouch! long to pointer cast */
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// Rewinddir resets the string pointer to the start
 | 
						|
//
 | 
						|
 | 
						|
void
 | 
						|
rb_w32_rewinddir(DIR *dirp)
 | 
						|
{
 | 
						|
	dirp->curr = dirp->start;
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// This just free's the memory allocated by opendir
 | 
						|
//
 | 
						|
 | 
						|
void
 | 
						|
rb_w32_closedir(DIR *dirp)
 | 
						|
{
 | 
						|
	free(dirp->start);
 | 
						|
	free(dirp);
 | 
						|
}
 | 
						|
 | 
						|
EXTERN_C void __cdecl _lock_fhandle(int);
 | 
						|
EXTERN_C void __cdecl _unlock_fhandle(int);
 | 
						|
EXTERN_C void __cdecl _unlock(int);
 | 
						|
 | 
						|
#if (defined _MT || defined __MSVCRT__) && !defined __BORLANDC__
 | 
						|
#define MSVCRT_THREADS
 | 
						|
#endif
 | 
						|
#ifdef MSVCRT_THREADS
 | 
						|
# define MTHREAD_ONLY(x) x
 | 
						|
# define STHREAD_ONLY(x)
 | 
						|
#elif defined(__BORLANDC__)
 | 
						|
# define MTHREAD_ONLY(x)
 | 
						|
# define STHREAD_ONLY(x)
 | 
						|
#else
 | 
						|
# define MTHREAD_ONLY(x)
 | 
						|
# define STHREAD_ONLY(x) x
 | 
						|
#endif
 | 
						|
 | 
						|
typedef struct	{
 | 
						|
    long osfhnd;    /* underlying OS file HANDLE */
 | 
						|
    char osfile;    /* attributes of file (e.g., open in text mode?) */
 | 
						|
    char pipech;    /* one char buffer for handles opened on pipes */
 | 
						|
#ifdef MSVCRT_THREADS
 | 
						|
    int lockinitflag;
 | 
						|
    CRITICAL_SECTION lock;
 | 
						|
#endif
 | 
						|
}	ioinfo;
 | 
						|
 | 
						|
#if !defined _CRTIMP || defined __MINGW32__
 | 
						|
#undef _CRTIMP
 | 
						|
#define _CRTIMP __declspec(dllimport)
 | 
						|
#endif
 | 
						|
 | 
						|
#if !defined(__BORLANDC__) && !defined(_WIN32_WCE)
 | 
						|
EXTERN_C _CRTIMP ioinfo * __pioinfo[];
 | 
						|
 | 
						|
#define IOINFO_L2E			5
 | 
						|
#define IOINFO_ARRAY_ELTS	(1 << IOINFO_L2E)
 | 
						|
#define _pioinfo(i)	(__pioinfo[i >> IOINFO_L2E] + (i & (IOINFO_ARRAY_ELTS - 1)))
 | 
						|
#define _osfhnd(i)  (_pioinfo(i)->osfhnd)
 | 
						|
#define _osfile(i)  (_pioinfo(i)->osfile)
 | 
						|
#define _pipech(i)  (_pioinfo(i)->pipech)
 | 
						|
 | 
						|
#define _set_osfhnd(fh, osfh) (void)(_osfhnd(fh) = osfh)
 | 
						|
#define _set_osflags(fh, flags) (_osfile(fh) = (flags))
 | 
						|
 | 
						|
#define FOPEN			0x01	/* file handle open */
 | 
						|
#define FNOINHERIT		0x10	/* file handle opened O_NOINHERIT */
 | 
						|
#define FAPPEND			0x20	/* file handle opened O_APPEND */
 | 
						|
#define FDEV			0x40	/* file handle refers to device */
 | 
						|
#define FTEXT			0x80	/* file handle is in text mode */
 | 
						|
 | 
						|
static int
 | 
						|
rb_w32_open_osfhandle(long osfhandle, int flags)
 | 
						|
{
 | 
						|
    int fh;
 | 
						|
    char fileflags;		/* _osfile flags */
 | 
						|
    HANDLE hF;
 | 
						|
 | 
						|
    /* copy relevant flags from second parameter */
 | 
						|
    fileflags = FDEV;
 | 
						|
 | 
						|
    if (flags & O_APPEND)
 | 
						|
	fileflags |= FAPPEND;
 | 
						|
 | 
						|
    if (flags & O_TEXT)
 | 
						|
	fileflags |= FTEXT;
 | 
						|
 | 
						|
    if (flags & O_NOINHERIT)
 | 
						|
	fileflags |= FNOINHERIT;
 | 
						|
 | 
						|
    /* attempt to allocate a C Runtime file handle */
 | 
						|
    hF = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
 | 
						|
    fh = _open_osfhandle((long)hF, 0);
 | 
						|
    CloseHandle(hF);
 | 
						|
    if (fh == -1) {
 | 
						|
	errno = EMFILE;		/* too many open files */
 | 
						|
	_doserrno = 0L;		/* not an OS error */
 | 
						|
    }
 | 
						|
    else {
 | 
						|
 | 
						|
	MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fh)->lock)));
 | 
						|
	/* the file is open. now, set the info in _osfhnd array */
 | 
						|
	_set_osfhnd(fh, osfhandle);
 | 
						|
 | 
						|
	fileflags |= FOPEN;		/* mark as open */
 | 
						|
 | 
						|
	_set_osflags(fh, fileflags); /* set osfile entry */
 | 
						|
	MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fh)->lock));
 | 
						|
    }
 | 
						|
    return fh;			/* return handle */
 | 
						|
}
 | 
						|
#else
 | 
						|
 | 
						|
#define _set_osfhnd(fh, osfh) (void)((fh), (osfh))
 | 
						|
#define _set_osflags(fh, flags) (void)((fh), (flags))
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
#undef getsockopt
 | 
						|
 | 
						|
static int
 | 
						|
is_socket(SOCKET fd)
 | 
						|
{
 | 
						|
    char sockbuf[80];
 | 
						|
    int optlen;
 | 
						|
    int retval;
 | 
						|
    int result = TRUE;
 | 
						|
 | 
						|
    optlen = sizeof(sockbuf);
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	retval = getsockopt(fd, SOL_SOCKET, SO_TYPE, sockbuf, &optlen);
 | 
						|
	if (retval == SOCKET_ERROR) {
 | 
						|
	    int iRet;
 | 
						|
	    iRet = WSAGetLastError();
 | 
						|
	    if (iRet == WSAENOTSOCK || iRet == WSANOTINITIALISED)
 | 
						|
		result = FALSE;
 | 
						|
	}
 | 
						|
    });
 | 
						|
 | 
						|
    //
 | 
						|
    // If we get here, then fd is actually a socket.
 | 
						|
    //
 | 
						|
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// Since the errors returned by the socket error function 
 | 
						|
// WSAGetLastError() are not known by the library routine strerror
 | 
						|
// we have to roll our own.
 | 
						|
//
 | 
						|
 | 
						|
#undef strerror
 | 
						|
 | 
						|
char *
 | 
						|
rb_w32_strerror(int e)
 | 
						|
{
 | 
						|
    static char buffer[512];
 | 
						|
#if !defined __MINGW32__
 | 
						|
    extern int sys_nerr;
 | 
						|
#endif
 | 
						|
    DWORD source = 0;
 | 
						|
    char *p;
 | 
						|
 | 
						|
    if (e < 0 || e > sys_nerr) {
 | 
						|
	if (e < 0)
 | 
						|
	    e = GetLastError();
 | 
						|
	if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
 | 
						|
			  FORMAT_MESSAGE_IGNORE_INSERTS, &source, e, 0,
 | 
						|
			  buffer, 512, NULL) == 0) {
 | 
						|
	    strcpy(buffer, "Unknown Error");
 | 
						|
	}
 | 
						|
	for (p = buffer + strlen(buffer) - 1; buffer <= p; p--) {
 | 
						|
	    if (*p != '\r' && *p != '\n') break;
 | 
						|
	    *p = 0;
 | 
						|
	}
 | 
						|
	return buffer;
 | 
						|
    }
 | 
						|
    return strerror(e);
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// various stubs
 | 
						|
//
 | 
						|
 | 
						|
 | 
						|
// Ownership
 | 
						|
//
 | 
						|
// Just pretend that everyone is a superuser. NT will let us know if
 | 
						|
// we don't really have permission to do something.
 | 
						|
//
 | 
						|
 | 
						|
#define ROOT_UID	0
 | 
						|
#define ROOT_GID	0
 | 
						|
 | 
						|
UIDTYPE
 | 
						|
getuid(void)
 | 
						|
{
 | 
						|
	return ROOT_UID;
 | 
						|
}
 | 
						|
 | 
						|
UIDTYPE
 | 
						|
geteuid(void)
 | 
						|
{
 | 
						|
	return ROOT_UID;
 | 
						|
}
 | 
						|
 | 
						|
GIDTYPE
 | 
						|
getgid(void)
 | 
						|
{
 | 
						|
	return ROOT_GID;
 | 
						|
}
 | 
						|
 | 
						|
GIDTYPE
 | 
						|
getegid(void)
 | 
						|
{
 | 
						|
    return ROOT_GID;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
setuid(int uid)
 | 
						|
{ 
 | 
						|
    return (uid == ROOT_UID ? 0 : -1);
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
setgid(int gid)
 | 
						|
{
 | 
						|
    return (gid == ROOT_GID ? 0 : -1);
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// File system stuff
 | 
						|
//
 | 
						|
 | 
						|
int
 | 
						|
/* ioctl(int i, unsigned int u, char *data) */
 | 
						|
#ifdef __BORLANDC__
 | 
						|
  ioctl(int i, int u, ...)
 | 
						|
#else
 | 
						|
  ioctl(int i, unsigned int u, long data)
 | 
						|
#endif
 | 
						|
{
 | 
						|
    return -1;
 | 
						|
}
 | 
						|
 | 
						|
#undef FD_SET
 | 
						|
 | 
						|
void
 | 
						|
rb_w32_fdset(int fd, fd_set *set)
 | 
						|
{
 | 
						|
    unsigned int i;
 | 
						|
    SOCKET s = TO_SOCKET(fd);
 | 
						|
 | 
						|
    for (i = 0; i < set->fd_count; i++) {
 | 
						|
        if (set->fd_array[i] == s) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if (i == set->fd_count) {
 | 
						|
        if (set->fd_count < FD_SETSIZE) {
 | 
						|
            set->fd_array[i] = s;
 | 
						|
            set->fd_count++;
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#undef FD_CLR
 | 
						|
 | 
						|
void
 | 
						|
rb_w32_fdclr(int fd, fd_set *set)
 | 
						|
{
 | 
						|
    unsigned int i;
 | 
						|
    SOCKET s = TO_SOCKET(fd);
 | 
						|
 | 
						|
    for (i = 0; i < set->fd_count; i++) {
 | 
						|
        if (set->fd_array[i] == s) {
 | 
						|
            while (i < set->fd_count - 1) {
 | 
						|
                set->fd_array[i] = set->fd_array[i + 1];
 | 
						|
                i++;
 | 
						|
            }
 | 
						|
            set->fd_count--;
 | 
						|
            break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#undef FD_ISSET
 | 
						|
 | 
						|
int
 | 
						|
rb_w32_fdisset(int fd, fd_set *set)
 | 
						|
{
 | 
						|
       return __WSAFDIsSet(TO_SOCKET(fd), set);
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// Networking trampolines
 | 
						|
// These are used to avoid socket startup/shutdown overhead in case 
 | 
						|
// the socket routines aren't used.
 | 
						|
//
 | 
						|
 | 
						|
#undef select
 | 
						|
 | 
						|
static int NtSocketsInitialized = 0;
 | 
						|
 | 
						|
static int
 | 
						|
extract_file_fd(fd_set *set, fd_set *fileset)
 | 
						|
{
 | 
						|
    int idx;
 | 
						|
 | 
						|
    fileset->fd_count = 0;
 | 
						|
    if (!set)
 | 
						|
	return 0;
 | 
						|
    for (idx = 0; idx < set->fd_count; idx++) {
 | 
						|
	SOCKET fd = set->fd_array[idx];
 | 
						|
 | 
						|
	if (!is_socket(fd)) {
 | 
						|
	    int i;
 | 
						|
 | 
						|
	    for (i = 0; i < fileset->fd_count; i++) {
 | 
						|
		if (fileset->fd_array[i] == fd) {
 | 
						|
		    break;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	    if (i == fileset->fd_count) {
 | 
						|
		if (fileset->fd_count < FD_SETSIZE) {
 | 
						|
		    fileset->fd_array[i] = fd;
 | 
						|
		    fileset->fd_count++;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
    return fileset->fd_count;
 | 
						|
}
 | 
						|
 | 
						|
long 
 | 
						|
rb_w32_select (int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
 | 
						|
	       struct timeval *timeout)
 | 
						|
{
 | 
						|
    long r;
 | 
						|
    fd_set file_rd;
 | 
						|
    fd_set file_wr;
 | 
						|
#ifdef USE_INTERRUPT_WINSOCK
 | 
						|
    fd_set trap;
 | 
						|
#endif /* USE_INTERRUPT_WINSOCK */
 | 
						|
    int file_nfds;
 | 
						|
 | 
						|
    if (!NtSocketsInitialized) {
 | 
						|
	StartSockets();
 | 
						|
    }
 | 
						|
    r = 0;
 | 
						|
    if (rd && rd->fd_count > r) r = rd->fd_count;
 | 
						|
    if (wr && wr->fd_count > r) r = wr->fd_count;
 | 
						|
    if (ex && ex->fd_count > r) r = ex->fd_count;
 | 
						|
    if (nfds > r) nfds = r;
 | 
						|
    if (nfds == 0 && timeout) {
 | 
						|
	Sleep(timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
 | 
						|
	return 0;
 | 
						|
    }
 | 
						|
    file_nfds = extract_file_fd(rd, &file_rd);
 | 
						|
    file_nfds += extract_file_fd(wr, &file_wr);
 | 
						|
    if (file_nfds)
 | 
						|
    {
 | 
						|
	// assume normal files are always readable/writable
 | 
						|
	// fake read/write fd_set and return value
 | 
						|
	if (rd) *rd = file_rd;
 | 
						|
	if (wr) *wr = file_wr;
 | 
						|
	return file_nfds;
 | 
						|
    }
 | 
						|
 | 
						|
#if USE_INTERRUPT_WINSOCK
 | 
						|
    if (ex)
 | 
						|
	trap = *ex;
 | 
						|
    else
 | 
						|
	trap.fd_count = 0;
 | 
						|
    if (trap.fd_count < FD_SETSIZE)
 | 
						|
	trap.fd_array[trap.fd_count++] = (SOCKET)interrupted_event;
 | 
						|
    // else unable to catch interrupt.
 | 
						|
    ex = &trap;
 | 
						|
#endif /* USE_INTERRUPT_WINSOCK */
 | 
						|
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	r = select(nfds, rd, wr, ex, timeout);
 | 
						|
	if (r == SOCKET_ERROR) {
 | 
						|
	    errno = map_errno(WSAGetLastError());
 | 
						|
	}
 | 
						|
    });
 | 
						|
    return r;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
StartSockets ()
 | 
						|
{
 | 
						|
    WORD version;
 | 
						|
    WSADATA retdata;
 | 
						|
    int ret;
 | 
						|
    int iSockOpt;
 | 
						|
    
 | 
						|
    //
 | 
						|
    // initalize the winsock interface and insure that it's
 | 
						|
    // cleaned up at exit.
 | 
						|
    //
 | 
						|
    version = MAKEWORD(1, 1);
 | 
						|
    if (ret = WSAStartup(version, &retdata))
 | 
						|
	rb_fatal ("Unable to locate winsock library!\n");
 | 
						|
    if (LOBYTE(retdata.wVersion) != 1)
 | 
						|
	rb_fatal("could not find version 1 of winsock dll\n");
 | 
						|
 | 
						|
    if (HIBYTE(retdata.wVersion) != 1)
 | 
						|
	rb_fatal("could not find version 1 of winsock dll\n");
 | 
						|
 | 
						|
    atexit((void (*)(void)) WSACleanup);
 | 
						|
 | 
						|
#ifndef SO_SYNCHRONOUS_NONALERT
 | 
						|
#define SO_SYNCHRONOUS_NONALERT 0x20
 | 
						|
#endif
 | 
						|
 | 
						|
    iSockOpt = SO_SYNCHRONOUS_NONALERT;
 | 
						|
    /*
 | 
						|
     * Enable the use of sockets as filehandles
 | 
						|
     */
 | 
						|
#ifndef SO_OPENTYPE
 | 
						|
#define SO_OPENTYPE     0x7008
 | 
						|
#endif
 | 
						|
 | 
						|
    setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
 | 
						|
	       (char *)&iSockOpt, sizeof(iSockOpt));
 | 
						|
 | 
						|
    main_thread.handle = GetCurrentThreadHandle();
 | 
						|
    main_thread.id = GetCurrentThreadId();
 | 
						|
 | 
						|
    interrupted_event = CreateSignal();
 | 
						|
    if (!interrupted_event)
 | 
						|
	rb_fatal("Unable to create interrupt event!\n");
 | 
						|
    NtSocketsInitialized = 1;
 | 
						|
}
 | 
						|
 | 
						|
#undef accept
 | 
						|
 | 
						|
int
 | 
						|
rb_w32_accept(int s, struct sockaddr *addr, int *addrlen)
 | 
						|
{
 | 
						|
    SOCKET r;
 | 
						|
 | 
						|
    if (!NtSocketsInitialized) {
 | 
						|
	StartSockets();
 | 
						|
    }
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	r = accept(TO_SOCKET(s), addr, addrlen);
 | 
						|
	if (r == INVALID_SOCKET) {
 | 
						|
	    errno = map_errno(WSAGetLastError());
 | 
						|
	    s = -1;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
	    s = rb_w32_open_osfhandle(r, O_RDWR|O_BINARY);
 | 
						|
	}
 | 
						|
    });
 | 
						|
    return s;
 | 
						|
}
 | 
						|
 | 
						|
#undef bind
 | 
						|
 | 
						|
int 
 | 
						|
rb_w32_bind(int s, struct sockaddr *addr, int addrlen)
 | 
						|
{
 | 
						|
    int r;
 | 
						|
 | 
						|
    if (!NtSocketsInitialized) {
 | 
						|
	StartSockets();
 | 
						|
    }
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	r = bind(TO_SOCKET(s), addr, addrlen);
 | 
						|
	if (r == SOCKET_ERROR)
 | 
						|
	    errno = map_errno(WSAGetLastError());
 | 
						|
    });
 | 
						|
    return r;
 | 
						|
}
 | 
						|
 | 
						|
#undef connect
 | 
						|
 | 
						|
int 
 | 
						|
rb_w32_connect(int s, struct sockaddr *addr, int addrlen)
 | 
						|
{
 | 
						|
    int r;
 | 
						|
    if (!NtSocketsInitialized) {
 | 
						|
	StartSockets();
 | 
						|
    }
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	r = connect(TO_SOCKET(s), addr, addrlen);
 | 
						|
	if (r == SOCKET_ERROR)
 | 
						|
	    errno = map_errno(WSAGetLastError());
 | 
						|
    });
 | 
						|
    return r;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#undef getpeername
 | 
						|
 | 
						|
int 
 | 
						|
rb_w32_getpeername(int s, struct sockaddr *addr, int *addrlen)
 | 
						|
{
 | 
						|
    int r;
 | 
						|
    if (!NtSocketsInitialized) {
 | 
						|
	StartSockets();
 | 
						|
    }
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	r = getpeername(TO_SOCKET(s), addr, addrlen);
 | 
						|
	if (r == SOCKET_ERROR)
 | 
						|
	    errno = map_errno(WSAGetLastError());
 | 
						|
    });
 | 
						|
    return r;
 | 
						|
}
 | 
						|
 | 
						|
#undef getsockname
 | 
						|
 | 
						|
int 
 | 
						|
rb_w32_getsockname(int s, struct sockaddr *addr, int *addrlen)
 | 
						|
{
 | 
						|
    int r;
 | 
						|
    if (!NtSocketsInitialized) {
 | 
						|
	StartSockets();
 | 
						|
    }
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	r = getsockname(TO_SOCKET(s), addr, addrlen);
 | 
						|
	if (r == SOCKET_ERROR)
 | 
						|
	    errno = map_errno(WSAGetLastError());
 | 
						|
    });
 | 
						|
    return r;
 | 
						|
}
 | 
						|
 | 
						|
int 
 | 
						|
rb_w32_getsockopt(int s, int level, int optname, char *optval, int *optlen)
 | 
						|
{
 | 
						|
    int r;
 | 
						|
    if (!NtSocketsInitialized) {
 | 
						|
	StartSockets();
 | 
						|
    }
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	r = getsockopt(TO_SOCKET(s), level, optname, optval, optlen);
 | 
						|
	if (r == SOCKET_ERROR)
 | 
						|
	    errno = map_errno(WSAGetLastError());
 | 
						|
    });
 | 
						|
    return r;
 | 
						|
}
 | 
						|
 | 
						|
#undef ioctlsocket
 | 
						|
 | 
						|
int 
 | 
						|
rb_w32_ioctlsocket(int s, long cmd, u_long *argp)
 | 
						|
{
 | 
						|
    int r;
 | 
						|
    if (!NtSocketsInitialized) {
 | 
						|
	StartSockets();
 | 
						|
    }
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	r = ioctlsocket(TO_SOCKET(s), cmd, argp);
 | 
						|
	if (r == SOCKET_ERROR)
 | 
						|
	    errno = map_errno(WSAGetLastError());
 | 
						|
    });
 | 
						|
    return r;
 | 
						|
}
 | 
						|
 | 
						|
#undef listen
 | 
						|
 | 
						|
int 
 | 
						|
rb_w32_listen(int s, int backlog)
 | 
						|
{
 | 
						|
    int r;
 | 
						|
    if (!NtSocketsInitialized) {
 | 
						|
	StartSockets();
 | 
						|
    }
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	r = listen(TO_SOCKET(s), backlog);
 | 
						|
	if (r == SOCKET_ERROR)
 | 
						|
	    errno = map_errno(WSAGetLastError());
 | 
						|
    });
 | 
						|
    return r;
 | 
						|
}
 | 
						|
 | 
						|
#undef recv
 | 
						|
 | 
						|
int 
 | 
						|
rb_w32_recv(int s, char *buf, int len, int flags)
 | 
						|
{
 | 
						|
    int r;
 | 
						|
    if (!NtSocketsInitialized) {
 | 
						|
	StartSockets();
 | 
						|
    }
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	r = recv(TO_SOCKET(s), buf, len, flags);
 | 
						|
	if (r == SOCKET_ERROR)
 | 
						|
	    errno = map_errno(WSAGetLastError());
 | 
						|
    });
 | 
						|
    return r;
 | 
						|
}
 | 
						|
 | 
						|
#undef recvfrom
 | 
						|
 | 
						|
int 
 | 
						|
rb_w32_recvfrom(int s, char *buf, int len, int flags, 
 | 
						|
		struct sockaddr *from, int *fromlen)
 | 
						|
{
 | 
						|
    int r;
 | 
						|
    if (!NtSocketsInitialized) {
 | 
						|
	StartSockets();
 | 
						|
    }
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	r = recvfrom(TO_SOCKET(s), buf, len, flags, from, fromlen);
 | 
						|
	if (r == SOCKET_ERROR)
 | 
						|
	    errno = map_errno(WSAGetLastError());
 | 
						|
    });
 | 
						|
    return r;
 | 
						|
}
 | 
						|
 | 
						|
#undef send
 | 
						|
 | 
						|
int 
 | 
						|
rb_w32_send(int s, char *buf, int len, int flags)
 | 
						|
{
 | 
						|
    int r;
 | 
						|
    if (!NtSocketsInitialized) {
 | 
						|
	StartSockets();
 | 
						|
    }
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	r = send(TO_SOCKET(s), buf, len, flags);
 | 
						|
	if (r == SOCKET_ERROR)
 | 
						|
	    errno = map_errno(WSAGetLastError());
 | 
						|
    });
 | 
						|
    return r;
 | 
						|
}
 | 
						|
 | 
						|
#undef sendto
 | 
						|
 | 
						|
int 
 | 
						|
rb_w32_sendto(int s, char *buf, int len, int flags, 
 | 
						|
	      struct sockaddr *to, int tolen)
 | 
						|
{
 | 
						|
    int r;
 | 
						|
    if (!NtSocketsInitialized) {
 | 
						|
	StartSockets();
 | 
						|
    }
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	r = sendto(TO_SOCKET(s), buf, len, flags, to, tolen);
 | 
						|
	if (r == SOCKET_ERROR)
 | 
						|
	    errno = map_errno(WSAGetLastError());
 | 
						|
    });
 | 
						|
    return r;
 | 
						|
}
 | 
						|
 | 
						|
#undef setsockopt
 | 
						|
 | 
						|
int 
 | 
						|
rb_w32_setsockopt(int s, int level, int optname, char *optval, int optlen)
 | 
						|
{
 | 
						|
    int r;
 | 
						|
    if (!NtSocketsInitialized) {
 | 
						|
	StartSockets();
 | 
						|
    }
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	r = setsockopt(TO_SOCKET(s), level, optname, optval, optlen);
 | 
						|
	if (r == SOCKET_ERROR)
 | 
						|
	    errno = map_errno(WSAGetLastError());
 | 
						|
    });
 | 
						|
    return r;
 | 
						|
}
 | 
						|
    
 | 
						|
#undef shutdown
 | 
						|
 | 
						|
int 
 | 
						|
rb_w32_shutdown(int s, int how)
 | 
						|
{
 | 
						|
    int r;
 | 
						|
    if (!NtSocketsInitialized) {
 | 
						|
	StartSockets();
 | 
						|
    }
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	r = shutdown(TO_SOCKET(s), how);
 | 
						|
	if (r == SOCKET_ERROR)
 | 
						|
	    errno = map_errno(WSAGetLastError());
 | 
						|
    });
 | 
						|
    return r;
 | 
						|
}
 | 
						|
 | 
						|
#undef socket
 | 
						|
 | 
						|
int 
 | 
						|
rb_w32_socket(int af, int type, int protocol)
 | 
						|
{
 | 
						|
    SOCKET s;
 | 
						|
    int fd;
 | 
						|
 | 
						|
    if (!NtSocketsInitialized) {
 | 
						|
	StartSockets();
 | 
						|
    }
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	s = socket(af, type, protocol);
 | 
						|
	if (s == INVALID_SOCKET) {
 | 
						|
	    errno = map_errno(WSAGetLastError());
 | 
						|
	    fd = -1;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
	    fd = rb_w32_open_osfhandle(s, O_RDWR|O_BINARY);
 | 
						|
	}
 | 
						|
    });
 | 
						|
    return fd;
 | 
						|
}
 | 
						|
 | 
						|
#undef gethostbyaddr
 | 
						|
 | 
						|
struct hostent *
 | 
						|
rb_w32_gethostbyaddr (char *addr, int len, int type)
 | 
						|
{
 | 
						|
    struct hostent *r;
 | 
						|
    if (!NtSocketsInitialized) {
 | 
						|
	StartSockets();
 | 
						|
    }
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	r = gethostbyaddr(addr, len, type);
 | 
						|
	if (r == NULL)
 | 
						|
	    errno = map_errno(WSAGetLastError());
 | 
						|
    });
 | 
						|
    return r;
 | 
						|
}
 | 
						|
 | 
						|
#undef gethostbyname
 | 
						|
 | 
						|
struct hostent *
 | 
						|
rb_w32_gethostbyname (char *name)
 | 
						|
{
 | 
						|
    struct hostent *r;
 | 
						|
    if (!NtSocketsInitialized) {
 | 
						|
	StartSockets();
 | 
						|
    }
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	r = gethostbyname(name);
 | 
						|
	if (r == NULL)
 | 
						|
	    errno = map_errno(WSAGetLastError());
 | 
						|
    });
 | 
						|
    return r;
 | 
						|
}
 | 
						|
 | 
						|
#undef gethostname
 | 
						|
 | 
						|
int
 | 
						|
rb_w32_gethostname (char *name, int len)
 | 
						|
{
 | 
						|
    int r;
 | 
						|
    if (!NtSocketsInitialized) {
 | 
						|
	StartSockets();
 | 
						|
    }
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	r = gethostname(name, len);
 | 
						|
	if (r == SOCKET_ERROR)
 | 
						|
	    errno = map_errno(WSAGetLastError());
 | 
						|
    });
 | 
						|
    return r;
 | 
						|
}
 | 
						|
 | 
						|
#undef getprotobyname
 | 
						|
 | 
						|
struct protoent *
 | 
						|
rb_w32_getprotobyname (char *name)
 | 
						|
{
 | 
						|
    struct protoent *r;
 | 
						|
    if (!NtSocketsInitialized) {
 | 
						|
	StartSockets();
 | 
						|
    }
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	r = getprotobyname(name);
 | 
						|
	if (r == NULL)
 | 
						|
	    errno = map_errno(WSAGetLastError());
 | 
						|
    });
 | 
						|
    return r;
 | 
						|
}
 | 
						|
 | 
						|
#undef getprotobynumber
 | 
						|
 | 
						|
struct protoent *
 | 
						|
rb_w32_getprotobynumber (int num)
 | 
						|
{
 | 
						|
    struct protoent *r;
 | 
						|
    if (!NtSocketsInitialized) {
 | 
						|
	StartSockets();
 | 
						|
    }
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	r = getprotobynumber(num);
 | 
						|
	if (r == NULL)
 | 
						|
	    errno = map_errno(WSAGetLastError());
 | 
						|
    });
 | 
						|
    return r;
 | 
						|
}
 | 
						|
 | 
						|
#undef getservbyname
 | 
						|
 | 
						|
struct servent *
 | 
						|
rb_w32_getservbyname (char *name, char *proto)
 | 
						|
{
 | 
						|
    struct servent *r;
 | 
						|
    if (!NtSocketsInitialized) {
 | 
						|
	StartSockets();
 | 
						|
    }
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	r = getservbyname(name, proto);
 | 
						|
	if (r == NULL)
 | 
						|
	    errno = map_errno(WSAGetLastError());
 | 
						|
    });
 | 
						|
    return r;
 | 
						|
}
 | 
						|
 | 
						|
#undef getservbyport
 | 
						|
 | 
						|
struct servent *
 | 
						|
rb_w32_getservbyport (int port, char *proto)
 | 
						|
{
 | 
						|
    struct servent *r;
 | 
						|
    if (!NtSocketsInitialized) {
 | 
						|
	StartSockets();
 | 
						|
    }
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	r = getservbyport(port, proto);
 | 
						|
	if (r == NULL)
 | 
						|
	    errno = map_errno(WSAGetLastError());
 | 
						|
    });
 | 
						|
    return r;
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// Networking stubs
 | 
						|
//
 | 
						|
 | 
						|
void endhostent() {}
 | 
						|
void endnetent() {}
 | 
						|
void endprotoent() {}
 | 
						|
void endservent() {}
 | 
						|
 | 
						|
struct netent *getnetent (void) {return (struct netent *) NULL;}
 | 
						|
 | 
						|
struct netent *getnetbyaddr(char *name) {return (struct netent *)NULL;}
 | 
						|
 | 
						|
struct netent *getnetbyname(long net, int type) {return (struct netent *)NULL;}
 | 
						|
 | 
						|
struct protoent *getprotoent (void) {return (struct protoent *) NULL;}
 | 
						|
 | 
						|
struct servent *getservent (void) {return (struct servent *) NULL;}
 | 
						|
 | 
						|
void sethostent (int stayopen) {}
 | 
						|
 | 
						|
void setnetent (int stayopen) {}
 | 
						|
 | 
						|
void setprotoent (int stayopen) {}
 | 
						|
 | 
						|
void setservent (int stayopen) {}
 | 
						|
 | 
						|
#ifndef WNOHANG
 | 
						|
#define WNOHANG -1
 | 
						|
#endif
 | 
						|
 | 
						|
static pid_t
 | 
						|
poll_child_status(struct ChildRecord *child, int *stat_loc)
 | 
						|
{
 | 
						|
    DWORD exitcode;
 | 
						|
    DWORD err;
 | 
						|
 | 
						|
    if (!GetExitCodeProcess(child->hProcess, &exitcode)) {
 | 
						|
	/* If an error occured, return immediatly. */
 | 
						|
	err = GetLastError();
 | 
						|
	if (err == ERROR_INVALID_PARAMETER)
 | 
						|
	    errno = ECHILD;
 | 
						|
	else
 | 
						|
	    errno = map_errno(GetLastError());
 | 
						|
	CloseChildHandle(child);
 | 
						|
	return -1;
 | 
						|
    }
 | 
						|
    if (exitcode != STILL_ACTIVE) {
 | 
						|
	/* If already died, return immediatly. */
 | 
						|
	pid_t pid = child->pid;
 | 
						|
	CloseChildHandle(child);
 | 
						|
	if (stat_loc) *stat_loc = exitcode << 8;
 | 
						|
	return pid;
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
pid_t
 | 
						|
waitpid (pid_t pid, int *stat_loc, int options)
 | 
						|
{
 | 
						|
    DWORD timeout;
 | 
						|
 | 
						|
    if (options == WNOHANG) {
 | 
						|
	timeout = 0;
 | 
						|
    } else {
 | 
						|
	timeout = INFINITE;
 | 
						|
    }
 | 
						|
 | 
						|
    if (pid == -1) {
 | 
						|
	int count = 0;
 | 
						|
	DWORD ret;
 | 
						|
	HANDLE events[MAXCHILDNUM + 1];
 | 
						|
 | 
						|
	FOREACH_CHILD(child) {
 | 
						|
	    if (!child->pid || child->pid < 0) continue;
 | 
						|
	    if ((pid = poll_child_status(child, stat_loc))) return pid;
 | 
						|
	    events[count++] = child->hProcess;
 | 
						|
	} END_FOREACH_CHILD;
 | 
						|
	if (!count) {
 | 
						|
	    errno = ECHILD;
 | 
						|
	    return -1;
 | 
						|
	}
 | 
						|
	events[count] = interrupted_event;
 | 
						|
 | 
						|
	ret = WaitForMultipleEvents(count + 1, events, FALSE, timeout, TRUE);
 | 
						|
	if (ret == WAIT_TIMEOUT) return 0;
 | 
						|
	if ((ret -= WAIT_OBJECT_0) == count) {
 | 
						|
	    ResetSignal(interrupted_event);
 | 
						|
	    errno = EINTR;
 | 
						|
	    return -1;
 | 
						|
	}
 | 
						|
	if (ret > count) {
 | 
						|
	    errno = map_errno(GetLastError());
 | 
						|
	    return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	return poll_child_status(ChildRecord + ret, stat_loc);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
	struct ChildRecord* child = FindChildSlot(pid);
 | 
						|
	if (!child) {
 | 
						|
	    errno = ECHILD;
 | 
						|
	    return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	while (!(pid = poll_child_status(child, stat_loc))) {
 | 
						|
	    /* wait... */
 | 
						|
	    if (wait_events(child->hProcess, timeout) != WAIT_OBJECT_0) {
 | 
						|
		/* still active */
 | 
						|
		pid = 0;
 | 
						|
		break;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
    return pid;
 | 
						|
}
 | 
						|
 | 
						|
#include <sys/timeb.h>
 | 
						|
 | 
						|
int _cdecl
 | 
						|
gettimeofday(struct timeval *tv, struct timezone *tz)
 | 
						|
{
 | 
						|
    SYSTEMTIME st;
 | 
						|
    time_t t;
 | 
						|
    struct tm tm;
 | 
						|
 | 
						|
    GetLocalTime(&st);
 | 
						|
    tm.tm_sec = st.wSecond;
 | 
						|
    tm.tm_min = st.wMinute;
 | 
						|
    tm.tm_hour = st.wHour;
 | 
						|
    tm.tm_mday = st.wDay;
 | 
						|
    tm.tm_mon = st.wMonth - 1;
 | 
						|
    tm.tm_year = st.wYear - 1900;
 | 
						|
    tm.tm_isdst = -1;
 | 
						|
    t = mktime(&tm);
 | 
						|
    tv->tv_sec = t;
 | 
						|
    tv->tv_usec = st.wMilliseconds * 1000;
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
char *
 | 
						|
rb_w32_getcwd(buffer, size)
 | 
						|
    char *buffer;
 | 
						|
    int size;
 | 
						|
{
 | 
						|
    int length;
 | 
						|
    char *bp;
 | 
						|
 | 
						|
#undef getcwd
 | 
						|
    if (getcwd(buffer, size) == NULL) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
    length = strlen(buffer);
 | 
						|
    if (length >= size) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    for (bp = buffer; *bp != '\0'; bp = CharNext(bp)) {
 | 
						|
	if (*bp == '\\') {
 | 
						|
	    *bp = '/';
 | 
						|
	}
 | 
						|
    }
 | 
						|
    return buffer;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
chown(const char *path, int owner, int group)
 | 
						|
{
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
kill(int pid, int sig)
 | 
						|
{
 | 
						|
    int ret = 0;
 | 
						|
    DWORD err;
 | 
						|
 | 
						|
    if (pid <= 0) {
 | 
						|
	errno = EINVAL;
 | 
						|
	return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    if (IsWin95()) pid = -pid;
 | 
						|
    if ((unsigned int)pid == GetCurrentProcessId() &&
 | 
						|
	(sig != 0 && sig != SIGKILL)) {
 | 
						|
	if ((ret = raise(sig)) != 0) {
 | 
						|
	    /* MSVCRT doesn't set errno... */
 | 
						|
	    errno = EINVAL;
 | 
						|
	}
 | 
						|
	return ret;
 | 
						|
    }
 | 
						|
 | 
						|
    switch (sig) {
 | 
						|
      case 0:
 | 
						|
	RUBY_CRITICAL({
 | 
						|
	    HANDLE hProc =
 | 
						|
		OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)pid);
 | 
						|
	    if (hProc == NULL || hProc == INVALID_HANDLE_VALUE) {
 | 
						|
		if (GetLastError() == ERROR_INVALID_PARAMETER) {
 | 
						|
		    errno = ESRCH;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
		    errno = EPERM;
 | 
						|
		}
 | 
						|
		ret = -1;
 | 
						|
	    }
 | 
						|
	    else {
 | 
						|
		CloseHandle(hProc);
 | 
						|
	    }
 | 
						|
	});
 | 
						|
	break;
 | 
						|
 | 
						|
      case SIGINT:
 | 
						|
	RUBY_CRITICAL({
 | 
						|
	    if (!GenerateConsoleCtrlEvent(CTRL_C_EVENT, (DWORD)pid)) {
 | 
						|
		if ((err = GetLastError()) == 0)
 | 
						|
		    errno = EPERM;
 | 
						|
		else
 | 
						|
		    errno = map_errno(GetLastError());
 | 
						|
		ret = -1;
 | 
						|
	    }
 | 
						|
	});
 | 
						|
	break;
 | 
						|
 | 
						|
      case SIGKILL:
 | 
						|
	RUBY_CRITICAL({
 | 
						|
	    HANDLE hProc = OpenProcess(PROCESS_TERMINATE, FALSE, (DWORD)pid);
 | 
						|
	    if (hProc == NULL || hProc == INVALID_HANDLE_VALUE) {
 | 
						|
		if (GetLastError() == ERROR_INVALID_PARAMETER) {
 | 
						|
		    errno = ESRCH;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
		    errno = EPERM;
 | 
						|
		}
 | 
						|
		ret = -1;
 | 
						|
	    }
 | 
						|
	    else {
 | 
						|
		if (!TerminateProcess(hProc, 0)) {
 | 
						|
		    errno = EPERM;
 | 
						|
		    ret = -1;
 | 
						|
		}
 | 
						|
		CloseHandle(hProc);
 | 
						|
	    }
 | 
						|
	});
 | 
						|
	break;
 | 
						|
 | 
						|
      default:
 | 
						|
	errno = EINVAL;
 | 
						|
	ret = -1;
 | 
						|
	break;
 | 
						|
    }
 | 
						|
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
link(char *from, char *to)
 | 
						|
{
 | 
						|
    static BOOL (WINAPI *pCreateHardLink)(LPCTSTR, LPCTSTR, LPSECURITY_ATTRIBUTES) = NULL;
 | 
						|
    static int myerrno = 0;
 | 
						|
 | 
						|
    if (!pCreateHardLink && !myerrno) {
 | 
						|
	HANDLE hKernel;
 | 
						|
 | 
						|
	hKernel = GetModuleHandle("kernel32.dll");
 | 
						|
	if (hKernel) {
 | 
						|
	    pCreateHardLink = (BOOL (WINAPI *)(LPCTSTR, LPCTSTR, LPSECURITY_ATTRIBUTES))GetProcAddress(hKernel, "CreateHardLinkA");
 | 
						|
	    if (!pCreateHardLink) {
 | 
						|
		myerrno = map_errno(GetLastError());
 | 
						|
	    }
 | 
						|
	    CloseHandle(hKernel);
 | 
						|
	}
 | 
						|
	else {
 | 
						|
	    myerrno = map_errno(GetLastError());
 | 
						|
	}
 | 
						|
    }
 | 
						|
    if (!pCreateHardLink) {
 | 
						|
	errno = myerrno;
 | 
						|
	return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!pCreateHardLink(to, from, NULL)) {
 | 
						|
	errno = map_errno(GetLastError());
 | 
						|
	return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
wait()
 | 
						|
{
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
char *
 | 
						|
rb_w32_getenv(const char *name)
 | 
						|
{
 | 
						|
    static char *curitem = NULL;
 | 
						|
    static DWORD curlen = 0;
 | 
						|
    DWORD needlen;
 | 
						|
 | 
						|
    if (curitem == NULL || curlen == 0) {
 | 
						|
	curlen = 512;
 | 
						|
	curitem = ALLOC_N(char, curlen);
 | 
						|
    }
 | 
						|
 | 
						|
    needlen = GetEnvironmentVariable(name, curitem, curlen);
 | 
						|
    if (needlen != 0) {
 | 
						|
	while (needlen > curlen) {
 | 
						|
	    REALLOC_N(curitem, char, needlen);
 | 
						|
	    curlen = needlen;
 | 
						|
	    needlen = GetEnvironmentVariable(name, curitem, curlen);
 | 
						|
	}
 | 
						|
    }
 | 
						|
    else {
 | 
						|
	return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    return curitem;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
rb_w32_rename(const char *oldpath, const char *newpath)
 | 
						|
{
 | 
						|
    int res = 0;
 | 
						|
    int oldatts;
 | 
						|
    int newatts;
 | 
						|
 | 
						|
    oldatts = GetFileAttributes(oldpath);
 | 
						|
    newatts = GetFileAttributes(newpath);
 | 
						|
 | 
						|
    if (oldatts == -1) {
 | 
						|
	errno = map_errno(GetLastError());
 | 
						|
	return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	if (newatts != -1 && newatts & FILE_ATTRIBUTE_READONLY)
 | 
						|
	    SetFileAttributesA(newpath, newatts & ~ FILE_ATTRIBUTE_READONLY);
 | 
						|
 | 
						|
	if (!MoveFile(oldpath, newpath))
 | 
						|
	    res = -1;
 | 
						|
 | 
						|
	if (res) {
 | 
						|
	    switch (GetLastError()) {
 | 
						|
	      case ERROR_ALREADY_EXISTS:
 | 
						|
	      case ERROR_FILE_EXISTS:
 | 
						|
		if (IsWinNT()) {
 | 
						|
		    if (MoveFileEx(oldpath, newpath, MOVEFILE_REPLACE_EXISTING))
 | 
						|
			res = 0;
 | 
						|
		} else {
 | 
						|
		    for (;;) {
 | 
						|
			if (!DeleteFile(newpath) && GetLastError() != ERROR_FILE_NOT_FOUND)
 | 
						|
			    break;
 | 
						|
			else if (MoveFile(oldpath, newpath)) {
 | 
						|
			    res = 0;
 | 
						|
			    break;
 | 
						|
			}
 | 
						|
		    }
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	}
 | 
						|
 | 
						|
	if (res)
 | 
						|
	    errno = map_errno(GetLastError());
 | 
						|
	else
 | 
						|
	    SetFileAttributes(newpath, oldatts);
 | 
						|
    });
 | 
						|
 | 
						|
    return res;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
isUNCRoot(const char *path)
 | 
						|
{
 | 
						|
    if (path[0] == '\\' && path[1] == '\\') {
 | 
						|
	const char *p;
 | 
						|
	for (p = path + 2; *p; p = CharNext(p)) {
 | 
						|
	    if (*p == '\\')
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	if (p[0] && p[1]) {
 | 
						|
	    for (p++; *p; p = CharNext(p)) {
 | 
						|
		if (*p == '\\')
 | 
						|
		    break;
 | 
						|
	    }
 | 
						|
	    if (!p[0] || !p[1] || (p[1] == '.' && !p[2]))
 | 
						|
		return 1;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
rb_w32_stat(const char *path, struct stat *st)
 | 
						|
{
 | 
						|
    const char *p;
 | 
						|
    char *buf1, *s, *end;
 | 
						|
    int len;
 | 
						|
    int ret;
 | 
						|
 | 
						|
    if (!path || !st) {
 | 
						|
	errno = EFAULT;
 | 
						|
	return -1;
 | 
						|
    }
 | 
						|
    buf1 = ALLOCA_N(char, strlen(path) + 2);
 | 
						|
    for (p = path, s = buf1; *p; p++, s++) {
 | 
						|
	if (*p == '/')
 | 
						|
	    *s = '\\';
 | 
						|
	else
 | 
						|
	    *s = *p;
 | 
						|
    }
 | 
						|
    *s = '\0';
 | 
						|
    len = s - buf1;
 | 
						|
    if (!len || '\"' == *(--s)) {
 | 
						|
	errno = ENOENT;
 | 
						|
	return -1;
 | 
						|
    }
 | 
						|
    end = CharPrev(buf1, buf1 + len);
 | 
						|
 | 
						|
    if (isUNCRoot(buf1)) {
 | 
						|
	if (*end == '.')
 | 
						|
	    *end = '\0';
 | 
						|
	else if (*end != '\\')
 | 
						|
	    strcat(buf1, "\\");
 | 
						|
    } else if (*end == '\\' || (buf1 + 1 == end && *end == ':'))
 | 
						|
	strcat(buf1, ".");
 | 
						|
 | 
						|
    ret = stat(buf1, st);
 | 
						|
    if (ret == 0) {
 | 
						|
	st->st_mode &= ~(S_IWGRP | S_IWOTH);
 | 
						|
    }
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
static long
 | 
						|
filetime_to_clock(FILETIME *ft)
 | 
						|
{
 | 
						|
    __int64 qw = ft->dwHighDateTime;
 | 
						|
    qw <<= 32;
 | 
						|
    qw |= ft->dwLowDateTime;
 | 
						|
    qw /= 10000;  /* File time ticks at 0.1uS, clock at 1mS */
 | 
						|
    return (long) qw;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
rb_w32_times(struct tms *tmbuf)
 | 
						|
{
 | 
						|
    FILETIME create, exit, kernel, user;
 | 
						|
 | 
						|
    if (GetProcessTimes(GetCurrentProcess(),&create, &exit, &kernel, &user)) {
 | 
						|
	tmbuf->tms_utime = filetime_to_clock(&user);
 | 
						|
	tmbuf->tms_stime = filetime_to_clock(&kernel);
 | 
						|
	tmbuf->tms_cutime = 0;
 | 
						|
	tmbuf->tms_cstime = 0;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
	tmbuf->tms_utime = clock();
 | 
						|
	tmbuf->tms_stime = 0;
 | 
						|
	tmbuf->tms_cutime = 0;
 | 
						|
	tmbuf->tms_cstime = 0;
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
#undef Sleep
 | 
						|
#define yield_once() Sleep(0)
 | 
						|
#define yield_until(condition) do yield_once(); while (!(condition))
 | 
						|
 | 
						|
static DWORD wait_events(HANDLE event, DWORD timeout)
 | 
						|
{
 | 
						|
    HANDLE events[2];
 | 
						|
    int count = 0;
 | 
						|
    DWORD ret;
 | 
						|
 | 
						|
    if (event) {
 | 
						|
	events[count++] = event;
 | 
						|
    }
 | 
						|
    events[count++] = interrupted_event;
 | 
						|
 | 
						|
    ret = WaitForMultipleEvents(count, events, FALSE, timeout, TRUE);
 | 
						|
 | 
						|
    if (ret == WAIT_OBJECT_0 + count - 1) {
 | 
						|
	ResetSignal(interrupted_event);
 | 
						|
	errno = EINTR;
 | 
						|
    }
 | 
						|
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
static CRITICAL_SECTION* system_state(void)
 | 
						|
{
 | 
						|
    static int initialized = 0;
 | 
						|
    static CRITICAL_SECTION syssect;
 | 
						|
 | 
						|
    if (!initialized) {
 | 
						|
	InitializeCriticalSection(&syssect);
 | 
						|
	initialized = 1;
 | 
						|
    }
 | 
						|
    return &syssect;
 | 
						|
}
 | 
						|
 | 
						|
static LONG flag_interrupt = -1;
 | 
						|
static volatile DWORD tlsi_interrupt = TLS_OUT_OF_INDEXES;
 | 
						|
 | 
						|
void rb_w32_enter_critical(void)
 | 
						|
{
 | 
						|
    if (IsWinNT()) {
 | 
						|
	EnterCriticalSection(system_state());
 | 
						|
	return;
 | 
						|
    }
 | 
						|
 | 
						|
    if (tlsi_interrupt == TLS_OUT_OF_INDEXES) {
 | 
						|
	tlsi_interrupt = TlsAlloc();
 | 
						|
    }
 | 
						|
 | 
						|
    {
 | 
						|
	DWORD ti = (DWORD)TlsGetValue(tlsi_interrupt);
 | 
						|
	while (InterlockedIncrement(&flag_interrupt) > 0 && !ti) {
 | 
						|
	    InterlockedDecrement(&flag_interrupt);
 | 
						|
	    Sleep(1);
 | 
						|
	}
 | 
						|
	TlsSetValue(tlsi_interrupt, (PVOID)++ti);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void rb_w32_leave_critical(void)
 | 
						|
{
 | 
						|
    if (IsWinNT()) {
 | 
						|
	LeaveCriticalSection(system_state());
 | 
						|
	return;
 | 
						|
    }
 | 
						|
 | 
						|
    InterlockedDecrement(&flag_interrupt);
 | 
						|
    TlsSetValue(tlsi_interrupt, (PVOID)((DWORD)TlsGetValue(tlsi_interrupt) - 1));
 | 
						|
}
 | 
						|
 | 
						|
struct handler_arg_t {
 | 
						|
    void (*handler)(int);
 | 
						|
    int arg;
 | 
						|
    int status;
 | 
						|
    int finished;
 | 
						|
    HANDLE handshake;
 | 
						|
};
 | 
						|
 | 
						|
static void rb_w32_call_handler(struct handler_arg_t* h)
 | 
						|
{
 | 
						|
    int status;
 | 
						|
    RUBY_CRITICAL(rb_protect((VALUE (*)(VALUE))h->handler, (VALUE)h->arg, &h->status);
 | 
						|
		  status = h->status;
 | 
						|
		  SetEvent(h->handshake));
 | 
						|
    if (status) {
 | 
						|
	rb_jump_tag(status);
 | 
						|
    }
 | 
						|
    h->finished = 1;
 | 
						|
    yield_until(0);
 | 
						|
}
 | 
						|
 | 
						|
static struct handler_arg_t* setup_handler(struct handler_arg_t *harg,
 | 
						|
					   int arg,
 | 
						|
					   void (*handler)(int),
 | 
						|
					   HANDLE handshake)
 | 
						|
{
 | 
						|
    harg->handler = handler;
 | 
						|
    harg->arg = arg;
 | 
						|
    harg->status = 0;
 | 
						|
    harg->finished = 0;
 | 
						|
    harg->handshake = handshake;
 | 
						|
    return harg;
 | 
						|
}
 | 
						|
 | 
						|
static void setup_call(CONTEXT* ctx, struct handler_arg_t *harg)
 | 
						|
{
 | 
						|
#ifdef _M_IX86
 | 
						|
    DWORD *esp = (DWORD *)ctx->Esp;
 | 
						|
    *--esp = (DWORD)harg;
 | 
						|
    *--esp = ctx->Eip;
 | 
						|
    ctx->Esp = (DWORD)esp;
 | 
						|
    ctx->Eip = (DWORD)rb_w32_call_handler;
 | 
						|
#else
 | 
						|
#ifndef _WIN32_WCE
 | 
						|
#error unsupported processor
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
int rb_w32_main_context(int arg, void (*handler)(int))
 | 
						|
{
 | 
						|
    static HANDLE interrupt_done = NULL;
 | 
						|
    struct handler_arg_t harg;
 | 
						|
    CONTEXT ctx_orig;
 | 
						|
    HANDLE current_thread = GetCurrentThread();
 | 
						|
    int old_priority = GetThreadPriority(current_thread);
 | 
						|
 | 
						|
    if (GetCurrentThreadId() == main_thread.id) return FALSE;
 | 
						|
 | 
						|
    SetSignal(interrupted_event);
 | 
						|
 | 
						|
    RUBY_CRITICAL({		/* the main thread must be in user state */
 | 
						|
	CONTEXT ctx;
 | 
						|
 | 
						|
	SuspendThread(main_thread.handle);
 | 
						|
	SetThreadPriority(current_thread, GetThreadPriority(main_thread.handle));
 | 
						|
 | 
						|
	ZeroMemory(&ctx, sizeof(CONTEXT));
 | 
						|
	ctx.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT;
 | 
						|
	GetThreadContext(main_thread.handle, &ctx);
 | 
						|
	ctx_orig = ctx;
 | 
						|
 | 
						|
	/* handler context setup */
 | 
						|
	if (!interrupt_done) {
 | 
						|
	    interrupt_done = CreateEvent(NULL, FALSE, FALSE, NULL);
 | 
						|
	    /* anonymous one-shot event */
 | 
						|
	}
 | 
						|
	else {
 | 
						|
	    ResetEvent(interrupt_done);
 | 
						|
	}
 | 
						|
	setup_call(&ctx, setup_handler(&harg, arg, handler, interrupt_done));
 | 
						|
 | 
						|
	ctx.ContextFlags = CONTEXT_CONTROL;
 | 
						|
	SetThreadContext(main_thread.handle, &ctx);
 | 
						|
	ResumeThread(main_thread.handle);
 | 
						|
    });
 | 
						|
 | 
						|
    /* give a chance to the main thread */
 | 
						|
    yield_once();
 | 
						|
    WaitForSingleObject(interrupt_done, INFINITE); /* handshaking */
 | 
						|
 | 
						|
    if (!harg.status) {
 | 
						|
	/* no exceptions raised, restore old context. */
 | 
						|
	RUBY_CRITICAL({
 | 
						|
	    /* ensure the main thread is in user state. */
 | 
						|
	    yield_until(harg.finished);
 | 
						|
 | 
						|
	    SuspendThread(main_thread.handle);
 | 
						|
	    ctx_orig.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT;
 | 
						|
	    SetThreadContext(main_thread.handle, &ctx_orig);
 | 
						|
	    ResumeThread(main_thread.handle);
 | 
						|
	});
 | 
						|
    }
 | 
						|
    /* otherwise leave the main thread raised */
 | 
						|
 | 
						|
    SetThreadPriority(current_thread, old_priority);
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
int rb_w32_sleep(unsigned long msec)
 | 
						|
{
 | 
						|
    DWORD ret;
 | 
						|
    RUBY_CRITICAL(ret = wait_events(NULL, msec));
 | 
						|
    yield_once();
 | 
						|
    CHECK_INTS;
 | 
						|
    return ret != WAIT_TIMEOUT;
 | 
						|
}
 | 
						|
 | 
						|
static void catch_interrupt(void)
 | 
						|
{
 | 
						|
    yield_once();
 | 
						|
    RUBY_CRITICAL(wait_events(NULL, 0));
 | 
						|
    CHECK_INTS;
 | 
						|
}
 | 
						|
 | 
						|
#undef fgetc
 | 
						|
int rb_w32_getc(FILE* stream)
 | 
						|
{
 | 
						|
    int c, trap_immediate = rb_trap_immediate;
 | 
						|
#ifndef _WIN32_WCE
 | 
						|
    if (enough_to_get(stream->FILE_COUNT)) {
 | 
						|
	c = (unsigned char)*stream->FILE_READPTR++;
 | 
						|
	rb_trap_immediate = trap_immediate;
 | 
						|
    }
 | 
						|
    else 
 | 
						|
#endif
 | 
						|
    {
 | 
						|
	c = _filbuf(stream);
 | 
						|
#if defined __BORLANDC__ || defined _WIN32_WCE
 | 
						|
        if ((c == EOF) && (errno == EPIPE)) {
 | 
						|
	    clearerr(stream);
 | 
						|
        }
 | 
						|
#endif
 | 
						|
	rb_trap_immediate = trap_immediate;
 | 
						|
	catch_interrupt();
 | 
						|
    }
 | 
						|
    return c;
 | 
						|
}
 | 
						|
 | 
						|
#undef fputc
 | 
						|
int rb_w32_putc(int c, FILE* stream)
 | 
						|
{
 | 
						|
    int trap_immediate = rb_trap_immediate;
 | 
						|
#ifndef _WIN32_WCE
 | 
						|
    if (enough_to_put(stream->FILE_COUNT)) {
 | 
						|
	c = (unsigned char)(*stream->FILE_READPTR++ = (char)c);
 | 
						|
	rb_trap_immediate = trap_immediate;
 | 
						|
    }
 | 
						|
    else 
 | 
						|
#endif
 | 
						|
    {
 | 
						|
	c = _flsbuf(c, stream);
 | 
						|
	rb_trap_immediate = trap_immediate;
 | 
						|
	catch_interrupt();
 | 
						|
    }
 | 
						|
    return c;
 | 
						|
}
 | 
						|
 | 
						|
struct asynchronous_arg_t {
 | 
						|
    /* output field */
 | 
						|
    void* stackaddr;
 | 
						|
    int errnum;
 | 
						|
 | 
						|
    /* input field */
 | 
						|
    VALUE (*func)(VALUE self, int argc, VALUE* argv);
 | 
						|
    VALUE self;
 | 
						|
    int argc;
 | 
						|
    VALUE* argv;
 | 
						|
};
 | 
						|
 | 
						|
static DWORD WINAPI
 | 
						|
call_asynchronous(PVOID argp)
 | 
						|
{
 | 
						|
    DWORD ret;
 | 
						|
    struct asynchronous_arg_t *arg = argp;
 | 
						|
    arg->stackaddr = &argp;
 | 
						|
    ret = (DWORD)arg->func(arg->self, arg->argc, arg->argv);
 | 
						|
    arg->errnum = errno;
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
VALUE
 | 
						|
rb_w32_asynchronize(asynchronous_func_t func, VALUE self,
 | 
						|
		    int argc, VALUE* argv, VALUE intrval)
 | 
						|
{
 | 
						|
    DWORD val;
 | 
						|
    BOOL interrupted = FALSE;
 | 
						|
    HANDLE thr;
 | 
						|
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	struct asynchronous_arg_t arg;
 | 
						|
 | 
						|
	arg.stackaddr = NULL;
 | 
						|
	arg.errnum = 0;
 | 
						|
	arg.func = func;
 | 
						|
	arg.self = self;
 | 
						|
	arg.argc = argc;
 | 
						|
	arg.argv = argv;
 | 
						|
 | 
						|
	thr = CreateThread(NULL, 0, call_asynchronous, &arg, 0, &val);
 | 
						|
 | 
						|
	if (thr) {
 | 
						|
	    yield_until(arg.stackaddr);
 | 
						|
 | 
						|
	    if (wait_events(thr, INFINITE) != WAIT_OBJECT_0) {
 | 
						|
		interrupted = TRUE;
 | 
						|
 | 
						|
		if (TerminateThread(thr, intrval)) {
 | 
						|
		    yield_once();
 | 
						|
		}
 | 
						|
	    }
 | 
						|
 | 
						|
	    GetExitCodeThread(thr, &val);
 | 
						|
	    CloseHandle(thr);
 | 
						|
 | 
						|
	    if (interrupted) {
 | 
						|
		/* must release stack of killed thread, why doesn't Windows? */
 | 
						|
		MEMORY_BASIC_INFORMATION m;
 | 
						|
 | 
						|
		memset(&m, 0, sizeof(m));
 | 
						|
		if (!VirtualQuery(arg.stackaddr, &m, sizeof(m))) {
 | 
						|
		    Debug(fprintf(stderr, "couldn't get stack base:%p:%d\n",
 | 
						|
				  arg.stackaddr, GetLastError()));
 | 
						|
		}
 | 
						|
		else if (!VirtualFree(m.AllocationBase, 0, MEM_RELEASE)) {
 | 
						|
		    Debug(fprintf(stderr, "couldn't release stack:%p:%d\n",
 | 
						|
				  m.AllocationBase, GetLastError()));
 | 
						|
		}
 | 
						|
		errno = EINTR;
 | 
						|
	    }
 | 
						|
	    else {
 | 
						|
		errno = arg.errnum;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    });
 | 
						|
 | 
						|
    if (!thr) {
 | 
						|
	rb_fatal("failed to launch waiter thread:%d", GetLastError());
 | 
						|
    }
 | 
						|
 | 
						|
    if (interrupted) {
 | 
						|
	CHECK_INTS;
 | 
						|
    }
 | 
						|
 | 
						|
    return val;
 | 
						|
}
 | 
						|
 | 
						|
char **rb_w32_get_environ(void)
 | 
						|
{
 | 
						|
    char *envtop, *env;
 | 
						|
    char **myenvtop, **myenv;
 | 
						|
    int num;
 | 
						|
 | 
						|
    /*
 | 
						|
     * We avoid values started with `='. If you want to deal those values,
 | 
						|
     * change this function, and some functions in hash.c which recognize
 | 
						|
     * `=' as delimiter or rb_w32_getenv() and ruby_setenv().
 | 
						|
     * CygWin deals these values by changing first `=' to '!'. But we don't
 | 
						|
     * use such trick and follow cmd.exe's way that just doesn't show these
 | 
						|
     * values.
 | 
						|
     * (U.N. 2001-11-15)
 | 
						|
     */
 | 
						|
    envtop = GetEnvironmentStrings();
 | 
						|
    for (env = envtop, num = 0; *env; env += strlen(env) + 1)
 | 
						|
	if (*env != '=') num++;
 | 
						|
 | 
						|
    myenvtop = ALLOC_N(char*, num + 1);
 | 
						|
    for (env = envtop, myenv = myenvtop; *env; env += strlen(env) + 1) {
 | 
						|
	if (*env != '=') {
 | 
						|
	    *myenv = ALLOC_N(char, strlen(env) + 1);
 | 
						|
	    strcpy(*myenv, env);
 | 
						|
	    myenv++;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    *myenv = NULL;
 | 
						|
    FreeEnvironmentStrings(envtop);
 | 
						|
 | 
						|
    return myenvtop;
 | 
						|
}
 | 
						|
 | 
						|
void rb_w32_free_environ(char **env)
 | 
						|
{
 | 
						|
    char **t = env;
 | 
						|
 | 
						|
    while (*t) free(*t++);
 | 
						|
    free(env);
 | 
						|
}
 | 
						|
 | 
						|
pid_t rb_w32_getpid(void)
 | 
						|
{
 | 
						|
    pid_t pid;
 | 
						|
 | 
						|
    pid = _getpid();
 | 
						|
    if (IsWin95()) pid = -pid;
 | 
						|
 | 
						|
    return pid;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
rb_w32_fclose(FILE *fp)
 | 
						|
{
 | 
						|
    int fd = fileno(fp);
 | 
						|
    SOCKET sock = TO_SOCKET(fd);
 | 
						|
 | 
						|
    if (fflush(fp)) return -1;
 | 
						|
    if (!is_socket(sock)) {
 | 
						|
	UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN);
 | 
						|
	return fclose(fp);
 | 
						|
    }
 | 
						|
    _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE);
 | 
						|
    fclose(fp);
 | 
						|
    if (closesocket(sock) == SOCKET_ERROR) {
 | 
						|
	errno = map_errno(WSAGetLastError());
 | 
						|
	return -1;
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
rb_w32_close(int fd)
 | 
						|
{
 | 
						|
    SOCKET sock = TO_SOCKET(fd);
 | 
						|
 | 
						|
    if (!is_socket(sock)) {
 | 
						|
	UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN);
 | 
						|
	return _close(fd);
 | 
						|
    }
 | 
						|
    if (closesocket(sock) == SOCKET_ERROR) {
 | 
						|
	errno = map_errno(WSAGetLastError());
 | 
						|
	return -1;
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
unixtime_to_filetime(time_t time, FILETIME *ft)
 | 
						|
{
 | 
						|
    struct tm *tm;
 | 
						|
    SYSTEMTIME st;
 | 
						|
 | 
						|
    tm = gmtime(&time);
 | 
						|
    st.wYear = tm->tm_year + 1900;
 | 
						|
    st.wMonth = tm->tm_mon + 1;
 | 
						|
    st.wDayOfWeek = tm->tm_wday;
 | 
						|
    st.wDay = tm->tm_mday;
 | 
						|
    st.wHour = tm->tm_hour;
 | 
						|
    st.wMinute = tm->tm_min;
 | 
						|
    st.wSecond = tm->tm_sec;
 | 
						|
    st.wMilliseconds = 0;
 | 
						|
    if (!SystemTimeToFileTime(&st, ft)) {
 | 
						|
	errno = map_errno(GetLastError());
 | 
						|
	return -1;
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
#undef utime
 | 
						|
#ifdef __BORLANDC__
 | 
						|
#define utime _utime
 | 
						|
#endif
 | 
						|
int
 | 
						|
rb_w32_utime(const char *path, struct utimbuf *times)
 | 
						|
{
 | 
						|
    HANDLE hFile;
 | 
						|
    SYSTEMTIME st;
 | 
						|
    FILETIME atime, mtime;
 | 
						|
    struct tm *tm;
 | 
						|
    struct stat stat;
 | 
						|
    int ret = 0;
 | 
						|
 | 
						|
    if (rb_w32_stat(path, &stat)) {
 | 
						|
	return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    if (unixtime_to_filetime(times->actime, &atime)) {
 | 
						|
	return -1;
 | 
						|
    }
 | 
						|
    if (unixtime_to_filetime(times->modtime, &mtime)) {
 | 
						|
	return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    RUBY_CRITICAL({
 | 
						|
	hFile = CreateFile(path, GENERIC_WRITE, 0, 0, OPEN_EXISTING,
 | 
						|
			   IsWin95() ? 0 : FILE_FLAG_BACKUP_SEMANTICS, 0);
 | 
						|
	if (hFile == INVALID_HANDLE_VALUE) {
 | 
						|
	    errno = map_errno(GetLastError());
 | 
						|
	    ret = -1;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
	    if (!SetFileTime(hFile, NULL, &atime, &mtime)) {
 | 
						|
		errno = map_errno(GetLastError());
 | 
						|
		ret = -1;
 | 
						|
	    }
 | 
						|
	    CloseHandle(hFile);
 | 
						|
	}
 | 
						|
    });
 | 
						|
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
rb_w32_vsnprintf(char *buf, size_t size, const char *format, va_list va)
 | 
						|
{
 | 
						|
    int ret = _vsnprintf(buf, size, format, va);
 | 
						|
    if (size > 0) buf[size - 1] = 0;
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
rb_w32_snprintf(char *buf, size_t size, const char *format, ...)
 | 
						|
{
 | 
						|
    int ret;
 | 
						|
    va_list va;
 | 
						|
 | 
						|
    va_start(va, format);
 | 
						|
    ret = vsnprintf(buf, size, format, va);
 | 
						|
    va_end(va);
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// Fix bcc32's stdio bug
 | 
						|
//
 | 
						|
 | 
						|
#ifdef __BORLANDC__
 | 
						|
static int
 | 
						|
too_many_files()
 | 
						|
{
 | 
						|
    FILE *f;
 | 
						|
    for (f = _streams; f < _streams + _nfile; f++) {
 | 
						|
	if (f->fd < 0) return 0;
 | 
						|
    }
 | 
						|
    return 1;
 | 
						|
}
 | 
						|
 | 
						|
#undef fopen
 | 
						|
FILE *
 | 
						|
rb_w32_fopen(const char *path, const char *mode)
 | 
						|
{
 | 
						|
    FILE *f = (errno = 0, fopen(path, mode));
 | 
						|
    if (f == NULL && errno == 0) {
 | 
						|
	if (too_many_files())
 | 
						|
	    errno = EMFILE;
 | 
						|
    }
 | 
						|
    return f;
 | 
						|
}
 | 
						|
 | 
						|
FILE *
 | 
						|
rb_w32_fdopen(int handle, char *type)
 | 
						|
{
 | 
						|
    FILE *f = (errno = 0, _fdopen(handle, type));
 | 
						|
    if (f == NULL && errno == 0) {
 | 
						|
	if (handle < 0)
 | 
						|
	    errno = EBADF;
 | 
						|
	else if (too_many_files())
 | 
						|
	    errno = EMFILE;
 | 
						|
    }
 | 
						|
    return f;
 | 
						|
}
 | 
						|
 | 
						|
FILE *
 | 
						|
rb_w32_fsopen(const char *path, const char *mode, int shflags)
 | 
						|
{
 | 
						|
    FILE *f = (errno = 0, _fsopen(path, mode, shflags));
 | 
						|
    if (f == NULL && errno == 0) {
 | 
						|
	if (too_many_files())
 | 
						|
	    errno = EMFILE;
 | 
						|
    }
 | 
						|
    return f;
 | 
						|
}
 | 
						|
#endif
 |