noderb 0.0.8 → 0.0.9

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 (84) hide show
  1. data/ext/noderb_extension/extconf.rb +4 -2
  2. data/ext/noderb_extension/libuv/AUTHORS +2 -0
  3. data/ext/noderb_extension/libuv/Makefile +1 -1
  4. data/ext/noderb_extension/libuv/common.gypi +51 -51
  5. data/ext/noderb_extension/libuv/config-mingw.mk +3 -9
  6. data/ext/noderb_extension/libuv/config-unix.mk +10 -1
  7. data/ext/noderb_extension/libuv/include/uv-private/uv-unix.h +3 -2
  8. data/ext/noderb_extension/libuv/include/uv-private/uv-win.h +7 -6
  9. data/ext/noderb_extension/libuv/include/uv.h +47 -13
  10. data/ext/noderb_extension/libuv/src/ares/config_netbsd/ares_config.h +510 -0
  11. data/ext/noderb_extension/libuv/src/unix/core.c +20 -65
  12. data/ext/noderb_extension/libuv/src/unix/darwin.c +1 -0
  13. data/ext/noderb_extension/libuv/src/unix/eio/config_netbsd.h +81 -0
  14. data/ext/noderb_extension/libuv/src/unix/error.c +9 -1
  15. data/ext/noderb_extension/libuv/src/unix/ev/config_netbsd.h +120 -0
  16. data/ext/noderb_extension/libuv/src/unix/fs.c +151 -21
  17. data/ext/noderb_extension/libuv/src/unix/internal.h +30 -0
  18. data/ext/noderb_extension/libuv/src/unix/netbsd.c +68 -0
  19. data/ext/noderb_extension/libuv/src/unix/pipe.c +20 -30
  20. data/ext/noderb_extension/libuv/src/unix/process.c +13 -0
  21. data/ext/noderb_extension/libuv/src/unix/stream.c +105 -63
  22. data/ext/noderb_extension/libuv/src/unix/tcp.c +75 -21
  23. data/ext/noderb_extension/libuv/src/unix/tty.c +69 -0
  24. data/ext/noderb_extension/libuv/src/unix/udp.c +31 -0
  25. data/ext/noderb_extension/libuv/src/uv-common.c +2 -0
  26. data/ext/noderb_extension/libuv/src/uv-common.h +0 -6
  27. data/ext/noderb_extension/libuv/src/win/cares.c +7 -7
  28. data/ext/noderb_extension/libuv/src/win/core.c +25 -17
  29. data/ext/noderb_extension/libuv/src/win/error.c +7 -0
  30. data/ext/noderb_extension/libuv/src/win/fs.c +587 -92
  31. data/ext/noderb_extension/libuv/src/win/getaddrinfo.c +3 -1
  32. data/ext/noderb_extension/libuv/src/win/handle.c +0 -17
  33. data/ext/noderb_extension/libuv/src/win/internal.h +15 -5
  34. data/ext/noderb_extension/libuv/src/win/loop-watcher.c +1 -1
  35. data/ext/noderb_extension/libuv/src/win/pipe.c +6 -0
  36. data/ext/noderb_extension/libuv/src/win/process.c +90 -43
  37. data/ext/noderb_extension/libuv/src/win/tcp.c +37 -4
  38. data/ext/noderb_extension/libuv/src/win/threads.c +81 -0
  39. data/ext/noderb_extension/libuv/src/win/timer.c +15 -15
  40. data/ext/noderb_extension/libuv/src/win/tty.c +37 -0
  41. data/ext/noderb_extension/libuv/src/win/udp.c +8 -2
  42. data/ext/noderb_extension/libuv/src/win/winapi.c +12 -0
  43. data/ext/noderb_extension/libuv/src/win/winapi.h +1146 -1015
  44. data/ext/noderb_extension/libuv/test/benchmark-ares.c +0 -1
  45. data/ext/noderb_extension/libuv/test/benchmark-getaddrinfo.c +0 -1
  46. data/ext/noderb_extension/libuv/test/benchmark-ping-pongs.c +0 -1
  47. data/ext/noderb_extension/libuv/test/benchmark-pound.c +0 -1
  48. data/ext/noderb_extension/libuv/test/benchmark-pump.c +4 -6
  49. data/ext/noderb_extension/libuv/test/benchmark-spawn.c +0 -1
  50. data/ext/noderb_extension/libuv/test/benchmark-udp-packet-storm.c +0 -1
  51. data/ext/noderb_extension/libuv/test/dns-server.c +2 -2
  52. data/ext/noderb_extension/libuv/test/echo-server.c +4 -5
  53. data/ext/noderb_extension/libuv/test/run-tests.c +0 -2
  54. data/ext/noderb_extension/libuv/test/test-async.c +0 -2
  55. data/ext/noderb_extension/libuv/test/test-callback-stack.c +0 -2
  56. data/ext/noderb_extension/libuv/test/test-connection-fail.c +3 -5
  57. data/ext/noderb_extension/libuv/test/test-delayed-accept.c +2 -3
  58. data/ext/noderb_extension/libuv/test/test-fs.c +578 -42
  59. data/ext/noderb_extension/libuv/test/test-get-currentexe.c +12 -2
  60. data/ext/noderb_extension/libuv/test/test-getaddrinfo.c +10 -5
  61. data/ext/noderb_extension/libuv/test/test-gethostbyname.c +0 -2
  62. data/ext/noderb_extension/libuv/test/test-getsockname.c +92 -72
  63. data/ext/noderb_extension/libuv/test/test-idle.c +0 -3
  64. data/ext/noderb_extension/libuv/test/test-list.h +13 -0
  65. data/ext/noderb_extension/libuv/test/test-loop-handles.c +0 -3
  66. data/ext/noderb_extension/libuv/test/test-ping-pong.c +13 -19
  67. data/ext/noderb_extension/libuv/test/test-pipe-bind-error.c +0 -12
  68. data/ext/noderb_extension/libuv/test/test-ref.c +0 -7
  69. data/ext/noderb_extension/libuv/test/test-shutdown-eof.c +3 -3
  70. data/ext/noderb_extension/libuv/test/test-spawn.c +2 -11
  71. data/ext/noderb_extension/libuv/test/test-tcp-bind-error.c +0 -19
  72. data/ext/noderb_extension/libuv/test/test-tcp-bind6-error.c +0 -15
  73. data/ext/noderb_extension/libuv/test/test-tcp-close.c +129 -0
  74. data/ext/noderb_extension/libuv/test/test-tcp-writealot.c +0 -3
  75. data/ext/noderb_extension/libuv/test/test-threadpool.c +0 -2
  76. data/ext/noderb_extension/libuv/test/test-timer-again.c +0 -3
  77. data/ext/noderb_extension/libuv/test/test-timer.c +0 -2
  78. data/ext/noderb_extension/libuv/test/test-udp-dgram-too-big.c +0 -2
  79. data/ext/noderb_extension/libuv/test/test-udp-ipv6.c +0 -2
  80. data/ext/noderb_extension/libuv/test/test-udp-send-and-recv.c +0 -2
  81. data/ext/noderb_extension/libuv/uv.gyp +18 -2
  82. data/ext/noderb_extension/noderb_fs.c +1 -2
  83. data/lib/noderb/version.rb +1 -1
  84. metadata +10 -2
@@ -27,28 +27,8 @@
27
27
 
28
28
 
29
29
  int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) {
30
- uv__handle_init(loop, (uv_handle_t*)tcp, UV_TCP);
30
+ uv__stream_init(loop, (uv_stream_t*)tcp, UV_TCP);
31
31
  loop->counters.tcp_init++;
32
-
33
- tcp->alloc_cb = NULL;
34
- tcp->connect_req = NULL;
35
- tcp->accepted_fd = -1;
36
- tcp->fd = -1;
37
- tcp->delayed_error = 0;
38
- ngx_queue_init(&tcp->write_queue);
39
- ngx_queue_init(&tcp->write_completed_queue);
40
- tcp->write_queue_size = 0;
41
-
42
- ev_init(&tcp->read_watcher, uv__stream_io);
43
- tcp->read_watcher.data = tcp;
44
-
45
- ev_init(&tcp->write_watcher, uv__stream_io);
46
- tcp->write_watcher.data = tcp;
47
-
48
- assert(ngx_queue_empty(&tcp->write_queue));
49
- assert(ngx_queue_empty(&tcp->write_completed_queue));
50
- assert(tcp->write_queue_size == 0);
51
-
52
32
  return 0;
53
33
  }
54
34
 
