rbuv 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (233) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +5 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +5 -0
  5. data/Gemfile +0 -1
  6. data/README.md +6 -1
  7. data/Rakefile +42 -0
  8. data/deps/libuv/.gitignore +34 -0
  9. data/deps/libuv/.mailmap +16 -0
  10. data/deps/libuv/AUTHORS +81 -0
  11. data/deps/libuv/ChangeLog +45 -0
  12. data/deps/libuv/LICENSE +41 -0
  13. data/deps/libuv/Makefile +53 -0
  14. data/deps/libuv/README.md +118 -0
  15. data/deps/libuv/build.mk +164 -0
  16. data/deps/libuv/checksparse.sh +230 -0
  17. data/deps/libuv/common.gypi +197 -0
  18. data/deps/libuv/config-mingw.mk +48 -0
  19. data/deps/libuv/config-unix.mk +167 -0
  20. data/deps/libuv/gyp_uv +98 -0
  21. data/deps/libuv/include/uv-private/ngx-queue.h +129 -0
  22. data/deps/libuv/include/uv-private/stdint-msvc2008.h +247 -0
  23. data/deps/libuv/include/uv-private/tree.h +768 -0
  24. data/deps/libuv/include/uv-private/uv-bsd.h +34 -0
  25. data/deps/libuv/include/uv-private/uv-darwin.h +61 -0
  26. data/deps/libuv/include/uv-private/uv-linux.h +34 -0
  27. data/deps/libuv/include/uv-private/uv-sunos.h +44 -0
  28. data/deps/libuv/include/uv-private/uv-unix.h +332 -0
  29. data/deps/libuv/include/uv-private/uv-win.h +585 -0
  30. data/deps/libuv/include/uv.h +1987 -0
  31. data/deps/libuv/src/fs-poll.c +248 -0
  32. data/deps/libuv/src/inet.c +298 -0
  33. data/deps/libuv/src/unix/aix.c +393 -0
  34. data/deps/libuv/src/unix/async.c +281 -0
  35. data/deps/libuv/src/unix/core.c +714 -0
  36. data/deps/libuv/src/unix/cygwin.c +93 -0
  37. data/deps/libuv/src/unix/darwin-proctitle.m +78 -0
  38. data/deps/libuv/src/unix/darwin.c +431 -0
  39. data/deps/libuv/src/unix/dl.c +83 -0
  40. data/deps/libuv/src/unix/error.c +109 -0
  41. data/deps/libuv/src/unix/freebsd.c +343 -0
  42. data/deps/libuv/src/unix/fs.c +869 -0
  43. data/deps/libuv/src/unix/fsevents.c +299 -0
  44. data/deps/libuv/src/unix/getaddrinfo.c +159 -0
  45. data/deps/libuv/src/unix/internal.h +259 -0
  46. data/deps/libuv/src/unix/kqueue.c +347 -0
  47. data/deps/libuv/src/unix/linux-core.c +724 -0
  48. data/deps/libuv/src/unix/linux-inotify.c +236 -0
  49. data/deps/libuv/src/unix/linux-syscalls.c +388 -0
  50. data/deps/libuv/src/unix/linux-syscalls.h +150 -0
  51. data/deps/libuv/src/unix/loop-watcher.c +64 -0
  52. data/deps/libuv/src/unix/loop.c +114 -0
  53. data/deps/libuv/src/unix/netbsd.c +353 -0
  54. data/deps/libuv/src/unix/openbsd.c +304 -0
  55. data/deps/libuv/src/unix/pipe.c +261 -0
  56. data/deps/libuv/src/unix/poll.c +108 -0
  57. data/deps/libuv/src/unix/process.c +501 -0
  58. data/deps/libuv/src/unix/proctitle.c +103 -0
  59. data/deps/libuv/src/unix/signal.c +455 -0
  60. data/deps/libuv/src/unix/stream.c +1380 -0
  61. data/deps/libuv/src/unix/sunos.c +647 -0
  62. data/deps/libuv/src/unix/tcp.c +357 -0
  63. data/deps/libuv/src/unix/thread.c +431 -0
  64. data/deps/libuv/src/unix/threadpool.c +286 -0
  65. data/deps/libuv/src/unix/timer.c +153 -0
  66. data/deps/libuv/src/unix/tty.c +179 -0
  67. data/deps/libuv/src/unix/udp.c +715 -0
  68. data/deps/libuv/src/uv-common.c +431 -0
  69. data/deps/libuv/src/uv-common.h +204 -0
  70. data/deps/libuv/src/version.c +60 -0
  71. data/deps/libuv/src/win/async.c +99 -0
  72. data/deps/libuv/src/win/atomicops-inl.h +56 -0
  73. data/deps/libuv/src/win/core.c +310 -0
  74. data/deps/libuv/src/win/dl.c +86 -0
  75. data/deps/libuv/src/win/error.c +164 -0
  76. data/deps/libuv/src/win/fs-event.c +506 -0
  77. data/deps/libuv/src/win/fs.c +1951 -0
  78. data/deps/libuv/src/win/getaddrinfo.c +365 -0
  79. data/deps/libuv/src/win/handle-inl.h +164 -0
  80. data/deps/libuv/src/win/handle.c +153 -0
  81. data/deps/libuv/src/win/internal.h +346 -0
  82. data/deps/libuv/src/win/loop-watcher.c +124 -0
  83. data/deps/libuv/src/win/pipe.c +1656 -0
  84. data/deps/libuv/src/win/poll.c +615 -0
  85. data/deps/libuv/src/win/process-stdio.c +503 -0
  86. data/deps/libuv/src/win/process.c +1048 -0
  87. data/deps/libuv/src/win/req-inl.h +224 -0
  88. data/deps/libuv/src/win/req.c +25 -0
  89. data/deps/libuv/src/win/signal.c +354 -0
  90. data/deps/libuv/src/win/stream-inl.h +67 -0
  91. data/deps/libuv/src/win/stream.c +198 -0
  92. data/deps/libuv/src/win/tcp.c +1422 -0
  93. data/deps/libuv/src/win/thread.c +666 -0
  94. data/deps/libuv/src/win/threadpool.c +82 -0
  95. data/deps/libuv/src/win/timer.c +230 -0
  96. data/deps/libuv/src/win/tty.c +1857 -0
  97. data/deps/libuv/src/win/udp.c +744 -0
  98. data/deps/libuv/src/win/util.c +946 -0
  99. data/deps/libuv/src/win/winapi.c +152 -0
  100. data/deps/libuv/src/win/winapi.h +4476 -0
  101. data/deps/libuv/src/win/winsock.c +560 -0
  102. data/deps/libuv/src/win/winsock.h +171 -0
  103. data/deps/libuv/test/benchmark-async-pummel.c +119 -0
  104. data/deps/libuv/test/benchmark-async.c +139 -0
  105. data/deps/libuv/test/benchmark-fs-stat.c +136 -0
  106. data/deps/libuv/test/benchmark-getaddrinfo.c +91 -0
  107. data/deps/libuv/test/benchmark-list.h +163 -0
  108. data/deps/libuv/test/benchmark-loop-count.c +90 -0
  109. data/deps/libuv/test/benchmark-million-async.c +112 -0
  110. data/deps/libuv/test/benchmark-million-timers.c +77 -0
  111. data/deps/libuv/test/benchmark-multi-accept.c +432 -0
  112. data/deps/libuv/test/benchmark-ping-pongs.c +212 -0
  113. data/deps/libuv/test/benchmark-pound.c +325 -0
  114. data/deps/libuv/test/benchmark-pump.c +459 -0
  115. data/deps/libuv/test/benchmark-sizes.c +45 -0
  116. data/deps/libuv/test/benchmark-spawn.c +163 -0
  117. data/deps/libuv/test/benchmark-tcp-write-batch.c +141 -0
  118. data/deps/libuv/test/benchmark-thread.c +64 -0
  119. data/deps/libuv/test/benchmark-udp-pummel.c +238 -0
  120. data/deps/libuv/test/blackhole-server.c +118 -0
  121. data/deps/libuv/test/dns-server.c +329 -0
  122. data/deps/libuv/test/echo-server.c +384 -0
  123. data/deps/libuv/test/fixtures/empty_file +0 -0
  124. data/deps/libuv/test/fixtures/load_error.node +1 -0
  125. data/deps/libuv/test/run-benchmarks.c +64 -0
  126. data/deps/libuv/test/run-tests.c +159 -0
  127. data/deps/libuv/test/runner-unix.c +328 -0
  128. data/deps/libuv/test/runner-unix.h +36 -0
  129. data/deps/libuv/test/runner-win.c +318 -0
  130. data/deps/libuv/test/runner-win.h +43 -0
  131. data/deps/libuv/test/runner.c +394 -0
  132. data/deps/libuv/test/runner.h +165 -0
  133. data/deps/libuv/test/task.h +122 -0
  134. data/deps/libuv/test/test-active.c +83 -0
  135. data/deps/libuv/test/test-async.c +136 -0
  136. data/deps/libuv/test/test-barrier.c +98 -0
  137. data/deps/libuv/test/test-callback-order.c +77 -0
  138. data/deps/libuv/test/test-callback-stack.c +204 -0
  139. data/deps/libuv/test/test-condvar.c +173 -0
  140. data/deps/libuv/test/test-connection-fail.c +150 -0
  141. data/deps/libuv/test/test-cwd-and-chdir.c +64 -0
  142. data/deps/libuv/test/test-delayed-accept.c +189 -0
  143. data/deps/libuv/test/test-dlerror.c +58 -0
  144. data/deps/libuv/test/test-embed.c +136 -0
  145. data/deps/libuv/test/test-error.c +59 -0
  146. data/deps/libuv/test/test-fail-always.c +29 -0
  147. data/deps/libuv/test/test-fs-event.c +504 -0
  148. data/deps/libuv/test/test-fs-poll.c +148 -0
  149. data/deps/libuv/test/test-fs.c +1899 -0
  150. data/deps/libuv/test/test-get-currentexe.c +63 -0
  151. data/deps/libuv/test/test-get-loadavg.c +36 -0
  152. data/deps/libuv/test/test-get-memory.c +38 -0
  153. data/deps/libuv/test/test-getaddrinfo.c +120 -0
  154. data/deps/libuv/test/test-getsockname.c +344 -0
  155. data/deps/libuv/test/test-hrtime.c +54 -0
  156. data/deps/libuv/test/test-idle.c +82 -0
  157. data/deps/libuv/test/test-ipc-send-recv.c +218 -0
  158. data/deps/libuv/test/test-ipc.c +625 -0
  159. data/deps/libuv/test/test-list.h +492 -0
  160. data/deps/libuv/test/test-loop-handles.c +337 -0
  161. data/deps/libuv/test/test-loop-stop.c +73 -0
  162. data/deps/libuv/test/test-multiple-listen.c +103 -0
  163. data/deps/libuv/test/test-mutexes.c +63 -0
  164. data/deps/libuv/test/test-pass-always.c +28 -0
  165. data/deps/libuv/test/test-ping-pong.c +250 -0
  166. data/deps/libuv/test/test-pipe-bind-error.c +144 -0
  167. data/deps/libuv/test/test-pipe-connect-error.c +98 -0
  168. data/deps/libuv/test/test-platform-output.c +87 -0
  169. data/deps/libuv/test/test-poll-close.c +73 -0
  170. data/deps/libuv/test/test-poll.c +575 -0
  171. data/deps/libuv/test/test-process-title.c +49 -0
  172. data/deps/libuv/test/test-ref.c +415 -0
  173. data/deps/libuv/test/test-run-nowait.c +46 -0
  174. data/deps/libuv/test/test-run-once.c +49 -0
  175. data/deps/libuv/test/test-semaphore.c +111 -0
  176. data/deps/libuv/test/test-shutdown-close.c +105 -0
  177. data/deps/libuv/test/test-shutdown-eof.c +184 -0
  178. data/deps/libuv/test/test-signal-multiple-loops.c +270 -0
  179. data/deps/libuv/test/test-signal.c +152 -0
  180. data/deps/libuv/test/test-spawn.c +938 -0
  181. data/deps/libuv/test/test-stdio-over-pipes.c +250 -0
  182. data/deps/libuv/test/test-tcp-bind-error.c +198 -0
  183. data/deps/libuv/test/test-tcp-bind6-error.c +159 -0
  184. data/deps/libuv/test/test-tcp-close-while-connecting.c +81 -0
  185. data/deps/libuv/test/test-tcp-close.c +130 -0
  186. data/deps/libuv/test/test-tcp-connect-error-after-write.c +96 -0
  187. data/deps/libuv/test/test-tcp-connect-error.c +71 -0
  188. data/deps/libuv/test/test-tcp-connect-timeout.c +86 -0
  189. data/deps/libuv/test/test-tcp-connect6-error.c +69 -0
  190. data/deps/libuv/test/test-tcp-flags.c +52 -0
  191. data/deps/libuv/test/test-tcp-open.c +175 -0
  192. data/deps/libuv/test/test-tcp-read-stop.c +73 -0
  193. data/deps/libuv/test/test-tcp-shutdown-after-write.c +132 -0
  194. data/deps/libuv/test/test-tcp-unexpected-read.c +114 -0
  195. data/deps/libuv/test/test-tcp-write-to-half-open-connection.c +136 -0
  196. data/deps/libuv/test/test-tcp-writealot.c +171 -0
  197. data/deps/libuv/test/test-thread.c +183 -0
  198. data/deps/libuv/test/test-threadpool-cancel.c +311 -0
  199. data/deps/libuv/test/test-threadpool.c +77 -0
  200. data/deps/libuv/test/test-timer-again.c +142 -0
  201. data/deps/libuv/test/test-timer.c +266 -0
  202. data/deps/libuv/test/test-tty.c +111 -0
  203. data/deps/libuv/test/test-udp-dgram-too-big.c +87 -0
  204. data/deps/libuv/test/test-udp-ipv6.c +158 -0
  205. data/deps/libuv/test/test-udp-multicast-join.c +140 -0
  206. data/deps/libuv/test/test-udp-multicast-ttl.c +87 -0
  207. data/deps/libuv/test/test-udp-open.c +154 -0
  208. data/deps/libuv/test/test-udp-options.c +87 -0
  209. data/deps/libuv/test/test-udp-send-and-recv.c +210 -0
  210. data/deps/libuv/test/test-util.c +97 -0
  211. data/deps/libuv/test/test-walk-handles.c +78 -0
  212. data/deps/libuv/uv.gyp +431 -0
  213. data/deps/libuv/vcbuild.bat +128 -0
  214. data/ext/rbuv/debug.h +27 -0
  215. data/ext/rbuv/error.c +7 -0
  216. data/ext/rbuv/error.h +10 -0
  217. data/ext/rbuv/extconf.rb +35 -0
  218. data/ext/rbuv/handle.c +40 -0
  219. data/ext/rbuv/handle.h +14 -0
  220. data/ext/rbuv/libuv.mk +12 -0
  221. data/ext/rbuv/loop.c +50 -0
  222. data/ext/rbuv/loop.h +13 -0
  223. data/ext/rbuv/rbuv.c +15 -0
  224. data/ext/rbuv/rbuv.h +27 -0
  225. data/ext/rbuv/timer.c +133 -0
  226. data/ext/rbuv/timer.h +13 -0
  227. data/lib/rbuv/timer.rb +7 -0
  228. data/lib/rbuv/version.rb +1 -1
  229. data/lib/rbuv.rb +24 -2
  230. data/rbuv.gemspec +5 -1
  231. data/spec/spec_helper.rb +22 -0
  232. data/spec/timer_spec.rb +144 -0
  233. metadata +278 -9
