noderb 0.0.10 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. data/ext/noderb_extension/extconf.rb +15 -11
  2. data/ext/noderb_extension/libuv/AUTHORS +3 -0
  3. data/ext/noderb_extension/libuv/{README → README.md} +48 -6
  4. data/ext/noderb_extension/libuv/common.gypi +6 -1
  5. data/ext/noderb_extension/libuv/config-unix.mk +1 -1
  6. data/ext/noderb_extension/libuv/include/uv-private/uv-linux.h +29 -0
  7. data/ext/noderb_extension/libuv/include/uv-private/uv-unix.h +9 -0
  8. data/ext/noderb_extension/libuv/include/uv-private/uv-win.h +38 -3
  9. data/ext/noderb_extension/libuv/include/uv.h +55 -3
  10. data/ext/noderb_extension/libuv/src/unix/cares.c +1 -0
  11. data/ext/noderb_extension/libuv/src/unix/core.c +20 -4
  12. data/ext/noderb_extension/libuv/src/unix/cygwin.c +16 -0
  13. data/ext/noderb_extension/libuv/src/unix/darwin.c +18 -0
  14. data/ext/noderb_extension/libuv/src/unix/freebsd.c +18 -1
  15. data/ext/noderb_extension/libuv/src/unix/fs.c +18 -9
  16. data/ext/noderb_extension/libuv/src/unix/internal.h +24 -0
  17. data/ext/noderb_extension/libuv/src/unix/linux.c +133 -1
  18. data/ext/noderb_extension/libuv/src/unix/netbsd.c +18 -1
  19. data/ext/noderb_extension/libuv/src/unix/stream.c +21 -7
  20. data/ext/noderb_extension/libuv/src/unix/sunos.c +18 -1
  21. data/ext/noderb_extension/libuv/src/unix/tty.c +41 -0
  22. data/ext/noderb_extension/libuv/src/unix/udp.c +1 -0
  23. data/ext/noderb_extension/libuv/src/win/core.c +3 -0
  24. data/ext/noderb_extension/libuv/src/win/fs-event.c +384 -0
  25. data/ext/noderb_extension/libuv/src/win/getaddrinfo.c +7 -2
  26. data/ext/noderb_extension/libuv/src/win/handle.c +41 -0
  27. data/ext/noderb_extension/libuv/src/win/internal.h +36 -0
  28. data/ext/noderb_extension/libuv/src/win/pipe.c +3 -0
  29. data/ext/noderb_extension/libuv/src/win/process.c +7 -2
  30. data/ext/noderb_extension/libuv/src/win/req.c +10 -0
  31. data/ext/noderb_extension/libuv/src/win/stream.c +10 -3
  32. data/ext/noderb_extension/libuv/src/win/tcp.c +3 -1
  33. data/ext/noderb_extension/libuv/src/win/tty.c +1559 -5
  34. data/ext/noderb_extension/libuv/test/benchmark-getaddrinfo.c +2 -0
  35. data/ext/noderb_extension/libuv/test/runner-unix.c +2 -0
  36. data/ext/noderb_extension/libuv/test/test-fs-event.c +217 -0
  37. data/ext/noderb_extension/libuv/test/test-fs.c +0 -4
  38. data/ext/noderb_extension/libuv/test/test-getaddrinfo.c +7 -3
  39. data/ext/noderb_extension/libuv/test/test-list.h +23 -0
  40. data/ext/noderb_extension/libuv/test/test-tcp-close.c +47 -0
  41. data/ext/noderb_extension/libuv/test/test-tcp-write-error.c +168 -0
  42. data/ext/noderb_extension/libuv/test/test-timer.c +40 -0
  43. data/ext/noderb_extension/libuv/test/test-tty.c +56 -0
  44. data/ext/noderb_extension/libuv/uv.gyp +17 -18
  45. data/ext/noderb_extension/noderb.c +0 -2
  46. data/ext/noderb_extension/noderb_dns.c +6 -7
  47. data/ext/noderb_extension/noderb_fs.c +11 -10
  48. data/ext/noderb_extension/noderb_timers.c +5 -5
  49. data/lib/noderb/version.rb +1 -1
  50. metadata +8 -3
