foolio 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (261) hide show
  1. data/.gitignore +22 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE +22 -0
  4. data/README.md +29 -0
  5. data/Rakefile +21 -0
  6. data/examples/timer.rb +20 -0
  7. data/ext/foolio/extconf.rb +34 -0
  8. data/ext/foolio/foolio_ext.c +921 -0
  9. data/ext/foolio/gen.rb +50 -0
  10. data/ext/foolio/make_table.rb +12 -0
  11. data/ext/foolio/templ +243 -0
  12. data/ext/libuv/.gitignore +33 -0
  13. data/ext/libuv/.mailmap +13 -0
  14. data/ext/libuv/.travis.yml +9 -0
  15. data/ext/libuv/AUTHORS +61 -0
  16. data/ext/libuv/LICENSE +44 -0
  17. data/ext/libuv/Makefile +71 -0
  18. data/ext/libuv/README.md +90 -0
  19. data/ext/libuv/common.gypi +178 -0
  20. data/ext/libuv/gyp_uv +73 -0
  21. data/ext/libuv/include/uv-private/eio.h +403 -0
  22. data/ext/libuv/include/uv-private/ev.h +838 -0
  23. data/ext/libuv/include/uv-private/ngx-queue.h +108 -0
  24. data/ext/libuv/include/uv-private/tree.h +768 -0
  25. data/ext/libuv/include/uv-private/uv-unix.h +324 -0
  26. data/ext/libuv/include/uv-private/uv-win.h +517 -0
  27. data/ext/libuv/include/uv.h +1838 -0
  28. data/ext/libuv/src/fs-poll.c +235 -0
  29. data/ext/libuv/src/inet.c +293 -0
  30. data/ext/libuv/src/unix/async.c +148 -0
  31. data/ext/libuv/src/unix/core.c +696 -0
  32. data/ext/libuv/src/unix/cygwin.c +83 -0
  33. data/ext/libuv/src/unix/darwin.c +342 -0
  34. data/ext/libuv/src/unix/dl.c +83 -0
  35. data/ext/libuv/src/unix/eio/Changes +63 -0
  36. data/ext/libuv/src/unix/eio/LICENSE +36 -0
  37. data/ext/libuv/src/unix/eio/Makefile.am +15 -0
  38. data/ext/libuv/src/unix/eio/aclocal.m4 +8957 -0
  39. data/ext/libuv/src/unix/eio/autogen.sh +3 -0
  40. data/ext/libuv/src/unix/eio/config.h.in +86 -0
  41. data/ext/libuv/src/unix/eio/config_cygwin.h +80 -0
  42. data/ext/libuv/src/unix/eio/config_darwin.h +141 -0
  43. data/ext/libuv/src/unix/eio/config_freebsd.h +81 -0
  44. data/ext/libuv/src/unix/eio/config_linux.h +94 -0
  45. data/ext/libuv/src/unix/eio/config_netbsd.h +81 -0
  46. data/ext/libuv/src/unix/eio/config_openbsd.h +137 -0
  47. data/ext/libuv/src/unix/eio/config_sunos.h +84 -0
  48. data/ext/libuv/src/unix/eio/configure.ac +22 -0
  49. data/ext/libuv/src/unix/eio/demo.c +194 -0
  50. data/ext/libuv/src/unix/eio/ecb.h +370 -0
  51. data/ext/libuv/src/unix/eio/eio.3 +3428 -0
  52. data/ext/libuv/src/unix/eio/eio.c +2593 -0
  53. data/ext/libuv/src/unix/eio/eio.pod +969 -0
  54. data/ext/libuv/src/unix/eio/libeio.m4 +195 -0
  55. data/ext/libuv/src/unix/eio/xthread.h +164 -0
  56. data/ext/libuv/src/unix/error.c +105 -0
  57. data/ext/libuv/src/unix/ev/Changes +388 -0
  58. data/ext/libuv/src/unix/ev/LICENSE +36 -0
  59. data/ext/libuv/src/unix/ev/Makefile.am +18 -0
  60. data/ext/libuv/src/unix/ev/Makefile.in +771 -0
  61. data/ext/libuv/src/unix/ev/README +58 -0
  62. data/ext/libuv/src/unix/ev/aclocal.m4 +8957 -0
  63. data/ext/libuv/src/unix/ev/autogen.sh +6 -0
  64. data/ext/libuv/src/unix/ev/config.guess +1526 -0
  65. data/ext/libuv/src/unix/ev/config.h.in +125 -0
  66. data/ext/libuv/src/unix/ev/config.sub +1658 -0
  67. data/ext/libuv/src/unix/ev/config_cygwin.h +123 -0
  68. data/ext/libuv/src/unix/ev/config_darwin.h +122 -0
  69. data/ext/libuv/src/unix/ev/config_freebsd.h +120 -0
  70. data/ext/libuv/src/unix/ev/config_linux.h +141 -0
  71. data/ext/libuv/src/unix/ev/config_netbsd.h +120 -0
  72. data/ext/libuv/src/unix/ev/config_openbsd.h +126 -0
  73. data/ext/libuv/src/unix/ev/config_sunos.h +122 -0
  74. data/ext/libuv/src/unix/ev/configure +13037 -0
  75. data/ext/libuv/src/unix/ev/configure.ac +18 -0
  76. data/ext/libuv/src/unix/ev/depcomp +630 -0
  77. data/ext/libuv/src/unix/ev/ev++.h +816 -0
  78. data/ext/libuv/src/unix/ev/ev.3 +5311 -0
  79. data/ext/libuv/src/unix/ev/ev.c +3925 -0
  80. data/ext/libuv/src/unix/ev/ev.pod +5243 -0
  81. data/ext/libuv/src/unix/ev/ev_epoll.c +266 -0
  82. data/ext/libuv/src/unix/ev/ev_kqueue.c +235 -0
  83. data/ext/libuv/src/unix/ev/ev_poll.c +148 -0
  84. data/ext/libuv/src/unix/ev/ev_port.c +179 -0
  85. data/ext/libuv/src/unix/ev/ev_select.c +310 -0
  86. data/ext/libuv/src/unix/ev/ev_vars.h +203 -0
  87. data/ext/libuv/src/unix/ev/ev_win32.c +153 -0
  88. data/ext/libuv/src/unix/ev/ev_wrap.h +196 -0
  89. data/ext/libuv/src/unix/ev/event.c +402 -0
  90. data/ext/libuv/src/unix/ev/event.h +170 -0
  91. data/ext/libuv/src/unix/ev/install-sh +294 -0
  92. data/ext/libuv/src/unix/ev/libev.m4 +39 -0
  93. data/ext/libuv/src/unix/ev/ltmain.sh +8413 -0
  94. data/ext/libuv/src/unix/ev/missing +336 -0
  95. data/ext/libuv/src/unix/ev/mkinstalldirs +111 -0
  96. data/ext/libuv/src/unix/freebsd.c +326 -0
  97. data/ext/libuv/src/unix/fs.c +739 -0
  98. data/ext/libuv/src/unix/internal.h +188 -0
  99. data/ext/libuv/src/unix/kqueue.c +120 -0
  100. data/ext/libuv/src/unix/linux/inotify.c +239 -0
  101. data/ext/libuv/src/unix/linux/linux-core.c +557 -0
  102. data/ext/libuv/src/unix/linux/syscalls.c +388 -0
  103. data/ext/libuv/src/unix/linux/syscalls.h +124 -0
  104. data/ext/libuv/src/unix/loop-watcher.c +62 -0
  105. data/ext/libuv/src/unix/loop.c +94 -0
  106. data/ext/libuv/src/unix/netbsd.c +108 -0
  107. data/ext/libuv/src/unix/openbsd.c +295 -0
  108. data/ext/libuv/src/unix/pipe.c +259 -0
  109. data/ext/libuv/src/unix/poll.c +114 -0
  110. data/ext/libuv/src/unix/process.c +495 -0
  111. data/ext/libuv/src/unix/signal.c +269 -0
  112. data/ext/libuv/src/unix/stream.c +990 -0
  113. data/ext/libuv/src/unix/sunos.c +481 -0
  114. data/ext/libuv/src/unix/tcp.c +393 -0
  115. data/ext/libuv/src/unix/thread.c +251 -0
  116. data/ext/libuv/src/unix/timer.c +136 -0
  117. data/ext/libuv/src/unix/tty.c +145 -0
  118. data/ext/libuv/src/unix/udp.c +659 -0
  119. data/ext/libuv/src/unix/uv-eio.c +107 -0
  120. data/ext/libuv/src/unix/uv-eio.h +13 -0
  121. data/ext/libuv/src/uv-common.c +380 -0
  122. data/ext/libuv/src/uv-common.h +170 -0
  123. data/ext/libuv/src/win/async.c +100 -0
  124. data/ext/libuv/src/win/atomicops-inl.h +56 -0
  125. data/ext/libuv/src/win/core.c +278 -0
  126. data/ext/libuv/src/win/dl.c +86 -0
  127. data/ext/libuv/src/win/error.c +155 -0
  128. data/ext/libuv/src/win/fs-event.c +510 -0
  129. data/ext/libuv/src/win/fs.c +1948 -0
  130. data/ext/libuv/src/win/getaddrinfo.c +365 -0
  131. data/ext/libuv/src/win/handle-inl.h +149 -0
  132. data/ext/libuv/src/win/handle.c +154 -0
  133. data/ext/libuv/src/win/internal.h +343 -0
  134. data/ext/libuv/src/win/loop-watcher.c +122 -0
  135. data/ext/libuv/src/win/pipe.c +1672 -0
  136. data/ext/libuv/src/win/poll.c +616 -0
  137. data/ext/libuv/src/win/process-stdio.c +500 -0
  138. data/ext/libuv/src/win/process.c +1013 -0
  139. data/ext/libuv/src/win/req-inl.h +220 -0
  140. data/ext/libuv/src/win/req.c +25 -0
  141. data/ext/libuv/src/win/signal.c +57 -0
  142. data/ext/libuv/src/win/stream-inl.h +67 -0
  143. data/ext/libuv/src/win/stream.c +167 -0
  144. data/ext/libuv/src/win/tcp.c +1394 -0
  145. data/ext/libuv/src/win/thread.c +372 -0
  146. data/ext/libuv/src/win/threadpool.c +74 -0
  147. data/ext/libuv/src/win/timer.c +224 -0
  148. data/ext/libuv/src/win/tty.c +1799 -0
  149. data/ext/libuv/src/win/udp.c +716 -0
  150. data/ext/libuv/src/win/util.c +864 -0
  151. data/ext/libuv/src/win/winapi.c +132 -0
  152. data/ext/libuv/src/win/winapi.h +4452 -0
  153. data/ext/libuv/src/win/winsock.c +557 -0
  154. data/ext/libuv/src/win/winsock.h +171 -0
  155. data/ext/libuv/test/benchmark-async-pummel.c +97 -0
  156. data/ext/libuv/test/benchmark-async.c +137 -0
  157. data/ext/libuv/test/benchmark-fs-stat.c +135 -0
  158. data/ext/libuv/test/benchmark-getaddrinfo.c +94 -0
  159. data/ext/libuv/test/benchmark-list.h +127 -0
  160. data/ext/libuv/test/benchmark-loop-count.c +88 -0
  161. data/ext/libuv/test/benchmark-million-timers.c +65 -0
  162. data/ext/libuv/test/benchmark-ping-pongs.c +213 -0
  163. data/ext/libuv/test/benchmark-pound.c +324 -0
  164. data/ext/libuv/test/benchmark-pump.c +462 -0
  165. data/ext/libuv/test/benchmark-sizes.c +44 -0
  166. data/ext/libuv/test/benchmark-spawn.c +162 -0
  167. data/ext/libuv/test/benchmark-tcp-write-batch.c +140 -0
  168. data/ext/libuv/test/benchmark-thread.c +64 -0
  169. data/ext/libuv/test/benchmark-udp-packet-storm.c +247 -0
  170. data/ext/libuv/test/blackhole-server.c +118 -0
  171. data/ext/libuv/test/dns-server.c +321 -0
  172. data/ext/libuv/test/echo-server.c +378 -0
  173. data/ext/libuv/test/fixtures/empty_file +0 -0
  174. data/ext/libuv/test/fixtures/load_error.node +1 -0
  175. data/ext/libuv/test/run-benchmarks.c +64 -0
  176. data/ext/libuv/test/run-tests.c +138 -0
  177. data/ext/libuv/test/runner-unix.c +295 -0
  178. data/ext/libuv/test/runner-unix.h +36 -0
  179. data/ext/libuv/test/runner-win.c +285 -0
  180. data/ext/libuv/test/runner-win.h +42 -0
  181. data/ext/libuv/test/runner.c +355 -0
  182. data/ext/libuv/test/runner.h +159 -0
  183. data/ext/libuv/test/task.h +112 -0
  184. data/ext/libuv/test/test-async.c +118 -0
  185. data/ext/libuv/test/test-callback-order.c +76 -0
  186. data/ext/libuv/test/test-callback-stack.c +203 -0
  187. data/ext/libuv/test/test-connection-fail.c +148 -0
  188. data/ext/libuv/test/test-cwd-and-chdir.c +64 -0
  189. data/ext/libuv/test/test-delayed-accept.c +188 -0
  190. data/ext/libuv/test/test-dlerror.c +58 -0
  191. data/ext/libuv/test/test-error.c +59 -0
  192. data/ext/libuv/test/test-fail-always.c +29 -0
  193. data/ext/libuv/test/test-fs-event.c +474 -0
  194. data/ext/libuv/test/test-fs-poll.c +146 -0
  195. data/ext/libuv/test/test-fs.c +1843 -0
  196. data/ext/libuv/test/test-get-currentexe.c +63 -0
  197. data/ext/libuv/test/test-get-loadavg.c +36 -0
  198. data/ext/libuv/test/test-get-memory.c +38 -0
  199. data/ext/libuv/test/test-getaddrinfo.c +122 -0
  200. data/ext/libuv/test/test-getsockname.c +342 -0
  201. data/ext/libuv/test/test-hrtime.c +54 -0
  202. data/ext/libuv/test/test-idle.c +81 -0
  203. data/ext/libuv/test/test-ipc-send-recv.c +209 -0
  204. data/ext/libuv/test/test-ipc.c +620 -0
  205. data/ext/libuv/test/test-list.h +427 -0
  206. data/ext/libuv/test/test-loop-handles.c +336 -0
  207. data/ext/libuv/test/test-multiple-listen.c +102 -0
  208. data/ext/libuv/test/test-mutexes.c +63 -0
  209. data/ext/libuv/test/test-pass-always.c +28 -0
  210. data/ext/libuv/test/test-ping-pong.c +253 -0
  211. data/ext/libuv/test/test-pipe-bind-error.c +140 -0
  212. data/ext/libuv/test/test-pipe-connect-error.c +96 -0
  213. data/ext/libuv/test/test-platform-output.c +87 -0
  214. data/ext/libuv/test/test-poll-close.c +72 -0
  215. data/ext/libuv/test/test-poll.c +573 -0
  216. data/ext/libuv/test/test-process-title.c +49 -0
  217. data/ext/libuv/test/test-ref.c +338 -0
  218. data/ext/libuv/test/test-run-once.c +48 -0
  219. data/ext/libuv/test/test-semaphore.c +111 -0
  220. data/ext/libuv/test/test-shutdown-close.c +103 -0
  221. data/ext/libuv/test/test-shutdown-eof.c +183 -0
  222. data/ext/libuv/test/test-signal.c +162 -0
  223. data/ext/libuv/test/test-spawn.c +863 -0
  224. data/ext/libuv/test/test-stdio-over-pipes.c +246 -0
  225. data/ext/libuv/test/test-tcp-bind-error.c +191 -0
  226. data/ext/libuv/test/test-tcp-bind6-error.c +154 -0
  227. data/ext/libuv/test/test-tcp-close-while-connecting.c +80 -0
  228. data/ext/libuv/test/test-tcp-close.c +129 -0
  229. data/ext/libuv/test/test-tcp-connect-error-after-write.c +95 -0
  230. data/ext/libuv/test/test-tcp-connect-error.c +70 -0
  231. data/ext/libuv/test/test-tcp-connect-timeout.c +85 -0
  232. data/ext/libuv/test/test-tcp-connect6-error.c +68 -0
  233. data/ext/libuv/test/test-tcp-flags.c +51 -0
  234. data/ext/libuv/test/test-tcp-shutdown-after-write.c +131 -0
  235. data/ext/libuv/test/test-tcp-unexpected-read.c +113 -0
  236. data/ext/libuv/test/test-tcp-write-error.c +168 -0
  237. data/ext/libuv/test/test-tcp-write-to-half-open-connection.c +135 -0
  238. data/ext/libuv/test/test-tcp-writealot.c +170 -0
  239. data/ext/libuv/test/test-thread.c +183 -0
  240. data/ext/libuv/test/test-threadpool.c +57 -0
  241. data/ext/libuv/test/test-timer-again.c +141 -0
  242. data/ext/libuv/test/test-timer.c +152 -0
  243. data/ext/libuv/test/test-tty.c +110 -0
  244. data/ext/libuv/test/test-udp-dgram-too-big.c +86 -0
  245. data/ext/libuv/test/test-udp-ipv6.c +156 -0
  246. data/ext/libuv/test/test-udp-multicast-join.c +139 -0
  247. data/ext/libuv/test/test-udp-multicast-ttl.c +86 -0
  248. data/ext/libuv/test/test-udp-options.c +86 -0
  249. data/ext/libuv/test/test-udp-send-and-recv.c +208 -0
  250. data/ext/libuv/test/test-util.c +97 -0
  251. data/ext/libuv/test/test-walk-handles.c +77 -0
  252. data/ext/libuv/uv.gyp +375 -0
  253. data/ext/libuv/vcbuild.bat +105 -0
  254. data/foolio.gemspec +18 -0
  255. data/lib/foolio.rb +9 -0
  256. data/lib/foolio/handle.rb +27 -0
  257. data/lib/foolio/listener.rb +26 -0
  258. data/lib/foolio/loop.rb +79 -0
  259. data/lib/foolio/stream.rb +109 -0
  260. data/lib/foolio/version.rb +3 -0
  261. metadata +309 -0