@@ -0,0 +1,1951 @@
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 <direct.h>
25
+ #include <errno.h>
26
+ #include <fcntl.h>
27
+ #include <io.h>
28
+ #include <limits.h>
29
+ #include <sys/stat.h>
30
+ #include <sys/utime.h>
31
+ #include <stdio.h>
32
+
33
+ #include "uv.h"
34
+ #include "internal.h"
35
+ #include "req-inl.h"
36
+
37
+
38
+ #define UV_FS_FREE_PATHS 0x0002
39
+ #define UV_FS_FREE_PTR 0x0008
40
+ #define UV_FS_CLEANEDUP 0x0010
41
+
42
+
43
+ #define QUEUE_FS_TP_JOB(loop, req) \
44
+ if (!QueueUserWorkItem(&uv_fs_thread_proc, \
45
+ req, \
46
+ WT_EXECUTEDEFAULT)) { \
47
+ uv__set_sys_error((loop), GetLastError()); \
48
+ return -1; \
49
+ } \
50
+ uv__req_register(loop, req);
51
+
52
+ #define SET_UV_LAST_ERROR_FROM_REQ(req) \
53
+ uv__set_error(req->loop, req->errorno, req->sys_errno_);
54
+
55
+ #define SET_REQ_RESULT(req, result_value) \
56
+ req->result = (result_value); \
57
+ if (req->result == -1) { \
58
+ req->sys_errno_ = _doserrno; \
59
+ req->errorno = uv_translate_sys_error(req->sys_errno_); \
60
+ }
61
+
62
+ #define SET_REQ_WIN32_ERROR(req, sys_errno) \
63
+ req->result = -1; \
64
+ req->sys_errno_ = (sys_errno); \
65
+ req->errorno = uv_translate_sys_error(req->sys_errno_);
66
+
67
+ #define SET_REQ_UV_ERROR(req, uv_errno, sys_errno) \
68
+ req->result = -1; \
69
+ req->sys_errno_ = (sys_errno); \
70
+ req->errorno = (uv_errno);
71
+
72
+ #define VERIFY_FD(fd, req) \
73
+ if (fd == -1) { \
74
+ req->result = -1; \
75
+ req->errorno = UV_EBADF; \
76
+ req->sys_errno_ = ERROR_INVALID_HANDLE; \
77
+ return; \
78
+ }
79
+
80
+ #define FILETIME_TO_TIME_T(filetime) \
81
+ ((*((uint64_t*) &(filetime)) - 116444736000000000ULL) / 10000000ULL);
82
+
83
+ #define TIME_T_TO_FILETIME(time, filetime_ptr) \
84
+ do { \
85
+ *(uint64_t*) (filetime_ptr) = ((int64_t) (time) * 10000000LL) + \
86
+ 116444736000000000ULL; \
87
+ } while(0)
88
+
89
+
90
+ #define IS_SLASH(c) ((c) == L'\\' || (c) == L'/')
91
+ #define IS_LETTER(c) (((c) >= L'a' && (c) <= L'z') || \
92
+ ((c) >= L'A' && (c) <= L'Z'))
93
+
94
+ const WCHAR JUNCTION_PREFIX[] = L"\\??\\";
95
+ const WCHAR JUNCTION_PREFIX_LEN = 4;
96
+
97
+ const WCHAR LONG_PATH_PREFIX[] = L"\\\\?\\";
98
+ const WCHAR LONG_PATH_PREFIX_LEN = 4;
99
+
100
+
101
+ void uv_fs_init() {
102
+ _fmode = _O_BINARY;
103
+ }
104
+
105
+
106
+ INLINE static int fs__capture_path(uv_loop_t* loop, uv_fs_t* req,
107
+ const char* path, const char* new_path, const int copy_path) {
108
+ char* buf;
109
+ char* pos;
110
+ ssize_t buf_sz = 0, path_len, pathw_len, new_pathw_len;
111
+
112
+ /* new_path can only be set if path is also set. */
113
+ assert(new_path == NULL || path != NULL);
114
+
115
+ if (path != NULL) {
116
+ pathw_len = MultiByteToWideChar(CP_UTF8,
117
+ 0,
118
+ path,
119
+ -1,
120
+ NULL,
121
+ 0);
122
+ if (pathw_len == 0) {
123
+ uv__set_sys_error(loop, GetLastError());
124
+ return -1;
125
+ }
126
+
127
+ buf_sz += pathw_len * sizeof(WCHAR);
128
+ }
129
+
130
+ if (path != NULL && copy_path) {
131
+ path_len = 1 + strlen(path);
132
+ buf_sz += path_len;
133
+ }
134
+
135
+ if (new_path != NULL) {
136
+ new_pathw_len = MultiByteToWideChar(CP_UTF8,
137
+ 0,
138
+ new_path,
139
+ -1,
140
+ NULL,
141
+ 0);
142
+ if (new_pathw_len == 0) {
143
+ uv__set_sys_error(loop, GetLastError());
144
+ return -1;
145
+ }
146
+
147
+ buf_sz += new_pathw_len * sizeof(WCHAR);
148
+ }
149
+
150
+
151
+ if (buf_sz == 0) {
152
+ req->pathw = NULL;
153
+ req->new_pathw = NULL;
154
+ req->path = NULL;
155
+ return 0;
156
+ }
157
+
158
+ buf = (char*) malloc(buf_sz);
159
+ if (buf == NULL) {
160
+ uv__set_artificial_error(loop, UV_ENOMEM);
161
+ return -1;
162
+ }
163
+
164
+ pos = buf;
165
+
166
+ if (path != NULL) {
167
+ DWORD r = MultiByteToWideChar(CP_UTF8,
168
+ 0,
169
+ path,
170
+ -1,
171
+ (WCHAR*) pos,
172
+ pathw_len);
173
+ assert(r == pathw_len);
174
+ req->pathw = (WCHAR*) pos;
175
+ pos += r * sizeof(WCHAR);
176
+ } else {
177
+ req->pathw = NULL;
178
+ }
179
+
180
+ if (new_path != NULL) {
181
+ DWORD r = MultiByteToWideChar(CP_UTF8,
182
+ 0,
183
+ new_path,
184
+ -1,
185
+ (WCHAR*) pos,
186
+ new_pathw_len);
187
+ assert(r == new_pathw_len);
188
+ req->new_pathw = (WCHAR*) pos;
189
+ pos += r * sizeof(WCHAR);
190
+ } else {
191
+ req->new_pathw = NULL;
192
+ }
193
+
194
+ if (!copy_path) {
195
+ req->path = path;
196
+ } else if (path) {
197
+ memcpy(pos, path, path_len);
198
+ assert(path_len == buf_sz - (pos - buf));
199
+ req->path = pos;
200
+ } else {
201
+ req->path = NULL;
202
+ }
203
+
204
+ req->flags |= UV_FS_FREE_PATHS;
205
+
206
+ return 0;
207
+ }
208
+
209
+
210
+
211
+ INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req,
212
+ uv_fs_type fs_type, const uv_fs_cb cb) {
213
+ uv_req_init(loop, (uv_req_t*) req);
214
+
215
+ req->type = UV_FS;
216
+ req->loop = loop;
217
+ req->flags = 0;
218
+ req->fs_type = fs_type;
219
+ req->result = 0;
220
+ req->ptr = NULL;
221
+ req->errorno = UV_OK;
222
+ req->path = NULL;
223
+
224
+ if (cb != NULL) {
225
+ req->cb = cb;
226
+ memset(&req->overlapped, 0, sizeof(req->overlapped));
227
+ }
228
+ }
229
+
230
+
231
+ static int is_path_dir(const WCHAR* path) {
232
+ DWORD attr = GetFileAttributesW(path);
233
+
234
+ if (attr != INVALID_FILE_ATTRIBUTES) {
235
+ return attr & FILE_ATTRIBUTE_DIRECTORY ? 1 : 0;
236
+ } else {
237
+ return 0;
238
+ }
239
+ }
240
+
241
+
242
+ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
243
+ int64_t* target_len_ptr) {
244
+ char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
245
+ REPARSE_DATA_BUFFER* reparse_data = (REPARSE_DATA_BUFFER*) buffer;
246
+ WCHAR *w_target;
247
+ DWORD w_target_len;
248
+ char* target;
249
+ int target_len;
250
+ DWORD bytes;
251
+
252
+ if (!DeviceIoControl(handle,
253
+ FSCTL_GET_REPARSE_POINT,
254
+ NULL,
255
+ 0,
256
+ buffer,
257
+ sizeof buffer,
258
+ &bytes,
259
+ NULL)) {
260
+ return -1;
261
+ }
262
+
263
+ if (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
264
+ /* Real symlink */
265
+ w_target = reparse_data->SymbolicLinkReparseBuffer.PathBuffer +
266
+ (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset /
267
+ sizeof(WCHAR));
268
+ w_target_len =
269
+ reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength /
270
+ sizeof(WCHAR);
271
+
272
+ /* Real symlinks can contain pretty much everything, but the only thing */
273
+ /* we really care about is undoing the implicit conversion to an NT */
274
+ /* namespaced path that CreateSymbolicLink will perform on absolute */
275
+ /* paths. If the path is win32-namespaced then the user must have */
276
+ /* explicitly made it so, and we better just return the unmodified */
277
+ /* reparse data. */
278
+ if (w_target_len >= 4 &&
279
+ w_target[0] == L'\\' &&
280
+ w_target[1] == L'?' &&
281
+ w_target[2] == L'?' &&
282
+ w_target[3] == L'\\') {
283
+ /* Starts with \??\ */
284
+ if (w_target_len >= 6 &&
285
+ ((w_target[4] >= L'A' && w_target[4] <= L'Z') ||
286
+ (w_target[4] >= L'a' && w_target[4] <= L'z')) &&
287
+ w_target[5] == L':' &&
288
+ (w_target_len == 6 || w_target[6] == L'\\')) {
289
+ /* \??\�drive�:\ */
290
+ w_target += 4;
291
+ w_target_len -= 4;
292
+
293
+ } else if (w_target_len >= 8 &&
294
+ (w_target[4] == L'U' || w_target[4] == L'u') &&
295
+ (w_target[5] == L'N' || w_target[5] == L'n') &&
296
+ (w_target[6] == L'C' || w_target[6] == L'c') &&
297
+ w_target[7] == L'\\') {
298
+ /* \??\UNC\�server�\�share�\ - make sure the final path looks like */
299
+ /* \\�server�\�share�\ */
300
+ w_target += 6;
301
+ w_target[0] = L'\\';
302
+ w_target_len -= 6;
303
+ }
304
+ }
305
+
306
+ } else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
307
+ /* Junction. */
308
+ w_target = reparse_data->MountPointReparseBuffer.PathBuffer +
309
+ (reparse_data->MountPointReparseBuffer.SubstituteNameOffset /
310
+ sizeof(WCHAR));
311
+ w_target_len = reparse_data->MountPointReparseBuffer.SubstituteNameLength /
312
+ sizeof(WCHAR);
313
+
314
+ /* Only treat junctions that look like \??\�drive�:\ as symlink. */
315
+ /* Junctions can also be used as mount points, like \??\Volume{�guid�}, */
316
+ /* but that's confusing for programs since they wouldn't be able to */
317
+ /* actually understand such a path when returned by uv_readlink(). */
318
+ /* UNC paths are never valid for junctions so we don't care about them. */
319
+ if (!(w_target_len >= 6 &&
320
+ w_target[0] == L'\\' &&
321
+ w_target[1] == L'?' &&
322
+ w_target[2] == L'?' &&
323
+ w_target[3] == L'\\' &&
324
+ ((w_target[4] >= L'A' && w_target[4] <= L'Z') ||
325
+ (w_target[4] >= L'a' && w_target[4] <= L'z')) &&
326
+ w_target[5] == L':' &&
327
+ (w_target_len == 6 || w_target[6] == L'\\'))) {
328
+ SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
329
+ return -1;
330
+ }
331
+
332
+ /* Remove leading \??\ */
333
+ w_target += 4;
334
+ w_target_len -= 4;
335
+
336
+ } else {
337
+ /* Reparse tag does not indicate a symlink. */
338
+ SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
339
+ return -1;
340
+ }
341
+
342
+ /* If needed, compute the length of the target. */
343
+ if (target_ptr != NULL || target_len_ptr != NULL) {
344
+ /* Compute the length of the target. */
345
+ target_len = WideCharToMultiByte(CP_UTF8,
346
+ 0,
347
+ w_target,
348
+ w_target_len,
349
+ NULL,
350
+ 0,
351
+ NULL,
352
+ NULL);
353
+ if (target_len == 0) {
354
+ return -1;
355
+ }
356
+ }
357
+
358
+ /* If requested, allocate memory and convert to UTF8. */
359
+ if (target_ptr != NULL) {
360
+ int r;
361
+ target = (char*) malloc(target_len + 1);
362
+ if (target == NULL) {
363
+ SetLastError(ERROR_OUTOFMEMORY);
364
+ return -1;
365
+ }
366
+
367
+ r = WideCharToMultiByte(CP_UTF8,
368
+ 0,
369
+ w_target,
370
+ w_target_len,
371
+ target,
372
+ target_len,
373
+ NULL,
374
+ NULL);
375
+ assert(r == target_len);
376
+ target[target_len] = '\0';
377
+
378
+ *target_ptr = target;
379
+ }
380
+
381
+ if (target_len_ptr != NULL) {
382
+ *target_len_ptr = target_len;
383
+ }
384
+
385
+ return 0;
386
+ }
387
+
388
+
389
+ void fs__open(uv_fs_t* req) {
390
+ DWORD access;
391
+ DWORD share;
392
+ DWORD disposition;
393
+ DWORD attributes = 0;
394
+ HANDLE file;
395
+ int result, current_umask;
396
+ int flags = req->file_flags;
397
+
398
+ /* Obtain the active umask. umask() never fails and returns the previous */
399
+ /* umask. */
400
+ current_umask = umask(0);
401
+ umask(current_umask);
402
+
403
+ /* convert flags and mode to CreateFile parameters */
404
+ switch (flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
405
+ case _O_RDONLY:
406
+ access = FILE_GENERIC_READ;
407
+ attributes |= FILE_FLAG_BACKUP_SEMANTICS;
408
+ break;
409
+ case _O_WRONLY:
410
+ access = FILE_GENERIC_WRITE;
411
+ break;
412
+ case _O_RDWR:
413
+ access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
414
+ break;
415
+ default:
416
+ result = -1;
417
+ goto end;
418
+ }
419
+
420
+ if (flags & _O_APPEND) {
421
+ access &= ~FILE_WRITE_DATA;
422
+ access |= FILE_APPEND_DATA;
423
+ attributes &= ~FILE_FLAG_BACKUP_SEMANTICS;
424
+ }
425
+
426
+ /*
427
+ * Here is where we deviate significantly from what CRT's _open()
428
+ * does. We indiscriminately use all the sharing modes, to match
429
+ * UNIX semantics. In particular, this ensures that the file can
430
+ * be deleted even whilst it's open, fixing issue #1449.
431
+ */
432
+ share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
433
+
434
+ switch (flags & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
435
+ case 0:
436
+ case _O_EXCL:
437
+ disposition = OPEN_EXISTING;
438
+ break;
439
+ case _O_CREAT:
440
+ disposition = OPEN_ALWAYS;
441
+ break;
442
+ case _O_CREAT | _O_EXCL:
443
+ case _O_CREAT | _O_TRUNC | _O_EXCL:
444
+ disposition = CREATE_NEW;
445
+ break;
446
+ case _O_TRUNC:
447
+ case _O_TRUNC | _O_EXCL:
448
+ disposition = TRUNCATE_EXISTING;
449
+ break;
450
+ case _O_CREAT | _O_TRUNC:
451
+ disposition = CREATE_ALWAYS;
452
+ break;
453
+ default:
454
+ result = -1;
455
+ goto end;
456
+ }
457
+
458
+ attributes |= FILE_ATTRIBUTE_NORMAL;
459
+ if (flags & _O_CREAT) {
460
+ if (!((req->mode & ~current_umask) & _S_IWRITE)) {
461
+ attributes |= FILE_ATTRIBUTE_READONLY;
462
+ }
463
+ }
464
+
465
+ if (flags & _O_TEMPORARY ) {
466
+ attributes |= FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY;
467
+ access |= DELETE;
468
+ }
469
+
470
+ if (flags & _O_SHORT_LIVED) {
471
+ attributes |= FILE_ATTRIBUTE_TEMPORARY;
472
+ }
473
+
474
+ switch (flags & (_O_SEQUENTIAL | _O_RANDOM)) {
475
+ case 0:
476
+ break;
477
+ case _O_SEQUENTIAL:
478
+ attributes |= FILE_FLAG_SEQUENTIAL_SCAN;
479
+ break;
480
+ case _O_RANDOM:
481
+ attributes |= FILE_FLAG_RANDOM_ACCESS;
482
+ break;
483
+ default:
484
+ result = -1;
485
+ goto end;
486
+ }
487
+
488
+ /* Setting this flag makes it possible to open a directory. */
489
+ attributes |= FILE_FLAG_BACKUP_SEMANTICS;
490
+
491
+ file = CreateFileW(req->pathw,
492
+ access,
493
+ share,
494
+ NULL,
495
+ disposition,
496
+ attributes,
497
+ NULL);
498
+ if (file == INVALID_HANDLE_VALUE) {
499
+ DWORD error = GetLastError();
500
+ if (error == ERROR_FILE_EXISTS && (flags & _O_CREAT) &&
501
+ !(flags & _O_EXCL)) {
502
+ /* Special case: when ERROR_FILE_EXISTS happens and O_CREAT was */
503
+ /* specified, it means the path referred to a directory. */
504
+ SET_REQ_UV_ERROR(req, UV_EISDIR, error);
505
+ } else {
506
+ SET_REQ_WIN32_ERROR(req, GetLastError());
507
+ }
508
+ return;
509
+ }
510
+ result = _open_osfhandle((intptr_t) file, flags);
511
+ end:
512
+ SET_REQ_RESULT(req, result);
513
+ }
514
+
515
+ void fs__close(uv_fs_t* req) {
516
+ int fd = req->fd;
517
+ int result;
518
+
519
+ VERIFY_FD(fd, req);
520
+
521
+ result = _close(fd);
522
+ SET_REQ_RESULT(req, result);
523
+ }
524
+
525
+
526
+ void fs__read(uv_fs_t* req) {
527
+ int fd = req->fd;
528
+ size_t length = req->length;
529
+ int64_t offset = req->offset;
530
+ HANDLE handle;
531
+ OVERLAPPED overlapped, *overlapped_ptr;
532
+ LARGE_INTEGER offset_;
533
+ DWORD bytes;
534
+ DWORD error;
535
+
536
+ VERIFY_FD(fd, req);
537
+
538
+ handle = (HANDLE) _get_osfhandle(fd);
539
+ if (handle == INVALID_HANDLE_VALUE) {
540
+ SET_REQ_RESULT(req, -1);
541
+ return;
542
+ }
543
+
544
+ if (length > INT_MAX) {
545
+ SET_REQ_WIN32_ERROR(req, ERROR_INSUFFICIENT_BUFFER);
546
+ return;
547
+ }
548
+
549
+ if (offset != -1) {
550
+ memset(&overlapped, 0, sizeof overlapped);
551
+
552
+ offset_.QuadPart = offset;
553
+ overlapped.Offset = offset_.LowPart;
554
+ overlapped.OffsetHigh = offset_.HighPart;
555
+
556
+ overlapped_ptr = &overlapped;
557
+ } else {
558
+ overlapped_ptr = NULL;
559
+ }
560
+
561
+ if (ReadFile(handle, req->buf, req->length, &bytes, overlapped_ptr)) {
562
+ SET_REQ_RESULT(req, bytes);
563
+ } else {
564
+ error = GetLastError();
565
+ if (error == ERROR_HANDLE_EOF) {
566
+ SET_REQ_RESULT(req, bytes);
567
+ } else {
568
+ SET_REQ_WIN32_ERROR(req, error);
569
+ }
570
+ }
571
+ }
572
+
573
+
574
+ void fs__write(uv_fs_t* req) {
575
+ int fd = req->fd;
576
+ size_t length = req->length;
577
+ int64_t offset = req->offset;
578
+ HANDLE handle;
579
+ OVERLAPPED overlapped, *overlapped_ptr;
580
+ LARGE_INTEGER offset_;
581
+ DWORD bytes;
582
+
583
+ VERIFY_FD(fd, req);
584
+
585
+ handle = (HANDLE) _get_osfhandle(fd);
586
+ if (handle == INVALID_HANDLE_VALUE) {
587
+ SET_REQ_RESULT(req, -1);
588
+ return;
589
+ }
590
+
591
+ if (length > INT_MAX) {
592
+ SET_REQ_WIN32_ERROR(req, ERROR_INSUFFICIENT_BUFFER);
593
+ return;
594
+ }
595
+
596
+ if (offset != -1) {
597
+ memset(&overlapped, 0, sizeof overlapped);
598
+
599
+ offset_.QuadPart = offset;
600
+ overlapped.Offset = offset_.LowPart;
601
+ overlapped.OffsetHigh = offset_.HighPart;
602
+
603
+ overlapped_ptr = &overlapped;
604
+ } else {
605
+ overlapped_ptr = NULL;
606
+ }
607
+
608
+ if (WriteFile(handle, req->buf, length, &bytes, overlapped_ptr)) {
609
+ SET_REQ_RESULT(req, bytes);
610
+ } else {
611
+ SET_REQ_WIN32_ERROR(req, GetLastError());
612
+ }
613
+ }
614
+
615
+
616
+ void fs__rmdir(uv_fs_t* req) {
617
+ int result = _wrmdir(req->pathw);
618
+ SET_REQ_RESULT(req, result);
619
+ }
620
+
621
+
622
+ void fs__unlink(uv_fs_t* req) {
623
+ const WCHAR* pathw = req->pathw;
624
+ HANDLE handle;
625
+ BY_HANDLE_FILE_INFORMATION info;
626
+ FILE_DISPOSITION_INFORMATION disposition;
627
+ IO_STATUS_BLOCK iosb;
628
+ NTSTATUS status;
629
+
630
+ handle = CreateFileW(pathw,
631
+ FILE_READ_ATTRIBUTES | DELETE,
632
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
633
+ NULL,
634
+ OPEN_EXISTING,
635
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
636
+ NULL);
637
+
638
+ if (handle == INVALID_HANDLE_VALUE) {
639
+ SET_REQ_WIN32_ERROR(req, GetLastError());
640
+ return;
641
+ }
642
+
643
+ if (!GetFileInformationByHandle(handle, &info)) {
644
+ SET_REQ_WIN32_ERROR(req, GetLastError());
645
+ CloseHandle(handle);
646
+ return;
647
+ }
648
+
649
+ if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
650
+ /* Do not allow deletion of directories, unless it is a symlink. When */
651
+ /* the path refers to a non-symlink directory, report EPERM as mandated */
652
+ /* by POSIX.1. */
653
+
654
+ /* Check if it is a reparse point. If it's not, it's a normal directory. */
655
+ if (!(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
656
+ SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED);
657
+ CloseHandle(handle);
658
+ return;
659
+ }
660
+
661
+ /* Read the reparse point and check if it is a valid symlink. */
662
+ /* If not, don't unlink. */
663
+ if (fs__readlink_handle(handle, NULL, NULL) < 0) {
664
+ DWORD error = GetLastError();
665
+ if (error == ERROR_SYMLINK_NOT_SUPPORTED)
666
+ error = ERROR_ACCESS_DENIED;
667
+ SET_REQ_WIN32_ERROR(req, error);
668
+ CloseHandle(handle);
669
+ return;
670
+ }
671
+ }
672
+
673
+ /* Try to set the delete flag. */
674
+ disposition.DeleteFile = TRUE;
675
+ status = pNtSetInformationFile(handle,
676
+ &iosb,
677
+ &disposition,
678
+ sizeof disposition,
679
+ FileDispositionInformation);
680
+ if (NT_SUCCESS(status)) {
681
+ SET_REQ_SUCCESS(req);
682
+ } else {
683
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
684
+ }
685
+
686
+ CloseHandle(handle);
687
+ }
688
+
689
+
690
+ void fs__mkdir(uv_fs_t* req) {
691
+ /* TODO: use req->mode. */
692
+ int result = _wmkdir(req->pathw);
693
+ SET_REQ_RESULT(req, result);
694
+ }
695
+
696
+
697
+ void fs__readdir(uv_fs_t* req) {
698
+ WCHAR* pathw = req->pathw;
699
+ size_t len = wcslen(pathw);
700
+ int result, size;
701
+ WCHAR* buf = NULL, *ptr, *name;
702
+ HANDLE dir;
703
+ WIN32_FIND_DATAW ent = { 0 };
704
+ size_t buf_char_len = 4096;
705
+ WCHAR* path2;
706
+ const WCHAR* fmt;
707
+
708
+ if (len == 0) {
709
+ fmt = L"./*";
710
+ } else if (pathw[len - 1] == L'/' || pathw[len - 1] == L'\\') {
711
+ fmt = L"%s*";
712
+ } else {
713
+ fmt = L"%s\\*";
714
+ }
715
+
716
+ /* Figure out whether path is a file or a directory. */
717
+ if (!(GetFileAttributesW(pathw) & FILE_ATTRIBUTE_DIRECTORY)) {
718
+ req->result = -1;
719
+ req->errorno = UV_ENOTDIR;
720
+ req->sys_errno_ = ERROR_SUCCESS;
721
+ return;
722
+ }
723
+
724
+ path2 = (WCHAR*)malloc(sizeof(WCHAR) * (len + 4));
725
+ if (!path2) {
726
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
727
+ }
728
+
729
+ #ifdef _MSC_VER
730
+ swprintf(path2, len + 3, fmt, pathw);
731
+ #else
732
+ swprintf(path2, fmt, pathw);
733
+ #endif
734
+ dir = FindFirstFileW(path2, &ent);
735
+ free(path2);
736
+
737
+ if(dir == INVALID_HANDLE_VALUE) {
738
+ SET_REQ_WIN32_ERROR(req, GetLastError());
739
+ return;
740
+ }
741
+
742
+ result = 0;
743
+
744
+ do {
745
+ name = ent.cFileName;
746
+
747
+ if (name[0] != L'.' || (name[1] && (name[1] != L'.' || name[2]))) {
748
+ len = wcslen(name);
749
+
750
+ if (!buf) {
751
+ buf = (WCHAR*)malloc(buf_char_len * sizeof(WCHAR));
752
+ if (!buf) {
753
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
754
+ }
755
+
756
+ ptr = buf;
757
+ }
758
+
759
+ while ((ptr - buf) + len + 1 > buf_char_len) {
760
+ buf_char_len *= 2;
761
+ path2 = buf;
762
+ buf = (WCHAR*)realloc(buf, buf_char_len * sizeof(WCHAR));
763
+ if (!buf) {
764
+ uv_fatal_error(ERROR_OUTOFMEMORY, "realloc");
765
+ }
766
+
767
+ ptr = buf + (ptr - path2);
768
+ }
769
+
770
+ wcscpy(ptr, name);
771
+ ptr += len + 1;
772
+ result++;
773
+ }
774
+ } while(FindNextFileW(dir, &ent));
775
+
776
+ FindClose(dir);
777
+
778
+ if (buf) {
779
+ /* Convert result to UTF8. */
780
+ size = uv_utf16_to_utf8(buf, buf_char_len, NULL, 0);
781
+ if (!size) {
782
+ SET_REQ_WIN32_ERROR(req, GetLastError());
783
+ return;
784
+ }
785
+
786
+ req->ptr = (char*)malloc(size + 1);
787
+ if (!req->ptr) {
788
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
789
+ }
790
+
791
+ size = uv_utf16_to_utf8(buf, buf_char_len, (char*)req->ptr, size);
792
+ if (!size) {
793
+ free(buf);
794
+ free(req->ptr);
795
+ req->ptr = NULL;
796
+ SET_REQ_WIN32_ERROR(req, GetLastError());
797
+ return;
798
+ }
799
+ free(buf);
800
+
801
+ ((char*)req->ptr)[size] = '\0';
802
+ req->flags |= UV_FS_FREE_PTR;
803
+ } else {
804
+ req->ptr = NULL;
805
+ }
806
+
807
+ SET_REQ_RESULT(req, result);
808
+ }
809
+
810
+
811
+ INLINE static int fs__stat_handle(HANDLE handle, uv_statbuf_t* statbuf) {
812
+ BY_HANDLE_FILE_INFORMATION info;
813
+
814
+ if (!GetFileInformationByHandle(handle, &info)) {
815
+ return -1;
816
+ }
817
+
818
+ /* TODO: set st_dev, st_rdev and st_ino to something meaningful. */
819
+ statbuf->st_ino = 0;
820
+ statbuf->st_dev = 0;
821
+ statbuf->st_rdev = 0;
822
+
823
+ statbuf->st_gid = 0;
824
+ statbuf->st_uid = 0;
825
+
826
+ statbuf->st_mode = 0;
827
+
828
+ if (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
829
+ if (fs__readlink_handle(handle, NULL, &statbuf->st_size) != 0) {
830
+ return -1;
831
+ }
832
+ statbuf->st_mode |= S_IFLNK;
833
+ } else if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
834
+ statbuf->st_mode |= _S_IFDIR;
835
+ statbuf->st_size = 0;
836
+ } else {
837
+ statbuf->st_mode |= _S_IFREG;
838
+ statbuf->st_size = ((int64_t) info.nFileSizeHigh << 32) +
839
+ (int64_t) info.nFileSizeLow;
840
+ }
841
+
842
+ if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
843
+ statbuf->st_mode |= (_S_IREAD + (_S_IREAD >> 3) + (_S_IREAD >> 6));
844
+ } else {
845
+ statbuf->st_mode |= ((_S_IREAD|_S_IWRITE) + ((_S_IREAD|_S_IWRITE) >> 3) +
846
+ ((_S_IREAD|_S_IWRITE) >> 6));
847
+ }
848
+
849
+ statbuf->st_mtime = FILETIME_TO_TIME_T(info.ftLastWriteTime);
850
+ statbuf->st_atime = FILETIME_TO_TIME_T(info.ftLastAccessTime);
851
+ statbuf->st_ctime = FILETIME_TO_TIME_T(info.ftCreationTime);
852
+
853
+ statbuf->st_nlink = (info.nNumberOfLinks <= SHRT_MAX) ?
854
+ (short) info.nNumberOfLinks : SHRT_MAX;
855
+
856
+ return 0;
857
+ }
858
+
859
+
860
+ INLINE static void fs__stat_prepare_path(WCHAR* pathw) {
861
+ size_t len = wcslen(pathw);
862
+
863
+ /* TODO: ignore namespaced paths. */
864
+ if (len > 1 && pathw[len - 2] != L':' &&
865
+ (pathw[len - 1] == L'\\' || pathw[len - 1] == L'/')) {
866
+ pathw[len - 1] = '\0';
867
+ }
868
+ }
869
+
870
+
871
+ INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) {
872
+ HANDLE handle;
873
+ DWORD flags;
874
+
875
+ flags = FILE_FLAG_BACKUP_SEMANTICS;
876
+ if (do_lstat) {
877
+ flags |= FILE_FLAG_OPEN_REPARSE_POINT;
878
+ }
879
+
880
+ handle = CreateFileW(req->pathw,
881
+ FILE_READ_ATTRIBUTES,
882
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
883
+ NULL,
884
+ OPEN_EXISTING,
885
+ flags,
886
+ NULL);
887
+ if (handle == INVALID_HANDLE_VALUE) {
888
+ SET_REQ_WIN32_ERROR(req, GetLastError());
889
+ return;
890
+ }
891
+
892
+ if (fs__stat_handle(handle, &req->statbuf) != 0) {
893
+ DWORD error = GetLastError();
894
+ if (do_lstat && error == ERROR_SYMLINK_NOT_SUPPORTED) {
895
+ /* We opened a reparse point but it was not a symlink. Try again. */
896
+ fs__stat_impl(req, 0);
897
+
898
+ } else {
899
+ /* Stat failed. */
900
+ SET_REQ_WIN32_ERROR(req, GetLastError());
901
+ }
902
+
903
+ CloseHandle(handle);
904
+ return;
905
+ }
906
+
907
+ req->ptr = &req->statbuf;
908
+ req->result = 0;
909
+ CloseHandle(handle);
910
+ }
911
+
912
+
913
+ static void fs__stat(uv_fs_t* req) {
914
+ fs__stat_prepare_path(req->pathw);
915
+ fs__stat_impl(req, 0);
916
+ }
917
+
918
+
919
+ static void fs__lstat(uv_fs_t* req) {
920
+ fs__stat_prepare_path(req->pathw);
921
+ fs__stat_impl(req, 1);
922
+ }
923
+
924
+
925
+ static void fs__fstat(uv_fs_t* req) {
926
+ int fd = req->fd;
927
+ HANDLE handle;
928
+
929
+ VERIFY_FD(fd, req);
930
+
931
+ handle = (HANDLE) _get_osfhandle(fd);
932
+
933
+ if (handle == INVALID_HANDLE_VALUE) {
934
+ SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
935
+ return;
936
+ }
937
+
938
+ if (fs__stat_handle(handle, &req->statbuf) != 0) {
939
+ SET_REQ_WIN32_ERROR(req, GetLastError());
940
+ return;
941
+ }
942
+
943
+ req->ptr = &req->statbuf;
944
+ req->result = 0;
945
+ }
946
+
947
+
948
+ static void fs__rename(uv_fs_t* req) {
949
+ if (!MoveFileExW(req->pathw, req->new_pathw, MOVEFILE_REPLACE_EXISTING)) {
950
+ SET_REQ_WIN32_ERROR(req, GetLastError());
951
+ return;
952
+ }
953
+
954
+ SET_REQ_RESULT(req, 0);
955
+ }
956
+
957
+
958
+ INLINE static void fs__sync_impl(uv_fs_t* req) {
959
+ int fd = req->fd;
960
+ int result;
961
+
962
+ VERIFY_FD(fd, req);
963
+
964
+ result = FlushFileBuffers((HANDLE) _get_osfhandle(fd)) ? 0 : -1;
965
+ if (result == -1) {
966
+ SET_REQ_WIN32_ERROR(req, GetLastError());
967
+ } else {
968
+ SET_REQ_RESULT(req, result);
969
+ }
970
+ }
971
+
972
+
973
+ static void fs__fsync(uv_fs_t* req) {
974
+ fs__sync_impl(req);
975
+ }
976
+
977
+
978
+ static void fs__fdatasync(uv_fs_t* req) {
979
+ fs__sync_impl(req);
980
+ }
981
+
982
+
983
+ static void fs__ftruncate(uv_fs_t* req) {
984
+ int fd = req->fd;
985
+ HANDLE handle;
986
+ NTSTATUS status;
987
+ IO_STATUS_BLOCK io_status;
988
+ FILE_END_OF_FILE_INFORMATION eof_info;
989
+
990
+ VERIFY_FD(fd, req);
991
+
992
+ handle = (HANDLE)_get_osfhandle(fd);
993
+
994
+ eof_info.EndOfFile.QuadPart = req->offset;
995
+
996
+ status = pNtSetInformationFile(handle,
997
+ &io_status,
998
+ &eof_info,
999
+ sizeof eof_info,
1000
+ FileEndOfFileInformation);
1001
+
1002
+ if (NT_SUCCESS(status)) {
1003
+ SET_REQ_RESULT(req, 0);
1004
+ } else {
1005
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
1006
+ }
1007
+ }
1008
+
1009
+
1010
+ static void fs__sendfile(uv_fs_t* req) {
1011
+ int fd_in = req->fd, fd_out = req->fd_out;
1012
+ size_t length = req->length;
1013
+ int64_t offset = req->offset;
1014
+ const size_t max_buf_size = 65536;
1015
+ size_t buf_size = length < max_buf_size ? length : max_buf_size;
1016
+ int n, result = 0;
1017
+ int64_t result_offset = 0;
1018
+ char* buf = (char*) malloc(buf_size);
1019
+ if (!buf) {
1020
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
1021
+ }
1022
+
1023
+ if (offset != -1) {
1024
+ result_offset = _lseeki64(fd_in, offset, SEEK_SET);
1025
+ }
1026
+
1027
+ if (result_offset == -1) {
1028
+ result = -1;
1029
+ } else {
1030
+ while (length > 0) {
1031
+ n = _read(fd_in, buf, length < buf_size ? length : buf_size);
1032
+ if (n == 0) {
1033
+ break;
1034
+ } else if (n == -1) {
1035
+ result = -1;
1036
+ break;
1037
+ }
1038
+
1039
+ length -= n;
1040
+
1041
+ n = _write(fd_out, buf, n);
1042
+ if (n == -1) {
1043
+ result = -1;
1044
+ break;
1045
+ }
1046
+
1047
+ result += n;
1048
+ }
1049
+ }
1050
+
1051
+ SET_REQ_RESULT(req, result);
1052
+ }
1053
+
1054
+
1055
+ static void fs__chmod(uv_fs_t* req) {
1056
+ int result = _wchmod(req->pathw, req->mode);
1057
+ SET_REQ_RESULT(req, result);
1058
+ }
1059
+
1060
+
1061
+ static void fs__fchmod(uv_fs_t* req) {
1062
+ int fd = req->fd;
1063
+ int result;
1064
+ HANDLE handle;
1065
+ NTSTATUS nt_status;
1066
+ IO_STATUS_BLOCK io_status;
1067
+ FILE_BASIC_INFORMATION file_info;
1068
+
1069
+ VERIFY_FD(fd, req);
1070
+
1071
+ handle = (HANDLE)_get_osfhandle(fd);
1072
+
1073
+ nt_status = pNtQueryInformationFile(handle,
1074
+ &io_status,
1075
+ &file_info,
1076
+ sizeof file_info,
1077
+ FileBasicInformation);
1078
+
1079
+ if (nt_status != STATUS_SUCCESS) {
1080
+ result = -1;
1081
+ goto done;
1082
+ }
1083
+
1084
+ if (req->mode & _S_IWRITE) {
1085
+ file_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY;
1086
+ } else {
1087
+ file_info.FileAttributes |= FILE_ATTRIBUTE_READONLY;
1088
+ }
1089
+
1090
+ nt_status = pNtSetInformationFile(handle,
1091
+ &io_status,
1092
+ &file_info,
1093
+ sizeof file_info,
1094
+ FileBasicInformation);
1095
+
1096
+ if (nt_status != STATUS_SUCCESS) {
1097
+ result = -1;
1098
+ goto done;
1099
+ }
1100
+
1101
+ result = 0;
1102
+
1103
+ done:
1104
+ SET_REQ_RESULT(req, result);
1105
+ }
1106
+
1107
+
1108
+ INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) {
1109
+ FILETIME filetime_a, filetime_m;
1110
+
1111
+ TIME_T_TO_FILETIME((time_t) atime, &filetime_a);
1112
+ TIME_T_TO_FILETIME((time_t) mtime, &filetime_m);
1113
+
1114
+ if (!SetFileTime(handle, NULL, &filetime_a, &filetime_m)) {
1115
+ return -1;
1116
+ }
1117
+
1118
+ return 0;
1119
+ }
1120
+
1121
+
1122
+ static void fs__utime(uv_fs_t* req) {
1123
+ HANDLE handle;
1124
+
1125
+ handle = CreateFileW(req->pathw,
1126
+ FILE_WRITE_ATTRIBUTES,
1127
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1128
+ NULL,
1129
+ OPEN_EXISTING,
1130
+ FILE_FLAG_BACKUP_SEMANTICS,
1131
+ NULL);
1132
+
1133
+ if (handle == INVALID_HANDLE_VALUE) {
1134
+ SET_REQ_WIN32_ERROR(req, GetLastError());
1135
+ return;
1136
+ }
1137
+
1138
+ if (fs__utime_handle(handle, req->atime, req->mtime) != 0) {
1139
+ SET_REQ_WIN32_ERROR(req, GetLastError());
1140
+ CloseHandle(handle);
1141
+ return;
1142
+ }
1143
+
1144
+ CloseHandle(handle);
1145
+
1146
+ req->result = 0;
1147
+ }
1148
+
1149
+
1150
+ static void fs__futime(uv_fs_t* req) {
1151
+ int fd = req->fd;
1152
+ HANDLE handle;
1153
+ VERIFY_FD(fd, req);
1154
+
1155
+ handle = (HANDLE) _get_osfhandle(fd);
1156
+
1157
+ if (handle == INVALID_HANDLE_VALUE) {
1158
+ SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
1159
+ return;
1160
+ }
1161
+
1162
+ if (fs__utime_handle(handle, req->atime, req->mtime) != 0) {
1163
+ SET_REQ_WIN32_ERROR(req, GetLastError());
1164
+ return;
1165
+ }
1166
+
1167
+ req->result = 0;
1168
+ }
1169
+
1170
+
1171
+ static void fs__link(uv_fs_t* req) {
1172
+ DWORD r = CreateHardLinkW(req->new_pathw, req->pathw, NULL);
1173
+ if (r == 0) {
1174
+ SET_REQ_WIN32_ERROR(req, GetLastError());
1175
+ } else {
1176
+ req->result = 0;
1177
+ }
1178
+ }
1179
+
1180
+
1181
+ static void fs__create_junction(uv_fs_t* req, const WCHAR* path,
1182
+ const WCHAR* new_path) {
1183
+ HANDLE handle = INVALID_HANDLE_VALUE;
1184
+ REPARSE_DATA_BUFFER *buffer = NULL;
1185
+ int created = 0;
1186
+ int target_len;
1187
+ int is_absolute, is_long_path;
1188
+ int needed_buf_size, used_buf_size, used_data_size, path_buf_len;
1189
+ int start, len, i;
1190
+ int add_slash;
1191
+ DWORD bytes;
1192
+ WCHAR* path_buf;
1193
+
1194
+ target_len = wcslen(path);
1195
+ is_long_path = wcsncmp(path, LONG_PATH_PREFIX, LONG_PATH_PREFIX_LEN) == 0;
1196
+
1197
+ if (is_long_path) {
1198
+ is_absolute = 1;
1199
+ } else {
1200
+ is_absolute = target_len >= 3 && IS_LETTER(path[0]) &&
1201
+ path[1] == L':' && IS_SLASH(path[2]);
1202
+ }
1203
+
1204
+ if (!is_absolute) {
1205
+ /* Not supporting relative paths */
1206
+ SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_NOT_SUPPORTED);
1207
+ return;
1208
+ }
1209
+
1210
+ // Do a pessimistic calculation of the required buffer size
1211
+ needed_buf_size =
1212
+ FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) +
1213
+ JUNCTION_PREFIX_LEN * sizeof(WCHAR) +
1214
+ 2 * (target_len + 2) * sizeof(WCHAR);
1215
+
1216
+ // Allocate the buffer
1217
+ buffer = (REPARSE_DATA_BUFFER*)malloc(needed_buf_size);
1218
+ if (!buffer) {
1219
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
1220
+ }
1221
+
1222
+ // Grab a pointer to the part of the buffer where filenames go
1223
+ path_buf = (WCHAR*)&(buffer->MountPointReparseBuffer.PathBuffer);
1224
+ path_buf_len = 0;
1225
+
1226
+ // Copy the substitute (internal) target path
1227
+ start = path_buf_len;
1228
+
1229
+ wcsncpy((WCHAR*)&path_buf[path_buf_len], JUNCTION_PREFIX,
1230
+ JUNCTION_PREFIX_LEN);
1231
+ path_buf_len += JUNCTION_PREFIX_LEN;
1232
+
1233
+ add_slash = 0;
1234
+ for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) {
1235
+ if (IS_SLASH(path[i])) {
1236
+ add_slash = 1;
1237
+ continue;
1238
+ }
1239
+
1240
+ if (add_slash) {
1241
+ path_buf[path_buf_len++] = L'\\';
1242
+ add_slash = 0;
1243
+ }
1244
+
1245
+ path_buf[path_buf_len++] = path[i];
1246
+ }
1247
+ path_buf[path_buf_len++] = L'\\';
1248
+ len = path_buf_len - start;
1249
+
1250
+ // Set the info about the substitute name
1251
+ buffer->MountPointReparseBuffer.SubstituteNameOffset = start * sizeof(WCHAR);
1252
+ buffer->MountPointReparseBuffer.SubstituteNameLength = len * sizeof(WCHAR);
1253
+
1254
+ // Insert null terminator
1255
+ path_buf[path_buf_len++] = L'\0';
1256
+
1257
+ // Copy the print name of the target path
1258
+ start = path_buf_len;
1259
+ add_slash = 0;
1260
+ for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) {
1261
+ if (IS_SLASH(path[i])) {
1262
+ add_slash = 1;
1263
+ continue;
1264
+ }
1265
+
1266
+ if (add_slash) {
1267
+ path_buf[path_buf_len++] = L'\\';
1268
+ add_slash = 0;
1269
+ }
1270
+
1271
+ path_buf[path_buf_len++] = path[i];
1272
+ }
1273
+ len = path_buf_len - start;
1274
+ if (len == 2) {
1275
+ path_buf[path_buf_len++] = L'\\';
1276
+ len++;
1277
+ }
1278
+
1279
+ // Set the info about the print name
1280
+ buffer->MountPointReparseBuffer.PrintNameOffset = start * sizeof(WCHAR);
1281
+ buffer->MountPointReparseBuffer.PrintNameLength = len * sizeof(WCHAR);
1282
+
1283
+ // Insert another null terminator
1284
+ path_buf[path_buf_len++] = L'\0';
1285
+
1286
+ // Calculate how much buffer space was actually used
1287
+ used_buf_size = FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) +
1288
+ path_buf_len * sizeof(WCHAR);
1289
+ used_data_size = used_buf_size -
1290
+ FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer);
1291
+
1292
+ // Put general info in the data buffer
1293
+ buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
1294
+ buffer->ReparseDataLength = used_data_size;
1295
+ buffer->Reserved = 0;
1296
+
1297
+ // Create a new directory
1298
+ if (!CreateDirectoryW(new_path, NULL)) {
1299
+ SET_REQ_WIN32_ERROR(req, GetLastError());
1300
+ goto error;
1301
+ }
1302
+ created = 1;
1303
+
1304
+ // Open the directory
1305
+ handle = CreateFileW(new_path,
1306
+ GENERIC_ALL,
1307
+ 0,
1308
+ NULL,
1309
+ OPEN_EXISTING,
1310
+ FILE_FLAG_BACKUP_SEMANTICS |
1311
+ FILE_FLAG_OPEN_REPARSE_POINT,
1312
+ NULL);
1313
+ if (handle == INVALID_HANDLE_VALUE) {
1314
+ SET_REQ_WIN32_ERROR(req, GetLastError());
1315
+ goto error;
1316
+ }
1317
+
1318
+ // Create the actual reparse point
1319
+ if (!DeviceIoControl(handle,
1320
+ FSCTL_SET_REPARSE_POINT,
1321
+ buffer,
1322
+ used_buf_size,
1323
+ NULL,
1324
+ 0,
1325
+ &bytes,
1326
+ NULL)) {
1327
+ SET_REQ_WIN32_ERROR(req, GetLastError());
1328
+ goto error;
1329
+ }
1330
+
1331
+ // Clean up
1332
+ CloseHandle(handle);
1333
+ free(buffer);
1334
+
1335
+ SET_REQ_RESULT(req, 0);
1336
+ return;
1337
+
1338
+ error:
1339
+ free(buffer);
1340
+
1341
+ if (handle != INVALID_HANDLE_VALUE) {
1342
+ CloseHandle(handle);
1343
+ }
1344
+
1345
+ if (created) {
1346
+ RemoveDirectoryW(new_path);
1347
+ }
1348
+ }
1349
+
1350
+
1351
+ static void fs__symlink(uv_fs_t* req) {
1352
+ WCHAR* pathw = req->pathw;
1353
+ WCHAR* new_pathw = req->new_pathw;
1354
+ int flags = req->file_flags;
1355
+ int result;
1356
+
1357
+
1358
+ if (flags & UV_FS_SYMLINK_JUNCTION) {
1359
+ fs__create_junction(req, pathw, new_pathw);
1360
+ } else if (pCreateSymbolicLinkW) {
1361
+ result = pCreateSymbolicLinkW(new_pathw,
1362
+ pathw,
1363
+ flags & UV_FS_SYMLINK_DIR ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) ? 0 : -1;
1364
+ if (result == -1) {
1365
+ SET_REQ_WIN32_ERROR(req, GetLastError());
1366
+ } else {
1367
+ SET_REQ_RESULT(req, result);
1368
+ }
1369
+ } else {
1370
+ SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED);
1371
+ }
1372
+ }
1373
+
1374
+
1375
+ static void fs__readlink(uv_fs_t* req) {
1376
+ HANDLE handle;
1377
+
1378
+ handle = CreateFileW(req->pathw,
1379
+ 0,
1380
+ 0,
1381
+ NULL,
1382
+ OPEN_EXISTING,
1383
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
1384
+ NULL);
1385
+
1386
+ if (handle == INVALID_HANDLE_VALUE) {
1387
+ SET_REQ_WIN32_ERROR(req, GetLastError());
1388
+ return;
1389
+ }
1390
+
1391
+ if (fs__readlink_handle(handle, (char**) &req->ptr, NULL) != 0) {
1392
+ SET_REQ_WIN32_ERROR(req, GetLastError());
1393
+ CloseHandle(handle);
1394
+ return;
1395
+ }
1396
+
1397
+ req->flags |= UV_FS_FREE_PTR;
1398
+ SET_REQ_RESULT(req, 0);
1399
+
1400
+ CloseHandle(handle);
1401
+ }
1402
+
1403
+
1404
+
1405
+ static void fs__chown(uv_fs_t* req) {
1406
+ req->result = 0;
1407
+ }
1408
+
1409
+
1410
+ static void fs__fchown(uv_fs_t* req) {
1411
+ req->result = 0;
1412
+ }
1413
+
1414
+
1415
+ static DWORD WINAPI uv_fs_thread_proc(void* parameter) {
1416
+ uv_fs_t* req = (uv_fs_t*) parameter;
1417
+ uv_loop_t* loop = req->loop;
1418
+
1419
+ assert(req != NULL);
1420
+ assert(req->type == UV_FS);
1421
+
1422
+ #define XX(uc, lc) case UV_FS_##uc: fs__##lc(req); break;
1423
+ switch (req->fs_type) {
1424
+ XX(OPEN, open)
1425
+ XX(CLOSE, close)
1426
+ XX(READ, read)
1427
+ XX(WRITE, write)
1428
+ XX(SENDFILE, sendfile)
1429
+ XX(STAT, stat)
1430
+ XX(LSTAT, lstat)
1431
+ XX(FSTAT, fstat)
1432
+ XX(FTRUNCATE, ftruncate)
1433
+ XX(UTIME, utime)
1434
+ XX(FUTIME, futime)
1435
+ XX(CHMOD, chmod)
1436
+ XX(FCHMOD, fchmod)
1437
+ XX(FSYNC, fsync)
1438
+ XX(FDATASYNC, fdatasync)
1439
+ XX(UNLINK, unlink)
1440
+ XX(RMDIR, rmdir)
1441
+ XX(MKDIR, mkdir)
1442
+ XX(RENAME, rename)
1443
+ XX(READDIR, readdir)
1444
+ XX(LINK, link)
1445
+ XX(SYMLINK, symlink)
1446
+ XX(READLINK, readlink)
1447
+ XX(CHOWN, chown)
1448
+ XX(FCHOWN, fchown);
1449
+ default:
1450
+ assert(!"bad uv_fs_type");
1451
+ }
1452
+
1453
+ POST_COMPLETION_FOR_REQ(loop, req);
1454
+ return 0;
1455
+ }
1456
+
1457
+
1458
+ int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
1459
+ int mode, uv_fs_cb cb) {
1460
+ uv_fs_req_init(loop, req, UV_FS_OPEN, cb);
1461
+
1462
+ if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
1463
+ return -1;
1464
+ }
1465
+
1466
+ req->file_flags = flags;
1467
+ req->mode = mode;
1468
+
1469
+ if (cb) {
1470
+ QUEUE_FS_TP_JOB(loop, req);
1471
+ return 0;
1472
+ } else {
1473
+ fs__open(req);
1474
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1475
+ return req->result;
1476
+ }
1477
+ }
1478
+
1479
+
1480
+ int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
1481
+ uv_fs_req_init(loop, req, UV_FS_CLOSE, cb);
1482
+ req->fd = fd;
1483
+
1484
+ if (cb) {
1485
+ QUEUE_FS_TP_JOB(loop, req);
1486
+ return 0;
1487
+ } else {
1488
+ fs__close(req);
1489
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1490
+ return req->result;
1491
+ }
1492
+ }
1493
+
1494
+
1495
+ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file fd, void* buf,
1496
+ size_t length, int64_t offset, uv_fs_cb cb) {
1497
+ uv_fs_req_init(loop, req, UV_FS_READ, cb);
1498
+
1499
+ req->fd = fd;
1500
+ req->buf = buf;
1501
+ req->length = length;
1502
+ req->offset = offset;
1503
+
1504
+ if (cb) {
1505
+ QUEUE_FS_TP_JOB(loop, req);
1506
+ return 0;
1507
+ } else {
1508
+ fs__read(req);
1509
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1510
+ return req->result;
1511
+ }
1512
+ }
1513
+
1514
+
1515
+ int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file fd, void* buf,
1516
+ size_t length, int64_t offset, uv_fs_cb cb) {
1517
+ uv_fs_req_init(loop, req, UV_FS_WRITE, cb);
1518
+
1519
+ req->fd = fd;
1520
+ req->buf = buf;
1521
+ req->length = length;
1522
+ req->offset = offset;
1523
+
1524
+ if (cb) {
1525
+ QUEUE_FS_TP_JOB(loop, req);
1526
+ return 0;
1527
+ } else {
1528
+ fs__write(req);
1529
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1530
+ return req->result;
1531
+ }
1532
+ }
1533
+
1534
+
1535
+ int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
1536
+ uv_fs_cb cb) {
1537
+ uv_fs_req_init(loop, req, UV_FS_UNLINK, cb);
1538
+
1539
+ if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
1540
+ return -1;
1541
+ }
1542
+
1543
+ if (cb) {
1544
+ QUEUE_FS_TP_JOB(loop, req);
1545
+ return 0;
1546
+ } else {
1547
+ fs__unlink(req);
1548
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1549
+ return req->result;
1550
+ }
1551
+ }
1552
+
1553
+
1554
+ int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
1555
+ uv_fs_cb cb) {
1556
+ uv_fs_req_init(loop, req, UV_FS_MKDIR, cb);
1557
+
1558
+ if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
1559
+ return -1;
1560
+ }
1561
+
1562
+ req->mode = mode;
1563
+
1564
+ if (cb) {
1565
+ QUEUE_FS_TP_JOB(loop, req);
1566
+ return 0;
1567
+ } else {
1568
+ fs__mkdir(req);
1569
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1570
+ return req->result;
1571
+ }
1572
+ }
1573
+
1574
+
1575
+ int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
1576
+ uv_fs_req_init(loop, req, UV_FS_RMDIR, cb);
1577
+
1578
+ if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
1579
+ return -1;
1580
+ }
1581
+
1582
+ if (cb) {
1583
+ QUEUE_FS_TP_JOB(loop, req);
1584
+ return 0;
1585
+ } else {
1586
+ fs__rmdir(req);
1587
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1588
+ return req->result;
1589
+ }
1590
+ }
1591
+
1592
+
1593
+ int uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
1594
+ uv_fs_cb cb) {
1595
+ uv_fs_req_init(loop, req, UV_FS_READDIR, cb);
1596
+
1597
+ if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
1598
+ return -1;
1599
+ }
1600
+
1601
+ req->file_flags;
1602
+
1603
+ if (cb) {
1604
+ QUEUE_FS_TP_JOB(loop, req);
1605
+ return 0;
1606
+ } else {
1607
+ fs__readdir(req);
1608
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1609
+ return req->result;
1610
+ }
1611
+ }
1612
+
1613
+
1614
+ int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path,
1615
+ const char* new_path, uv_fs_cb cb) {
1616
+ uv_fs_req_init(loop, req, UV_FS_LINK, cb);
1617
+
1618
+ if (fs__capture_path(loop, req, path, new_path, cb != NULL) < 0) {
1619
+ return -1;
1620
+ }
1621
+
1622
+ if (cb) {
1623
+ QUEUE_FS_TP_JOB(loop, req);
1624
+ return 0;
1625
+ } else {
1626
+ fs__link(req);
1627
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1628
+ return req->result;
1629
+ }
1630
+ }
1631
+
1632
+
1633
+ int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
1634
+ const char* new_path, int flags, uv_fs_cb cb) {
1635
+ uv_fs_req_init(loop, req, UV_FS_SYMLINK, cb);
1636
+
1637
+ if (fs__capture_path(loop, req, path, new_path, cb != NULL) < 0) {
1638
+ return -1;
1639
+ }
1640
+
1641
+ req->file_flags = flags;
1642
+
1643
+ if (cb) {
1644
+ QUEUE_FS_TP_JOB(loop, req);
1645
+ return 0;
1646
+ } else {
1647
+ fs__symlink(req);
1648
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1649
+ return req->result;
1650
+ }
1651
+ }
1652
+
1653
+
1654
+ int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
1655
+ uv_fs_cb cb) {
1656
+ uv_fs_req_init(loop, req, UV_FS_READLINK, cb);
1657
+
1658
+ if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
1659
+ return -1;
1660
+ }
1661
+
1662
+ if (cb) {
1663
+ QUEUE_FS_TP_JOB(loop, req);
1664
+ return 0;
1665
+ } else {
1666
+ fs__readlink(req);
1667
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1668
+ return req->result;
1669
+ }
1670
+ }
1671
+
1672
+
1673
+ int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, int uid,
1674
+ int gid, uv_fs_cb cb) {
1675
+ uv_fs_req_init(loop, req, UV_FS_CHOWN, cb);
1676
+
1677
+ if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
1678
+ return -1;
1679
+ }
1680
+
1681
+ if (cb) {
1682
+ QUEUE_FS_TP_JOB(loop, req);
1683
+ return 0;
1684
+ } else {
1685
+ fs__chown(req);
1686
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1687
+ return req->result;
1688
+ }
1689
+ }
1690
+
1691
+
1692
+ int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int uid,
1693
+ int gid, uv_fs_cb cb) {
1694
+ uv_fs_req_init(loop, req, UV_FS_FCHOWN, cb);
1695
+
1696
+ if (cb) {
1697
+ QUEUE_FS_TP_JOB(loop, req);
1698
+ return 0;
1699
+ } else {
1700
+ fs__fchown(req);
1701
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1702
+ return req->result;
1703
+ }
1704
+ }
1705
+
1706
+
1707
+ int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
1708
+ uv_fs_req_init(loop, req, UV_FS_STAT, cb);
1709
+
1710
+ if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
1711
+ return -1;
1712
+ }
1713
+
1714
+ if (cb) {
1715
+ QUEUE_FS_TP_JOB(loop, req);
1716
+ return 0;
1717
+ } else {
1718
+ fs__stat(req);
1719
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1720
+ return req->result;
1721
+ }
1722
+ }
1723
+
1724
+
1725
+ int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
1726
+ uv_fs_req_init(loop, req, UV_FS_LSTAT, cb);
1727
+
1728
+ if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
1729
+ return -1;
1730
+ }
1731
+
1732
+ if (cb) {
1733
+ QUEUE_FS_TP_JOB(loop, req);
1734
+ return 0;
1735
+ } else {
1736
+ fs__lstat(req);
1737
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1738
+ return req->result;
1739
+ }
1740
+ }
1741
+
1742
+
1743
+ int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
1744
+ uv_fs_req_init(loop, req, UV_FS_FSTAT, cb);
1745
+ req->fd = fd;
1746
+
1747
+ if (cb) {
1748
+ QUEUE_FS_TP_JOB(loop, req);
1749
+ return 0;
1750
+ } else {
1751
+ fs__fstat(req);
1752
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1753
+ return req->result;
1754
+ }
1755
+ }
1756
+
1757
+
1758
+ int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path,
1759
+ const char* new_path, uv_fs_cb cb) {
1760
+ uv_fs_req_init(loop, req, UV_FS_RENAME, cb);
1761
+
1762
+ if (fs__capture_path(loop, req, path, new_path, cb != NULL) < 0) {
1763
+ return -1;
1764
+ }
1765
+
1766
+ if (cb) {
1767
+ QUEUE_FS_TP_JOB(loop, req);
1768
+ return 0;
1769
+ } else {
1770
+ fs__rename(req);
1771
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1772
+ return req->result;
1773
+ }
1774
+ }
1775
+
1776
+
1777
+ int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
1778
+ uv_fs_req_init(loop, req, UV_FS_FSYNC, cb);
1779
+ req->fd = fd;
1780
+
1781
+ if (cb) {
1782
+ QUEUE_FS_TP_JOB(loop, req);
1783
+ return 0;
1784
+ } else {
1785
+ fs__fsync(req);
1786
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1787
+ return req->result;
1788
+ }
1789
+ }
1790
+
1791
+
1792
+ int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
1793
+ uv_fs_req_init(loop, req, UV_FS_FDATASYNC, cb);
1794
+ req->fd = fd;
1795
+
1796
+ if (cb) {
1797
+ QUEUE_FS_TP_JOB(loop, req);
1798
+ return 0;
1799
+ } else {
1800
+ fs__fdatasync(req);
1801
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1802
+ return req->result;
1803
+ }
1804
+ }
1805
+
1806
+
1807
+ int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file fd,
1808
+ int64_t offset, uv_fs_cb cb) {
1809
+ uv_fs_req_init(loop, req, UV_FS_FTRUNCATE, cb);
1810
+
1811
+ req->fd = fd;
1812
+ req->offset = offset;
1813
+
1814
+ if (cb) {
1815
+ QUEUE_FS_TP_JOB(loop, req);
1816
+ return 0;
1817
+ } else {
1818
+ fs__ftruncate(req);
1819
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1820
+ return req->result;
1821
+ }
1822
+ }
1823
+
1824
+
1825
+
1826
+ int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file fd_out,
1827
+ uv_file fd_in, int64_t in_offset, size_t length, uv_fs_cb cb) {
1828
+ uv_fs_req_init(loop, req, UV_FS_SENDFILE, cb);
1829
+
1830
+ req->fd = fd_in;
1831
+ req->fd_out = fd_out;
1832
+ req->offset = in_offset;
1833
+ req->length = length;
1834
+
1835
+ if (cb) {
1836
+ QUEUE_FS_TP_JOB(loop, req);
1837
+ return 0;
1838
+ } else {
1839
+ fs__sendfile(req);
1840
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1841
+ return req->result;
1842
+ }
1843
+ }
1844
+
1845
+
1846
+ int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
1847
+ uv_fs_cb cb) {
1848
+ uv_fs_req_init(loop, req, UV_FS_CHMOD, cb);
1849
+
1850
+ if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
1851
+ return -1;
1852
+ }
1853
+
1854
+ req->mode = mode;
1855
+
1856
+ if (cb) {
1857
+ QUEUE_FS_TP_JOB(loop, req);
1858
+ return 0;
1859
+ } else {
1860
+ fs__chmod(req);
1861
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1862
+ return req->result;
1863
+ }
1864
+ }
1865
+
1866
+
1867
+ int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int mode,
1868
+ uv_fs_cb cb) {
1869
+ uv_fs_req_init(loop, req, UV_FS_FCHMOD, cb);
1870
+
1871
+ req->fd = fd;
1872
+ req->mode = mode;
1873
+
1874
+ if (cb) {
1875
+ QUEUE_FS_TP_JOB(loop, req);
1876
+ return 0;
1877
+ } else {
1878
+ fs__fchmod(req);
1879
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1880
+ return req->result;
1881
+ }
1882
+ }
1883
+
1884
+
1885
+ int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
1886
+ double mtime, uv_fs_cb cb) {
1887
+ uv_fs_req_init(loop, req, UV_FS_UTIME, cb);
1888
+
1889
+ if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
1890
+ return -1;
1891
+ }
1892
+
1893
+ req->atime = atime;
1894
+ req->mtime = mtime;
1895
+
1896
+ if (cb) {
1897
+ QUEUE_FS_TP_JOB(loop, req);
1898
+ return 0;
1899
+ } else {
1900
+ fs__utime(req);
1901
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1902
+ return req->result;
1903
+ }
1904
+ }
1905
+
1906
+
1907
+ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime,
1908
+ double mtime, uv_fs_cb cb) {
1909
+ uv_fs_req_init(loop, req, UV_FS_FUTIME, cb);
1910
+
1911
+ req->fd = fd;
1912
+ req->atime = atime;
1913
+ req->mtime = mtime;
1914
+
1915
+ if (cb) {
1916
+ QUEUE_FS_TP_JOB(loop, req);
1917
+ return 0;
1918
+ } else {
1919
+ fs__futime(req);
1920
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1921
+ return req->result;
1922
+ }
1923
+ }
1924
+
1925
+
1926
+ void uv_process_fs_req(uv_loop_t* loop, uv_fs_t* req) {
1927
+ assert(req->cb);
1928
+ uv__req_unregister(loop, req);
1929
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1930
+ req->cb(req);
1931
+ }
1932
+
1933
+
1934
+ void uv_fs_req_cleanup(uv_fs_t* req) {
1935
+ if (req->flags & UV_FS_CLEANEDUP)
1936
+ return;
1937
+
1938
+ if (req->flags & UV_FS_FREE_PATHS)
1939
+ free(req->pathw);
1940
+
1941
+ if (req->flags & UV_FS_FREE_PTR)
1942
+ free(req->ptr);
1943
+
1944
+ req->path = NULL;
1945
+ req->pathw = NULL;
1946
+ req->new_pathw = NULL;
1947
+ req->ptr = NULL;
1948
+
1949
+ req->flags |= UV_FS_CLEANEDUP;
1950
+ }
1951
+