@@ -1848,7 +1848,7 @@ static void eof_timer_cb(uv_timer_t* timer) {


static void eof_timer_destroy(uv_pipe_t* pipe) {
assert(pipe->flags && UV_HANDLE_CONNECTION);
assert(pipe->flags & UV_HANDLE_CONNECTION);

if (pipe->eof_timer) {
uv_close((uv_handle_t*) pipe->eof_timer, eof_timer_close_cb);
@@ -1910,7 +1910,7 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
}


int uv_pipe_getsockname(const uv_pipe_t* handle, char* buf, size_t* len) {
static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) {
NTSTATUS nt_status;
IO_STATUS_BLOCK io_status;
FILE_NAME_INFORMATION tmp_name_info;
@@ -1924,7 +1924,7 @@ int uv_pipe_getsockname(const uv_pipe_t* handle, char* buf, size_t* len) {
name_info = NULL;

if (handle->handle == INVALID_HANDLE_VALUE) {
*len = 0;
*size = 0;
return UV_EINVAL;
}

@@ -1939,7 +1939,7 @@ int uv_pipe_getsockname(const uv_pipe_t* handle, char* buf, size_t* len) {
name_size = sizeof(*name_info) + tmp_name_info.FileNameLength;
name_info = malloc(name_size);
if (!name_info) {
*len = 0;
*size = 0;
err = UV_ENOMEM;
goto cleanup;
}
@@ -1952,7 +1952,7 @@ int uv_pipe_getsockname(const uv_pipe_t* handle, char* buf, size_t* len) {
}

if (nt_status != STATUS_SUCCESS) {
*len = 0;
*size = 0;
err = uv_translate_sys_error(pRtlNtStatusToDosError(nt_status));
goto error;
}
@@ -1967,7 +1967,7 @@ int uv_pipe_getsockname(const uv_pipe_t* handle, char* buf, size_t* len) {
}

if (name_len == 0) {
*len = 0;
*size = 0;
err = 0;
goto error;
}
@@ -1984,34 +1984,33 @@ int uv_pipe_getsockname(const uv_pipe_t* handle, char* buf, size_t* len) {
NULL,
NULL);
if (!addrlen) {
*len = 0;
*size = 0;
err = uv_translate_sys_error(GetLastError());
goto error;
} else if (pipe_prefix_len + addrlen + 1 > *len) {
/* "\\\\.\\pipe" + name + '\0' */
*len = pipe_prefix_len + addrlen + 1;
} else if (pipe_prefix_len + addrlen > *size) {
/* "\\\\.\\pipe" + name */
*size = pipe_prefix_len + addrlen;
err = UV_ENOBUFS;
goto error;
}

memcpy(buf, pipe_prefix, pipe_prefix_len);
memcpy(buffer, pipe_prefix, pipe_prefix_len);
addrlen = WideCharToMultiByte(CP_UTF8,
0,
name_buf,
name_len,
buf+pipe_prefix_len,
*len-pipe_prefix_len,
buffer+pipe_prefix_len,
*size-pipe_prefix_len,
NULL,
NULL);
if (!addrlen) {
*len = 0;
*size = 0;
err = uv_translate_sys_error(GetLastError());
goto error;
}

addrlen += pipe_prefix_len;
buf[addrlen++] = '\0';
*len = addrlen;
*size = addrlen;

err = 0;
goto cleanup;
@@ -2032,6 +2031,32 @@ int uv_pipe_pending_count(uv_pipe_t* handle) {
}


int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) {
if (handle->flags & UV_HANDLE_BOUND)
return uv__pipe_getname(handle, buffer, size);

if (handle->flags & UV_HANDLE_CONNECTION ||
handle->handle != INVALID_HANDLE_VALUE) {
*size = 0;
return 0;
}

return UV_EBADF;
}


int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) {
/* emulate unix behaviour */
if (handle->flags & UV_HANDLE_BOUND)
return UV_ENOTCONN;

if (handle->handle != INVALID_HANDLE_VALUE)
return uv__pipe_getname(handle, buffer, size);

return UV_EBADF;
}


uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
if (!handle->ipc)
return UV_UNKNOWN_HANDLE;
@@ -46,6 +46,8 @@ typedef struct uv_single_fd_set_s {
static OVERLAPPED overlapped_dummy_;
static uv_once_t overlapped_dummy_init_guard_ = UV_ONCE_INIT;

static AFD_POLL_INFO afd_poll_info_dummy_;


static void uv__init_overlapped_dummy(void) {
HANDLE event;
@@ -65,6 +67,11 @@ static OVERLAPPED* uv__get_overlapped_dummy() {
}


static AFD_POLL_INFO* uv__get_afd_poll_info_dummy() {
return &afd_poll_info_dummy_;
}


static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
uv_req_t* req;
AFD_POLL_INFO* afd_poll_info;
@@ -79,7 +86,7 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
handle->mask_events_2 = handle->events;
} else if (handle->submitted_events_2 == 0) {
req = &handle->poll_req_2;
afd_poll_info = &handle->afd_poll_info_2.afd_poll_info_ptr[0];
afd_poll_info = &handle->afd_poll_info_2;
handle->submitted_events_2 = handle->events;
handle->mask_events_1 = handle->events;
handle->mask_events_2 = 0;
@@ -108,6 +115,7 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
memset(&req->overlapped, 0, sizeof req->overlapped);

result = uv_msafd_poll((SOCKET) handle->peer_socket,
afd_poll_info,
afd_poll_info,
&req->overlapped);
if (result != 0 && WSAGetLastError() != WSA_IO_PENDING) {
@@ -119,26 +127,25 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {


static int uv__fast_poll_cancel_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
AFD_POLL_INFO* afd_poll_info;
AFD_POLL_INFO afd_poll_info;
DWORD result;

afd_poll_info = &handle->afd_poll_info_2.afd_poll_info_ptr[1];
afd_poll_info->Exclusive = TRUE;
afd_poll_info->NumberOfHandles = 1;
afd_poll_info->Timeout.QuadPart = INT64_MAX;
afd_poll_info->Handles[0].Handle = (HANDLE) handle->socket;
afd_poll_info->Handles[0].Status = 0;
afd_poll_info->Handles[0].Events = AFD_POLL_ALL;
afd_poll_info.Exclusive = TRUE;
afd_poll_info.NumberOfHandles = 1;
afd_poll_info.Timeout.QuadPart = INT64_MAX;
afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket;
afd_poll_info.Handles[0].Status = 0;
afd_poll_info.Handles[0].Events = AFD_POLL_ALL;

result = uv_msafd_poll(handle->socket,
afd_poll_info,
&afd_poll_info,
uv__get_afd_poll_info_dummy(),
uv__get_overlapped_dummy());

if (result == SOCKET_ERROR) {
DWORD error = WSAGetLastError();
if (error != WSA_IO_PENDING) {
return WSAGetLastError();
}
if (error != WSA_IO_PENDING)
return error;
}

return 0;
@@ -155,7 +162,7 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
handle->submitted_events_1 = 0;
mask_events = handle->mask_events_1;
} else if (req == &handle->poll_req_2) {
afd_poll_info = &handle->afd_poll_info_2.afd_poll_info_ptr[0];
afd_poll_info = &handle->afd_poll_info_2;
handle->submitted_events_2 = 0;
mask_events = handle->mask_events_2;
} else {
@@ -498,6 +505,11 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
int len;
SOCKET peer_socket, base_socket;
DWORD bytes;
DWORD yes = 1;

/* Set the socket to nonblocking mode */
if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR)
return uv_translate_sys_error(WSAGetLastError());

/* Try to obtain a base handle for the socket. This increases this chances */
/* that we find an AFD handle and are able to use the fast poll mechanism. */
@@ -558,11 +570,6 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
handle->poll_req_2.type = UV_POLL_REQ;
handle->poll_req_2.data = handle;

handle->afd_poll_info_2.afd_poll_info_ptr = malloc(sizeof(*handle->afd_poll_info_2.afd_poll_info_ptr) * 2);
if (handle->afd_poll_info_2.afd_poll_info_ptr == NULL) {
return UV_ENOMEM;
}

return 0;
}

@@ -624,9 +631,5 @@ void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) {
assert(handle->submitted_events_1 == 0);
assert(handle->submitted_events_2 == 0);

if (handle->afd_poll_info_2.afd_poll_info_ptr) {
free(handle->afd_poll_info_2.afd_poll_info_ptr);
handle->afd_poll_info_2.afd_poll_info_ptr = NULL;
}
uv__handle_close(handle);
}
@@ -130,14 +130,13 @@ INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) {
} while (0)


INLINE static void uv_process_reqs(uv_loop_t* loop) {
INLINE static int uv_process_reqs(uv_loop_t* loop) {
uv_req_t* req;
uv_req_t* first;
uv_req_t* next;

if (loop->pending_reqs_tail == NULL) {
return;
}
if (loop->pending_reqs_tail == NULL)
return 0;

first = loop->pending_reqs_tail->next_req;
next = first;
@@ -207,6 +206,8 @@ INLINE static void uv_process_reqs(uv_loop_t* loop) {
assert(0);
}
}

return 1;
}

#endif /* UV_WIN_REQ_INL_H_ */
@@ -184,8 +184,22 @@ int uv_write2(uv_write_t* req,
int uv_try_write(uv_stream_t* stream,
const uv_buf_t bufs[],
unsigned int nbufs) {
/* NOTE: Won't work with overlapped writes */
return UV_ENOSYS;
if (stream->flags & UV__HANDLE_CLOSING)
return UV_EBADF;
if (!(stream->flags & UV_HANDLE_WRITABLE))
return UV_EPIPE;

switch (stream->type) {
case UV_TCP:
return uv__tcp_try_write((uv_tcp_t*) stream, bufs, nbufs);
case UV_TTY:
return uv__tty_try_write((uv_tty_t*) stream, bufs, nbufs);
case UV_NAMED_PIPE:
return UV_EAGAIN;
default:
assert(0);
return UV_ENOSYS;
}
}


@@ -876,6 +876,30 @@ int uv_tcp_write(uv_loop_t* loop,
}


int uv__tcp_try_write(uv_tcp_t* handle,
const uv_buf_t bufs[],
unsigned int nbufs) {
int result;
DWORD bytes;

if (handle->write_reqs_pending > 0)
return UV_EAGAIN;

result = WSASend(handle->socket,
(WSABUF*) bufs,
nbufs,
&bytes,
0,
NULL,
NULL);

if (result == SOCKET_ERROR)
return uv_translate_sys_error(WSAGetLastError());
else
return bytes;
}


void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
uv_req_t* req) {
DWORD bytes, flags, err;
@@ -117,7 +117,19 @@ void uv_once(uv_once_t* guard, void (*callback)(void)) {
uv__once_inner(guard, callback);
}

static UV_THREAD_LOCAL uv_thread_t uv__current_thread = NULL;

/* Verify that uv_thread_t can be stored in a TLS slot. */
STATIC_ASSERT(sizeof(uv_thread_t) <= sizeof(void*));

static uv_key_t uv__current_thread_key;
static uv_once_t uv__current_thread_init_guard = UV_ONCE_INIT;


static void uv__init_current_thread_key(void) {
if (uv_key_create(&uv__current_thread_key))
abort();
}


struct thread_ctx {
void (*entry)(void* arg);
@@ -126,16 +138,17 @@ struct thread_ctx {
};


static UINT __stdcall uv__thread_start(void* arg)
{
static UINT __stdcall uv__thread_start(void* arg) {
struct thread_ctx *ctx_p;
struct thread_ctx ctx;

ctx_p = arg;
ctx = *ctx_p;
free(ctx_p);

uv__current_thread = ctx.self;
uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
uv_key_set(&uv__current_thread_key, (void*) ctx.self);

ctx.entry(ctx.arg);

return 0;
@@ -177,9 +190,10 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {


uv_thread_t uv_thread_self(void) {
return uv__current_thread;
return (uv_thread_t) uv_key_get(&uv__current_thread_key);
}


int uv_thread_join(uv_thread_t *tid) {
if (WaitForSingleObject(*tid, INFINITE))
return uv_translate_sys_error(GetLastError());
@@ -170,7 +170,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
}


int uv_tty_set_mode(uv_tty_t* tty, int mode) {
int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
DWORD flags;
unsigned char was_reading;
uv_alloc_cb alloc_cb;
@@ -185,12 +185,15 @@ int uv_tty_set_mode(uv_tty_t* tty, int mode) {
return 0;
}

if (mode) {
/* Raw input */
flags = ENABLE_WINDOW_INPUT;
} else {
/* Line-buffered mode. */
flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
switch (mode) {
case UV_TTY_MODE_NORMAL:
flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
break;
case UV_TTY_MODE_RAW:
flags = ENABLE_WINDOW_INPUT;
break;
case UV_TTY_MODE_IO:
return UV_ENOTSUP;
}

if (!SetConsoleMode(tty->handle, flags)) {
@@ -1875,6 +1878,21 @@ int uv_tty_write(uv_loop_t* loop,
}


int uv__tty_try_write(uv_tty_t* handle,
const uv_buf_t bufs[],
unsigned int nbufs) {
DWORD error;

if (handle->write_reqs_pending > 0)
return UV_EAGAIN;

if (uv_tty_write_bufs(handle, bufs, nbufs, &error))
return uv_translate_sys_error(error);

return uv__count_bufs(bufs, nbufs);
}


void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
uv_write_t* req) {
int err;
@@ -31,6 +31,7 @@ sNtDeviceIoControlFile pNtDeviceIoControlFile;
sNtQueryInformationFile pNtQueryInformationFile;
sNtSetInformationFile pNtSetInformationFile;
sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
sNtQueryDirectoryFile pNtQueryDirectoryFile;
sNtQuerySystemInformation pNtQuerySystemInformation;


@@ -97,6 +98,12 @@ void uv_winapi_init() {
uv_fatal_error(GetLastError(), "GetProcAddress");
}

pNtQueryDirectoryFile = (sNtQueryDirectoryFile)
GetProcAddress(ntdll_module, "NtQueryDirectoryFile");
if (pNtQueryVolumeInformationFile == NULL) {
uv_fatal_error(GetLastError(), "GetProcAddress");
}

pNtQuerySystemInformation = (sNtQuerySystemInformation) GetProcAddress(
ntdll_module,
"NtQuerySystemInformation");
@@ -4104,12 +4104,23 @@
# define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 0x00002000
#endif

/* from winternl.h */
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

typedef const UNICODE_STRING *PCUNICODE_STRING;

/* from ntifs.h */
#ifndef DEVICE_TYPE
# define DEVICE_TYPE DWORD
#endif

/* from ntifs.h */
/* MinGW already has it, mingw-w64 does not. */
/* MinGW already has a definition for REPARSE_DATA_BUFFER, but mingw-w64 does
* not.
*/
#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
typedef struct _REPARSE_DATA_BUFFER {
ULONG ReparseTag;
@@ -4205,6 +4216,37 @@ typedef enum _FILE_INFORMATION_CLASS {
FileMaximumInformation
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;

typedef struct _FILE_DIRECTORY_INFORMATION {
ULONG NextEntryOffset;
ULONG FileIndex;
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
LARGE_INTEGER EndOfFile;
LARGE_INTEGER AllocationSize;
ULONG FileAttributes;
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION;

typedef struct _FILE_BOTH_DIR_INFORMATION {
ULONG NextEntryOffset;
ULONG FileIndex;
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
LARGE_INTEGER EndOfFile;
LARGE_INTEGER AllocationSize;
ULONG FileAttributes;
ULONG FileNameLength;
ULONG EaSize;
CCHAR ShortNameLength;
WCHAR ShortName[12];
WCHAR FileName[1];
} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;

typedef struct _FILE_BASIC_INFORMATION {
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
@@ -4512,6 +4554,19 @@ typedef NTSTATUS (NTAPI *sNtQuerySystemInformation)
ULONG SystemInformationLength,
PULONG ReturnLength);

typedef NTSTATUS (NTAPI *sNtQueryDirectoryFile)
(HANDLE FileHandle,
HANDLE Event,
PIO_APC_ROUTINE ApcRoutine,
PVOID ApcContext,
PIO_STATUS_BLOCK IoStatusBlock,
PVOID FileInformation,
ULONG Length,
FILE_INFORMATION_CLASS FileInformationClass,
BOOLEAN ReturnSingleEntry,
PUNICODE_STRING FileName,
BOOLEAN RestartScan
);

/*
* Kernel32 headers
@@ -4555,6 +4610,30 @@ typedef NTSTATUS (NTAPI *sNtQuerySystemInformation)
# define ERROR_SYMLINK_NOT_SUPPORTED 1464
#endif

#ifndef ERROR_MUI_FILE_NOT_FOUND
# define ERROR_MUI_FILE_NOT_FOUND 15100
#endif

#ifndef ERROR_MUI_INVALID_FILE
# define ERROR_MUI_INVALID_FILE 15101
#endif

#ifndef ERROR_MUI_INVALID_RC_CONFIG
# define ERROR_MUI_INVALID_RC_CONFIG 15102
#endif

#ifndef ERROR_MUI_INVALID_LOCALE_NAME
# define ERROR_MUI_INVALID_LOCALE_NAME 15103
#endif

#ifndef ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME
# define ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME 15104
#endif

#ifndef ERROR_MUI_FILE_NOT_LOADED
# define ERROR_MUI_FILE_NOT_LOADED 15105
#endif

typedef BOOL (WINAPI *sGetQueuedCompletionStatusEx)
(HANDLE CompletionPort,
LPOVERLAPPED_ENTRY lpCompletionPortEntries,
@@ -4626,6 +4705,7 @@ extern sNtDeviceIoControlFile pNtDeviceIoControlFile;
extern sNtQueryInformationFile pNtQueryInformationFile;
extern sNtSetInformationFile pNtSetInformationFile;
extern sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
extern sNtQueryDirectoryFile pNtQueryDirectoryFile;
extern sNtQuerySystemInformation pNtQuerySystemInformation;


@@ -474,8 +474,8 @@ int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
}


int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info,
OVERLAPPED* overlapped) {
int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
AFD_POLL_INFO* info_out, OVERLAPPED* overlapped) {
IO_STATUS_BLOCK iosb;
IO_STATUS_BLOCK* iosb_ptr;
HANDLE event = NULL;
@@ -513,10 +513,10 @@ int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info,
apc_context,
iosb_ptr,
IOCTL_AFD_POLL,
info,
sizeof *info,
info,
sizeof *info);
info_in,
sizeof *info_in,
info_out,
sizeof *info_out);

if (overlapped == NULL) {
/* If this is a blocking operation, wait for the event to become */
@@ -68,6 +68,7 @@ int process_start(char* name, char* part, process_info_t* p, int is_helper) {
const char* arg;
char* args[16];
int n;
pid_t pid;

stdout_file = tmpfile();
if (!stdout_file) {
@@ -78,7 +79,7 @@ int process_start(char* name, char* part, process_info_t* p, int is_helper) {
p->terminated = 0;
p->status = 0;

pid_t pid = fork();
pid = fork();

if (pid < 0) {
perror("fork");
@@ -167,8 +168,14 @@ static void* dowait(void* data) {
/* Return 0 if all processes are terminated, -1 on error, -2 on timeout. */
int process_wait(process_info_t* vec, int n, int timeout) {
int i;
int r;
int retval;
process_info_t* p;
dowait_args args;
pthread_t tid;
struct timeval tv;
fd_set fds;

args.vec = vec;
args.n = n;
args.pipe[0] = -1;
@@ -186,10 +193,7 @@ int process_wait(process_info_t* vec, int n, int timeout) {
* we'd need to lock vec.
*/

pthread_t tid;
int retval;

int r = pipe((int*)&(args.pipe));
r = pipe((int*)&(args.pipe));
if (r) {
perror("pipe()");
return -1;
@@ -202,11 +206,9 @@ int process_wait(process_info_t* vec, int n, int timeout) {
goto terminate;
}

struct timeval tv;
tv.tv_sec = timeout / 1000;
tv.tv_usec = 0;

fd_set fds;
FD_ZERO(&fds);
FD_SET(args.pipe[0], &fds);

@@ -259,15 +261,16 @@ long int process_output_size(process_info_t *p) {

/* Copy the contents of the stdio output buffer to `fd`. */
int process_copy_output(process_info_t *p, int fd) {
int r = fseek(p->stdout_file, 0, SEEK_SET);
ssize_t nwritten;
char buf[1024];
int r;

r = fseek(p->stdout_file, 0, SEEK_SET);
if (r < 0) {
perror("fseek");
return -1;
}

ssize_t nwritten;
char buf[1024];

/* TODO: what if the line is longer than buf */
while (fgets(buf, sizeof(buf), p->stdout_file) != NULL) {
/* TODO: what if write doesn't write the whole buffer... */
@@ -39,6 +39,11 @@
# include <sys/resource.h> /* setrlimit() */
#endif

#ifdef __clang__
# pragma clang diagnostic ignored "-Wvariadic-macros"
# pragma clang diagnostic ignored "-Wc99-extensions"
#endif

#define TEST_PORT 9123
#define TEST_PORT_2 9124

@@ -229,4 +234,21 @@ UNUSED static void close_loop(uv_loop_t* loop) {
uv_run(loop, UV_RUN_DEFAULT);
}

UNUSED static int can_ipv6(void) {
uv_interface_address_t* addr;
int supported;
int count;
int i;

if (uv_interface_addresses(&addr, &count))
return 1; /* Assume IPv6 support on failure. */

supported = 0;
for (i = 0; supported == 0 && i < count; i += 1)
supported = (AF_INET6 == addr[i].address.address6.sin6_family);

uv_free_interface_addresses(addr, count);
return supported;
}

#endif /* TASK_H_ */
@@ -54,7 +54,6 @@ TEST_IMPL(close_fd) {
int fd[2];

ASSERT(0 == pipe(fd));
ASSERT(0 == fcntl(fd[0], F_SETFL, O_NONBLOCK));
ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0));
ASSERT(0 == uv_pipe_open(&pipe_handle, fd[0]));
fd[0] = -1; /* uv_pipe_open() takes ownership of the file descriptor. */
@@ -29,35 +29,22 @@ extern char executable_path[];
TEST_IMPL(cwd_and_chdir) {
char buffer_orig[PATHMAX];
char buffer_new[PATHMAX];
size_t size;
char* last_slash;
size_t size1;
size_t size2;
int err;

size = sizeof(buffer_orig);
err = uv_cwd(buffer_orig, &size);
size1 = sizeof buffer_orig;
err = uv_cwd(buffer_orig, &size1);
ASSERT(err == 0);

/* Remove trailing slash unless at a root directory. */
#ifdef _WIN32
last_slash = strrchr(buffer_orig, '\\');
ASSERT(last_slash);
if (last_slash > buffer_orig && *(last_slash - 1) != ':') {
*last_slash = '\0';
}
#else /* Unix */
last_slash = strrchr(buffer_orig, '/');
ASSERT(last_slash);
if (last_slash != buffer_orig) {
*last_slash = '\0';
}
#endif

err = uv_chdir(buffer_orig);
ASSERT(err == 0);

err = uv_cwd(buffer_new, &size);
size2 = sizeof buffer_new;
err = uv_cwd(buffer_new, &size2);
ASSERT(err == 0);

ASSERT(size1 == size2);
ASSERT(strcmp(buffer_orig, buffer_new) == 0);

return 0;
@@ -26,31 +26,28 @@

TEST_IMPL(dlerror) {
const char* path = "test/fixtures/load_error.node";
const char* dlerror_no_error = "no error";
const char* msg;
uv_lib_t lib;
int r;

#ifdef __linux__
const char* dlerror_desc = "file too short";
#elif defined (__sun__)
const char* dlerror_desc = "unknown file type";
#elif defined (_WIN32)
const char* dlerror_desc = "%1 is not a valid Win32 application";
#else
const char* dlerror_desc = "";
#endif
lib.errmsg = NULL;
lib.handle = NULL;
msg = uv_dlerror(&lib);
ASSERT(msg != NULL);
ASSERT(strstr(msg, dlerror_no_error) != NULL);

r = uv_dlopen(path, &lib);
ASSERT(r == -1);

msg = uv_dlerror(&lib);
ASSERT(msg != NULL);
ASSERT(strstr(msg, dlerror_desc) != NULL);
ASSERT(strstr(msg, dlerror_no_error) == NULL);

/* Should return the same error twice in a row. */
msg = uv_dlerror(&lib);
ASSERT(msg != NULL);
ASSERT(strstr(msg, dlerror_desc) != NULL);
ASSERT(strstr(msg, dlerror_no_error) == NULL);

uv_dlclose(&lib);

@@ -642,6 +642,7 @@ TEST_IMPL(fs_event_getpath) {
len = sizeof buf;
r = uv_fs_event_getpath(&fs_event, buf, &len);
ASSERT(r == 0);
ASSERT(buf[len - 1] != 0);
ASSERT(memcmp(buf, "watch_dir", len) == 0);
r = uv_fs_event_stop(&fs_event);
ASSERT(r == 0);
@@ -172,6 +172,7 @@ TEST_IMPL(fs_poll_getpath) {
ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100));
len = sizeof buf;
ASSERT(0 == uv_fs_poll_getpath(&poll_handle, buf, &len));
ASSERT(buf[len - 1] != 0);
ASSERT(0 == memcmp(buf, FIXTURE, len));

uv_close((uv_handle_t*) &poll_handle, close_cb);
@@ -568,7 +568,17 @@ TEST_IMPL(fs_file_loop) {
loop = uv_default_loop();

unlink("test_symlink");
uv_fs_symlink(loop, &req, "test_symlink", "test_symlink", 0, NULL);
r = uv_fs_symlink(loop, &req, "test_symlink", "test_symlink", 0, NULL);
#ifdef _WIN32
/*
* Windows XP and Server 2003 don't support symlinks; we'll get UV_ENOTSUP.
* Starting with vista they are supported, but only when elevated, otherwise
* we'll see UV_EPERM.
*/
if (r == UV_ENOTSUP || r == UV_EPERM)
return 0;
#endif
ASSERT(r == 0);
uv_fs_req_cleanup(&req);

r = uv_fs_open(loop, &req, "test_symlink", O_RDONLY, 0, NULL);
@@ -61,5 +61,26 @@ TEST_IMPL(get_currentexe) {
r = uv_exepath(buffer, NULL);
ASSERT(r == UV_EINVAL);

size = 0;
r = uv_exepath(buffer, &size);
ASSERT(r == UV_EINVAL);

memset(buffer, -1, sizeof(buffer));

size = 1;
r = uv_exepath(buffer, &size);
ASSERT(r == 0);
ASSERT(size == 0);
ASSERT(buffer[0] == '\0');

memset(buffer, -1, sizeof(buffer));

size = 2;
r = uv_exepath(buffer, &size);
ASSERT(r == 0);
ASSERT(size == 1);
ASSERT(buffer[0] != '\0');
ASSERT(buffer[1] == '\0');

return 0;
}
@@ -97,6 +97,22 @@ TEST_IMPL(getaddrinfo_fail) {
}


TEST_IMPL(getaddrinfo_fail_sync) {
uv_getaddrinfo_t req;

ASSERT(0 > uv_getaddrinfo(uv_default_loop(),
&req,
NULL,
"xyzzy.xyzzy.xyzzy",
NULL,
NULL));
uv_freeaddrinfo(req.addrinfo);

MAKE_VALGRIND_HAPPY();
return 0;
}


TEST_IMPL(getaddrinfo_basic) {
int r;
getaddrinfo_handle = (uv_getaddrinfo_t*)malloc(sizeof(uv_getaddrinfo_t));
@@ -118,6 +134,22 @@ TEST_IMPL(getaddrinfo_basic) {
}


TEST_IMPL(getaddrinfo_basic_sync) {
uv_getaddrinfo_t req;

ASSERT(0 == uv_getaddrinfo(uv_default_loop(),
&req,
NULL,
name,
NULL,
NULL));
uv_freeaddrinfo(req.addrinfo);

MAKE_VALGRIND_HAPPY();
return 0;
}


TEST_IMPL(getaddrinfo_concurrent) {
int i, r;
int* data;
@@ -44,6 +44,7 @@ static void getnameinfo_req(uv_getnameinfo_t* handle,
ASSERT(service != NULL);
}


TEST_IMPL(getnameinfo_basic_ip4) {
int r;

@@ -63,6 +64,23 @@ TEST_IMPL(getnameinfo_basic_ip4) {
return 0;
}


TEST_IMPL(getnameinfo_basic_ip4_sync) {
ASSERT(0 == uv_ip4_addr(address_ip4, port, &addr4));

ASSERT(0 == uv_getnameinfo(uv_default_loop(),
&req,
NULL,
(const struct sockaddr*)&addr4,
0));
ASSERT(req.host != NULL);
ASSERT(req.service != NULL);

MAKE_VALGRIND_HAPPY();
return 0;
}


TEST_IMPL(getnameinfo_basic_ip6) {
int r;

@@ -29,6 +29,7 @@ TEST_DECLARE (loop_close)
TEST_DECLARE (loop_stop)
TEST_DECLARE (loop_update_time)
TEST_DECLARE (loop_backend_timeout)
TEST_DECLARE (loop_configure)
TEST_DECLARE (default_loop_close)
TEST_DECLARE (barrier_1)
TEST_DECLARE (barrier_2)
@@ -103,6 +104,7 @@ TEST_DECLARE (udp_dgram_too_big)
TEST_DECLARE (udp_dual_stack)
TEST_DECLARE (udp_ipv6_only)
TEST_DECLARE (udp_options)
TEST_DECLARE (udp_options6)
TEST_DECLARE (udp_no_autobind)
TEST_DECLARE (udp_open)
TEST_DECLARE (udp_try_send)
@@ -165,6 +167,7 @@ TEST_DECLARE (pipe_ref4)
#ifndef _WIN32
TEST_DECLARE (pipe_close_stdout_read_stdin)
#endif
TEST_DECLARE (pipe_set_non_blocking)
TEST_DECLARE (process_ref)
TEST_DECLARE (has_ref)
TEST_DECLARE (active)
@@ -178,9 +181,12 @@ TEST_DECLARE (get_memory)
TEST_DECLARE (handle_fileno)
TEST_DECLARE (hrtime)
TEST_DECLARE (getaddrinfo_fail)
TEST_DECLARE (getaddrinfo_fail_sync)
TEST_DECLARE (getaddrinfo_basic)
TEST_DECLARE (getaddrinfo_basic_sync)
TEST_DECLARE (getaddrinfo_concurrent)
TEST_DECLARE (getnameinfo_basic_ip4)
TEST_DECLARE (getnameinfo_basic_ip4_sync)
TEST_DECLARE (getnameinfo_basic_ip6)
TEST_DECLARE (getsockname_tcp)
TEST_DECLARE (getsockname_udp)
@@ -269,6 +275,7 @@ TEST_DECLARE (ip4_addr)
TEST_DECLARE (ip6_addr_link_local)

#ifdef _WIN32
TEST_DECLARE (poll_close_doesnt_corrupt_stack)
TEST_DECLARE (poll_closesocket)
TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows)
TEST_DECLARE (argument_escaping)
@@ -312,6 +319,7 @@ TASK_LIST_START
TEST_ENTRY (loop_stop)
TEST_ENTRY (loop_update_time)
TEST_ENTRY (loop_backend_timeout)
TEST_ENTRY (loop_configure)
TEST_ENTRY (default_loop_close)
TEST_ENTRY (barrier_1)
TEST_ENTRY (barrier_2)
@@ -332,6 +340,7 @@ TASK_LIST_START
#ifndef _WIN32
TEST_ENTRY (pipe_close_stdout_read_stdin)
#endif
TEST_ENTRY (pipe_set_non_blocking)
TEST_ENTRY (tty)
TEST_ENTRY (stdio_over_pipes)
TEST_ENTRY (ip6_pton)
@@ -410,6 +419,7 @@ TASK_LIST_START
TEST_ENTRY (udp_dual_stack)
TEST_ENTRY (udp_ipv6_only)
TEST_ENTRY (udp_options)
TEST_ENTRY (udp_options6)
TEST_ENTRY (udp_no_autobind)
TEST_ENTRY (udp_multicast_interface)
TEST_ENTRY (udp_multicast_interface6)
@@ -519,11 +529,14 @@ TASK_LIST_START
TEST_ENTRY (hrtime)

TEST_ENTRY_CUSTOM (getaddrinfo_fail, 0, 0, 10000)
TEST_ENTRY (getaddrinfo_fail_sync)

TEST_ENTRY (getaddrinfo_basic)
TEST_ENTRY (getaddrinfo_basic_sync)
TEST_ENTRY (getaddrinfo_concurrent)

TEST_ENTRY (getnameinfo_basic_ip4)
TEST_ENTRY (getnameinfo_basic_ip4_sync)
TEST_ENTRY (getnameinfo_basic_ip6)

TEST_ENTRY (getsockname_tcp)
@@ -558,6 +571,7 @@ TASK_LIST_START
TEST_ENTRY (kill)

#ifdef _WIN32
TEST_ENTRY (poll_close_doesnt_corrupt_stack)
TEST_ENTRY (poll_closesocket)
TEST_ENTRY (spawn_detect_pipe_name_collisions_on_windows)
TEST_ENTRY (argument_escaping)
@@ -0,0 +1,38 @@
/* Copyright (c) 2014, Ben Noordhuis <info@bnoordhuis.nl>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "uv.h"
#include "task.h"

static void timer_cb(uv_timer_t* handle) {
uv_close((uv_handle_t*) handle, NULL);
}


TEST_IMPL(loop_configure) {
uv_timer_t timer_handle;
uv_loop_t loop;
ASSERT(0 == uv_loop_init(&loop));
#ifdef _WIN32
ASSERT(UV_ENOSYS == uv_loop_configure(&loop, UV_LOOP_BLOCK_SIGNAL, 0));
#else
ASSERT(0 == uv_loop_configure(&loop, UV_LOOP_BLOCK_SIGNAL, SIGPROF));
#endif
ASSERT(0 == uv_timer_init(&loop, &timer_handle));
ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 10, 0));
ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT));
ASSERT(0 == uv_loop_close(&loop));
return 0;
}
@@ -54,8 +54,10 @@ TEST_IMPL(osx_select) {
uv_tty_t tty;

fd = open("/dev/tty", O_RDONLY);

ASSERT(fd >= 0);
if (fd < 0) {
LOGF("Cannot open /dev/tty as read-only: %s\n", strerror(errno));
return TEST_SKIP;
}

r = uv_tty_init(uv_default_loop(), &tty, fd, 1);
ASSERT(r == 0);
@@ -90,7 +92,7 @@ TEST_IMPL(osx_select_many_fds) {
uv_tty_t tty;
uv_tcp_t tcps[1500];

TEST_FILE_LIMIT(ARRAY_SIZE(tcps) + 2);
TEST_FILE_LIMIT(ARRAY_SIZE(tcps) + 100);

r = uv_ip4_addr("127.0.0.1", 0, &addr);
ASSERT(r == 0);
@@ -104,7 +106,10 @@ TEST_IMPL(osx_select_many_fds) {
}

fd = open("/dev/tty", O_RDONLY);
ASSERT(fd >= 0);
if (fd < 0) {
LOGF("Cannot open /dev/tty as read-only: %s\n", strerror(errno));
return TEST_SKIP;
}

r = uv_tty_init(uv_default_loop(), &tty, fd, 1);
ASSERT(r == 0);
@@ -246,6 +246,9 @@ TEST_IMPL(tcp_ping_pong) {


TEST_IMPL(tcp_ping_pong_v6) {
if (!can_ipv6())
RETURN_SKIP("IPv6 not supported");

tcp_pinger_v6_new();
uv_run(uv_default_loop(), UV_RUN_DEFAULT);

@@ -53,6 +53,7 @@ TEST_IMPL(pipe_close_stdout_read_stdin) {
int pid;
int fd[2];
int status;
uv_pipe_t stdin_pipe;

r = pipe(fd);
ASSERT(r == 0);
@@ -68,8 +69,6 @@ TEST_IMPL(pipe_close_stdout_read_stdin) {
ASSERT(r != -1);

/* Create a stream that reads from the pipe. */
uv_pipe_t stdin_pipe;

r = uv_pipe_init(uv_default_loop(), (uv_pipe_t *)&stdin_pipe, 0);
ASSERT(r == 0);

@@ -36,38 +36,121 @@
# include <fcntl.h>
#endif

static uv_pipe_t pipe_client;
static uv_pipe_t pipe_server;
static uv_connect_t connect_req;

static int close_cb_called = 0;
static int pipe_close_cb_called = 0;
static int pipe_client_connect_cb_called = 0;


static void close_cb(uv_handle_t* handle) {
ASSERT(handle != NULL);
close_cb_called++;
static void pipe_close_cb(uv_handle_t* handle) {
ASSERT(handle == (uv_handle_t*) &pipe_client ||
handle == (uv_handle_t*) &pipe_server);
pipe_close_cb_called++;
}


static void pipe_client_connect_cb(uv_connect_t* req, int status) {
char buf[1024];
size_t len;
int r;

ASSERT(req == &connect_req);
ASSERT(status == 0);

len = sizeof buf;
r = uv_pipe_getpeername(&pipe_client, buf, &len);
ASSERT(r == 0);

ASSERT(buf[len - 1] != 0);
ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);

len = sizeof buf;
r = uv_pipe_getsockname(&pipe_client, buf, &len);
ASSERT(r == 0 && len == 0);

pipe_client_connect_cb_called++;


uv_close((uv_handle_t*) &pipe_client, pipe_close_cb);
uv_close((uv_handle_t*) &pipe_server, pipe_close_cb);
}


static void pipe_server_connection_cb(uv_stream_t* handle, int status) {
/* This function *may* be called, depending on whether accept or the
* connection callback is called first.
*/
ASSERT(status == 0);
}


TEST_IMPL(pipe_getsockname) {
uv_pipe_t server;
uv_loop_t* loop;
char buf[1024];
size_t len;
int r;

r = uv_pipe_init(uv_default_loop(), &server, 0);
loop = uv_default_loop();
ASSERT(loop != NULL);

r = uv_pipe_init(loop, &pipe_server, 0);
ASSERT(r == 0);
r = uv_pipe_bind(&server, TEST_PIPENAME);

len = sizeof buf;
r = uv_pipe_getsockname(&pipe_server, buf, &len);
ASSERT(r == UV_EBADF);

len = sizeof buf;
r = uv_pipe_getpeername(&pipe_server, buf, &len);
ASSERT(r == UV_EBADF);

r = uv_pipe_bind(&pipe_server, TEST_PIPENAME);
ASSERT(r == 0);

len = sizeof buf;
r = uv_pipe_getsockname(&server, buf, &len);
r = uv_pipe_getsockname(&pipe_server, buf, &len);
ASSERT(r == 0);

ASSERT(buf[len - 1] != 0);
ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);

uv_close((uv_handle_t*)&server, close_cb);
len = sizeof buf;
r = uv_pipe_getpeername(&pipe_server, buf, &len);
ASSERT(r == UV_ENOTCONN);

uv_run(uv_default_loop(), UV_RUN_DEFAULT);
r = uv_listen((uv_stream_t*) &pipe_server, 0, pipe_server_connection_cb);
ASSERT(r == 0);

r = uv_pipe_init(loop, &pipe_client, 0);
ASSERT(r == 0);

len = sizeof buf;
r = uv_pipe_getsockname(&pipe_client, buf, &len);
ASSERT(r == UV_EBADF);

ASSERT(close_cb_called == 1);
len = sizeof buf;
r = uv_pipe_getpeername(&pipe_client, buf, &len);
ASSERT(r == UV_EBADF);

uv_pipe_connect(&connect_req, &pipe_client, TEST_PIPENAME, pipe_client_connect_cb);

len = sizeof buf;
r = uv_pipe_getsockname(&pipe_client, buf, &len);
ASSERT(r == 0 && len == 0);

len = sizeof buf;
r = uv_pipe_getpeername(&pipe_client, buf, &len);
ASSERT(r == 0);

ASSERT(buf[len - 1] != 0);
ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);

r = uv_run(loop, UV_RUN_DEFAULT);
ASSERT(r == 0);
ASSERT(pipe_client_connect_cb_called == 1);
ASSERT(pipe_close_cb_called == 2);

MAKE_VALGRIND_HAPPY();
return 0;
@@ -76,7 +159,6 @@ TEST_IMPL(pipe_getsockname) {

TEST_IMPL(pipe_getsockname_abstract) {
#if defined(__linux__)
uv_pipe_t server;
char buf[1024];
size_t len;
int r;
@@ -96,24 +178,24 @@ TEST_IMPL(pipe_getsockname_abstract) {
r = bind(sock, (struct sockaddr*)&sun, sun_len);
ASSERT(r == 0);

r = uv_pipe_init(uv_default_loop(), &server, 0);
r = uv_pipe_init(uv_default_loop(), &pipe_server, 0);
ASSERT(r == 0);
r = uv_pipe_open(&server, sock);
r = uv_pipe_open(&pipe_server, sock);
ASSERT(r == 0);

len = sizeof buf;
r = uv_pipe_getsockname(&server, buf, &len);
r = uv_pipe_getsockname(&pipe_server, buf, &len);
ASSERT(r == 0);

ASSERT(memcmp(buf, abstract_pipe, sizeof abstract_pipe) == 0);

uv_close((uv_handle_t*)&server, close_cb);
uv_close((uv_handle_t*)&pipe_server, pipe_close_cb);

uv_run(uv_default_loop(), UV_RUN_DEFAULT);

close(sock);

ASSERT(close_cb_called == 1);
ASSERT(pipe_close_cb_called == 1);
MAKE_VALGRIND_HAPPY();
return 0;
#else
@@ -124,7 +206,6 @@ TEST_IMPL(pipe_getsockname_abstract) {

TEST_IMPL(pipe_getsockname_blocking) {
#ifdef _WIN32
uv_pipe_t reader;
HANDLE readh, writeh;
int readfd;
char buf1[1024], buf2[1024];
@@ -134,42 +215,44 @@ TEST_IMPL(pipe_getsockname_blocking) {
r = CreatePipe(&readh, &writeh, NULL, 65536);
ASSERT(r != 0);

r = uv_pipe_init(uv_default_loop(), &reader, 0);
r = uv_pipe_init(uv_default_loop(), &pipe_client, 0);
ASSERT(r == 0);
readfd = _open_osfhandle((intptr_t)readh, _O_RDONLY);
ASSERT(r != -1);
r = uv_pipe_open(&reader, readfd);
r = uv_pipe_open(&pipe_client, readfd);
ASSERT(r == 0);
r = uv_read_start((uv_stream_t*)&reader, NULL, NULL);
r = uv_read_start((uv_stream_t*)&pipe_client, NULL, NULL);
ASSERT(r == 0);
Sleep(100);
r = uv_read_stop((uv_stream_t*)&reader);
r = uv_read_stop((uv_stream_t*)&pipe_client);
ASSERT(r == 0);

len1 = sizeof buf1;
r = uv_pipe_getsockname(&reader, buf1, &len1);
r = uv_pipe_getsockname(&pipe_client, buf1, &len1);
ASSERT(r == 0);
ASSERT(buf1[len1 - 1] != 0);

r = uv_read_start((uv_stream_t*)&reader, NULL, NULL);
r = uv_read_start((uv_stream_t*)&pipe_client, NULL, NULL);
ASSERT(r == 0);
Sleep(100);

len2 = sizeof buf2;
r = uv_pipe_getsockname(&reader, buf2, &len2);
r = uv_pipe_getsockname(&pipe_client, buf2, &len2);
ASSERT(r == 0);
ASSERT(buf2[len2 - 1] != 0);

r = uv_read_stop((uv_stream_t*)&reader);
r = uv_read_stop((uv_stream_t*)&pipe_client);
ASSERT(r == 0);

ASSERT(len1 == len2);
ASSERT(memcmp(buf1, buf2, len1) == 0);

close_cb_called = 0;
uv_close((uv_handle_t*)&reader, close_cb);
pipe_close_cb_called = 0;
uv_close((uv_handle_t*)&pipe_client, pipe_close_cb);

uv_run(uv_default_loop(), UV_RUN_DEFAULT);

ASSERT(close_cb_called == 1);
ASSERT(pipe_close_cb_called == 1);

_close(readfd);
CloseHandle(writeh);
@@ -0,0 +1,99 @@
/* Copyright (c) 2015, Ben Noordhuis <info@bnoordhuis.nl>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "uv.h"
#include "task.h"

#ifdef _WIN32

TEST_IMPL(pipe_set_non_blocking) {
RETURN_SKIP("Test not implemented on Windows.");
}

#else /* !_WIN32 */

#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>

struct thread_ctx {
uv_barrier_t barrier;
int fd;
};

static void thread_main(void* arg) {
struct thread_ctx* ctx;
char buf[4096];
ssize_t n;

ctx = arg;
uv_barrier_wait(&ctx->barrier);

do
n = read(ctx->fd, buf, sizeof(buf));
while (n > 0 || (n == -1 && errno == EINTR));

ASSERT(n == 0);
}

TEST_IMPL(pipe_set_non_blocking) {
struct thread_ctx ctx;
uv_pipe_t pipe_handle;
uv_thread_t thread;
size_t nwritten;
char data[4096];
uv_buf_t buf;
int fd[2];
int n;

ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0));
ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, fd));
ASSERT(0 == uv_pipe_open(&pipe_handle, fd[0]));
ASSERT(0 == uv_stream_set_blocking((uv_stream_t*) &pipe_handle, 1));

ctx.fd = fd[1];
ASSERT(0 == uv_barrier_init(&ctx.barrier, 2));
ASSERT(0 == uv_thread_create(&thread, thread_main, &ctx));
uv_barrier_wait(&ctx.barrier);

buf.len = sizeof(data);
buf.base = data;
memset(data, '.', sizeof(data));

nwritten = 0;
while (nwritten < 10 << 20) {
/* The stream is in blocking mode so uv_try_write() should always succeed
* with the exact number of bytes that we wanted written.
*/
n = uv_try_write((uv_stream_t*) &pipe_handle, &buf, 1);
ASSERT(n == sizeof(data));
nwritten += n;
}

uv_close((uv_handle_t*) &pipe_handle, NULL);
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));

ASSERT(0 == close(fd[1])); /* fd[0] is closed by uv_close(). */
ASSERT(0 == uv_thread_join(&thread));
uv_barrier_destroy(&ctx.barrier);

MAKE_VALGRIND_HAPPY();
return 0;
}

#endif /* !_WIN32 */
@@ -27,6 +27,7 @@
TEST_IMPL(platform_output) {
char buffer[512];
size_t rss;
size_t size;
double uptime;
uv_rusage_t rusage;
uv_cpu_info_t* cpus;
@@ -39,6 +40,11 @@ TEST_IMPL(platform_output) {
ASSERT(err == 0);
printf("uv_get_process_title: %s\n", buffer);

size = sizeof(buffer);
err = uv_cwd(buffer, &size);
ASSERT(err == 0);
printf("uv_cwd: %s\n", buffer);

err = uv_resident_set_memory(&rss);
ASSERT(err == 0);
printf("uv_resident_set_memory: %llu\n", (unsigned long long) rss);
@@ -0,0 +1,114 @@
/* Copyright Bert Belder, and other libuv contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/

#ifdef _WIN32

#include <errno.h>
#include <stdio.h>

#include "uv.h"
#include "task.h"

#ifdef _MSC_VER /* msvc */
# define NO_INLINE __declspec(noinline)
#else /* gcc */
# define NO_INLINE __attribute__ ((noinline))
#endif


uv_os_sock_t sock;
uv_poll_t handle;

static int close_cb_called = 0;


static void close_cb(uv_handle_t* h) {
close_cb_called++;
}


static void poll_cb(uv_poll_t* h, int status, int events) {
ASSERT(0 && "should never get here");
}


static void NO_INLINE close_socket_and_verify_stack() {
const uint32_t MARKER = 0xDEADBEEF;
const int VERIFY_AFTER = 10; /* ms */
int r;

volatile uint32_t data[65536];
size_t i;

for (i = 0; i < ARRAY_SIZE(data); i++)
data[i] = MARKER;

r = closesocket(sock);
ASSERT(r == 0);

uv_sleep(VERIFY_AFTER);

for (i = 0; i < ARRAY_SIZE(data); i++)
ASSERT(data[i] == MARKER);
}


TEST_IMPL(poll_close_doesnt_corrupt_stack) {
struct WSAData wsa_data;
int r;
unsigned long on;
struct sockaddr_in addr;

r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
ASSERT(r == 0);

sock = socket(AF_INET, SOCK_STREAM, 0);
ASSERT(sock != INVALID_SOCKET);
on = 1;
r = ioctlsocket(sock, FIONBIO, &on);
ASSERT(r == 0);

r = uv_ip4_addr("127.0.0.1", TEST_PORT, &addr);
ASSERT(r == 0);

r = connect(sock, (const struct sockaddr*) &addr, sizeof addr);
ASSERT(r != 0);
ASSERT(WSAGetLastError() == WSAEWOULDBLOCK);

r = uv_poll_init_socket(uv_default_loop(), &handle, sock);
ASSERT(r == 0);
r = uv_poll_start(&handle, UV_READABLE | UV_WRITABLE, poll_cb);
ASSERT(r == 0);

uv_close((uv_handle_t*) &handle, close_cb);

close_socket_and_verify_stack();

r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT(r == 0);

ASSERT(close_cb_called == 1);

MAKE_VALGRIND_HAPPY();
return 0;
}

#endif /* _WIN32 */
@@ -67,7 +67,8 @@ TEST_IMPL(poll_closesocket) {
r = ioctlsocket(sock, FIONBIO, &on);
ASSERT(r == 0);

addr = uv_ip4_addr("127.0.0.1", TEST_PORT);
r = uv_ip4_addr("127.0.0.1", TEST_PORT, &addr);
ASSERT(r == 0);

r = connect(sock, (const struct sockaddr*) &addr, sizeof addr);
ASSERT(r != 0);
@@ -22,7 +22,6 @@
#include <errno.h>

#ifndef _WIN32
# include <fcntl.h>
# include <sys/socket.h>
# include <unistd.h>
#endif
@@ -86,23 +85,7 @@ static int got_eagain(void) {
}


static void set_nonblocking(uv_os_sock_t sock) {
int r;
#ifdef _WIN32
unsigned long on = 1;
r = ioctlsocket(sock, FIONBIO, &on);
ASSERT(r == 0);
#else
int flags = fcntl(sock, F_GETFL, 0);
ASSERT(flags >= 0);
r = fcntl(sock, F_SETFL, flags | O_NONBLOCK);
ASSERT(r >= 0);
#endif
}


static uv_os_sock_t create_nonblocking_bound_socket(
struct sockaddr_in bind_addr) {
static uv_os_sock_t create_bound_socket (struct sockaddr_in bind_addr) {
uv_os_sock_t sock;
int r;

@@ -113,8 +96,6 @@ static uv_os_sock_t create_nonblocking_bound_socket(
ASSERT(sock >= 0);
#endif

set_nonblocking(sock);

#ifndef _WIN32
{
/* Allow reuse of the port. */
@@ -479,8 +460,6 @@ static void server_poll_cb(uv_poll_t* handle, int status, int events) {
ASSERT(sock >= 0);
#endif

set_nonblocking(sock);

connection_context = create_connection_context(sock, 1);
connection_context->events = UV_READABLE | UV_WRITABLE;
r = uv_poll_start(&connection_context->poll_handle,
@@ -502,7 +481,7 @@ static void start_server(void) {
int r;

ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
sock = create_nonblocking_bound_socket(addr);
sock = create_bound_socket(addr);
context = create_server_context(sock);

r = listen(sock, 100);
@@ -523,7 +502,7 @@ static void start_client(void) {
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &addr));

sock = create_nonblocking_bound_socket(addr);
sock = create_bound_socket(addr);
context = create_connection_context(sock, 0);

context->events = UV_READABLE | UV_WRITABLE;
@@ -988,7 +988,8 @@ TEST_IMPL(environment_creation) {
}
}
if (prev) { /* verify sort order -- requires Vista */
#if _WIN32_WINNT >= 0x0600
#if _WIN32_WINNT >= 0x0600 && \
(!defined(__MINGW32__) || defined(__MINGW64_VERSION_MAJOR))
ASSERT(CompareStringOrdinal(prev, -1, str, -1, TRUE) == 1);
#endif
}
@@ -1014,7 +1015,7 @@ TEST_IMPL(spawn_with_an_odd_path) {
char *path = getenv("PATH");
ASSERT(path != NULL);
snprintf(newpath, 2048, ";.;%s", path);
SetEnvironmentVariable("PATH", path);
SetEnvironmentVariable("PATH", newpath);

init_process_options("", exit_cb);
options.file = options.args[0] = "program-that-had-better-not-exist";
@@ -1032,6 +1033,7 @@ TEST_IMPL(spawn_with_an_odd_path) {
#ifndef _WIN32
TEST_IMPL(spawn_setuid_setgid) {
int r;
struct passwd* pw;

/* if not root, then this will fail. */
uv_uid_t uid = getuid();
@@ -1043,14 +1045,16 @@ TEST_IMPL(spawn_setuid_setgid) {
init_process_options("spawn_helper1", exit_cb);

/* become the "nobody" user. */
struct passwd* pw;
pw = getpwnam("nobody");
ASSERT(pw != NULL);
options.uid = pw->pw_uid;
options.gid = pw->pw_gid;
options.flags = UV_PROCESS_SETUID | UV_PROCESS_SETGID;

r = uv_spawn(uv_default_loop(), &process, &options);
if (r == UV_EACCES)
RETURN_SKIP("user 'nobody' cannot access the test runner");

ASSERT(r == 0);

r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
@@ -1240,7 +1244,6 @@ TEST_IMPL(closed_fd_events) {

/* create a pipe and share it with a child process */
ASSERT(0 == pipe(fd));
ASSERT(0 == fcntl(fd[0], F_SETFL, O_NONBLOCK));

/* spawn_helper4 blocks indefinitely. */
init_process_options("spawn_helper4", exit_cb);
@@ -1297,7 +1300,16 @@ TEST_IMPL(spawn_reads_child_path) {
int len;
char file[64];
char path[1024];
char *env[2] = {path, NULL};
char* env[3];

/* Need to carry over the dynamic linker path when the test runner is
* linked against libuv.so, see https://github.com/libuv/libuv/issues/85.
*/
#if defined(__APPLE__)
static const char dyld_path_var[] = "DYLD_LIBRARY_PATH";
#else
static const char dyld_path_var[] = "LD_LIBRARY_PATH";
#endif

/* Set up the process, but make sure that the file to run is relative and */
/* requires a lookup into PATH */
@@ -1312,6 +1324,16 @@ TEST_IMPL(spawn_reads_child_path) {
strcpy(path, "PATH=");
strcpy(path + 5, exepath);

env[0] = path;
env[1] = getenv(dyld_path_var);
env[2] = NULL;

if (env[1] != NULL) {
static char buf[1024 + sizeof(dyld_path_var)];
snprintf(buf, sizeof(buf), "%s=%s", dyld_path_var, env[1]);
env[1] = buf;
}

options.file = file;
options.args[0] = file;
options.env = env;
@@ -39,6 +39,9 @@ TEST_IMPL(tcp_bind6_error_addrinuse) {
uv_tcp_t server1, server2;
int r;

if (!can_ipv6())
RETURN_SKIP("IPv6 not supported");

ASSERT(0 == uv_ip6_addr("::", TEST_PORT, &addr));

r = uv_tcp_init(uv_default_loop(), &server1);
@@ -73,6 +76,9 @@ TEST_IMPL(tcp_bind6_error_addrnotavail) {
uv_tcp_t server;
int r;

if (!can_ipv6())
RETURN_SKIP("IPv6 not supported");

ASSERT(0 == uv_ip6_addr("4:4:4:4:4:4:4:4", TEST_PORT, &addr));

r = uv_tcp_init(uv_default_loop(), &server);
@@ -98,6 +104,9 @@ TEST_IMPL(tcp_bind6_error_fault) {
uv_tcp_t server;
int r;

if (!can_ipv6())
RETURN_SKIP("IPv6 not supported");

garbage_addr = (struct sockaddr_in6*) &garbage;

r = uv_tcp_init(uv_default_loop(), &server);
@@ -123,6 +132,9 @@ TEST_IMPL(tcp_bind6_error_inval) {
uv_tcp_t server;
int r;

if (!can_ipv6())
RETURN_SKIP("IPv6 not supported");

ASSERT(0 == uv_ip6_addr("::", TEST_PORT, &addr1));
ASSERT(0 == uv_ip6_addr("::", TEST_PORT_2, &addr2));

@@ -149,6 +161,9 @@ TEST_IMPL(tcp_bind6_localhost_ok) {
uv_tcp_t server;
int r;

if (!can_ipv6())
RETURN_SKIP("IPv6 not supported");

ASSERT(0 == uv_ip6_addr("::1", TEST_PORT, &addr));

r = uv_tcp_init(uv_default_loop(), &server);
@@ -28,16 +28,6 @@

#define MAX_BYTES 1024 * 1024

#ifdef _WIN32

TEST_IMPL(tcp_try_write) {

MAKE_VALGRIND_HAPPY();
return 0;
}

#else /* !_WIN32 */

static uv_tcp_t server;
static uv_tcp_t client;
static uv_tcp_t incoming;
@@ -138,5 +128,3 @@ TEST_IMPL(tcp_try_write) {
MAKE_VALGRIND_HAPPY();
return 0;
}

#endif /* !_WIN32 */
@@ -147,23 +147,22 @@ static void do_test(uv_udp_recv_cb recv_cb, int bind_flags) {


TEST_IMPL(udp_dual_stack) {
#if defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__OpenBSD__) || \
defined(__NetBSD__)
RETURN_SKIP("dual stack not enabled by default in this OS.");
#else
if (!can_ipv6())
RETURN_SKIP("IPv6 not supported");

do_test(ipv6_recv_ok, 0);

ASSERT(recv_cb_called == 1);
ASSERT(send_cb_called == 1);

return 0;
#endif
}


TEST_IMPL(udp_ipv6_only) {
if (!can_ipv6())
RETURN_SKIP("IPv6 not supported");

do_test(ipv6_recv_fail, UV_UDP_IPV6ONLY);

ASSERT(recv_cb_called == 0);
@@ -60,6 +60,9 @@ TEST_IMPL(udp_multicast_interface6) {
struct sockaddr_in6 addr;
struct sockaddr_in6 baddr;

if (!can_ipv6())
RETURN_SKIP("IPv6 not supported");

ASSERT(0 == uv_ip6_addr("::1", TEST_PORT, &addr));

r = uv_udp_init(uv_default_loop(), &server);
@@ -103,6 +103,9 @@ TEST_IMPL(udp_multicast_join6) {
uv_buf_t buf;
struct sockaddr_in6 addr;

if (!can_ipv6())
RETURN_SKIP("IPv6 not supported");

ASSERT(0 == uv_ip6_addr("::1", TEST_PORT, &addr));

r = uv_udp_init(uv_default_loop(), &server);
@@ -27,23 +27,20 @@
#include <string.h>


TEST_IMPL(udp_options) {
static int udp_options_test(const struct sockaddr* addr) {
static int invalid_ttls[] = { -1, 0, 256 };
struct sockaddr_in addr;
uv_loop_t* loop;
uv_udp_t h;
int i, r;

ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));

loop = uv_default_loop();

r = uv_udp_init(loop, &h);
ASSERT(r == 0);

uv_unref((uv_handle_t*)&h); /* don't keep the loop alive */

r = uv_udp_bind(&h, (const struct sockaddr*) &addr, 0);
r = uv_udp_bind(&h, addr, 0);
ASSERT(r == 0);

r = uv_udp_set_broadcast(&h, 1);
@@ -88,6 +85,25 @@ TEST_IMPL(udp_options) {
}


TEST_IMPL(udp_options) {
struct sockaddr_in addr;

ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
return udp_options_test((const struct sockaddr*) &addr);
}


TEST_IMPL(udp_options6) {
struct sockaddr_in6 addr;

if (!can_ipv6())
RETURN_SKIP("IPv6 not supported");

ASSERT(0 == uv_ip6_addr("::", TEST_PORT, &addr));
return udp_options_test((const struct sockaddr*) &addr);
}


TEST_IMPL(udp_no_autobind) {
uv_loop_t* loop;
uv_udp_t h;
@@ -17,28 +17,8 @@
}],
],
'xcode_settings': {
'conditions': [
[ 'clang==1', {
'WARNING_CFLAGS': [
'-Wall',
'-Wextra',
'-Wno-unused-parameter',
'-Wno-dollar-in-identifier-extension'
]}, {
'WARNING_CFLAGS': [
'-Wall',
'-Wextra',
'-Wno-unused-parameter'
]}
]
],
'OTHER_LDFLAGS': [
],
'OTHER_CFLAGS': [
'-g',
'--std=gnu89',
'-pedantic'
],
'WARNING_CFLAGS': [ '-Wall', '-Wextra', '-Wno-unused-parameter' ],
'OTHER_CFLAGS': [ '-g', '--std=gnu89', '-pedantic' ],
}
},

@@ -221,6 +201,7 @@
'cflags': [ '-Wstrict-aliasing' ],
}],
[ 'OS=="linux"', {
'defines': [ '_GNU_SOURCE' ],
'sources': [
'src/unix/linux-core.c',
'src/unix/linux-inotify.c',
@@ -341,6 +322,7 @@
'test/test-loop-close.c',
'test/test-loop-stop.c',
'test/test-loop-time.c',
'test/test-loop-configure.c',
'test/test-walk-handles.c',
'test/test-watcher-cross-stop.c',
'test/test-multiple-listen.c',
@@ -353,9 +335,11 @@
'test/test-pipe-sendmsg.c',
'test/test-pipe-server-close.c',
'test/test-pipe-close-stdout-read-stdin.c',
'test/test-pipe-set-non-blocking.c',
'test/test-platform-output.c',
'test/test-poll.c',
'test/test-poll-close.c',
'test/test-poll-close-doesnt-corrupt-stack.c',
'test/test-poll-closesocket.c',
'test/test-process-title.c',
'test/test-ref.c',
@@ -38,7 +38,7 @@ this it is possible to allocate external array data to more than a plain Object.
v8 does not support allocating external array data to an Array, and if passed
will throw.

It's possible is to specify the type of external array data you would like. All
It's possible to specify the type of external array data you would like. All
possible options are listed in `smalloc.Types`. Example usage:

var doubleArr = smalloc.alloc(3, smalloc.Types.Double);
@@ -586,6 +586,13 @@ exports._forkChild = function(fd) {
// set process.send()
var p = createPipe(true);
p.open(fd);

// p.open() puts the file descriptor in non-blocking mode
// but it must be synchronous for backwards compatibility.
var err = p.setBlocking(true);
if (err)
throw errnoException(err, 'setBlocking');

p.unref();
setupChannel(process, p);

@@ -50,10 +50,6 @@ var O_RDWR = constants.O_RDWR || 0;
var O_SYNC = constants.O_SYNC || 0;
var O_TRUNC = constants.O_TRUNC || 0;
var O_WRONLY = constants.O_WRONLY || 0;
var F_OK = constants.F_OK || 0;
var R_OK = constants.R_OK || 0;
var W_OK = constants.W_OK || 0;
var X_OK = constants.X_OK || 0;

var isWindows = process.platform === 'win32';

@@ -186,18 +182,20 @@ fs.Stats.prototype.isSocket = function() {
return this._checkModeProperty(constants.S_IFSOCK);
};

fs.F_OK = F_OK;
fs.R_OK = R_OK;
fs.W_OK = W_OK;
fs.X_OK = X_OK;
// don't allow fs.mode to accidentally be overwritten.
['F_OK', 'R_OK', 'W_OK', 'X_OK'].forEach(function(key) {
Object.defineProperty(fs, key, {
enumerable: true, value: constants[key] || 0, writable: false
});
});

fs.access = function(path, mode, callback) {
if (!nullCheck(path, callback))
return;

if (typeof mode === 'function') {
callback = mode;
mode = F_OK;
mode = fs.F_OK;
} else if (typeof callback !== 'function') {
throw new TypeError('callback must be a function');
}
@@ -212,7 +210,7 @@ fs.accessSync = function(path, mode) {
nullCheck(path);

if (mode === undefined)
mode = F_OK;
mode = fs.F_OK;
else
mode = mode | 0;

@@ -154,9 +154,9 @@ function Socket(options) {
} else if (!util.isUndefined(options.fd)) {
this._handle = createHandle(options.fd);
this._handle.open(options.fd);
if ((options.fd == 1 || options.fd == 2) &&
(this._handle instanceof Pipe) &&
process.platform === 'win32') {
// this._handle.open() puts the file descriptor in non-blocking
// mode but it must be synchronous for backwards compatibility.
if ((options.fd == 1 || options.fd == 2) && this._handle instanceof Pipe) {
// Make stdout and stderr blocking on Windows
var err = this._handle.setBlocking(true);
if (err)
@@ -0,0 +1,44 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

var common = require('../common');
var assert = require('assert');
var fork = require('child_process').fork;
var N = 4 << 20; // 4 MB

for (var big = '*'; big.length < N; big += big);

if (process.argv[2] === 'child') {
process.send(big);
process.exit(42);
}

var proc = fork(__filename, ['child']);

proc.on('message', common.mustCall(function(msg) {
assert.equal(typeof msg, 'string');
assert.equal(msg.length, N);
assert.equal(msg, big);
}));

proc.on('exit', common.mustCall(function(exitCode) {
assert.equal(exitCode, 42);
}));
@@ -77,6 +77,13 @@ if (process.platform !== 'win32' && process.getuid() === 0) {
}
}

// Check that {F,R,W,X}_OK are read only

fs.F_OK = null;
fs.R_OK = null;
fs.W_OK = null;
fs.X_OK = null;

assert(typeof fs.F_OK === 'number');
assert(typeof fs.R_OK === 'number');
assert(typeof fs.W_OK === 'number');
@@ -0,0 +1,44 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

var common = require('../common');
var assert = require('assert');
var spawn = require('child_process').spawn;
var N = 4 << 20; // 4 MB

for (var big = '*'; big.length < N; big += big);

if (process.argv[2] === 'child') {
process.stdout.write(big);
process.exit(42);
}

var stdio = ['inherit', 'pipe', 'inherit'];
var proc = spawn(process.execPath, [__filename, 'child'], { stdio: stdio });

var chunks = [];
proc.stdout.setEncoding('utf8');
proc.stdout.on('data', chunks.push.bind(chunks));

proc.on('exit', common.mustCall(function(exitCode) {
assert.equal(exitCode, 42);
assert.equal(chunks.join(''), big);
}));
@@ -42,7 +42,8 @@ setTimeout(function() {
interval = setInterval(function() {
unref_interval = true;
clearInterval(interval);
}, SHORT_TIME).unref();
}, SHORT_TIME);
interval.unref();

setTimeout(function() {
unref_timer = true;