@@ -0,0 +1,384 @@
1
+ /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2
+ *
3
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ * of this software and associated documentation files (the "Software"), to
5
+ * deal in the Software without restriction, including without limitation the
6
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
+ * sell copies of the Software, and to permit persons to whom the Software is
8
+ * furnished to do so, subject to the following conditions:
9
+ *
10
+ * The above copyright notice and this permission notice shall be included in
11
+ * all copies or substantial portions of the Software.
12
+ *
13
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19
+ * IN THE SOFTWARE.
20
+ */
21
+
22
+ #include <assert.h>
23
+ #include <malloc.h>
24
+ #include <errno.h>
25
+ #include <string.h>
26
+ #include "uv.h"
27
+ #include "internal.h"
28
+
29
+
30
+ const unsigned int uv_directory_watcher_buffer_size = 4096;
31
+
32
+
33
+ static void uv_fs_event_init_handle(uv_loop_t* loop, uv_fs_event_t* handle,
34
+ const char* filename, uv_fs_event_cb cb) {
35
+ handle->type = UV_FS_EVENT;
36
+ handle->loop = loop;
37
+ handle->flags = 0;
38
+ handle->cb = cb;
39
+ handle->is_path_dir = 0;
40
+ handle->dir_handle = INVALID_HANDLE_VALUE;
41
+ handle->buffer = NULL;
42
+ handle->req_pending = 0;
43
+ handle->filew = NULL;
44
+
45
+ uv_req_init(loop, (uv_req_t*)&handle->req);
46
+ handle->req.type = UV_FS_EVENT_REQ;
47
+ handle->req.data = (void*)handle;
48
+
49
+ handle->filename = strdup(filename);
50
+ if (!handle->filename) {
51
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
52
+ }
53
+
54
+ loop->counters.handle_init++;
55
+ loop->counters.fs_event_init++;
56
+
57
+ uv_ref(loop);
58
+ }
59
+
60
+
61
+ static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop,
62
+ uv_fs_event_t* handle) {
63
+ assert(handle->dir_handle != INVALID_HANDLE_VALUE);
64
+ assert(!handle->req_pending);
65
+
66
+ memset(&(handle->req.overlapped), 0, sizeof(handle->req.overlapped));
67
+ if (!ReadDirectoryChangesW(handle->dir_handle,
68
+ handle->buffer,
69
+ uv_directory_watcher_buffer_size,
70
+ FALSE,
71
+ FILE_NOTIFY_CHANGE_FILE_NAME |
72
+ FILE_NOTIFY_CHANGE_DIR_NAME |
73
+ FILE_NOTIFY_CHANGE_ATTRIBUTES |
74
+ FILE_NOTIFY_CHANGE_SIZE |
75
+ FILE_NOTIFY_CHANGE_LAST_WRITE |
76
+ FILE_NOTIFY_CHANGE_LAST_ACCESS |
77
+ FILE_NOTIFY_CHANGE_CREATION |
78
+ FILE_NOTIFY_CHANGE_SECURITY,
79
+ NULL,
80
+ &handle->req.overlapped,
81
+ NULL)) {
82
+ /* Make this req pending reporting an error. */
83
+ SET_REQ_ERROR(&handle->req, GetLastError());
84
+ uv_insert_pending_req(loop, (uv_req_t*)&handle->req);
85
+ }
86
+
87
+ handle->req_pending = 1;
88
+ }
89
+
90
+
91
+ static int uv_split_path(const wchar_t* filename, wchar_t** dir,
92
+ wchar_t** file) {
93
+ int len = wcslen(filename);
94
+ int i = len;
95
+ while (i > 0 && filename[--i] != '\\' && filename[i] != '/');
96
+
97
+ if (i == 0) {
98
+ *dir = (wchar_t*)malloc((MAX_PATH + 1) * sizeof(wchar_t));
99
+ if (!*dir) {
100
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
101
+ }
102
+
103
+ if (!GetCurrentDirectoryW(MAX_PATH, *dir)) {
104
+ free(*dir);
105
+ *dir = NULL;
106
+ return -1;
107
+ }
108
+
109
+ *file = wcsdup(filename);
110
+ } else {
111
+ *dir = (wchar_t*)malloc((i + 1) * sizeof(wchar_t));
112
+ if (!*dir) {
113
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
114
+ }
115
+ wcsncpy(*dir, filename, i);
116
+ (*dir)[i] = L'\0';
117
+
118
+ *file = (wchar_t*)malloc((len - i) * sizeof(wchar_t));
119
+ if (!*file) {
120
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
121
+ }
122
+ wcsncpy(*file, filename + i + 1, len - i - 1);
123
+ (*file)[len - i - 1] = L'\0';
124
+ }
125
+
126
+ return 0;
127
+ }
128
+
129
+
130
+ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle,
131
+ const char* filename, uv_fs_event_cb cb) {
132
+ int name_size;
133
+ DWORD attr, last_error;
134
+ wchar_t* dir = NULL, *dir_to_watch, *filenamew;
135
+
136
+ uv_fs_event_init_handle(loop, handle, filename, cb);
137
+
138
+ /* Convert name to UTF16. */
139
+ name_size = uv_utf8_to_utf16(filename, NULL, 0) * sizeof(wchar_t);
140
+ filenamew = (wchar_t*)malloc(name_size);
141
+ if (!filenamew) {
142
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
143
+ }
144
+
145
+ if (!uv_utf8_to_utf16(filename, filenamew,
146
+ name_size / sizeof(wchar_t))) {
147
+ uv_set_sys_error(loop, GetLastError());
148
+ return -1;
149
+ }
150
+
151
+ /* Determine whether filename is a file or a directory. */
152
+ attr = GetFileAttributesW(filenamew);
153
+ if (attr == INVALID_FILE_ATTRIBUTES) {
154
+ last_error = GetLastError();
155
+ goto error;
156
+ }
157
+
158
+ handle->is_path_dir = (attr & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0;
159
+
160
+ if (handle->is_path_dir) {
161
+ /* filename is a directory, so that's the directory that we will watch. */
162
+ dir_to_watch = filenamew;
163
+ } else {
164
+ /*
165
+ * filename is a file. So we split filename into dir & file parts, and
166
+ * watch the dir directory.
167
+ */
168
+ if (uv_split_path(filenamew, &dir, &handle->filew) != 0) {
169
+ last_error = GetLastError();
170
+ goto error;
171
+ }
172
+
173
+ dir_to_watch = dir;
174
+ }
175
+
176
+ handle->dir_handle = CreateFileW(dir_to_watch,
177
+ FILE_LIST_DIRECTORY,
178
+ FILE_SHARE_READ | FILE_SHARE_DELETE |
179
+ FILE_SHARE_WRITE,
180
+ NULL,
181
+ OPEN_EXISTING,
182
+ FILE_FLAG_BACKUP_SEMANTICS |
183
+ FILE_FLAG_OVERLAPPED,
184
+ NULL);
185
+
186
+ if (dir) {
187
+ free(dir);
188
+ dir = NULL;
189
+ }
190
+
191
+ if (handle->dir_handle == INVALID_HANDLE_VALUE) {
192
+ last_error = GetLastError();
193
+ goto error;
194
+ }
195
+
196
+ if (CreateIoCompletionPort(handle->dir_handle,
197
+ loop->iocp,
198
+ (ULONG_PTR)handle,
199
+ 0) == NULL) {
200
+ last_error = GetLastError();
201
+ goto error;
202
+ }
203
+
204
+ handle->buffer = (char*)_aligned_malloc(uv_directory_watcher_buffer_size,
205
+ sizeof(DWORD));
206
+ if (!handle->buffer) {
207
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
208
+ }
209
+
210
+ memset(&(handle->req.overlapped), 0, sizeof(handle->req.overlapped));
211
+
212
+ if (!ReadDirectoryChangesW(handle->dir_handle,
213
+ handle->buffer,
214
+ uv_directory_watcher_buffer_size,
215
+ FALSE,
216
+ FILE_NOTIFY_CHANGE_FILE_NAME |
217
+ FILE_NOTIFY_CHANGE_DIR_NAME |
218
+ FILE_NOTIFY_CHANGE_ATTRIBUTES |
219
+ FILE_NOTIFY_CHANGE_SIZE |
220
+ FILE_NOTIFY_CHANGE_LAST_WRITE |
221
+ FILE_NOTIFY_CHANGE_LAST_ACCESS |
222
+ FILE_NOTIFY_CHANGE_CREATION |
223
+ FILE_NOTIFY_CHANGE_SECURITY,
224
+ NULL,
225
+ &handle->req.overlapped,
226
+ NULL)) {
227
+ last_error = GetLastError();
228
+ goto error;
229
+ }
230
+
231
+ handle->req_pending = 1;
232
+ return 0;
233
+
234
+ error:
235
+ if (handle->filename) {
236
+ free(handle->filename);
237
+ handle->filename = NULL;
238
+ }
239
+
240
+ if (handle->filew) {
241
+ free(handle->filew);
242
+ handle->filew = NULL;
243
+ }
244
+
245
+ if (handle->dir_handle != INVALID_HANDLE_VALUE) {
246
+ CloseHandle(handle->dir_handle);
247
+ handle->dir_handle = INVALID_HANDLE_VALUE;
248
+ }
249
+
250
+ if (handle->buffer) {
251
+ _aligned_free(handle->buffer);
252
+ handle->buffer = NULL;
253
+ }
254
+
255
+ uv_set_sys_error(loop, last_error);
256
+ return -1;
257
+ }
258
+
259
+
260
+ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
261
+ uv_fs_event_t* handle) {
262
+ FILE_NOTIFY_INFORMATION* file_info;
263
+ char* filename = NULL;
264
+ int utf8size;
265
+ DWORD offset = 0;
266
+
267
+ assert(req->type == UV_FS_EVENT_REQ);
268
+ assert(handle->req_pending);
269
+ handle->req_pending = 0;
270
+
271
+ file_info = (FILE_NOTIFY_INFORMATION*)(handle->buffer + offset);
272
+
273
+ if (REQ_SUCCESS(req)) {
274
+ if (req->overlapped.InternalHigh > 0) {
275
+ do {
276
+ file_info = (FILE_NOTIFY_INFORMATION*)((char*)file_info + offset);
277
+
278
+ /*
279
+ * Fire the event only if we were asked to watch a directory,
280
+ * or if the filename filter matches.
281
+ */
282
+ if (handle->is_path_dir || _wcsnicmp(handle->filew, file_info->FileName,
283
+ file_info->FileNameLength / sizeof(wchar_t)) == 0) {
284
+
285
+ /* Convert the filename to utf8. */
286
+ utf8size = uv_utf16_to_utf8(file_info->FileName,
287
+ file_info->FileNameLength /
288
+ sizeof(wchar_t),
289
+ NULL,
290
+ 0);
291
+ if (utf8size) {
292
+ filename = (char*)malloc(utf8size + 1);
293
+ if (!filename) {
294
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
295
+ }
296
+
297
+ utf8size = uv_utf16_to_utf8(file_info->FileName,
298
+ file_info->FileNameLength /
299
+ sizeof(wchar_t),
300
+ filename,
301
+ utf8size);
302
+ if (utf8size) {
303
+ filename[utf8size] = L'\0';
304
+ } else {
305
+ free(filename);
306
+ filename = NULL;
307
+ }
308
+ }
309
+
310
+ switch (file_info->Action) {
311
+ case FILE_ACTION_ADDED:
312
+ case FILE_ACTION_REMOVED:
313
+ case FILE_ACTION_RENAMED_OLD_NAME:
314
+ case FILE_ACTION_RENAMED_NEW_NAME:
315
+ handle->cb(handle, filename, UV_RENAME, 0);
316
+ break;
317
+
318
+ case FILE_ACTION_MODIFIED:
319
+ handle->cb(handle, filename, UV_CHANGE, 0);
320
+ break;
321
+ }
322
+
323
+ free(filename);
324
+ filename = NULL;
325
+ }
326
+
327
+ offset = file_info->NextEntryOffset;
328
+ } while(offset);
329
+ } else {
330
+ handle->cb(handle, NULL, UV_CHANGE, 0);
331
+ }
332
+ } else {
333
+ loop->last_error = GET_REQ_UV_ERROR(req);
334
+ handle->cb(handle, NULL, 0, -1);
335
+ }
336
+
337
+ if (!(handle->flags & UV_HANDLE_CLOSING)) {
338
+ uv_fs_event_queue_readdirchanges(loop, handle);
339
+ } else {
340
+ uv_want_endgame(loop, (uv_handle_t*)handle);
341
+ }
342
+ }
343
+
344
+
345
+ void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) {
346
+ if (handle->dir_handle != INVALID_HANDLE_VALUE) {
347
+ CloseHandle(handle->dir_handle);
348
+ handle->dir_handle = INVALID_HANDLE_VALUE;
349
+ }
350
+
351
+ if (!handle->req_pending) {
352
+ uv_want_endgame(loop, (uv_handle_t*)handle);
353
+ }
354
+ }
355
+
356
+
357
+ void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) {
358
+ if (handle->flags & UV_HANDLE_CLOSING &&
359
+ !handle->req_pending) {
360
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
361
+ handle->flags |= UV_HANDLE_CLOSED;
362
+
363
+ if (handle->buffer) {
364
+ _aligned_free(handle->buffer);
365
+ handle->buffer = NULL;
366
+ }
367
+
368
+ if (handle->filew) {
369
+ free(handle->filew);
370
+ handle->filew = NULL;
371
+ }
372
+
373
+ if (handle->filename) {
374
+ free(handle->filename);
375
+ handle->filename = NULL;
376
+ }
377
+
378
+ if (handle->close_cb) {
379
+ handle->close_cb((uv_handle_t*)handle);
380
+ }
381
+
382
+ uv_unref(loop);
383
+ }
384
+ }
@@ -216,12 +216,17 @@ complete:
216
216
  /* finally do callback with converted result */
