foolio 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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
+