@@ -122,6 +102,80 @@ int uv_tcp_bind6(uv_tcp_t* tcp, struct sockaddr_in6 addr) {
122
102
  }
123
103
 
124
104
 
105
+ int uv_tcp_getsockname(uv_tcp_t* handle, struct sockaddr* name,
106
+ int* namelen) {
107
+ socklen_t socklen;
108
+ int saved_errno;
109
+ int rv = 0;
110
+
111
+ /* Don't clobber errno. */
112
+ saved_errno = errno;
113
+
114
+ if (handle->delayed_error) {
115
+ uv_err_new(handle->loop, handle->delayed_error);
116
+ rv = -1;
117
+ goto out;
118
+ }
119
+
120
+ if (handle->fd < 0) {
121
+ uv_err_new(handle->loop, EINVAL);
122
+ rv = -1;
123
+ goto out;
124
+ }
125
+
126
+ /* sizeof(socklen_t) != sizeof(int) on some systems. */
127
+ socklen = (socklen_t)*namelen;
128
+
129
+ if (getsockname(handle->fd, name, &socklen) == -1) {
130
+ uv_err_new(handle->loop, errno);
131
+ rv = -1;
132
+ } else {
133
+ *namelen = (int)socklen;
134
+ }
135
+
136
+ out:
137
+ errno = saved_errno;
138
+ return rv;
139
+ }
140
+
141
+
142
+ int uv_tcp_getpeername(uv_tcp_t* handle, struct sockaddr* name,
143
+ int* namelen) {
144
+ socklen_t socklen;
145
+ int saved_errno;
146
+ int rv = 0;
147
+
148
+ /* Don't clobber errno. */
149
+ saved_errno = errno;
150
+
151
+ if (handle->delayed_error) {
152
+ uv_err_new(handle->loop, handle->delayed_error);
153
+ rv = -1;
154
+ goto out;
155
+ }
156
+
157
+ if (handle->fd < 0) {
158
+ uv_err_new(handle->loop, EINVAL);
159
+ rv = -1;
160
+ goto out;
161
+ }
162
+
163
+ /* sizeof(socklen_t) != sizeof(int) on some systems. */
164
+ socklen = (socklen_t)*namelen;
165
+
166
+ if (getpeername(handle->fd, name, &socklen) == -1) {
167
+ uv_err_new(handle->loop, errno);
168
+ rv = -1;
169
+ } else {
170
+ *namelen = (int)socklen;
171
+ }
172
+
173
+ out:
174
+ errno = saved_errno;
175
+ return rv;
176
+ }
177
+
178
+
125
179
  int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
126
180
  int r;
127
181
 
@@ -0,0 +1,69 @@
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 "uv.h"
23
+ #include "internal.h"
24
+
25
+ #include <assert.h>
26
+ #include <termios.h>
27
+ #include <errno.h>
28
+
29
+
30
+ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd) {
31
+ uv__nonblock(fd, 1);
32
+ uv__stream_init(loop, (uv_stream_t*)tty, UV_TTY);
33
+ uv__stream_open((uv_stream_t*)tty, fd, UV_READABLE | UV_WRITABLE);
34
+ loop->counters.tty_init++;
35
+ return 0;
36
+ }
37
+
38
+
39
+ int uv_tty_set_mode(uv_tty_t* tty, int mode) {
40
+ int fd = tty->fd;
41
+ struct termios orig_termios; /* in order to restore at exit */
42
+ struct termios raw;
43
+
44
+ if (tcgetattr(fd, &orig_termios) == -1) goto fatal;
45
+
46
+ raw = orig_termios; /* modify the original mode */
47
+ /* input modes: no break, no CR to NL, no parity check, no strip char,
48
+ * no start/stop output control. */
49
+ raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
50
+ /* output modes */
51
+ raw.c_oflag |= (ONLCR);
52
+ /* control modes - set 8 bit chars */
53
+ raw.c_cflag |= (CS8);
54
+ /* local modes - echoing off, canonical off, no extended functions,
55
+ * no signal chars (^Z,^C) */
56
+ raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
57
+ /* control chars - set return condition: min number of bytes and timer.
58
+ * We want read to return every single byte, without timeout. */
59
+ raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
60
+
61
+ /* put terminal in raw mode after flushing */
62
+ if (tcsetattr(fd, TCSAFLUSH, &raw) < 0) goto fatal;
63
+ return 0;
64
+
65
+ fatal:
66
+ uv_err_new(tty->loop, ENOTTY);
67
+ return -1;
68
+ }
69
+
@@ -460,6 +460,37 @@ int uv_udp_bind6(uv_udp_t* handle, struct sockaddr_in6 addr, unsigned flags) {
460
460
  }
461
461
 
462
462
 