217
217
  handle->getaddrinfo_cb(handle, uv_ret, (struct addrinfo*)alloc_ptr);
218
218
 
219
+ uv_unref(loop);
220
+ }
221
+
222
+
223
+ void uv_freeaddrinfo(struct addrinfo* ai) {
224
+ char* alloc_ptr = (char*)ai;
225
+
219
226
  /* release copied result memory */
220
227
  if (alloc_ptr != NULL) {
221
228
  free(alloc_ptr);
222
229
  }
223
-
224
- uv_unref(loop);
225
230
  }
226
231
 
227
232
 
@@ -20,11 +20,36 @@
20
20
  */
21
21
 
22
22
  #include <assert.h>
23
+ #include <io.h>
23
24
 
24
25
  #include "uv.h"
25
26
  #include "internal.h"
26
27
 
27
28
 
29
+ uv_handle_type uv_guess_handle(uv_file file) {
30
+ HANDLE handle = (HANDLE) _get_osfhandle(file);
31
+ DWORD mode;
32
+
33
+ switch (GetFileType(handle)) {
34
+ case FILE_TYPE_CHAR:
35
+ if (GetConsoleMode(handle, &mode)) {
36
+ return UV_TTY;
37
+ } else {
38
+ return UV_UNKNOWN_HANDLE;
39
+ }
40
+
41
+ case FILE_TYPE_PIPE:
42
+ return UV_NAMED_PIPE;
43
+
44
+ case FILE_TYPE_DISK:
45
+ return UV_FILE;
46
+
47
+ default:
48
+ return UV_UNKNOWN_HANDLE;
49
+ }
50
+ }
51
+
52
+
28
53
  int uv_is_active(uv_handle_t* handle) {
29
54
  switch (handle->type) {
30
55
  case UV_TIMER:
@@ -80,6 +105,10 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) {
80
105
  }
81
106
  return;
82
107
 
108
+ case UV_TTY:
109
+ uv_tty_close((uv_tty_t*) handle);
110
+ return;
111
+
83
112
  case UV_UDP:
84
113
  udp = (uv_udp_t*) handle;
85
114
  uv_udp_recv_stop(udp);
@@ -120,6 +149,10 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) {
120
149
  uv_process_close(loop, process);
121
150
  return;
122
151
 
152
+ case UV_FS_EVENT:
153
+ uv_fs_event_close(loop, (uv_fs_event_t*)handle);
154
+ return;
155
+
123
156
  default:
124
157
  /* Not supported */
125
158
  abort();
@@ -155,6 +188,10 @@ void uv_process_endgames(uv_loop_t* loop) {
155
188
  uv_pipe_endgame(loop, (uv_pipe_t*) handle);
156
189
  break;
157
190
 
191
+ case UV_TTY:
192
+ uv_tty_endgame(loop, (uv_tty_t*) handle);
193
+ break;
194
+
158
195
  case UV_UDP:
159
196
  uv_udp_endgame(loop, (uv_udp_t*) handle);
160
197
  break;
@@ -177,6 +214,10 @@ void uv_process_endgames(uv_loop_t* loop) {
177
214
  uv_process_endgame(loop, (uv_process_t*) handle);
178
215
  break;
179
216
 
217
+ case UV_FS_EVENT:
218
+ uv_fs_event_endgame(loop, (uv_fs_event_t*) handle);
219
+ break;
220
+
180
221
  default:
181
222
  assert(0);
182
223
  break;
@@ -64,6 +64,7 @@ void uv_process_timers(uv_loop_t* loop);
64
64
  #define UV_HANDLE_UV_ALLOCED 0x20000
65
65
  #define UV_HANDLE_SYNC_BYPASS_IOCP 0x40000
66
66
  #define UV_HANDLE_ZERO_READ 0x80000
67
+ #define UV_HANDLE_TTY_RAW 0x100000
67
68
 
68
69
  void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle);
69
70
  void uv_process_endgames(uv_loop_t* loop);
@@ -173,6 +174,33 @@ void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
173
174
  void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
174
175
  uv_shutdown_t* req);
175
176
 
177
+
178
+ /*
179
+ * TTY
180
+ */
181
+ void uv_console_init();
182
+
183
+ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
184
+ uv_read_cb read_cb);
185
+ int uv_tty_read_stop(uv_tty_t* handle);
186
+ int uv_tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle,
187
+ uv_buf_t bufs[], int bufcnt, uv_write_cb cb);
188
+ void uv_tty_close(uv_tty_t* handle);
189
+
190
+ void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
191
+ uv_req_t* req);
192
+ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
193
+ uv_write_t* req);
194
+ /* TODO: remove me */
195
+ void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
196
+ uv_req_t* raw_req);
197
+ /* TODO: remove me */
198
+ void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle,
199
+ uv_connect_t* req);
200
+
201
+ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle);
202
+
203
+
176
204
  /*
177
205
  * Loop watchers
178
206
  */