@@ -0,0 +1,1948 @@
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->stat) != 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->stat;
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->stat) != 0) {
939
+ SET_REQ_WIN32_ERROR(req, GetLastError());
940
+ return;
941
+ }
942
+
943
+ req->ptr = &req->stat;
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
+ return;
1141
+ }
1142
+
1143
+ req->result = 0;
1144
+ }
1145
+
1146
+
1147
+ static void fs__futime(uv_fs_t* req) {
1148
+ int fd = req->fd;
1149
+ HANDLE handle;
1150
+ VERIFY_FD(fd, req);
1151
+
1152
+ handle = (HANDLE) _get_osfhandle(fd);
1153
+
1154
+ if (handle == INVALID_HANDLE_VALUE) {
1155
+ SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
1156
+ return;
1157
+ }
1158
+
1159
+ if (fs__utime_handle(handle, req->atime, req->mtime) != 0) {
1160
+ SET_REQ_WIN32_ERROR(req, GetLastError());
1161
+ return;
1162
+ }
1163
+
1164
+ req->result = 0;
1165
+ }
1166
+
1167
+
1168
+ static void fs__link(uv_fs_t* req) {
1169
+ DWORD r = CreateHardLinkW(req->new_pathw, req->pathw, NULL);
1170
+ if (r == 0) {
1171
+ SET_REQ_WIN32_ERROR(req, GetLastError());
1172
+ } else {
1173
+ req->result = 0;
1174
+ }
1175
+ }
1176
+
1177
+
1178
+ static void fs__create_junction(uv_fs_t* req, const WCHAR* path,
1179
+ const WCHAR* new_path) {
1180
+ HANDLE handle = INVALID_HANDLE_VALUE;
1181
+ REPARSE_DATA_BUFFER *buffer = NULL;
1182
+ int created = 0;
1183
+ int target_len;
1184
+ int is_absolute, is_long_path;
1185
+ int needed_buf_size, used_buf_size, used_data_size, path_buf_len;
1186
+ int start, len, i;
1187
+ int add_slash;
1188
+ DWORD bytes;
1189
+ WCHAR* path_buf;
1190
+
1191
+ target_len = wcslen(path);
1192
+ is_long_path = wcsncmp(path, LONG_PATH_PREFIX, LONG_PATH_PREFIX_LEN) == 0;
1193
+
1194
+ if (is_long_path) {
1195
+ is_absolute = 1;
1196
+ } else {
1197
+ is_absolute = target_len >= 3 && IS_LETTER(path[0]) &&
1198
+ path[1] == L':' && IS_SLASH(path[2]);
1199
+ }
1200
+
1201
+ if (!is_absolute) {
1202
+ /* Not supporting relative paths */
1203
+ SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_NOT_SUPPORTED);
1204
+ return;
1205
+ }
1206
+
1207
+ // Do a pessimistic calculation of the required buffer size
1208
+ needed_buf_size =
1209
+ FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) +
1210
+ JUNCTION_PREFIX_LEN * sizeof(WCHAR) +
1211
+ 2 * (target_len + 2) * sizeof(WCHAR);
1212
+
1213
+ // Allocate the buffer
1214
+ buffer = (REPARSE_DATA_BUFFER*)malloc(needed_buf_size);
1215
+ if (!buffer) {
1216
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
1217
+ }
1218
+
1219
+ // Grab a pointer to the part of the buffer where filenames go
1220
+ path_buf = (WCHAR*)&(buffer->MountPointReparseBuffer.PathBuffer);
1221
+ path_buf_len = 0;
1222
+
1223
+ // Copy the substitute (internal) target path
1224
+ start = path_buf_len;
1225
+
1226
+ wcsncpy((WCHAR*)&path_buf[path_buf_len], JUNCTION_PREFIX,
1227
+ JUNCTION_PREFIX_LEN);
1228
+ path_buf_len += JUNCTION_PREFIX_LEN;
1229
+
1230
+ add_slash = 0;
1231
+ for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) {
1232
+ if (IS_SLASH(path[i])) {
1233
+ add_slash = 1;
1234
+ continue;
1235
+ }
1236
+
1237
+ if (add_slash) {
1238
+ path_buf[path_buf_len++] = L'\\';
1239
+ add_slash = 0;
1240
+ }
1241
+
1242
+ path_buf[path_buf_len++] = path[i];
1243
+ }
1244
+ path_buf[path_buf_len++] = L'\\';
1245
+ len = path_buf_len - start;
1246
+
1247
+ // Set the info about the substitute name
1248
+ buffer->MountPointReparseBuffer.SubstituteNameOffset = start * sizeof(WCHAR);
1249
+ buffer->MountPointReparseBuffer.SubstituteNameLength = len * sizeof(WCHAR);
1250
+
1251
+ // Insert null terminator
1252
+ path_buf[path_buf_len++] = L'\0';
1253
+
1254
+ // Copy the print name of the target path
1255
+ start = path_buf_len;
1256
+ add_slash = 0;
1257
+ for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) {
1258
+ if (IS_SLASH(path[i])) {
1259
+ add_slash = 1;
1260
+ continue;
1261
+ }
1262
+
1263
+ if (add_slash) {
1264
+ path_buf[path_buf_len++] = L'\\';
1265
+ add_slash = 0;
1266
+ }
1267
+
1268
+ path_buf[path_buf_len++] = path[i];
1269
+ }
1270
+ len = path_buf_len - start;
1271
+ if (len == 2) {
1272
+ path_buf[path_buf_len++] = L'\\';
1273
+ len++;
1274
+ }
1275
+
1276
+ // Set the info about the print name
1277
+ buffer->MountPointReparseBuffer.PrintNameOffset = start * sizeof(WCHAR);
1278
+ buffer->MountPointReparseBuffer.PrintNameLength = len * sizeof(WCHAR);
1279
+
1280
+ // Insert another null terminator
1281
+ path_buf[path_buf_len++] = L'\0';
1282
+
1283
+ // Calculate how much buffer space was actually used
1284
+ used_buf_size = FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) +
1285
+ path_buf_len * sizeof(WCHAR);
1286
+ used_data_size = used_buf_size -
1287
+ FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer);
1288
+
1289
+ // Put general info in the data buffer
1290
+ buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
1291
+ buffer->ReparseDataLength = used_data_size;
1292
+ buffer->Reserved = 0;
1293
+
1294
+ // Create a new directory
1295
+ if (!CreateDirectoryW(new_path, NULL)) {
1296
+ SET_REQ_WIN32_ERROR(req, GetLastError());
1297
+ goto error;
1298
+ }
1299
+ created = 1;
1300
+
1301
+ // Open the directory
1302
+ handle = CreateFileW(new_path,
1303
+ GENERIC_ALL,
1304
+ 0,
1305
+ NULL,
1306
+ OPEN_EXISTING,
1307
+ FILE_FLAG_BACKUP_SEMANTICS |
1308
+ FILE_FLAG_OPEN_REPARSE_POINT,
1309
+ NULL);
1310
+ if (handle == INVALID_HANDLE_VALUE) {
1311
+ SET_REQ_WIN32_ERROR(req, GetLastError());
1312
+ goto error;
1313
+ }
1314
+
1315
+ // Create the actual reparse point
1316
+ if (!DeviceIoControl(handle,
1317
+ FSCTL_SET_REPARSE_POINT,
1318
+ buffer,
1319
+ used_buf_size,
1320
+ NULL,
1321
+ 0,
1322
+ &bytes,
1323
+ NULL)) {
1324
+ SET_REQ_WIN32_ERROR(req, GetLastError());
1325
+ goto error;
1326
+ }
1327
+
1328
+ // Clean up
1329
+ CloseHandle(handle);
1330
+ free(buffer);
1331
+
1332
+ SET_REQ_RESULT(req, 0);
1333
+ return;
1334
+
1335
+ error:
1336
+ free(buffer);
1337
+
1338
+ if (handle != INVALID_HANDLE_VALUE) {
1339
+ CloseHandle(handle);
1340
+ }
1341
+
1342
+ if (created) {
1343
+ RemoveDirectoryW(new_path);
1344
+ }
1345
+ }
1346
+
1347
+
1348
+ static void fs__symlink(uv_fs_t* req) {
1349
+ WCHAR* pathw = req->pathw;
1350
+ WCHAR* new_pathw = req->new_pathw;
1351
+ int flags = req->file_flags;
1352
+ int result;
1353
+
1354
+
1355
+ if (flags & UV_FS_SYMLINK_JUNCTION) {
1356
+ fs__create_junction(req, pathw, new_pathw);
1357
+ } else if (pCreateSymbolicLinkW) {
1358
+ result = pCreateSymbolicLinkW(new_pathw,
1359
+ pathw,
1360
+ flags & UV_FS_SYMLINK_DIR ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) ? 0 : -1;
1361
+ if (result == -1) {
1362
+ SET_REQ_WIN32_ERROR(req, GetLastError());
1363
+ } else {
1364
+ SET_REQ_RESULT(req, result);
1365
+ }
1366
+ } else {
1367
+ SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED);
1368
+ }
1369
+ }
1370
+
1371
+
1372
+ static void fs__readlink(uv_fs_t* req) {
1373
+ HANDLE handle;
1374
+
1375
+ handle = CreateFileW(req->pathw,
1376
+ 0,
1377
+ 0,
1378
+ NULL,
1379
+ OPEN_EXISTING,
1380
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
1381
+ NULL);
1382
+
1383
+ if (handle == INVALID_HANDLE_VALUE) {
1384
+ SET_REQ_WIN32_ERROR(req, GetLastError());
1385
+ return;
1386
+ }
1387
+
1388
+ if (fs__readlink_handle(handle, (char**) &req->ptr, NULL) != 0) {
1389
+ SET_REQ_WIN32_ERROR(req, GetLastError());
1390
+ CloseHandle(handle);
1391
+ return;
1392
+ }
1393
+
1394
+ req->flags |= UV_FS_FREE_PTR;
1395
+ SET_REQ_RESULT(req, 0);
1396
+
1397
+ CloseHandle(handle);
1398
+ }
1399
+
1400
+
1401
+
1402
+ static void fs__chown(uv_fs_t* req) {
1403
+ req->result = 0;
1404
+ }
1405
+
1406
+
1407
+ static void fs__fchown(uv_fs_t* req) {
1408
+ req->result = 0;
1409
+ }
1410
+
1411
+
1412
+ static DWORD WINAPI uv_fs_thread_proc(void* parameter) {
1413
+ uv_fs_t* req = (uv_fs_t*) parameter;
1414
+ uv_loop_t* loop = req->loop;
1415
+
1416
+ assert(req != NULL);
1417
+ assert(req->type == UV_FS);
1418
+
1419
+ #define XX(uc, lc) case UV_FS_##uc: fs__##lc(req); break;
1420
+ switch (req->fs_type) {
1421
+ XX(OPEN, open)
1422
+ XX(CLOSE, close)
1423
+ XX(READ, read)
1424
+ XX(WRITE, write)
1425
+ XX(SENDFILE, sendfile)
1426
+ XX(STAT, stat)
1427
+ XX(LSTAT, lstat)
1428
+ XX(FSTAT, fstat)
1429
+ XX(FTRUNCATE, ftruncate)
1430
+ XX(UTIME, utime)
1431
+ XX(FUTIME, futime)
1432
+ XX(CHMOD, chmod)
1433
+ XX(FCHMOD, fchmod)
1434
+ XX(FSYNC, fsync)
1435
+ XX(FDATASYNC, fdatasync)
1436
+ XX(UNLINK, unlink)
1437
+ XX(RMDIR, rmdir)
1438
+ XX(MKDIR, mkdir)
1439
+ XX(RENAME, rename)
1440
+ XX(READDIR, readdir)
1441
+ XX(LINK, link)
1442
+ XX(SYMLINK, symlink)
1443
+ XX(READLINK, readlink)
1444
+ XX(CHOWN, chown)
1445
+ XX(FCHOWN, fchown);
1446
+ default:
1447
+ assert(!"bad uv_fs_type");
1448
+ }
1449
+
1450
+ POST_COMPLETION_FOR_REQ(loop, req);
1451
+ return 0;
1452
+ }
1453
+
1454
+
1455
+ int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
1456
+ int mode, uv_fs_cb cb) {
1457
+ uv_fs_req_init(loop, req, UV_FS_OPEN, cb);
1458
+
1459
+ if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
1460
+ return -1;
1461
+ }
1462
+
1463
+ req->file_flags = flags;
1464
+ req->mode = mode;
1465
+
1466
+ if (cb) {
1467
+ QUEUE_FS_TP_JOB(loop, req);
1468
+ return 0;
1469
+ } else {
1470
+ fs__open(req);
1471
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1472
+ return req->result;
1473
+ }
1474
+ }
1475
+
1476
+
1477
+ int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
1478
+ uv_fs_req_init(loop, req, UV_FS_CLOSE, cb);
1479
+ req->fd = fd;
1480
+
1481
+ if (cb) {
1482
+ QUEUE_FS_TP_JOB(loop, req);
1483
+ return 0;
1484
+ } else {
1485
+ fs__close(req);
1486
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1487
+ return req->result;
1488
+ }
1489
+ }
1490
+
1491
+
1492
+ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file fd, void* buf,
1493
+ size_t length, int64_t offset, uv_fs_cb cb) {
1494
+ uv_fs_req_init(loop, req, UV_FS_READ, cb);
1495
+
1496
+ req->fd = fd;
1497
+ req->buf = buf;
1498
+ req->length = length;
1499
+ req->offset = offset;
1500
+
1501
+ if (cb) {
1502
+ QUEUE_FS_TP_JOB(loop, req);
1503
+ return 0;
1504
+ } else {
1505
+ fs__read(req);
1506
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1507
+ return req->result;
1508
+ }
1509
+ }
1510
+
1511
+
1512
+ int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file fd, void* buf,
1513
+ size_t length, int64_t offset, uv_fs_cb cb) {
1514
+ uv_fs_req_init(loop, req, UV_FS_WRITE, cb);
1515
+
1516
+ req->fd = fd;
1517
+ req->buf = buf;
1518
+ req->length = length;
1519
+ req->offset = offset;
1520
+
1521
+ if (cb) {
1522
+ QUEUE_FS_TP_JOB(loop, req);
1523
+ return 0;
1524
+ } else {
1525
+ fs__write(req);
1526
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1527
+ return req->result;
1528
+ }
1529
+ }
1530
+
1531
+
1532
+ int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
1533
+ uv_fs_cb cb) {
1534
+ uv_fs_req_init(loop, req, UV_FS_UNLINK, cb);
1535
+
1536
+ if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
1537
+ return -1;
1538
+ }
1539
+
1540
+ if (cb) {
1541
+ QUEUE_FS_TP_JOB(loop, req);
1542
+ return 0;
1543
+ } else {
1544
+ fs__unlink(req);
1545
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1546
+ return req->result;
1547
+ }
1548
+ }
1549
+
1550
+
1551
+ int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
1552
+ uv_fs_cb cb) {
1553
+ uv_fs_req_init(loop, req, UV_FS_MKDIR, cb);
1554
+
1555
+ if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
1556
+ return -1;
1557
+ }
1558
+
1559
+ req->mode = mode;
1560
+
1561
+ if (cb) {
1562
+ QUEUE_FS_TP_JOB(loop, req);
1563
+ return 0;
1564
+ } else {
1565
+ fs__mkdir(req);
1566
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1567
+ return req->result;
1568
+ }
1569
+ }
1570
+
1571
+
1572
+ int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
1573
+ uv_fs_req_init(loop, req, UV_FS_RMDIR, cb);
1574
+
1575
+ if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
1576
+ return -1;
1577
+ }
1578
+
1579
+ if (cb) {
1580
+ QUEUE_FS_TP_JOB(loop, req);
1581
+ return 0;
1582
+ } else {
1583
+ fs__rmdir(req);
1584
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1585
+ return req->result;
1586
+ }
1587
+ }
1588
+
1589
+
1590
+ int uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
1591
+ uv_fs_cb cb) {
1592
+ uv_fs_req_init(loop, req, UV_FS_READDIR, cb);
1593
+
1594
+ if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
1595
+ return -1;
1596
+ }
1597
+
1598
+ req->file_flags;
1599
+
1600
+ if (cb) {
1601
+ QUEUE_FS_TP_JOB(loop, req);
1602
+ return 0;
1603
+ } else {
1604
+ fs__readdir(req);
1605
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1606
+ return req->result;
1607
+ }
1608
+ }
1609
+
1610
+
1611
+ int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path,
1612
+ const char* new_path, uv_fs_cb cb) {
1613
+ uv_fs_req_init(loop, req, UV_FS_LINK, cb);
1614
+
1615
+ if (fs__capture_path(loop, req, path, new_path, cb != NULL) < 0) {
1616
+ return -1;
1617
+ }
1618
+
1619
+ if (cb) {
1620
+ QUEUE_FS_TP_JOB(loop, req);
1621
+ return 0;
1622
+ } else {
1623
+ fs__link(req);
1624
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1625
+ return req->result;
1626
+ }
1627
+ }
1628
+
1629
+
1630
+ int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
1631
+ const char* new_path, int flags, uv_fs_cb cb) {
1632
+ uv_fs_req_init(loop, req, UV_FS_SYMLINK, cb);
1633
+
1634
+ if (fs__capture_path(loop, req, path, new_path, cb != NULL) < 0) {
1635
+ return -1;
1636
+ }
1637
+
1638
+ req->file_flags = flags;
1639
+
1640
+ if (cb) {
1641
+ QUEUE_FS_TP_JOB(loop, req);
1642
+ return 0;
1643
+ } else {
1644
+ fs__symlink(req);
1645
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1646
+ return req->result;
1647
+ }
1648
+ }
1649
+
1650
+
1651
+ int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
1652
+ uv_fs_cb cb) {
1653
+ uv_fs_req_init(loop, req, UV_FS_READLINK, cb);
1654
+
1655
+ if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
1656
+ return -1;
1657
+ }
1658
+
1659
+ if (cb) {
1660
+ QUEUE_FS_TP_JOB(loop, req);
1661
+ return 0;
1662
+ } else {
1663
+ fs__readlink(req);
1664
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1665
+ return req->result;
1666
+ }
1667
+ }
1668
+
1669
+
1670
+ int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, int uid,
1671
+ int gid, uv_fs_cb cb) {
1672
+ uv_fs_req_init(loop, req, UV_FS_CHOWN, cb);
1673
+
1674
+ if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
1675
+ return -1;
1676
+ }
1677
+
1678
+ if (cb) {
1679
+ QUEUE_FS_TP_JOB(loop, req);
1680
+ return 0;
1681
+ } else {
1682
+ fs__chown(req);
1683
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1684
+ return req->result;
1685
+ }
1686
+ }
1687
+
1688
+
1689
+ int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int uid,
1690
+ int gid, uv_fs_cb cb) {
1691
+ uv_fs_req_init(loop, req, UV_FS_FCHOWN, cb);
1692
+
1693
+ if (cb) {
1694
+ QUEUE_FS_TP_JOB(loop, req);
1695
+ return 0;
1696
+ } else {
1697
+ fs__fchown(req);
1698
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1699
+ return req->result;
1700
+ }
1701
+ }
1702
+
1703
+
1704
+ int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
1705
+ uv_fs_req_init(loop, req, UV_FS_STAT, cb);
1706
+
1707
+ if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
1708
+ return -1;
1709
+ }
1710
+
1711
+ if (cb) {
1712
+ QUEUE_FS_TP_JOB(loop, req);
1713
+ return 0;
1714
+ } else {
1715
+ fs__stat(req);
1716
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1717
+ return req->result;
1718
+ }
1719
+ }
1720
+
1721
+
1722
+ int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
1723
+ uv_fs_req_init(loop, req, UV_FS_LSTAT, cb);
1724
+
1725
+ if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
1726
+ return -1;
1727
+ }
1728
+
1729
+ if (cb) {
1730
+ QUEUE_FS_TP_JOB(loop, req);
1731
+ return 0;
1732
+ } else {
1733
+ fs__lstat(req);
1734
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1735
+ return req->result;
1736
+ }
1737
+ }
1738
+
1739
+
1740
+ int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
1741
+ uv_fs_req_init(loop, req, UV_FS_FSTAT, cb);
1742
+ req->fd = fd;
1743
+
1744
+ if (cb) {
1745
+ QUEUE_FS_TP_JOB(loop, req);
1746
+ return 0;
1747
+ } else {
1748
+ fs__fstat(req);
1749
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1750
+ return req->result;
1751
+ }
1752
+ }
1753
+
1754
+
1755
+ int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path,
1756
+ const char* new_path, uv_fs_cb cb) {
1757
+ uv_fs_req_init(loop, req, UV_FS_RENAME, cb);
1758
+
1759
+ if (fs__capture_path(loop, req, path, new_path, cb != NULL) < 0) {
1760
+ return -1;
1761
+ }
1762
+
1763
+ if (cb) {
1764
+ QUEUE_FS_TP_JOB(loop, req);
1765
+ return 0;
1766
+ } else {
1767
+ fs__rename(req);
1768
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1769
+ return req->result;
1770
+ }
1771
+ }
1772
+
1773
+
1774
+ int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
1775
+ uv_fs_req_init(loop, req, UV_FS_FSYNC, cb);
1776
+ req->fd = fd;
1777
+
1778
+ if (cb) {
1779
+ QUEUE_FS_TP_JOB(loop, req);
1780
+ return 0;
1781
+ } else {
1782
+ fs__fsync(req);
1783
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1784
+ return req->result;
1785
+ }
1786
+ }
1787
+
1788
+
1789
+ int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
1790
+ uv_fs_req_init(loop, req, UV_FS_FDATASYNC, cb);
1791
+ req->fd = fd;
1792
+
1793
+ if (cb) {
1794
+ QUEUE_FS_TP_JOB(loop, req);
1795
+ return 0;
1796
+ } else {
1797
+ fs__fdatasync(req);
1798
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1799
+ return req->result;
1800
+ }
1801
+ }
1802
+
1803
+
1804
+ int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file fd,
1805
+ int64_t offset, uv_fs_cb cb) {
1806
+ uv_fs_req_init(loop, req, UV_FS_FTRUNCATE, cb);
1807
+
1808
+ req->fd = fd;
1809
+ req->offset = offset;
1810
+
1811
+ if (cb) {
1812
+ QUEUE_FS_TP_JOB(loop, req);
1813
+ return 0;
1814
+ } else {
1815
+ fs__ftruncate(req);
1816
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1817
+ return req->result;
1818
+ }
1819
+ }
1820
+
1821
+
1822
+
1823
+ int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file fd_out,
1824
+ uv_file fd_in, int64_t in_offset, size_t length, uv_fs_cb cb) {
1825
+ uv_fs_req_init(loop, req, UV_FS_SENDFILE, cb);
1826
+
1827
+ req->fd = fd_in;
1828
+ req->fd_out = fd_out;
1829
+ req->offset = in_offset;
1830
+ req->length = length;
1831
+
1832
+ if (cb) {
1833
+ QUEUE_FS_TP_JOB(loop, req);
1834
+ return 0;
1835
+ } else {
1836
+ fs__sendfile(req);
1837
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1838
+ return req->result;
1839
+ }
1840
+ }
1841
+
1842
+
1843
+ int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
1844
+ uv_fs_cb cb) {
1845
+ uv_fs_req_init(loop, req, UV_FS_CHMOD, cb);
1846
+
1847
+ if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
1848
+ return -1;
1849
+ }
1850
+
1851
+ req->mode = mode;
1852
+
1853
+ if (cb) {
1854
+ QUEUE_FS_TP_JOB(loop, req);
1855
+ return 0;
1856
+ } else {
1857
+ fs__chmod(req);
1858
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1859
+ return req->result;
1860
+ }
1861
+ }
1862
+
1863
+
1864
+ int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int mode,
1865
+ uv_fs_cb cb) {
1866
+ uv_fs_req_init(loop, req, UV_FS_FCHMOD, cb);
1867
+
1868
+ req->fd = fd;
1869
+ req->mode = mode;
1870
+
1871
+ if (cb) {
1872
+ QUEUE_FS_TP_JOB(loop, req);
1873
+ return 0;
1874
+ } else {
1875
+ fs__fchmod(req);
1876
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1877
+ return req->result;
1878
+ }
1879
+ }
1880
+
1881
+
1882
+ int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
1883
+ double mtime, uv_fs_cb cb) {
1884
+ uv_fs_req_init(loop, req, UV_FS_UTIME, cb);
1885
+
1886
+ if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
1887
+ return -1;
1888
+ }
1889
+
1890
+ req->atime = atime;
1891
+ req->mtime = mtime;
1892
+
1893
+ if (cb) {
1894
+ QUEUE_FS_TP_JOB(loop, req);
1895
+ return 0;
1896
+ } else {
1897
+ fs__utime(req);
1898
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1899
+ return req->result;
1900
+ }
1901
+ }
1902
+
1903
+
1904
+ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime,
1905
+ double mtime, uv_fs_cb cb) {
1906
+ uv_fs_req_init(loop, req, UV_FS_FUTIME, cb);
1907
+
1908
+ req->fd = fd;
1909
+ req->atime = atime;
1910
+ req->mtime = mtime;
1911
+
1912
+ if (cb) {
1913
+ QUEUE_FS_TP_JOB(loop, req);
1914
+ return 0;
1915
+ } else {
1916
+ fs__futime(req);
1917
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1918
+ return req->result;
1919
+ }
1920
+ }
1921
+
1922
+
1923
+ void uv_process_fs_req(uv_loop_t* loop, uv_fs_t* req) {
1924
+ assert(req->cb);
1925
+ uv__req_unregister(loop, req);
1926
+ SET_UV_LAST_ERROR_FROM_REQ(req);
1927
+ req->cb(req);
1928
+ }
1929
+
1930
+
1931
+ void uv_fs_req_cleanup(uv_fs_t* req) {
1932
+ if (req->flags & UV_FS_CLEANEDUP)
1933
+ return;
1934
+
1935
+ if (req->flags & UV_FS_FREE_PATHS)
1936
+ free(req->pathw);
1937
+
1938
+ if (req->flags & UV_FS_FREE_PTR)
1939
+ free(req->ptr);
1940
+
1941
+ req->path = NULL;
1942
+ req->pathw = NULL;
1943
+ req->new_pathw = NULL;
1944
+ req->ptr = NULL;
1945
+
1946
+ req->flags |= UV_FS_CLEANEDUP;
1947
+ }
1948
+