463
+ int uv_udp_getsockname(uv_udp_t* handle, struct sockaddr* name,
464
+ int* namelen) {
465
+ socklen_t socklen;
466
+ int saved_errno;
467
+ int rv = 0;
468
+
469
+ /* Don't clobber errno. */
470
+ saved_errno = errno;
471
+
472
+ if (handle->fd < 0) {
473
+ uv_err_new(handle->loop, EINVAL);
474
+ rv = -1;
475
+ goto out;
476
+ }
477
+
478
+ /* sizeof(socklen_t) != sizeof(int) on some systems. */
479
+ socklen = (socklen_t)*namelen;
480
+
481
+ if (getsockname(handle->fd, name, &socklen) == -1) {
482
+ uv_err_new(handle->loop, errno);
483
+ rv = -1;
484
+ } else {
485
+ *namelen = (int)socklen;
486
+ }
487
+
488
+ out:
489
+ errno = saved_errno;
490
+ return rv;
491
+ }
492
+
493
+
463
494
  int uv_udp_send(uv_udp_send_t* req,
464
495
  uv_udp_t* handle,
465
496
  uv_buf_t bufs[],
@@ -81,11 +81,13 @@ const char* uv_err_name(uv_err_t err) {
81
81
  case UV_ENOTCONN: return "ENOTCONN";
82
82
  case UV_ENOTSOCK: return "ENOTSOCK";
83
83
  case UV_ENOTSUP: return "ENOTSUP";
84
+ case UV_ENOENT: return "ENOENT";
84
85
  case UV_EPIPE: return "EPIPE";
85
86
  case UV_EPROTO: return "EPROTO";
86
87
  case UV_EPROTONOSUPPORT: return "EPROTONOSUPPORT";
87
88
  case UV_EPROTOTYPE: return "EPROTOTYPE";
88
89
  case UV_ETIMEDOUT: return "ETIMEDOUT";
90
+ case UV_EEXIST: return "EEXIST";
89
91
  default:
90
92
  assert(0);
91
93
  return NULL;
@@ -31,12 +31,6 @@
31
31
 
32
32
  #define COUNTOF(a) (sizeof(a) / sizeof(a[0]))
33
33
 
34
- /* Used for the uv_fs_ functions */
35
- #define SET_REQ_RESULT(req, result) \
36
- req->result = result; \
37
- if (result == -1) { \
38
- req->errorno = errno; \
39
- }
40
34
 
41
35
  struct uv_ares_task_s {
42
36
  UV_HANDLE_FIELDS
@@ -95,8 +95,8 @@ static void CALLBACK uv_ares_socksignal_tp(void* parameter,
95
95
  /* periodically call ares to check for timeouts */
96
96
  static void uv_ares_poll(uv_timer_t* handle, int status) {
97
97
  uv_loop_t* loop = handle->loop;
98
- if (loop->ares_channel != NULL && loop->ares_active_sockets > 0) {
99
- ares_process_fd(loop->ares_channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
98
+ if (loop->ares_chan != NULL && loop->ares_active_sockets > 0) {
99
+ ares_process_fd(loop->ares_chan, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
100
100
  }
101
101
  }
102
102
 
@@ -214,7 +214,7 @@ static void uv_ares_sockstate_cb(void *data, ares_socket_t sock, int read,
214
214
  /* called via uv_poll when ares completion port signaled */
215
215
  void uv_process_ares_event_req(uv_loop_t* loop, uv_ares_action_t* handle,
216
216
  uv_req_t* req) {
217
- ares_process_fd(loop->ares_channel,
217
+ ares_process_fd(loop->ares_chan,
218
218
  handle->read ? handle->sock : INVALID_SOCKET,
219
219
  handle->write ? handle->sock : INVALID_SOCKET);
220
220
 
@@ -258,7 +258,7 @@ int uv_ares_init_options(uv_loop_t* loop,
258
258
  int rc;
259
259
 
260
260
  /* only allow single init at a time */
261
- if (loop->ares_channel != NULL) {
261
+ if (loop->ares_chan != NULL) {
262
262
  return UV_EALREADY;
263
263
  }
264
264
 
@@ -272,7 +272,7 @@ int uv_ares_init_options(uv_loop_t* loop,
272
272
 
273
273
  /* if success, save channel */
274
274
  if (rc == ARES_SUCCESS) {
275
- loop->ares_channel = *channelptr;
275
+ loop->ares_chan = *channelptr;
276
276
  }
277
277
 
278
278
  return rc;
@@ -282,8 +282,8 @@ int uv_ares_init_options(uv_loop_t* loop,
282
282
  /* release memory */
283
283
  void uv_ares_destroy(uv_loop_t* loop, ares_channel channel) {
284
284
  /* only allow destroy if did init */
285
- if (loop->ares_channel != NULL) {
285
+ if (loop->ares_chan != NULL) {
286
286
  ares_destroy(channel);
287
- loop->ares_channel = NULL;
287
+ loop->ares_chan = NULL;
288
288
  }
289
289
  }
@@ -33,7 +33,22 @@
33
33
 
34
34
  /* The only event loop we support right now */
35
35
  static uv_loop_t uv_default_loop_;
36
- static int uv_default_loop_initialized_ = 0;
36
+
37
+ /* uv_once intialization guards */
38
+ static uv_once_t uv_init_guard_ = UV_ONCE_INIT;
39
+ static uv_once_t uv_default_loop_init_guard_ = UV_ONCE_INIT;
40
+
41
+
42
+ static void uv_init(void) {
43
+ /* Initialize winsock */
44
+ uv_winsock_init();
45
+
46
+ /* Fetch winapi function pointers */
47
+ uv_winapi_init();
48
+
49
+ /* Initialize FS */
50
+ uv_fs_init();
51
+ }
37
52
 
38
53
 
39
54
  static void uv_loop_init(uv_loop_t* loop) {
@@ -62,31 +77,24 @@ static void uv_loop_init(uv_loop_t* loop) {
62
77
  loop->next_idle_handle = NULL;
63
78
 
64
79
  loop->ares_active_sockets = 0;
65
- loop->ares_channel = NULL;
80
+ loop->ares_chan = NULL;
66
81
 
67
82
  loop->last_error = uv_ok_;
68
83
  }
69
84
 
70
85
 
71
- uv_loop_t* uv_default_loop() {
72
- if (!uv_default_loop_initialized_) {
73
- uv_loop_init(&uv_default_loop_);
74
- uv_default_loop_initialized_ = 1;
75
- }
86
+ static void uv_default_loop_init(void) {
87
+ /* Intialize libuv itself first */
88
+ uv_once(&uv_init_guard_, uv_init);
76
89
 
77
- return &uv_default_loop_;
90
+ /* Initialize the main loop */
91
+ uv_loop_init(&uv_default_loop_);
78
92
  }
79
93
 
80
94
 
81
- void uv_init() {
82
- /* Initialize winsock */
83
- uv_winsock_init();
84
-
85
- /* Fetch winapi function pointers */
86
- uv_winapi_init();
87
-
88
- /* Initialize FS */
89
- uv_fs_init();
95
+ uv_loop_t* uv_default_loop() {
96
+ uv_once(&uv_default_loop_init_guard_, uv_default_loop_init);
97
+ return &uv_default_loop_;
90
98
  }
91
99
 
92
100
 
@@ -96,6 +96,8 @@ char* uv_strerror(uv_err_t err) {
96
96
  uv_err_code uv_translate_sys_error(int sys_errno) {
97
97
  switch (sys_errno) {
98
98
  case ERROR_SUCCESS: return UV_OK;
99
+ case ERROR_FILE_NOT_FOUND: return UV_ENOENT;
100
+ case ERROR_PATH_NOT_FOUND: return UV_ENOENT;
99
101
  case ERROR_NOACCESS: return UV_EACCESS;
100
102
  case WSAEACCES: return UV_EACCESS;
101
103
  case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE;
@@ -104,6 +106,8 @@ uv_err_code uv_translate_sys_error(int sys_errno) {
104
106
  case WSAEAFNOSUPPORT: return UV_EAFNOSUPPORT;
105
107
  case WSAEWOULDBLOCK: return UV_EAGAIN;
106
108
  case WSAEALREADY: return UV_EALREADY;
109
+ case ERROR_CONNECTION_ABORTED: return UV_ECONNABORTED;
110
+ case WSAECONNABORTED: return UV_ECONNABORTED;
107
111
  case ERROR_CONNECTION_REFUSED: return UV_ECONNREFUSED;
108
112
  case WSAECONNREFUSED: return UV_ECONNREFUSED;
109
113
  case WSAEFAULT: return UV_EFAULT;
@@ -117,6 +121,8 @@ uv_err_code uv_translate_sys_error(int sys_errno) {
117
121
  case ERROR_NETWORK_UNREACHABLE: return UV_ENETUNREACH;
118
122
  case WSAENETUNREACH: return UV_ENETUNREACH;
119
123
  case ERROR_OUTOFMEMORY: return UV_ENOMEM;
124
+ case ERROR_NOT_CONNECTED: return UV_ENOTCONN;
125
+ case WSAENOTCONN: return UV_ENOTCONN;
120
126
  case ERROR_NOT_SUPPORTED: return UV_ENOTSUP;
121
127
  case ERROR_INSUFFICIENT_BUFFER: return UV_EINVAL;
122
128
  case ERROR_INVALID_FLAGS: return UV_EBADF;
@@ -125,6 +131,7 @@ uv_err_code uv_translate_sys_error(int sys_errno) {
125
131
  case ERROR_BROKEN_PIPE: return UV_EOF;
126
132
  case ERROR_PIPE_BUSY: return UV_EBUSY;
127
133
  case ERROR_SEM_TIMEOUT: return UV_ETIMEDOUT;
134
+ case ERROR_ALREADY_EXISTS: return UV_EEXIST;
128
135
  default: return UV_UNKNOWN;
129
136
  }
130
137
  }
@@ -22,8 +22,10 @@
22
22
  #include <assert.h>
23
23
  #include <malloc.h>
24
24
  #include <direct.h>
25
+ #include <errno.h>
25
26
  #include <fcntl.h>
26
27
  #include <io.h>
28
+ #include <limits.h>
27
29
  #include <sys/stat.h>
28
30
  #include <sys/utime.h>
29
31
  #include <stdio.h>
@@ -36,6 +38,7 @@
36
38
  #define UV_FS_FREE_ARG1 0x0004
37
39
  #define UV_FS_FREE_PTR 0x0008
38
40
  #define UV_FS_CLEANEDUP 0x0010
41
+ #define UV_FS_LAST_ERROR_SET 0x0020
39
42
 
40
43
  #define STRDUP_ARG(req, i) \
41
44
  req->arg##i = (void*)strdup((const char*)req->arg##i); \
@@ -70,13 +73,34 @@
70
73
  uv_ref((loop));
71
74
 
72
75
 
76
+ #define SET_UV_LAST_ERROR_FROM_REQ(req) \
77
+ if (req->flags & UV_FS_LAST_ERROR_SET) { \
78
+ uv_set_sys_error(req->loop, req->last_error); \
79
+ }
80
+
81
+ #define SET_REQ_LAST_ERROR(req, error) \
82
+ req->last_error = error; \
83
+ req->flags |= UV_FS_LAST_ERROR_SET;
84
+
85
+ #define SET_REQ_RESULT(req, result_value) \
86
+ req->result = (result_value); \
87
+ if (req->result == -1) { \
88
+ req->errorno = uv_translate_sys_error(_doserrno); \
89
+ }
90
+
91
+ #define SET_REQ_RESULT_WIN32_ERROR(req, sys_errno) \
92
+ req->result = -1; \
93
+ req->errorno = uv_translate_sys_error(sys_errno); \
94
+ SET_REQ_LAST_ERROR(req, sys_errno);
95
+
96
+
73
97
  void uv_fs_init() {
74
98
  _fmode = _O_BINARY;
75
99
  }
76
100
 
77
101
 
78
102
  static void uv_fs_req_init_async(uv_loop_t* loop, uv_fs_t* req,
79
- uv_fs_type fs_type, uv_fs_cb cb) {
103
+ uv_fs_type fs_type, const char* path, uv_fs_cb cb) {
80
104
  uv_req_init(loop, (uv_req_t*) req);
81
105
  req->type = UV_FS;
82
106
  req->loop = loop;
@@ -85,7 +109,9 @@ static void uv_fs_req_init_async(uv_loop_t* loop, uv_fs_t* req,
85
109
  req->cb = cb;
86
110
  req->result = 0;
87
111
  req->ptr = NULL;
112
+ req->path = path ? strdup(path) : NULL;
88
113
  req->errorno = 0;
114
+ req->last_error = 0;
89
115
  memset(&req->overlapped, 0, sizeof(req->overlapped));
90
116
  }
91
117
 
@@ -99,16 +125,118 @@ static void uv_fs_req_init_sync(uv_loop_t* loop, uv_fs_t* req,
99
125
  req->fs_type = fs_type;
100
126
  req->result = 0;
101
127
  req->ptr = NULL;
128
+ req->path = NULL;
102
129
  req->errorno = 0;
103
130
  }
104
131
 
105
132
 
106
133
  void fs__open(uv_fs_t* req, const char* path, int flags, int mode) {
107
- int result = _open(path, flags, mode);
134
+ DWORD access;
135
+ DWORD share;
136
+ DWORD disposition;
137
+ DWORD attributes;
138
+ HANDLE file;
139
+ int result, current_umask;
140
+
141
+ /* Obtain the active umask. umask() never fails and returns the previous */
142
+ /* umask. */
143
+ current_umask = umask(0);
144
+ umask(current_umask);
145
+
146
+ /* convert flags and mode to CreateFile parameters */
147
+ switch (flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
148
+ case _O_RDONLY:
149
+ access = GENERIC_READ;
150
+ break;
151
+ case _O_WRONLY:
152
+ access = GENERIC_WRITE;
153
+ break;
154
+ case _O_RDWR:
155
+ access = GENERIC_READ | GENERIC_WRITE;
156
+ break;
157
+ default:
158
+ result = -1;
159
+ goto end;
160
+ }
161
+
162
+ /*
163
+ * Here is where we deviate significantly from what CRT's _open()
164
+ * does. We indiscriminately use all the sharing modes, to match
165
+ * UNIX semantics. In particular, this ensures that the file can
166
+ * be deleted even whilst it's open, fixing issue #1449.
167
+ */
168
+ share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
169
+
170
+ switch (flags & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
171
+ case 0:
172
+ case _O_EXCL:
173
+ disposition = OPEN_EXISTING;
174
+ break;
175
+ case _O_CREAT:
176
+ disposition = OPEN_ALWAYS;
177
+ break;
178
+ case _O_CREAT | _O_EXCL:
179
+ case _O_CREAT | _O_TRUNC | _O_EXCL:
180
+ disposition = CREATE_NEW;
181
+ break;
182
+ case _O_TRUNC:
183
+ case _O_TRUNC | _O_EXCL:
184
+ disposition = TRUNCATE_EXISTING;
185
+ break;
186
+ case _O_CREAT | _O_TRUNC:
187
+ disposition = CREATE_ALWAYS;
188
+ break;
189
+ default:
190
+ result = -1;
191
+ goto end;
192
+ }
193
+
194
+ attributes = FILE_ATTRIBUTE_NORMAL;
195
+ if (flags & _O_CREAT) {
196
+ if (!((mode & ~current_umask) & _S_IWRITE)) {
197
+ attributes |= FILE_ATTRIBUTE_READONLY;
198
+ }
199
+ }
200
+
201
+ if (flags & _O_TEMPORARY ) {
202
+ attributes |= FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY;
203
+ access |= DELETE;
204
+ }
205
+
206
+ if (flags & _O_SHORT_LIVED) {
207
+ attributes |= FILE_ATTRIBUTE_TEMPORARY;
208
+ }
209
+
210
+ switch (flags & (_O_SEQUENTIAL | _O_RANDOM)) {
211
+ case 0:
212
+ break;
213
+ case _O_SEQUENTIAL:
214
+ attributes |= FILE_FLAG_SEQUENTIAL_SCAN;
215
+ break;
216
+ case _O_RANDOM:
217
+ attributes |= FILE_FLAG_RANDOM_ACCESS;
218
+ break;
219
+ default:
220
+ result = -1;
221
+ goto end;
222
+ }
223
+
224
+ file = CreateFileA(path,
225
+ access,
226
+ share,
227
+ NULL,
228
+ disposition,
229
+ attributes,
230
+ NULL);
231
+ if (file == INVALID_HANDLE_VALUE) {
232
+ SET_REQ_RESULT_WIN32_ERROR(req, GetLastError());
233
+ return;
234
+ }
235
+ result = _open_osfhandle((intptr_t)file, flags);
236
+ end:
108
237
  SET_REQ_RESULT(req, result);
109
238
  }
110
239
 
111
-
112
240
  void fs__close(uv_fs_t* req, uv_file file) {
113
241
  int result = _close(file);
114
242
  SET_REQ_RESULT(req, result);
@@ -117,33 +245,77 @@ void fs__close(uv_fs_t* req, uv_file file) {
117
245
 
118
246
  void fs__read(uv_fs_t* req, uv_file file, void *buf, size_t length,
119
247
  off_t offset) {
120
- int result = 0;
248
+ HANDLE handle;
249
+ OVERLAPPED overlapped, *overlapped_ptr;
250
+ LARGE_INTEGER offset_;
251
+ DWORD bytes;
252
+
253
+ handle = (HANDLE) _get_osfhandle(file);
254
+ if (handle == INVALID_HANDLE_VALUE) {
255
+ SET_REQ_RESULT(req, -1);
256
+ return;
257
+ }
121
258
 
122
- if (offset != -1) {
123
- result = _lseek(file, offset, SEEK_SET);
259
+ if (length > INT_MAX) {
260
+ SET_REQ_ERROR(req, ERROR_INSUFFICIENT_BUFFER);
261
+ return;
124
262
  }
125
263
 
126
- if (result != -1) {
127
- result = _read(file, buf, length);
264
+ if (offset != -1) {
265
+ memset(&overlapped, 0, sizeof overlapped);
266
+
267
+ offset_.QuadPart = offset;
268
+ overlapped.Offset = offset_.LowPart;
269
+ overlapped.OffsetHigh = offset_.HighPart;
270
+
271
+ overlapped_ptr = &overlapped;
272
+ } else {
273
+ overlapped_ptr = NULL;
128
274
  }
129
275
 
130
- SET_REQ_RESULT(req, result);
276
+ if (ReadFile(handle, buf, length, &bytes, overlapped_ptr)) {
277
+ SET_REQ_RESULT(req, bytes);
278
+ } else {
279
+ SET_REQ_ERROR(req, GetLastError());
280
+ }
131
281
  }
132
282
 
133
283
 
134
284
  void fs__write(uv_fs_t* req, uv_file file, void *buf, size_t length,
135
285
  off_t offset) {
136
- int result = 0;
286
+ HANDLE handle;
287
+ OVERLAPPED overlapped, *overlapped_ptr;
288
+ LARGE_INTEGER offset_;
289
+ DWORD bytes;
290
+
291
+ handle = (HANDLE) _get_osfhandle(file);
292
+ if (handle == INVALID_HANDLE_VALUE) {
293
+ SET_REQ_RESULT(req, -1);
294
+ return;
295
+ }
137
296
 
138
- if (offset != -1) {
139
- result = _lseek(file, offset, SEEK_SET);
297
+ if (length > INT_MAX) {
298
+ SET_REQ_ERROR(req, ERROR_INSUFFICIENT_BUFFER);
299
+ return;
140
300
  }
141
301
 
142
- if (result != -1) {
143
- result = _write(file, buf, length);
302
+ if (offset != -1) {
303
+ memset(&overlapped, 0, sizeof overlapped);
304
+
305
+ offset_.QuadPart = offset;
306
+ overlapped.Offset = offset_.LowPart;
307
+ overlapped.OffsetHigh = offset_.HighPart;
308
+
309
+ overlapped_ptr = &overlapped;
310
+ } else {
311
+ overlapped_ptr = NULL;
144
312
  }
145
313
 
146
- SET_REQ_RESULT(req, result);
314
+ if (WriteFile(handle, buf, length, &bytes, overlapped_ptr)) {
315
+ SET_REQ_RESULT(req, bytes);
316
+ } else {
317
+ SET_REQ_ERROR(req, GetLastError());
318
+ }
147
319
  }
148
320
 
149
321
 
@@ -186,8 +358,8 @@ void fs__readdir(uv_fs_t* req, const char* path, int flags) {
186
358
  free(path2);
187
359
 
188
360
  if(dir == INVALID_HANDLE_VALUE) {
189
- result = -1;
190
- goto done;
361
+ SET_REQ_RESULT_WIN32_ERROR(req, GetLastError());
362
+ return;
191
363
  }
192
364
 
193
365
  buf = (char*)malloc(buf_size);
@@ -226,7 +398,6 @@ void fs__readdir(uv_fs_t* req, const char* path, int flags) {
226
398
  req->ptr = buf;
227
399
  req->flags |= UV_FS_FREE_PTR;
228
400
 
229
- done:
230
401
  SET_REQ_RESULT(req, result);
231
402
  }
232
403
 
@@ -234,7 +405,7 @@ done:
234
405
  void fs__stat(uv_fs_t* req, const char* path) {
235
406
  int result;
236
407
 
237
- result = _stat(path, &req->stat);
408
+ result = _stati64(path, &req->stat);
238
409
  if (result == -1) {
239
410
  req->ptr = NULL;
240
411
  } else {
@@ -248,7 +419,7 @@ void fs__stat(uv_fs_t* req, const char* path) {
248
419
  void fs__fstat(uv_fs_t* req, uv_file file) {
249
420
  int result;
250
421
 
251
- result = _fstat(file, &req->stat);
422
+ result = _fstati64(file, &req->stat);
252
423
  if (result == -1) {
253
424
  req->ptr = NULL;
254
425
  } else {
@@ -267,7 +438,11 @@ void fs__rename(uv_fs_t* req, const char* path, const char* new_path) {
267
438
 
268
439
  void fs__fsync(uv_fs_t* req, uv_file file) {
269
440
  int result = FlushFileBuffers((HANDLE)_get_osfhandle(file)) ? 0 : -1;
270
- SET_REQ_RESULT(req, result);
441
+ if (result == -1) {
442
+ SET_REQ_RESULT_WIN32_ERROR(req, GetLastError());
443
+ } else {
444
+ SET_REQ_RESULT(req, result);
445
+ }
271
446
  }
272
447
 
273
448
 
@@ -323,6 +498,50 @@ void fs__chmod(uv_fs_t* req, const char* path, int mode) {
323
498
  }
324
499
 
325
500
 
501
+ void fs__fchmod(uv_fs_t* req, uv_file file, int mode) {
502
+ int result;
503
+ HANDLE handle;
504
+ NTSTATUS nt_status;
505
+ IO_STATUS_BLOCK io_status;
506
+ FILE_BASIC_INFORMATION file_info;
507
+
508
+ handle = (HANDLE)_get_osfhandle(file);
509
+
510
+ nt_status = pNtQueryInformationFile(handle,
511
+ &io_status,
512
+ &file_info,
513
+ sizeof file_info,
514
+ FileBasicInformation);
515
+
516
+ if (nt_status != STATUS_SUCCESS) {
517
+ result = -1;
518
+ goto done;
519
+ }
520
+
521
+ if (mode & _S_IWRITE) {
522
+ file_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY;
523
+ } else {
524
+ file_info.FileAttributes |= FILE_ATTRIBUTE_READONLY;
525
+ }
526
+
527
+ nt_status = pNtSetInformationFile(handle,
528
+ &io_status,
529
+ &file_info,
530
+ sizeof file_info,
531
+ FileBasicInformation);
532
+
533
+ if (nt_status != STATUS_SUCCESS) {
534
+ result = -1;
535
+ goto done;
536
+ }
537
+
538
+ result = 0;
539
+
540
+ done:
541
+ SET_REQ_RESULT(req, result);
542
+ }
543
+
544
+
326
545
  void fs__utime(uv_fs_t* req, const char* path, double atime, double mtime) {
327
546
  int result;
328
547
  struct _utimbuf b = {(time_t)atime, (time_t)mtime};
@@ -339,6 +558,144 @@ void fs__futime(uv_fs_t* req, uv_file file, double atime, double mtime) {
339
558
  }
340
559
 
341
560
 
561
+ void fs__link(uv_fs_t* req, const char* path, const char* new_path) {
562
+ int result = CreateHardLinkA(new_path, path, NULL) ? 0 : -1;
563
+ if (result == -1) {
564
+ SET_REQ_RESULT_WIN32_ERROR(req, GetLastError());
565
+ } else {
566
+ SET_REQ_RESULT(req, result);
567
+ }
568
+ }
569
+
570
+
571
+ void fs__symlink(uv_fs_t* req, const char* path, const char* new_path,
572
+ int flags) {
573
+ int result;
574
+ if (pCreateSymbolicLinkA) {
575
+ result = pCreateSymbolicLinkA(new_path,
576
+ path,
577
+ flags & UV_FS_SYMLINK_DIR ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) ? 0 : -1;
578
+ if (result == -1) {
579
+ SET_REQ_LAST_ERROR(req, GetLastError());
580
+ }
581
+ } else {
582
+ result = -1;
583
+ errno = ENOSYS;
584
+ }
585
+
586
+ SET_REQ_RESULT(req, result);
587
+ }
588
+
589
+
590
+ void fs__readlink(uv_fs_t* req, const char* path) {
591
+ int result = -1;
592
+ BOOL rv;
593
+ HANDLE symlink;
594
+ void* buffer = NULL;
595
+ DWORD bytes_returned;
596
+ REPARSE_DATA_BUFFER* reparse_data;
597
+ int utf8size;
598
+ wchar_t* substitute_name;
599
+ int substitute_name_length;
600
+
601
+ symlink = CreateFileA(path,
602
+ 0,
603
+ 0,
604
+ NULL,
605
+ OPEN_EXISTING,
606
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
607
+ NULL);
608
+
609
+ if (INVALID_HANDLE_VALUE == symlink) {
610
+ result = -1;
611
+ SET_REQ_LAST_ERROR(req, GetLastError());
612
+ goto done;
613
+ }
614
+
615
+ buffer = malloc(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
616
+ if (!buffer) {
617
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
618
+ }
619
+
620
+ rv = DeviceIoControl(symlink,
621
+ FSCTL_GET_REPARSE_POINT,
622
+ NULL,
623
+ 0,
624
+ buffer,
625
+ MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
626
+ &bytes_returned,
627
+ NULL);
628
+
629
+ if (!rv) {
630
+ result = -1;
631
+ SET_REQ_LAST_ERROR(req, GetLastError());
632
+ goto done;
633
+ }
634
+
635
+ reparse_data = buffer;
636
+ if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK) {
637
+ result = -1;
638
+ /* something is seriously wrong */
639
+ SET_REQ_LAST_ERROR(req, GetLastError());
640
+ goto done;
641
+ }
642
+
643
+ substitute_name = reparse_data->SymbolicLinkReparseBuffer.PathBuffer + (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t));
644
+ substitute_name_length = reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t);
645
+
646
+ /* Strip off the leading \??\ from the substitute name buffer.*/
647
+ if (memcmp(substitute_name, L"\\??\\", 8) == 0) {
648
+ substitute_name += 4;
649
+ substitute_name_length -= 4;
650
+ }
651
+
652
+ utf8size = uv_utf16_to_utf8(substitute_name,
653
+ substitute_name_length,
654
+ NULL,
655
+ 0);
656
+ if (!utf8size) {
657
+ result = -1;
658
+ SET_REQ_LAST_ERROR(req, GetLastError());
659
+ goto done;
660
+ }
661
+
662
+ req->ptr = malloc(utf8size + 1);
663
+ if (!req->ptr) {
664
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
665
+ }
666
+
667
+ utf8size = uv_utf16_to_utf8(substitute_name,
668
+ substitute_name_length,
669
+ req->ptr,
670
+ utf8size);
671
+ if (!utf8size) {
672
+ result = -1;
673
+ SET_REQ_LAST_ERROR(req, GetLastError());
674
+ goto done;
675
+ }
676
+
677
+ req->flags |= UV_FS_FREE_PTR;
678
+ ((char*)req->ptr)[utf8size] = '\0';
679
+ result = 0;
680
+
681
+ done:
682
+ if (buffer) {
683
+ free(buffer);
684
+ }
685
+
686
+ if (symlink != INVALID_HANDLE_VALUE) {
687
+ CloseHandle(symlink);
688
+ }
689
+
690
+ SET_REQ_RESULT(req, result);
691
+ }
692
+
693
+
694
+ void fs__nop(uv_fs_t* req) {
695
+ req->result = 0;
696
+ }
697
+
698
+
342
699
  static DWORD WINAPI uv_fs_thread_proc(void* parameter) {
343
700
  uv_fs_t* req = (uv_fs_t*) parameter;
344
701
  uv_loop_t* loop = req->loop;
@@ -348,7 +705,7 @@ static DWORD WINAPI uv_fs_thread_proc(void* parameter) {
348
705
 
349
706
  switch (req->fs_type) {
350
707
  case UV_FS_OPEN:
351
- fs__open(req, (const char*)req->arg0, (int)req->arg1, (int)req->arg2);
708
+ fs__open(req, req->path, (int)req->arg0, (int)req->arg1);
352
709
  break;
353
710
  case UV_FS_CLOSE:
354
711
  fs__close(req, (uv_file)req->arg0);
@@ -368,25 +725,26 @@ static DWORD WINAPI uv_fs_thread_proc(void* parameter) {
368
725
  (off_t) req->arg3);
369
726
  break;
370
727
  case UV_FS_UNLINK:
371
- fs__unlink(req, (const char*)req->arg0);
728
+ fs__unlink(req, req->path);
372
729
  break;
373
730
  case UV_FS_MKDIR:
374
- fs__mkdir(req, (const char*)req->arg0, (int)req->arg1);
731
+ fs__mkdir(req, req->path, (int)req->arg0);
375
732
  break;
376
733
  case UV_FS_RMDIR:
377
- fs__rmdir(req, (const char*)req->arg0);
734
+ fs__rmdir(req, req->path);
378
735
  break;
379
736
  case UV_FS_READDIR:
380
- fs__readdir(req, (const char*)req->arg0, (int)req->arg1);
737
+ fs__readdir(req, req->path, (int)req->arg0);
381
738
  break;
382
739
  case UV_FS_STAT:
383
- fs__stat(req, (const char*)req->arg0);
740
+ case UV_FS_LSTAT:
741
+ fs__stat(req, req->path);
384
742
  break;
385
743
  case UV_FS_FSTAT:
386
744
  fs__fstat(req, (uv_file)req->arg0);
387
745
  break;
388
746
  case UV_FS_RENAME:
389
- fs__rename(req, (const char*)req->arg0, (const char*)req->arg1);
747
+ fs__rename(req, req->path, (const char*)req->arg0);
390
748
  break;
391
749
  case UV_FS_FSYNC:
392
750
  case UV_FS_FDATASYNC:
@@ -403,14 +761,30 @@ static DWORD WINAPI uv_fs_thread_proc(void* parameter) {
403
761
  (size_t) req->arg3);
404
762
  break;
405
763
  case UV_FS_CHMOD:
406
- fs__chmod(req, (const char*)req->arg0, (int)req->arg1);
764
+ fs__chmod(req, req->path, (int)req->arg0);
765
+ break;
766
+ case UV_FS_FCHMOD:
767
+ fs__fchmod(req, (uv_file)req->arg0, (int)req->arg1);
407
768
  break;
408
769
  case UV_FS_UTIME:
409
- fs__utime(req, (const char*)req->arg0, req->arg4, req->arg5);
770
+ fs__utime(req, req->path, req->arg4, req->arg5);
410
771
  break;
411
772
  case UV_FS_FUTIME:
412
773
  fs__futime(req, (uv_file)req->arg0, req->arg4, req->arg5);
413
774
  break;
775
+ case UV_FS_LINK:
776
+ fs__link(req, req->path, (const char*)req->arg0);
777
+ break;
778
+ case UV_FS_SYMLINK:
779
+ fs__symlink(req, req->path, (const char*)req->arg0, (int)req->arg1);
780
+ break;
781
+ case UV_FS_READLINK:
782
+ fs__readlink(req, req->path);
783
+ break;
784
+ case UV_FS_CHOWN:
785
+ case UV_FS_FCHOWN:
786
+ fs__nop(req);
787
+ break;
414
788
  default:
415
789
  assert(!"bad uv_fs_type");
416
790
  }
@@ -424,13 +798,14 @@ static DWORD WINAPI uv_fs_thread_proc(void* parameter) {
424
798
  int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
425
799
  int mode, uv_fs_cb cb) {
426
800
  if (cb) {
427
- uv_fs_req_init_async(loop, req, UV_FS_OPEN, cb);
428
- WRAP_REQ_ARGS3(req, path, flags, mode);
429
- STRDUP_ARG(req, 0);
801
+ uv_fs_req_init_async(loop, req, UV_FS_OPEN, path, cb);
802
+ WRAP_REQ_ARGS2(req, flags, mode);
430
803
  QUEUE_FS_TP_JOB(loop, req);
431
804
  } else {
432
805
  uv_fs_req_init_sync(loop, req, UV_FS_OPEN);
433
806
  fs__open(req, path, flags, mode);
807
+ SET_UV_LAST_ERROR_FROM_REQ(req);
808
+ return req->result;
434
809
  }
435
810
 
436
811
  return 0;
@@ -439,12 +814,14 @@ int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
439
814
 
440
815
  int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
441
816
  if (cb) {
442
- uv_fs_req_init_async(loop, req, UV_FS_CLOSE, cb);
817
+ uv_fs_req_init_async(loop, req, UV_FS_CLOSE, NULL, cb);
443
818
  WRAP_REQ_ARGS1(req, file);
444
819
  QUEUE_FS_TP_JOB(loop, req);
445
820
  } else {
446
821
  uv_fs_req_init_sync(loop, req, UV_FS_CLOSE);
447
822
  fs__close(req, file);
823
+ SET_UV_LAST_ERROR_FROM_REQ(req);
824
+ return req->result;
448
825
  }
449
826
 
450
827
  return 0;
@@ -454,12 +831,14 @@ int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
454
831
  int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file file, void* buf,
455
832
  size_t length, off_t offset, uv_fs_cb cb) {
456
833
  if (cb) {
457
- uv_fs_req_init_async(loop, req, UV_FS_READ, cb);
834
+ uv_fs_req_init_async(loop, req, UV_FS_READ, NULL, cb);
458
835
  WRAP_REQ_ARGS4(req, file, buf, length, offset);
459
836
  QUEUE_FS_TP_JOB(loop, req);
460
837
  } else {
461
838
  uv_fs_req_init_sync(loop, req, UV_FS_READ);
462
839
  fs__read(req, file, buf, length, offset);
840
+ SET_UV_LAST_ERROR_FROM_REQ(req);
841
+ return req->result;
463
842
  }
464
843
 
465
844
  return 0;
@@ -469,12 +848,14 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file file, void* buf,
469
848
  int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file, void* buf,
470
849
  size_t length, off_t offset, uv_fs_cb cb) {
471
850
  if (cb) {
472
- uv_fs_req_init_async(loop, req, UV_FS_WRITE, cb);
851
+ uv_fs_req_init_async(loop, req, UV_FS_WRITE, NULL, cb);
473
852
  WRAP_REQ_ARGS4(req, file, buf, length, offset);
474
853
  QUEUE_FS_TP_JOB(loop, req);
475
854
  } else {
476
855
  uv_fs_req_init_sync(loop, req, UV_FS_WRITE);
477
856
  fs__write(req, file, buf, length, offset);
857
+ SET_UV_LAST_ERROR_FROM_REQ(req);
858
+ return req->result;
478
859
  }
479
860
 
480
861
  return 0;
@@ -484,13 +865,13 @@ int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file, void* buf,
484
865
  int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
485
866
  uv_fs_cb cb) {
486
867
  if (cb) {
487
- uv_fs_req_init_async(loop, req, UV_FS_UNLINK, cb);
488
- WRAP_REQ_ARGS1(req, path);
489
- STRDUP_ARG(req, 0);
868
+ uv_fs_req_init_async(loop, req, UV_FS_UNLINK, path, cb);
490
869
  QUEUE_FS_TP_JOB(loop, req);
491
870
  } else {
492
871
  uv_fs_req_init_sync(loop, req, UV_FS_UNLINK);
493
872
  fs__unlink(req, path);
873
+ SET_UV_LAST_ERROR_FROM_REQ(req);
874
+ return req->result;
494
875
  }
495
876
 
496
877
  return 0;
@@ -500,13 +881,14 @@ int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
500
881
  int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
501
882
  uv_fs_cb cb) {
502
883
  if (cb) {
503
- uv_fs_req_init_async(loop, req, UV_FS_MKDIR, cb);
504
- WRAP_REQ_ARGS2(req, path, mode);
505
- STRDUP_ARG(req, 0);
884
+ uv_fs_req_init_async(loop, req, UV_FS_MKDIR, path, cb);
885
+ WRAP_REQ_ARGS1(req, mode);
506
886
  QUEUE_FS_TP_JOB(loop, req);
507
887
  } else {
508
888
  uv_fs_req_init_sync(loop, req, UV_FS_MKDIR);
509
889
  fs__mkdir(req, path, mode);
890
+ SET_UV_LAST_ERROR_FROM_REQ(req);
891
+ return req->result;
510
892
  }
511
893
 
512
894
  return 0;
@@ -515,13 +897,13 @@ int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
515
897
 
516
898
  int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
517
899
  if (cb) {
518
- uv_fs_req_init_async(loop, req, UV_FS_RMDIR, cb);
519
- WRAP_REQ_ARGS1(req, path);
520
- STRDUP_ARG(req, 0);
900
+ uv_fs_req_init_async(loop, req, UV_FS_RMDIR, path, cb);
521
901
  QUEUE_FS_TP_JOB(loop, req);
522
902
  } else {
523
903
  uv_fs_req_init_sync(loop, req, UV_FS_RMDIR);
524
904
  fs__rmdir(req, path);
905
+ SET_UV_LAST_ERROR_FROM_REQ(req);
906
+ return req->result;
525
907
  }
526
908
 
527
909
  return 0;
@@ -531,65 +913,103 @@ int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
531
913
  int uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
532
914
  uv_fs_cb cb) {
533
915
  if (cb) {
534
- uv_fs_req_init_async(loop, req, UV_FS_READDIR, cb);
535
- WRAP_REQ_ARGS2(req, path, flags);
536
- STRDUP_ARG(req, 0);
916
+ uv_fs_req_init_async(loop, req, UV_FS_READDIR, path, cb);
917
+ WRAP_REQ_ARGS1(req, flags);
537
918
  QUEUE_FS_TP_JOB(loop, req);
538
919
  } else {
539
920
  uv_fs_req_init_sync(loop, req, UV_FS_READDIR);
540
921
  fs__readdir(req, path, flags);
922
+ SET_UV_LAST_ERROR_FROM_REQ(req);
923
+ return req->result;
541
924
  }
542
925
 
543
926
  return 0;
544
927
  }
545
928
 
546
929
 
547
- int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
548
- assert(0 && "implement me");
549
- return -1;
550
- }
551
-
552
-
553
- // uv_fs_readlink, uv_fs_fchmod, uv_fs_chown, uv_fs_fchown
554
930
  int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path,
555
931
  const char* new_path, uv_fs_cb cb) {
556
- assert(0 && "implement me");
557
- return -1;
932
+ if (cb) {
933
+ uv_fs_req_init_async(loop, req, UV_FS_LINK, path, cb);
934
+ WRAP_REQ_ARGS1(req, new_path);
935
+ STRDUP_ARG(req, 0);
936
+ QUEUE_FS_TP_JOB(loop, req);
937
+ } else {
938
+ uv_fs_req_init_sync(loop, req, UV_FS_LINK);
939
+ fs__link(req, path, new_path);
940
+ SET_UV_LAST_ERROR_FROM_REQ(req);
941
+ return req->result;
942
+ }
943
+
944
+ return 0;
558
945
  }
559
946
 
560
947
 
561
948
  int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
562
- const char* new_path, uv_fs_cb cb) {
563
- assert(0 && "implement me");
564
- return -1;
949
+ const char* new_path, int flags, uv_fs_cb cb) {
950
+ if (cb) {
951
+ uv_fs_req_init_async(loop, req, UV_FS_SYMLINK, path, cb);
952
+ WRAP_REQ_ARGS2(req, new_path, flags);
953
+ STRDUP_ARG(req, 0);
954
+ QUEUE_FS_TP_JOB(loop, req);
955
+ } else {
956
+ uv_fs_req_init_sync(loop, req, UV_FS_SYMLINK);
957
+ fs__symlink(req, path, new_path, flags);
958
+ SET_UV_LAST_ERROR_FROM_REQ(req);
959
+ return req->result;
960
+ }
961
+
962
+ return 0;
565
963
  }
566
964
 
567
965
 
568
966
  int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
569
967
  uv_fs_cb cb) {
570
- assert(0 && "implement me");
571
- return -1;
572
- }
573
-
968
+ if (cb) {
969
+ uv_fs_req_init_async(loop, req, UV_FS_READLINK, path, cb);
970
+ QUEUE_FS_TP_JOB(loop, req);
971
+ } else {
972
+ uv_fs_req_init_sync(loop, req, UV_FS_READLINK);
973
+ fs__readlink(req, path);
974
+ SET_UV_LAST_ERROR_FROM_REQ(req);
975
+ return req->result;
976
+ }
574
977
 
575
- int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file file, int mode,
576
- uv_fs_cb cb) {
577
- assert(0 && "implement me");
578
- return -1;
978
+ return 0;
579
979
  }
580
980
 
581
981
 
582
982
  int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, int uid,
583
983
  int gid, uv_fs_cb cb) {
584
- assert(0 && "implement me");
585
- return -1;
984
+ if (cb) {
985
+ uv_fs_req_init_async(loop, req, UV_FS_CHOWN, path, cb);
986
+ WRAP_REQ_ARGS2(req, uid, gid);
987
+ QUEUE_FS_TP_JOB(loop, req);
988
+ } else {
989
+ uv_fs_req_init_sync(loop, req, UV_FS_CHOWN);
990
+ fs__nop(req);
991
+ SET_UV_LAST_ERROR_FROM_REQ(req);
992
+ return req->result;
993
+ }
994
+
995
+ return 0;
586
996
  }
587
997
 
588
998
 
589
999
  int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file file, int uid,
590
1000
  int gid, uv_fs_cb cb) {
591
- assert(0 && "implement me");
592
- return -1;
1001
+ if (cb) {
1002
+ uv_fs_req_init_async(loop, req, UV_FS_FCHOWN, NULL, cb);
1003
+ WRAP_REQ_ARGS3(req, file, uid, gid);
1004
+ QUEUE_FS_TP_JOB(loop, req);
1005
+ } else {
1006
+ uv_fs_req_init_sync(loop, req, UV_FS_FCHOWN);
1007
+ fs__nop(req);
1008
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1009
+ return req->result;
1010
+ }
1011
+
1012
+ return 0;
593
1013
  }
594
1014
 
595
1015
 
@@ -608,13 +1028,11 @@ int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
608
1028
  }
609
1029
 
610
1030
  if (cb) {
611
- uv_fs_req_init_async(loop, req, UV_FS_STAT, cb);
1031
+ uv_fs_req_init_async(loop, req, UV_FS_STAT, NULL, cb);
612
1032
  if (path2) {
613
- WRAP_REQ_ARGS1(req, path2);
614
- req->flags |= UV_FS_FREE_ARG0;
1033
+ req->path = path2;
615
1034
  } else {
616
- WRAP_REQ_ARGS1(req, path);
617
- STRDUP_ARG(req, 0);
1035
+ req->path = strdup(path);
618
1036
  }
619
1037
 
620
1038
  QUEUE_FS_TP_JOB(loop, req);
@@ -624,6 +1042,46 @@ int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
624
1042
  if (path2) {
625
1043
  free(path2);
626
1044
  }
1045
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1046
+ return req->result;
1047
+ }
1048
+
1049
+ return 0;
1050
+ }
1051
+
1052
+
1053
+ /* TODO: add support for links. */
1054
+ int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
1055
+ int len = strlen(path);
1056
+ char* path2 = NULL;
1057
+ int has_backslash = (path[len - 1] == '\\' || path[len - 1] == '/');
1058
+
1059
+ if (path[len - 1] == '\\' || path[len - 1] == '/') {
1060
+ path2 = strdup(path);
1061
+ if (!path2) {
1062
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
1063
+ }
1064
+
1065
+ path2[len - 1] = '\0';
1066
+ }
1067
+
1068
+ if (cb) {
1069
+ uv_fs_req_init_async(loop, req, UV_FS_LSTAT, NULL, cb);
1070
+ if (path2) {
1071
+ req->path = path2;
1072
+ } else {
1073
+ req->path = strdup(path);
1074
+ }
1075
+
1076
+ QUEUE_FS_TP_JOB(loop, req);
1077
+ } else {
1078
+ uv_fs_req_init_sync(loop, req, UV_FS_LSTAT);
1079
+ fs__stat(req, path2 ? path2 : path);
1080
+ if (path2) {
1081
+ free(path2);
1082
+ }
1083
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1084
+ return req->result;
627
1085
  }
628
1086
 
629
1087
  return 0;
@@ -632,12 +1090,14 @@ int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
632
1090
 
633
1091
  int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
634
1092
  if (cb) {
635
- uv_fs_req_init_async(loop, req, UV_FS_FSTAT, cb);
1093
+ uv_fs_req_init_async(loop, req, UV_FS_FSTAT, NULL, cb);
636
1094
  WRAP_REQ_ARGS1(req, file);
637
1095
  QUEUE_FS_TP_JOB(loop, req);
638
1096
  } else {
639
1097
  uv_fs_req_init_sync(loop, req, UV_FS_FSTAT);
640
1098
  fs__fstat(req, file);
1099
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1100
+ return req->result;
641
1101
  }
642
1102
 
643
1103
  return 0;
@@ -647,14 +1107,15 @@ int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
647
1107
  int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path,
648
1108
  const char* new_path, uv_fs_cb cb) {
649
1109
  if (cb) {
650
- uv_fs_req_init_async(loop, req, UV_FS_RENAME, cb);
651
- WRAP_REQ_ARGS2(req, path, new_path);
1110
+ uv_fs_req_init_async(loop, req, UV_FS_RENAME, path, cb);
1111
+ WRAP_REQ_ARGS1(req, new_path);
652
1112
  STRDUP_ARG(req, 0);
653
- STRDUP_ARG(req, 1);
654
1113
  QUEUE_FS_TP_JOB(loop, req);
655
1114
  } else {
656
1115
  uv_fs_req_init_sync(loop, req, UV_FS_RENAME);
657
1116
  fs__rename(req, path, new_path);
1117
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1118
+ return req->result;
658
1119
  }
659
1120
 
660
1121
  return 0;
@@ -663,12 +1124,14 @@ int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path,
663
1124
 
664
1125
  int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
665
1126
  if (cb) {
666
- uv_fs_req_init_async(loop, req, UV_FS_FDATASYNC, cb);
1127
+ uv_fs_req_init_async(loop, req, UV_FS_FDATASYNC, NULL, cb);
667
1128
  WRAP_REQ_ARGS1(req, file);
668
1129
  QUEUE_FS_TP_JOB(loop, req);
669
1130
  } else {
670
1131
  uv_fs_req_init_sync(loop, req, UV_FS_FDATASYNC);
671
1132
  fs__fsync(req, file);
1133
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1134
+ return req->result;
672
1135
  }
673
1136
 
674
1137
  return 0;
@@ -677,12 +1140,14 @@ int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
677
1140
 
678
1141
  int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
679
1142
  if (cb) {
680
- uv_fs_req_init_async(loop, req, UV_FS_FSYNC, cb);
1143
+ uv_fs_req_init_async(loop, req, UV_FS_FSYNC, NULL, cb);
681
1144
  WRAP_REQ_ARGS1(req, file);
682
1145
  QUEUE_FS_TP_JOB(loop, req);
683
1146
  } else {
684
1147
  uv_fs_req_init_sync(loop, req, UV_FS_FSYNC);
685
1148
  fs__fsync(req, file);
1149
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1150
+ return req->result;
686
1151
  }
687
1152
 
688
1153
  return 0;
@@ -692,12 +1157,14 @@ int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
692
1157
  int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file file,
693
1158
  off_t offset, uv_fs_cb cb) {
694
1159
  if (cb) {
695
- uv_fs_req_init_async(loop, req, UV_FS_FTRUNCATE, cb);
1160
+ uv_fs_req_init_async(loop, req, UV_FS_FTRUNCATE, NULL, cb);
696
1161
  WRAP_REQ_ARGS2(req, file, offset);
697
1162
  QUEUE_FS_TP_JOB(loop, req);
698
1163
  } else {
699
1164
  uv_fs_req_init_sync(loop, req, UV_FS_FTRUNCATE);
700
1165
  fs__ftruncate(req, file, offset);
1166
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1167
+ return req->result;
701
1168
  }
702
1169
 
703
1170
  return 0;
@@ -707,12 +1174,14 @@ int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file file,
707
1174
  int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file out_fd,
708
1175
  uv_file in_fd, off_t in_offset, size_t length, uv_fs_cb cb) {
709
1176
  if (cb) {
710
- uv_fs_req_init_async(loop, req, UV_FS_SENDFILE, cb);
1177
+ uv_fs_req_init_async(loop, req, UV_FS_SENDFILE, NULL, cb);
711
1178
  WRAP_REQ_ARGS4(req, out_fd, in_fd, in_offset, length);
712
1179
  QUEUE_FS_TP_JOB(loop, req);
713
1180
  } else {
714
1181
  uv_fs_req_init_sync(loop, req, UV_FS_SENDFILE);
715
1182
  fs__sendfile(req, out_fd, in_fd, in_offset, length);
1183
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1184
+ return req->result;
716
1185
  }
717
1186
 
718
1187
  return 0;
@@ -722,13 +1191,31 @@ int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file out_fd,
722
1191
  int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
723
1192
  uv_fs_cb cb) {
724
1193
  if (cb) {
725
- uv_fs_req_init_async(loop, req, UV_FS_CHMOD, cb);
726
- WRAP_REQ_ARGS2(req, path, mode);
727
- STRDUP_ARG(req, 0);
1194
+ uv_fs_req_init_async(loop, req, UV_FS_CHMOD, path, cb);
1195
+ WRAP_REQ_ARGS1(req, mode);
728
1196
  QUEUE_FS_TP_JOB(loop, req);
729
1197
  } else {
730
1198
  uv_fs_req_init_sync(loop, req, UV_FS_CHMOD);
731
1199
  fs__chmod(req, path, mode);
1200
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1201
+ return req->result;
1202
+ }
1203
+
1204
+ return 0;
1205
+ }
1206
+
1207
+
1208
+ int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file file, int mode,
1209
+ uv_fs_cb cb) {
1210
+ if (cb) {
1211
+ uv_fs_req_init_async(loop, req, UV_FS_FCHMOD, NULL, cb);
1212
+ WRAP_REQ_ARGS2(req, file, mode);
1213
+ QUEUE_FS_TP_JOB(loop, req);
1214
+ } else {
1215
+ uv_fs_req_init_sync(loop, req, UV_FS_FCHMOD);
1216
+ fs__fchmod(req, file, mode);
1217
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1218
+ return req->result;
732
1219
  }
733
1220
 
734
1221
  return 0;
@@ -738,15 +1225,15 @@ int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
738
1225
  int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
739
1226
  double mtime, uv_fs_cb cb) {
740
1227
  if (cb) {
741
- uv_fs_req_init_async(loop, req, UV_FS_UTIME, cb);
742
- WRAP_REQ_ARGS1(req, path);
743
- STRDUP_ARG(req, 0);
1228
+ uv_fs_req_init_async(loop, req, UV_FS_UTIME, path, cb);
744
1229
  req->arg4 = (ssize_t)atime;
745
1230
  req->arg5 = (ssize_t)mtime;
746
1231
  QUEUE_FS_TP_JOB(loop, req);
747
1232
  } else {
748
1233
  uv_fs_req_init_sync(loop, req, UV_FS_UTIME);
749
1234
  fs__utime(req, path, atime, mtime);
1235
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1236
+ return req->result;
750
1237
  }
751
1238
 
752
1239
  return 0;
@@ -756,7 +1243,7 @@ int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
756
1243
  int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, double atime,
757
1244
  double mtime, uv_fs_cb cb) {
758
1245
  if (cb) {
759
- uv_fs_req_init_async(loop, req, UV_FS_FUTIME, cb);
1246
+ uv_fs_req_init_async(loop, req, UV_FS_FUTIME, NULL, cb);
760
1247
  WRAP_REQ_ARGS1(req, file);
761
1248
  req->arg4 = (ssize_t)atime;
762
1249
  req->arg5 = (ssize_t)mtime;
@@ -764,6 +1251,8 @@ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, double atime,
764
1251
  } else {
765
1252
  uv_fs_req_init_sync(loop, req, UV_FS_FUTIME);
766
1253
  fs__futime(req, file, atime, mtime);
1254
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1255
+ return req->result;
767
1256
  }
768
1257
 
769
1258
  return 0;
@@ -772,6 +1261,7 @@ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, double atime,
772
1261
 
773
1262
  void uv_process_fs_req(uv_loop_t* loop, uv_fs_t* req) {
774
1263
  assert(req->cb);
1264
+ SET_UV_LAST_ERROR_FROM_REQ(req);
775
1265
  req->cb(req);
776
1266
  }
777
1267
 
@@ -799,6 +1289,11 @@ void uv_fs_req_cleanup(uv_fs_t* req) {
799
1289
 
800
1290
  req->ptr = NULL;
801
1291
 
1292
+ if (req->path) {
1293
+ free(req->path);
1294
+ req->path = NULL;
1295
+ }
1296
+
802
1297
  if (req->flags & UV_FS_ASYNC_QUEUED) {
803
1298
  uv_unref(loop);
804
1299
  }