@@ -231,6 +259,14 @@ void uv_process_fs_req(uv_loop_t* loop, uv_fs_t* req);
231
259
  void uv_process_work_req(uv_loop_t* loop, uv_work_t* req);
232
260
 
233
261
 
262
+ /*
263
+ * FS Event
264
+ */
265
+ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, uv_fs_event_t* handle);
266
+ void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle);
267
+ void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle);
268
+
269
+
234
270
  /*
235
271
  * Error handling
236
272
  */
@@ -231,6 +231,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
231
231
  if (result) {
232
232
  /* Mark the handle as shut now to avoid going through this again. */
233
233
  handle->flags |= UV_HANDLE_SHUT;
234
+ return;
234
235
 
235
236
  } else {
236
237
  /* Failure. */
@@ -678,6 +679,8 @@ static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
678
679
  /* Make this req pending reporting an error. */
679
680
  SET_REQ_ERROR(req, WSAGetLastError());
680
681
  uv_insert_pending_req(loop, req);
682
+
683
+ handle->flags |= UV_HANDLE_READ_PENDING;
681
684
  handle->reqs_pending++;
682
685
  return;
683
686
  }
@@ -845,14 +845,19 @@ static int duplicate_std_handle(uv_loop_t* loop, DWORD id, HANDLE* dup) {
845
845
  int uv_spawn(uv_loop_t* loop, uv_process_t* process,
846
846
  uv_process_options_t options) {
847
847
  int err = 0, keep_child_stdio_open = 0;
848
- wchar_t* path;
848
+ wchar_t* path = NULL;
849
849
  int size;
850
850
  BOOL result;
851
- wchar_t* application_path, *application, *arguments, *env, *cwd;
851
+ wchar_t* application_path = NULL, *application = NULL, *arguments = NULL, *env = NULL, *cwd = NULL;
852
852
  HANDLE* child_stdio = process->child_stdio;
853
853
  STARTUPINFOW startup;
854
854
  PROCESS_INFORMATION info;
855
855
 
856
+ if (!options.file) {
857
+ uv_set_error(loop, UV_EINVAL, 0);
858
+ return -1;
859
+ }
860
+
856
861
  uv_process_init(loop, process);
857
862
 
858
863
  process->exit_cb = options.exit_cb;
@@ -87,6 +87,12 @@ static uv_req_t* uv_remove_pending_req(uv_loop_t* loop) {
87
87
  req); \
88
88
  break; \
89
89
  \
90
+ case UV_TTY: \
91
+ uv_process_tty_##method##_req(loop, \
92
+ (uv_tty_t*) ((req)->handle_at), \
93
+ req); \
94
+ break; \
95
+ \
90
96
  default: \
91
97
  assert(0); \
92
98
  } \
@@ -165,6 +171,10 @@ void uv_process_reqs(uv_loop_t* loop) {
165
171
  uv_process_work_req(loop, (uv_work_t*) req);
166
172
  break;
167
173
 
174
+ case UV_FS_EVENT_REQ:
175
+ uv_process_fs_event_req(loop, req, (uv_fs_event_t*) req->data);
176
+ break;
177
+
168
178
  default:
169
179
  assert(0);
170
180
  }
@@ -83,6 +83,8 @@ int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb,
83
83
  return uv_tcp_read_start((uv_tcp_t*)handle, alloc_cb, read_cb);
84
84
  case UV_NAMED_PIPE:
85
85
  return uv_pipe_read_start((uv_pipe_t*)handle, alloc_cb, read_cb);
86
+ case UV_TTY:
87
+ return uv_tty_read_start((uv_tty_t*) handle, alloc_cb, read_cb);
86
88
  default:
87
89
  assert(0);
88
90
  return -1;
@@ -91,9 +93,12 @@ int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb,
91
93
 
92
94
 
93
95
  int uv_read_stop(uv_stream_t* handle) {
94
- handle->flags &= ~UV_HANDLE_READING;
95
-
96
- return 0;
96
+ if (handle->type = UV_TTY) {
97
+ return uv_tty_read_stop((uv_tty_t*) handle);
98
+ } else {
99
+ handle->flags &= ~UV_HANDLE_READING;
100
+ return 0;
101
+ }
97
102
  }
98
103
 
99
104
 
@@ -106,6 +111,8 @@ int uv_write(uv_write_t* req, uv_stream_t* handle, uv_buf_t bufs[], int bufcnt,
106
111
  return uv_tcp_write(loop, req, (uv_tcp_t*) handle, bufs, bufcnt, cb);
107
112
  case UV_NAMED_PIPE:
108
113
  return uv_pipe_write(loop, req, (uv_pipe_t*) handle, bufs, bufcnt, cb);
114
+ case UV_TTY:
115
+ return uv_tty_write(loop, req, (uv_tty_t*) handle, bufs, bufcnt, cb);
109
116
  default:
110
117
  assert(0);
111
118
  uv_set_sys_error(loop, WSAEINVAL);
@@ -128,7 +128,9 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
128
128
  }
129
129
  handle->shutdown_req->cb(handle->shutdown_req, status);
130
130
  }
131
- handle->reqs_pending--;
131
+
132
+ DECREASE_PENDING_REQ_COUNT(handle);
133
+ return;
132
134
  }
133
135
 
134
136
  if (handle->flags & UV_HANDLE_CLOSING &&