/src/win/fs.c

http://github.com/joyent/libuv · C · 1951 lines · 1483 code · 383 blank · 85 comment · 360 complexity · 3490ff24b3beb8ba60b467147e8ed109 MD5 · raw file

  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. #include <assert.h>
  22. #include <malloc.h>
  23. #include <direct.h>
  24. #include <errno.h>
  25. #include <fcntl.h>
  26. #include <io.h>
  27. #include <limits.h>
  28. #include <sys/stat.h>
  29. #include <sys/utime.h>
  30. #include <stdio.h>
  31. #include "uv.h"
  32. #include "internal.h"
  33. #include "req-inl.h"
  34. #define UV_FS_FREE_PATHS 0x0002
  35. #define UV_FS_FREE_PTR 0x0008
  36. #define UV_FS_CLEANEDUP 0x0010
  37. #define QUEUE_FS_TP_JOB(loop, req) \
  38. if (!QueueUserWorkItem(&uv_fs_thread_proc, \
  39. req, \
  40. WT_EXECUTEDEFAULT)) { \
  41. uv__set_sys_error((loop), GetLastError()); \
  42. return -1; \
  43. } \
  44. uv__req_register(loop, req);
  45. #define SET_UV_LAST_ERROR_FROM_REQ(req) \
  46. uv__set_error(req->loop, req->errorno, req->sys_errno_);
  47. #define SET_REQ_RESULT(req, result_value) \
  48. req->result = (result_value); \
  49. if (req->result == -1) { \
  50. req->sys_errno_ = _doserrno; \
  51. req->errorno = uv_translate_sys_error(req->sys_errno_); \
  52. }
  53. #define SET_REQ_WIN32_ERROR(req, sys_errno) \
  54. req->result = -1; \
  55. req->sys_errno_ = (sys_errno); \
  56. req->errorno = uv_translate_sys_error(req->sys_errno_);
  57. #define SET_REQ_UV_ERROR(req, uv_errno, sys_errno) \
  58. req->result = -1; \
  59. req->sys_errno_ = (sys_errno); \
  60. req->errorno = (uv_errno);
  61. #define VERIFY_FD(fd, req) \
  62. if (fd == -1) { \
  63. req->result = -1; \
  64. req->errorno = UV_EBADF; \
  65. req->sys_errno_ = ERROR_INVALID_HANDLE; \
  66. return; \
  67. }
  68. #define FILETIME_TO_TIME_T(filetime) \
  69. ((*((uint64_t*) &(filetime)) - 116444736000000000ULL) / 10000000ULL);
  70. #define TIME_T_TO_FILETIME(time, filetime_ptr) \
  71. do { \
  72. *(uint64_t*) (filetime_ptr) = ((int64_t) (time) * 10000000LL) + \
  73. 116444736000000000ULL; \
  74. } while(0)
  75. #define IS_SLASH(c) ((c) == L'\\' || (c) == L'/')
  76. #define IS_LETTER(c) (((c) >= L'a' && (c) <= L'z') || \
  77. ((c) >= L'A' && (c) <= L'Z'))
  78. const WCHAR JUNCTION_PREFIX[] = L"\\??\\";
  79. const WCHAR JUNCTION_PREFIX_LEN = 4;
  80. const WCHAR LONG_PATH_PREFIX[] = L"\\\\?\\";
  81. const WCHAR LONG_PATH_PREFIX_LEN = 4;
  82. void uv_fs_init() {
  83. _fmode = _O_BINARY;
  84. }
  85. INLINE static int fs__capture_path(uv_loop_t* loop, uv_fs_t* req,
  86. const char* path, const char* new_path, const int copy_path) {
  87. char* buf;
  88. char* pos;
  89. ssize_t buf_sz = 0, path_len, pathw_len, new_pathw_len;
  90. /* new_path can only be set if path is also set. */
  91. assert(new_path == NULL || path != NULL);
  92. if (path != NULL) {
  93. pathw_len = MultiByteToWideChar(CP_UTF8,
  94. 0,
  95. path,
  96. -1,
  97. NULL,
  98. 0);
  99. if (pathw_len == 0) {
  100. uv__set_sys_error(loop, GetLastError());
  101. return -1;
  102. }
  103. buf_sz += pathw_len * sizeof(WCHAR);
  104. }
  105. if (path != NULL && copy_path) {
  106. path_len = 1 + strlen(path);
  107. buf_sz += path_len;
  108. }
  109. if (new_path != NULL) {
  110. new_pathw_len = MultiByteToWideChar(CP_UTF8,
  111. 0,
  112. new_path,
  113. -1,
  114. NULL,
  115. 0);
  116. if (new_pathw_len == 0) {
  117. uv__set_sys_error(loop, GetLastError());
  118. return -1;
  119. }
  120. buf_sz += new_pathw_len * sizeof(WCHAR);
  121. }
  122. if (buf_sz == 0) {
  123. req->pathw = NULL;
  124. req->new_pathw = NULL;
  125. req->path = NULL;
  126. return 0;
  127. }
  128. buf = (char*) malloc(buf_sz);
  129. if (buf == NULL) {
  130. uv__set_artificial_error(loop, UV_ENOMEM);
  131. return -1;
  132. }
  133. pos = buf;
  134. if (path != NULL) {
  135. DWORD r = MultiByteToWideChar(CP_UTF8,
  136. 0,
  137. path,
  138. -1,
  139. (WCHAR*) pos,
  140. pathw_len);
  141. assert(r == pathw_len);
  142. req->pathw = (WCHAR*) pos;
  143. pos += r * sizeof(WCHAR);
  144. } else {
  145. req->pathw = NULL;
  146. }
  147. if (new_path != NULL) {
  148. DWORD r = MultiByteToWideChar(CP_UTF8,
  149. 0,
  150. new_path,
  151. -1,
  152. (WCHAR*) pos,
  153. new_pathw_len);
  154. assert(r == new_pathw_len);
  155. req->new_pathw = (WCHAR*) pos;
  156. pos += r * sizeof(WCHAR);
  157. } else {
  158. req->new_pathw = NULL;
  159. }
  160. if (!copy_path) {
  161. req->path = path;
  162. } else if (path) {
  163. memcpy(pos, path, path_len);
  164. assert(path_len == buf_sz - (pos - buf));
  165. req->path = pos;
  166. } else {
  167. req->path = NULL;
  168. }
  169. req->flags |= UV_FS_FREE_PATHS;
  170. return 0;
  171. }
  172. INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req,
  173. uv_fs_type fs_type, const uv_fs_cb cb) {
  174. uv_req_init(loop, (uv_req_t*) req);
  175. req->type = UV_FS;
  176. req->loop = loop;
  177. req->flags = 0;
  178. req->fs_type = fs_type;
  179. req->result = 0;
  180. req->ptr = NULL;
  181. req->errorno = UV_OK;
  182. req->path = NULL;
  183. if (cb != NULL) {
  184. req->cb = cb;
  185. memset(&req->overlapped, 0, sizeof(req->overlapped));
  186. }
  187. }
  188. static int is_path_dir(const WCHAR* path) {
  189. DWORD attr = GetFileAttributesW(path);
  190. if (attr != INVALID_FILE_ATTRIBUTES) {
  191. return attr & FILE_ATTRIBUTE_DIRECTORY ? 1 : 0;
  192. } else {
  193. return 0;
  194. }
  195. }
  196. INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
  197. int64_t* target_len_ptr) {
  198. char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
  199. REPARSE_DATA_BUFFER* reparse_data = (REPARSE_DATA_BUFFER*) buffer;
  200. WCHAR *w_target;
  201. DWORD w_target_len;
  202. char* target;
  203. int target_len;
  204. DWORD bytes;
  205. if (!DeviceIoControl(handle,
  206. FSCTL_GET_REPARSE_POINT,
  207. NULL,
  208. 0,
  209. buffer,
  210. sizeof buffer,
  211. &bytes,
  212. NULL)) {
  213. return -1;
  214. }
  215. if (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
  216. /* Real symlink */
  217. w_target = reparse_data->SymbolicLinkReparseBuffer.PathBuffer +
  218. (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset /
  219. sizeof(WCHAR));
  220. w_target_len =
  221. reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength /
  222. sizeof(WCHAR);
  223. /* Real symlinks can contain pretty much everything, but the only thing */
  224. /* we really care about is undoing the implicit conversion to an NT */
  225. /* namespaced path that CreateSymbolicLink will perform on absolute */
  226. /* paths. If the path is win32-namespaced then the user must have */
  227. /* explicitly made it so, and we better just return the unmodified */
  228. /* reparse data. */
  229. if (w_target_len >= 4 &&
  230. w_target[0] == L'\\' &&
  231. w_target[1] == L'?' &&
  232. w_target[2] == L'?' &&
  233. w_target[3] == L'\\') {
  234. /* Starts with \??\ */
  235. if (w_target_len >= 6 &&
  236. ((w_target[4] >= L'A' && w_target[4] <= L'Z') ||
  237. (w_target[4] >= L'a' && w_target[4] <= L'z')) &&
  238. w_target[5] == L':' &&
  239. (w_target_len == 6 || w_target[6] == L'\\')) {
  240. /* \??\?drive?:\ */
  241. w_target += 4;
  242. w_target_len -= 4;
  243. } else if (w_target_len >= 8 &&
  244. (w_target[4] == L'U' || w_target[4] == L'u') &&
  245. (w_target[5] == L'N' || w_target[5] == L'n') &&
  246. (w_target[6] == L'C' || w_target[6] == L'c') &&
  247. w_target[7] == L'\\') {
  248. /* \??\UNC\?server?\?share?\ - make sure the final path looks like */
  249. /* \\?server?\?share?\ */
  250. w_target += 6;
  251. w_target[0] = L'\\';
  252. w_target_len -= 6;
  253. }
  254. }
  255. } else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
  256. /* Junction. */
  257. w_target = reparse_data->MountPointReparseBuffer.PathBuffer +
  258. (reparse_data->MountPointReparseBuffer.SubstituteNameOffset /
  259. sizeof(WCHAR));
  260. w_target_len = reparse_data->MountPointReparseBuffer.SubstituteNameLength /
  261. sizeof(WCHAR);
  262. /* Only treat junctions that look like \??\?drive?:\ as symlink. */
  263. /* Junctions can also be used as mount points, like \??\Volume{?guid?}, */
  264. /* but that's confusing for programs since they wouldn't be able to */
  265. /* actually understand such a path when returned by uv_readlink(). */
  266. /* UNC paths are never valid for junctions so we don't care about them. */
  267. if (!(w_target_len >= 6 &&
  268. w_target[0] == L'\\' &&
  269. w_target[1] == L'?' &&
  270. w_target[2] == L'?' &&
  271. w_target[3] == L'\\' &&
  272. ((w_target[4] >= L'A' && w_target[4] <= L'Z') ||
  273. (w_target[4] >= L'a' && w_target[4] <= L'z')) &&
  274. w_target[5] == L':' &&
  275. (w_target_len == 6 || w_target[6] == L'\\'))) {
  276. SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
  277. return -1;
  278. }
  279. /* Remove leading \??\ */
  280. w_target += 4;
  281. w_target_len -= 4;
  282. } else {
  283. /* Reparse tag does not indicate a symlink. */
  284. SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
  285. return -1;
  286. }
  287. /* If needed, compute the length of the target. */
  288. if (target_ptr != NULL || target_len_ptr != NULL) {
  289. /* Compute the length of the target. */
  290. target_len = WideCharToMultiByte(CP_UTF8,
  291. 0,
  292. w_target,
  293. w_target_len,
  294. NULL,
  295. 0,
  296. NULL,
  297. NULL);
  298. if (target_len == 0) {
  299. return -1;
  300. }
  301. }
  302. /* If requested, allocate memory and convert to UTF8. */
  303. if (target_ptr != NULL) {
  304. int r;
  305. target = (char*) malloc(target_len + 1);
  306. if (target == NULL) {
  307. SetLastError(ERROR_OUTOFMEMORY);
  308. return -1;
  309. }
  310. r = WideCharToMultiByte(CP_UTF8,
  311. 0,
  312. w_target,
  313. w_target_len,
  314. target,
  315. target_len,
  316. NULL,
  317. NULL);
  318. assert(r == target_len);
  319. target[target_len] = '\0';
  320. *target_ptr = target;
  321. }
  322. if (target_len_ptr != NULL) {
  323. *target_len_ptr = target_len;
  324. }
  325. return 0;
  326. }
  327. void fs__open(uv_fs_t* req) {
  328. DWORD access;
  329. DWORD share;
  330. DWORD disposition;
  331. DWORD attributes = 0;
  332. HANDLE file;
  333. int result, current_umask;
  334. int flags = req->file_flags;
  335. /* Obtain the active umask. umask() never fails and returns the previous */
  336. /* umask. */
  337. current_umask = umask(0);
  338. umask(current_umask);
  339. /* convert flags and mode to CreateFile parameters */
  340. switch (flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
  341. case _O_RDONLY:
  342. access = FILE_GENERIC_READ;
  343. attributes |= FILE_FLAG_BACKUP_SEMANTICS;
  344. break;
  345. case _O_WRONLY:
  346. access = FILE_GENERIC_WRITE;
  347. break;
  348. case _O_RDWR:
  349. access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
  350. break;
  351. default:
  352. result = -1;
  353. goto end;
  354. }
  355. if (flags & _O_APPEND) {
  356. access &= ~FILE_WRITE_DATA;
  357. access |= FILE_APPEND_DATA;
  358. attributes &= ~FILE_FLAG_BACKUP_SEMANTICS;
  359. }
  360. /*
  361. * Here is where we deviate significantly from what CRT's _open()
  362. * does. We indiscriminately use all the sharing modes, to match
  363. * UNIX semantics. In particular, this ensures that the file can
  364. * be deleted even whilst it's open, fixing issue #1449.
  365. */
  366. share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
  367. switch (flags & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
  368. case 0:
  369. case _O_EXCL:
  370. disposition = OPEN_EXISTING;
  371. break;
  372. case _O_CREAT:
  373. disposition = OPEN_ALWAYS;
  374. break;
  375. case _O_CREAT | _O_EXCL:
  376. case _O_CREAT | _O_TRUNC | _O_EXCL:
  377. disposition = CREATE_NEW;
  378. break;
  379. case _O_TRUNC:
  380. case _O_TRUNC | _O_EXCL:
  381. disposition = TRUNCATE_EXISTING;
  382. break;
  383. case _O_CREAT | _O_TRUNC:
  384. disposition = CREATE_ALWAYS;
  385. break;
  386. default:
  387. result = -1;
  388. goto end;
  389. }
  390. attributes |= FILE_ATTRIBUTE_NORMAL;
  391. if (flags & _O_CREAT) {
  392. if (!((req->mode & ~current_umask) & _S_IWRITE)) {
  393. attributes |= FILE_ATTRIBUTE_READONLY;
  394. }
  395. }
  396. if (flags & _O_TEMPORARY ) {
  397. attributes |= FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY;
  398. access |= DELETE;
  399. }
  400. if (flags & _O_SHORT_LIVED) {
  401. attributes |= FILE_ATTRIBUTE_TEMPORARY;
  402. }
  403. switch (flags & (_O_SEQUENTIAL | _O_RANDOM)) {
  404. case 0:
  405. break;
  406. case _O_SEQUENTIAL:
  407. attributes |= FILE_FLAG_SEQUENTIAL_SCAN;
  408. break;
  409. case _O_RANDOM:
  410. attributes |= FILE_FLAG_RANDOM_ACCESS;
  411. break;
  412. default:
  413. result = -1;
  414. goto end;
  415. }
  416. /* Setting this flag makes it possible to open a directory. */
  417. attributes |= FILE_FLAG_BACKUP_SEMANTICS;
  418. file = CreateFileW(req->pathw,
  419. access,
  420. share,
  421. NULL,
  422. disposition,
  423. attributes,
  424. NULL);
  425. if (file == INVALID_HANDLE_VALUE) {
  426. DWORD error = GetLastError();
  427. if (error == ERROR_FILE_EXISTS && (flags & _O_CREAT) &&
  428. !(flags & _O_EXCL)) {
  429. /* Special case: when ERROR_FILE_EXISTS happens and O_CREAT was */
  430. /* specified, it means the path referred to a directory. */
  431. SET_REQ_UV_ERROR(req, UV_EISDIR, error);
  432. } else {
  433. SET_REQ_WIN32_ERROR(req, GetLastError());
  434. }
  435. return;
  436. }
  437. result = _open_osfhandle((intptr_t) file, flags);
  438. end:
  439. SET_REQ_RESULT(req, result);
  440. }
  441. void fs__close(uv_fs_t* req) {
  442. int fd = req->fd;
  443. int result;
  444. VERIFY_FD(fd, req);
  445. result = _close(fd);
  446. SET_REQ_RESULT(req, result);
  447. }
  448. void fs__read(uv_fs_t* req) {
  449. int fd = req->fd;
  450. size_t length = req->length;
  451. int64_t offset = req->offset;
  452. HANDLE handle;
  453. OVERLAPPED overlapped, *overlapped_ptr;
  454. LARGE_INTEGER offset_;
  455. DWORD bytes;
  456. DWORD error;
  457. VERIFY_FD(fd, req);
  458. handle = (HANDLE) _get_osfhandle(fd);
  459. if (handle == INVALID_HANDLE_VALUE) {
  460. SET_REQ_RESULT(req, -1);
  461. return;
  462. }
  463. if (length > INT_MAX) {
  464. SET_REQ_WIN32_ERROR(req, ERROR_INSUFFICIENT_BUFFER);
  465. return;
  466. }
  467. if (offset != -1) {
  468. memset(&overlapped, 0, sizeof overlapped);
  469. offset_.QuadPart = offset;
  470. overlapped.Offset = offset_.LowPart;
  471. overlapped.OffsetHigh = offset_.HighPart;
  472. overlapped_ptr = &overlapped;
  473. } else {
  474. overlapped_ptr = NULL;
  475. }
  476. if (ReadFile(handle, req->buf, req->length, &bytes, overlapped_ptr)) {
  477. SET_REQ_RESULT(req, bytes);
  478. } else {
  479. error = GetLastError();
  480. if (error == ERROR_HANDLE_EOF) {
  481. SET_REQ_RESULT(req, bytes);
  482. } else {
  483. SET_REQ_WIN32_ERROR(req, error);
  484. }
  485. }
  486. }
  487. void fs__write(uv_fs_t* req) {
  488. int fd = req->fd;
  489. size_t length = req->length;
  490. int64_t offset = req->offset;
  491. HANDLE handle;
  492. OVERLAPPED overlapped, *overlapped_ptr;
  493. LARGE_INTEGER offset_;
  494. DWORD bytes;
  495. VERIFY_FD(fd, req);
  496. handle = (HANDLE) _get_osfhandle(fd);
  497. if (handle == INVALID_HANDLE_VALUE) {
  498. SET_REQ_RESULT(req, -1);
  499. return;
  500. }
  501. if (length > INT_MAX) {
  502. SET_REQ_WIN32_ERROR(req, ERROR_INSUFFICIENT_BUFFER);
  503. return;
  504. }
  505. if (offset != -1) {
  506. memset(&overlapped, 0, sizeof overlapped);
  507. offset_.QuadPart = offset;
  508. overlapped.Offset = offset_.LowPart;
  509. overlapped.OffsetHigh = offset_.HighPart;
  510. overlapped_ptr = &overlapped;
  511. } else {
  512. overlapped_ptr = NULL;
  513. }
  514. if (WriteFile(handle, req->buf, length, &bytes, overlapped_ptr)) {
  515. SET_REQ_RESULT(req, bytes);
  516. } else {
  517. SET_REQ_WIN32_ERROR(req, GetLastError());
  518. }
  519. }
  520. void fs__rmdir(uv_fs_t* req) {
  521. int result = _wrmdir(req->pathw);
  522. SET_REQ_RESULT(req, result);
  523. }
  524. void fs__unlink(uv_fs_t* req) {
  525. const WCHAR* pathw = req->pathw;
  526. HANDLE handle;
  527. BY_HANDLE_FILE_INFORMATION info;
  528. FILE_DISPOSITION_INFORMATION disposition;
  529. IO_STATUS_BLOCK iosb;
  530. NTSTATUS status;
  531. handle = CreateFileW(pathw,
  532. FILE_READ_ATTRIBUTES | DELETE,
  533. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  534. NULL,
  535. OPEN_EXISTING,
  536. FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
  537. NULL);
  538. if (handle == INVALID_HANDLE_VALUE) {
  539. SET_REQ_WIN32_ERROR(req, GetLastError());
  540. return;
  541. }
  542. if (!GetFileInformationByHandle(handle, &info)) {
  543. SET_REQ_WIN32_ERROR(req, GetLastError());
  544. CloseHandle(handle);
  545. return;
  546. }
  547. if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  548. /* Do not allow deletion of directories, unless it is a symlink. When */
  549. /* the path refers to a non-symlink directory, report EPERM as mandated */
  550. /* by POSIX.1. */
  551. /* Check if it is a reparse point. If it's not, it's a normal directory. */
  552. if (!(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
  553. SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED);
  554. CloseHandle(handle);
  555. return;
  556. }
  557. /* Read the reparse point and check if it is a valid symlink. */
  558. /* If not, don't unlink. */
  559. if (fs__readlink_handle(handle, NULL, NULL) < 0) {
  560. DWORD error = GetLastError();
  561. if (error == ERROR_SYMLINK_NOT_SUPPORTED)
  562. error = ERROR_ACCESS_DENIED;
  563. SET_REQ_WIN32_ERROR(req, error);
  564. CloseHandle(handle);
  565. return;
  566. }
  567. }
  568. /* Try to set the delete flag. */
  569. disposition.DeleteFile = TRUE;
  570. status = pNtSetInformationFile(handle,
  571. &iosb,
  572. &disposition,
  573. sizeof disposition,
  574. FileDispositionInformation);
  575. if (NT_SUCCESS(status)) {
  576. SET_REQ_SUCCESS(req);
  577. } else {
  578. SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
  579. }
  580. CloseHandle(handle);
  581. }
  582. void fs__mkdir(uv_fs_t* req) {
  583. /* TODO: use req->mode. */
  584. int result = _wmkdir(req->pathw);
  585. SET_REQ_RESULT(req, result);
  586. }
  587. void fs__readdir(uv_fs_t* req) {
  588. WCHAR* pathw = req->pathw;
  589. size_t len = wcslen(pathw);
  590. int result, size;
  591. WCHAR* buf = NULL, *ptr, *name;
  592. HANDLE dir;
  593. WIN32_FIND_DATAW ent = { 0 };
  594. size_t buf_char_len = 4096;
  595. WCHAR* path2;
  596. const WCHAR* fmt;
  597. if (len == 0) {
  598. fmt = L"./*";
  599. } else if (pathw[len - 1] == L'/' || pathw[len - 1] == L'\\') {
  600. fmt = L"%s*";
  601. } else {
  602. fmt = L"%s\\*";
  603. }
  604. /* Figure out whether path is a file or a directory. */
  605. if (!(GetFileAttributesW(pathw) & FILE_ATTRIBUTE_DIRECTORY)) {
  606. req->result = -1;
  607. req->errorno = UV_ENOTDIR;
  608. req->sys_errno_ = ERROR_SUCCESS;
  609. return;
  610. }
  611. path2 = (WCHAR*)malloc(sizeof(WCHAR) * (len + 4));
  612. if (!path2) {
  613. uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
  614. }
  615. #ifdef _MSC_VER
  616. swprintf(path2, len + 3, fmt, pathw);
  617. #else
  618. swprintf(path2, fmt, pathw);
  619. #endif
  620. dir = FindFirstFileW(path2, &ent);
  621. free(path2);
  622. if(dir == INVALID_HANDLE_VALUE) {
  623. SET_REQ_WIN32_ERROR(req, GetLastError());
  624. return;
  625. }
  626. result = 0;
  627. do {
  628. name = ent.cFileName;
  629. if (name[0] != L'.' || (name[1] && (name[1] != L'.' || name[2]))) {
  630. len = wcslen(name);
  631. if (!buf) {
  632. buf = (WCHAR*)malloc(buf_char_len * sizeof(WCHAR));
  633. if (!buf) {
  634. uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
  635. }
  636. ptr = buf;
  637. }
  638. while ((ptr - buf) + len + 1 > buf_char_len) {
  639. buf_char_len *= 2;
  640. path2 = buf;
  641. buf = (WCHAR*)realloc(buf, buf_char_len * sizeof(WCHAR));
  642. if (!buf) {
  643. uv_fatal_error(ERROR_OUTOFMEMORY, "realloc");
  644. }
  645. ptr = buf + (ptr - path2);
  646. }
  647. wcscpy(ptr, name);
  648. ptr += len + 1;
  649. result++;
  650. }
  651. } while(FindNextFileW(dir, &ent));
  652. FindClose(dir);
  653. if (buf) {
  654. /* Convert result to UTF8. */
  655. size = uv_utf16_to_utf8(buf, buf_char_len, NULL, 0);
  656. if (!size) {
  657. SET_REQ_WIN32_ERROR(req, GetLastError());
  658. return;
  659. }
  660. req->ptr = (char*)malloc(size + 1);
  661. if (!req->ptr) {
  662. uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
  663. }
  664. size = uv_utf16_to_utf8(buf, buf_char_len, (char*)req->ptr, size);
  665. if (!size) {
  666. free(buf);
  667. free(req->ptr);
  668. req->ptr = NULL;
  669. SET_REQ_WIN32_ERROR(req, GetLastError());
  670. return;
  671. }
  672. free(buf);
  673. ((char*)req->ptr)[size] = '\0';
  674. req->flags |= UV_FS_FREE_PTR;
  675. } else {
  676. req->ptr = NULL;
  677. }
  678. SET_REQ_RESULT(req, result);
  679. }
  680. INLINE static int fs__stat_handle(HANDLE handle, uv_statbuf_t* statbuf) {
  681. BY_HANDLE_FILE_INFORMATION info;
  682. if (!GetFileInformationByHandle(handle, &info)) {
  683. return -1;
  684. }
  685. /* TODO: set st_dev, st_rdev and st_ino to something meaningful. */
  686. statbuf->st_ino = 0;
  687. statbuf->st_dev = 0;
  688. statbuf->st_rdev = 0;
  689. statbuf->st_gid = 0;
  690. statbuf->st_uid = 0;
  691. statbuf->st_mode = 0;
  692. if (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
  693. if (fs__readlink_handle(handle, NULL, &statbuf->st_size) != 0) {
  694. return -1;
  695. }
  696. statbuf->st_mode |= S_IFLNK;
  697. } else if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  698. statbuf->st_mode |= _S_IFDIR;
  699. statbuf->st_size = 0;
  700. } else {
  701. statbuf->st_mode |= _S_IFREG;
  702. statbuf->st_size = ((int64_t) info.nFileSizeHigh << 32) +
  703. (int64_t) info.nFileSizeLow;
  704. }
  705. if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
  706. statbuf->st_mode |= (_S_IREAD + (_S_IREAD >> 3) + (_S_IREAD >> 6));
  707. } else {
  708. statbuf->st_mode |= ((_S_IREAD|_S_IWRITE) + ((_S_IREAD|_S_IWRITE) >> 3) +
  709. ((_S_IREAD|_S_IWRITE) >> 6));
  710. }
  711. statbuf->st_mtime = FILETIME_TO_TIME_T(info.ftLastWriteTime);
  712. statbuf->st_atime = FILETIME_TO_TIME_T(info.ftLastAccessTime);
  713. statbuf->st_ctime = FILETIME_TO_TIME_T(info.ftCreationTime);
  714. statbuf->st_nlink = (info.nNumberOfLinks <= SHRT_MAX) ?
  715. (short) info.nNumberOfLinks : SHRT_MAX;
  716. return 0;
  717. }
  718. INLINE static void fs__stat_prepare_path(WCHAR* pathw) {
  719. size_t len = wcslen(pathw);
  720. /* TODO: ignore namespaced paths. */
  721. if (len > 1 && pathw[len - 2] != L':' &&
  722. (pathw[len - 1] == L'\\' || pathw[len - 1] == L'/')) {
  723. pathw[len - 1] = '\0';
  724. }
  725. }
  726. INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) {
  727. HANDLE handle;
  728. DWORD flags;
  729. flags = FILE_FLAG_BACKUP_SEMANTICS;
  730. if (do_lstat) {
  731. flags |= FILE_FLAG_OPEN_REPARSE_POINT;
  732. }
  733. handle = CreateFileW(req->pathw,
  734. FILE_READ_ATTRIBUTES,
  735. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  736. NULL,
  737. OPEN_EXISTING,
  738. flags,
  739. NULL);
  740. if (handle == INVALID_HANDLE_VALUE) {
  741. SET_REQ_WIN32_ERROR(req, GetLastError());
  742. return;
  743. }
  744. if (fs__stat_handle(handle, &req->stat) != 0) {
  745. DWORD error = GetLastError();
  746. if (do_lstat && error == ERROR_SYMLINK_NOT_SUPPORTED) {
  747. /* We opened a reparse point but it was not a symlink. Try again. */
  748. fs__stat_impl(req, 0);
  749. } else {
  750. /* Stat failed. */
  751. SET_REQ_WIN32_ERROR(req, GetLastError());
  752. }
  753. CloseHandle(handle);
  754. return;
  755. }
  756. req->ptr = &req->stat;
  757. req->result = 0;
  758. CloseHandle(handle);
  759. }
  760. static void fs__stat(uv_fs_t* req) {
  761. fs__stat_prepare_path(req->pathw);
  762. fs__stat_impl(req, 0);
  763. }
  764. static void fs__lstat(uv_fs_t* req) {
  765. fs__stat_prepare_path(req->pathw);
  766. fs__stat_impl(req, 1);
  767. }
  768. static void fs__fstat(uv_fs_t* req) {
  769. int fd = req->fd;
  770. HANDLE handle;
  771. VERIFY_FD(fd, req);
  772. handle = (HANDLE) _get_osfhandle(fd);
  773. if (handle == INVALID_HANDLE_VALUE) {
  774. SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
  775. return;
  776. }
  777. if (fs__stat_handle(handle, &req->stat) != 0) {
  778. SET_REQ_WIN32_ERROR(req, GetLastError());
  779. return;
  780. }
  781. req->ptr = &req->stat;
  782. req->result = 0;
  783. }
  784. static void fs__rename(uv_fs_t* req) {
  785. if (!MoveFileExW(req->pathw, req->new_pathw, MOVEFILE_REPLACE_EXISTING)) {
  786. SET_REQ_WIN32_ERROR(req, GetLastError());
  787. return;
  788. }
  789. SET_REQ_RESULT(req, 0);
  790. }
  791. INLINE static void fs__sync_impl(uv_fs_t* req) {
  792. int fd = req->fd;
  793. int result;
  794. VERIFY_FD(fd, req);
  795. result = FlushFileBuffers((HANDLE) _get_osfhandle(fd)) ? 0 : -1;
  796. if (result == -1) {
  797. SET_REQ_WIN32_ERROR(req, GetLastError());
  798. } else {
  799. SET_REQ_RESULT(req, result);
  800. }
  801. }
  802. static void fs__fsync(uv_fs_t* req) {
  803. fs__sync_impl(req);
  804. }
  805. static void fs__fdatasync(uv_fs_t* req) {
  806. fs__sync_impl(req);
  807. }
  808. static void fs__ftruncate(uv_fs_t* req) {
  809. int fd = req->fd;
  810. HANDLE handle;
  811. NTSTATUS status;
  812. IO_STATUS_BLOCK io_status;
  813. FILE_END_OF_FILE_INFORMATION eof_info;
  814. VERIFY_FD(fd, req);
  815. handle = (HANDLE)_get_osfhandle(fd);
  816. eof_info.EndOfFile.QuadPart = req->offset;
  817. status = pNtSetInformationFile(handle,
  818. &io_status,
  819. &eof_info,
  820. sizeof eof_info,
  821. FileEndOfFileInformation);
  822. if (NT_SUCCESS(status)) {
  823. SET_REQ_RESULT(req, 0);
  824. } else {
  825. SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
  826. }
  827. }
  828. static void fs__sendfile(uv_fs_t* req) {
  829. int fd_in = req->fd, fd_out = req->fd_out;
  830. size_t length = req->length;
  831. int64_t offset = req->offset;
  832. const size_t max_buf_size = 65536;
  833. size_t buf_size = length < max_buf_size ? length : max_buf_size;
  834. int n, result = 0;
  835. int64_t result_offset = 0;
  836. char* buf = (char*) malloc(buf_size);
  837. if (!buf) {
  838. uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
  839. }
  840. if (offset != -1) {
  841. result_offset = _lseeki64(fd_in, offset, SEEK_SET);
  842. }
  843. if (result_offset == -1) {
  844. result = -1;
  845. } else {
  846. while (length > 0) {
  847. n = _read(fd_in, buf, length < buf_size ? length : buf_size);
  848. if (n == 0) {
  849. break;
  850. } else if (n == -1) {
  851. result = -1;
  852. break;
  853. }
  854. length -= n;
  855. n = _write(fd_out, buf, n);
  856. if (n == -1) {
  857. result = -1;
  858. break;
  859. }
  860. result += n;
  861. }
  862. }
  863. SET_REQ_RESULT(req, result);
  864. }
  865. static void fs__chmod(uv_fs_t* req) {
  866. int result = _wchmod(req->pathw, req->mode);
  867. SET_REQ_RESULT(req, result);
  868. }
  869. static void fs__fchmod(uv_fs_t* req) {
  870. int fd = req->fd;
  871. int result;
  872. HANDLE handle;
  873. NTSTATUS nt_status;
  874. IO_STATUS_BLOCK io_status;
  875. FILE_BASIC_INFORMATION file_info;
  876. VERIFY_FD(fd, req);
  877. handle = (HANDLE)_get_osfhandle(fd);
  878. nt_status = pNtQueryInformationFile(handle,
  879. &io_status,
  880. &file_info,
  881. sizeof file_info,
  882. FileBasicInformation);
  883. if (nt_status != STATUS_SUCCESS) {
  884. result = -1;
  885. goto done;
  886. }
  887. if (req->mode & _S_IWRITE) {
  888. file_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY;
  889. } else {
  890. file_info.FileAttributes |= FILE_ATTRIBUTE_READONLY;
  891. }
  892. nt_status = pNtSetInformationFile(handle,
  893. &io_status,
  894. &file_info,
  895. sizeof file_info,
  896. FileBasicInformation);
  897. if (nt_status != STATUS_SUCCESS) {
  898. result = -1;
  899. goto done;
  900. }
  901. result = 0;
  902. done:
  903. SET_REQ_RESULT(req, result);
  904. }
  905. INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) {
  906. FILETIME filetime_a, filetime_m;
  907. TIME_T_TO_FILETIME((time_t) atime, &filetime_a);
  908. TIME_T_TO_FILETIME((time_t) mtime, &filetime_m);
  909. if (!SetFileTime(handle, NULL, &filetime_a, &filetime_m)) {
  910. return -1;
  911. }
  912. return 0;
  913. }
  914. static void fs__utime(uv_fs_t* req) {
  915. HANDLE handle;
  916. handle = CreateFileW(req->pathw,
  917. FILE_WRITE_ATTRIBUTES,
  918. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  919. NULL,
  920. OPEN_EXISTING,
  921. FILE_FLAG_BACKUP_SEMANTICS,
  922. NULL);
  923. if (handle == INVALID_HANDLE_VALUE) {
  924. SET_REQ_WIN32_ERROR(req, GetLastError());
  925. return;
  926. }
  927. if (fs__utime_handle(handle, req->atime, req->mtime) != 0) {
  928. SET_REQ_WIN32_ERROR(req, GetLastError());
  929. CloseHandle(handle);
  930. return;
  931. }
  932. CloseHandle(handle);
  933. req->result = 0;
  934. }
  935. static void fs__futime(uv_fs_t* req) {
  936. int fd = req->fd;
  937. HANDLE handle;
  938. VERIFY_FD(fd, req);
  939. handle = (HANDLE) _get_osfhandle(fd);
  940. if (handle == INVALID_HANDLE_VALUE) {
  941. SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
  942. return;
  943. }
  944. if (fs__utime_handle(handle, req->atime, req->mtime) != 0) {
  945. SET_REQ_WIN32_ERROR(req, GetLastError());
  946. return;
  947. }
  948. req->result = 0;
  949. }
  950. static void fs__link(uv_fs_t* req) {
  951. DWORD r = CreateHardLinkW(req->new_pathw, req->pathw, NULL);
  952. if (r == 0) {
  953. SET_REQ_WIN32_ERROR(req, GetLastError());
  954. } else {
  955. req->result = 0;
  956. }
  957. }
  958. static void fs__create_junction(uv_fs_t* req, const WCHAR* path,
  959. const WCHAR* new_path) {
  960. HANDLE handle = INVALID_HANDLE_VALUE;
  961. REPARSE_DATA_BUFFER *buffer = NULL;
  962. int created = 0;
  963. int target_len;
  964. int is_absolute, is_long_path;
  965. int needed_buf_size, used_buf_size, used_data_size, path_buf_len;
  966. int start, len, i;
  967. int add_slash;
  968. DWORD bytes;
  969. WCHAR* path_buf;
  970. target_len = wcslen(path);
  971. is_long_path = wcsncmp(path, LONG_PATH_PREFIX, LONG_PATH_PREFIX_LEN) == 0;
  972. if (is_long_path) {
  973. is_absolute = 1;
  974. } else {
  975. is_absolute = target_len >= 3 && IS_LETTER(path[0]) &&
  976. path[1] == L':' && IS_SLASH(path[2]);
  977. }
  978. if (!is_absolute) {
  979. /* Not supporting relative paths */
  980. SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_NOT_SUPPORTED);
  981. return;
  982. }
  983. // Do a pessimistic calculation of the required buffer size
  984. needed_buf_size =
  985. FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) +
  986. JUNCTION_PREFIX_LEN * sizeof(WCHAR) +
  987. 2 * (target_len + 2) * sizeof(WCHAR);
  988. // Allocate the buffer
  989. buffer = (REPARSE_DATA_BUFFER*)malloc(needed_buf_size);
  990. if (!buffer) {
  991. uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
  992. }
  993. // Grab a pointer to the part of the buffer where filenames go
  994. path_buf = (WCHAR*)&(buffer->MountPointReparseBuffer.PathBuffer);
  995. path_buf_len = 0;
  996. // Copy the substitute (internal) target path
  997. start = path_buf_len;
  998. wcsncpy((WCHAR*)&path_buf[path_buf_len], JUNCTION_PREFIX,
  999. JUNCTION_PREFIX_LEN);
  1000. path_buf_len += JUNCTION_PREFIX_LEN;
  1001. add_slash = 0;
  1002. for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) {
  1003. if (IS_SLASH(path[i])) {
  1004. add_slash = 1;
  1005. continue;
  1006. }
  1007. if (add_slash) {
  1008. path_buf[path_buf_len++] = L'\\';
  1009. add_slash = 0;
  1010. }
  1011. path_buf[path_buf_len++] = path[i];
  1012. }
  1013. path_buf[path_buf_len++] = L'\\';
  1014. len = path_buf_len - start;
  1015. // Set the info about the substitute name
  1016. buffer->MountPointReparseBuffer.SubstituteNameOffset = start * sizeof(WCHAR);
  1017. buffer->MountPointReparseBuffer.SubstituteNameLength = len * sizeof(WCHAR);
  1018. // Insert null terminator
  1019. path_buf[path_buf_len++] = L'\0';
  1020. // Copy the print name of the target path
  1021. start = path_buf_len;
  1022. add_slash = 0;
  1023. for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) {
  1024. if (IS_SLASH(path[i])) {
  1025. add_slash = 1;
  1026. continue;
  1027. }
  1028. if (add_slash) {
  1029. path_buf[path_buf_len++] = L'\\';
  1030. add_slash = 0;
  1031. }
  1032. path_buf[path_buf_len++] = path[i];
  1033. }
  1034. len = path_buf_len - start;
  1035. if (len == 2) {
  1036. path_buf[path_buf_len++] = L'\\';
  1037. len++;
  1038. }
  1039. // Set the info about the print name
  1040. buffer->MountPointReparseBuffer.PrintNameOffset = start * sizeof(WCHAR);
  1041. buffer->MountPointReparseBuffer.PrintNameLength = len * sizeof(WCHAR);
  1042. // Insert another null terminator
  1043. path_buf[path_buf_len++] = L'\0';
  1044. // Calculate how much buffer space was actually used
  1045. used_buf_size = FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) +
  1046. path_buf_len * sizeof(WCHAR);
  1047. used_data_size = used_buf_size -
  1048. FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer);
  1049. // Put general info in the data buffer
  1050. buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
  1051. buffer->ReparseDataLength = used_data_size;
  1052. buffer->Reserved = 0;
  1053. // Create a new directory
  1054. if (!CreateDirectoryW(new_path, NULL)) {
  1055. SET_REQ_WIN32_ERROR(req, GetLastError());
  1056. goto error;
  1057. }
  1058. created = 1;
  1059. // Open the directory
  1060. handle = CreateFileW(new_path,
  1061. GENERIC_ALL,
  1062. 0,
  1063. NULL,
  1064. OPEN_EXISTING,
  1065. FILE_FLAG_BACKUP_SEMANTICS |
  1066. FILE_FLAG_OPEN_REPARSE_POINT,
  1067. NULL);
  1068. if (handle == INVALID_HANDLE_VALUE) {
  1069. SET_REQ_WIN32_ERROR(req, GetLastError());
  1070. goto error;
  1071. }
  1072. // Create the actual reparse point
  1073. if (!DeviceIoControl(handle,
  1074. FSCTL_SET_REPARSE_POINT,
  1075. buffer,
  1076. used_buf_size,
  1077. NULL,
  1078. 0,
  1079. &bytes,
  1080. NULL)) {
  1081. SET_REQ_WIN32_ERROR(req, GetLastError());
  1082. goto error;
  1083. }
  1084. // Clean up
  1085. CloseHandle(handle);
  1086. free(buffer);
  1087. SET_REQ_RESULT(req, 0);
  1088. return;
  1089. error:
  1090. free(buffer);
  1091. if (handle != INVALID_HANDLE_VALUE) {
  1092. CloseHandle(handle);
  1093. }
  1094. if (created) {
  1095. RemoveDirectoryW(new_path);
  1096. }
  1097. }
  1098. static void fs__symlink(uv_fs_t* req) {
  1099. WCHAR* pathw = req->pathw;
  1100. WCHAR* new_pathw = req->new_pathw;
  1101. int flags = req->file_flags;
  1102. int result;
  1103. if (flags & UV_FS_SYMLINK_JUNCTION) {
  1104. fs__create_junction(req, pathw, new_pathw);
  1105. } else if (pCreateSymbolicLinkW) {
  1106. result = pCreateSymbolicLinkW(new_pathw,
  1107. pathw,
  1108. flags & UV_FS_SYMLINK_DIR ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) ? 0 : -1;
  1109. if (result == -1) {
  1110. SET_REQ_WIN32_ERROR(req, GetLastError());
  1111. } else {
  1112. SET_REQ_RESULT(req, result);
  1113. }
  1114. } else {
  1115. SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED);
  1116. }
  1117. }
  1118. static void fs__readlink(uv_fs_t* req) {
  1119. HANDLE handle;
  1120. handle = CreateFileW(req->pathw,
  1121. 0,
  1122. 0,
  1123. NULL,
  1124. OPEN_EXISTING,
  1125. FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
  1126. NULL);
  1127. if (handle == INVALID_HANDLE_VALUE) {
  1128. SET_REQ_WIN32_ERROR(req, GetLastError());
  1129. return;
  1130. }
  1131. if (fs__readlink_handle(handle, (char**) &req->ptr, NULL) != 0) {
  1132. SET_REQ_WIN32_ERROR(req, GetLastError());
  1133. CloseHandle(handle);
  1134. return;
  1135. }
  1136. req->flags |= UV_FS_FREE_PTR;
  1137. SET_REQ_RESULT(req, 0);
  1138. CloseHandle(handle);
  1139. }
  1140. static void fs__chown(uv_fs_t* req) {
  1141. req->result = 0;
  1142. }
  1143. static void fs__fchown(uv_fs_t* req) {
  1144. req->result = 0;
  1145. }
  1146. static DWORD WINAPI uv_fs_thread_proc(void* parameter) {
  1147. uv_fs_t* req = (uv_fs_t*) parameter;
  1148. uv_loop_t* loop = req->loop;
  1149. assert(req != NULL);
  1150. assert(req->type == UV_FS);
  1151. #define XX(uc, lc) case UV_FS_##uc: fs__##lc(req); break;
  1152. switch (req->fs_type) {
  1153. XX(OPEN, open)
  1154. XX(CLOSE, close)
  1155. XX(READ, read)
  1156. XX(WRITE, write)
  1157. XX(SENDFILE, sendfile)
  1158. XX(STAT, stat)
  1159. XX(LSTAT, lstat)
  1160. XX(FSTAT, fstat)
  1161. XX(FTRUNCATE, ftruncate)
  1162. XX(UTIME, utime)
  1163. XX(FUTIME, futime)
  1164. XX(CHMOD, chmod)
  1165. XX(FCHMOD, fchmod)
  1166. XX(FSYNC, fsync)
  1167. XX(FDATASYNC, fdatasync)
  1168. XX(UNLINK, unlink)
  1169. XX(RMDIR, rmdir)
  1170. XX(MKDIR, mkdir)
  1171. XX(RENAME, rename)
  1172. XX(READDIR, readdir)
  1173. XX(LINK, link)
  1174. XX(SYMLINK, symlink)
  1175. XX(READLINK, readlink)
  1176. XX(CHOWN, chown)
  1177. XX(FCHOWN, fchown);
  1178. default:
  1179. assert(!"bad uv_fs_type");
  1180. }
  1181. POST_COMPLETION_FOR_REQ(loop, req);
  1182. return 0;
  1183. }
  1184. int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
  1185. int mode, uv_fs_cb cb) {
  1186. uv_fs_req_init(loop, req, UV_FS_OPEN, cb);
  1187. if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
  1188. return -1;
  1189. }
  1190. req->file_flags = flags;
  1191. req->mode = mode;
  1192. if (cb) {
  1193. QUEUE_FS_TP_JOB(loop, req);
  1194. return 0;
  1195. } else {
  1196. fs__open(req);
  1197. SET_UV_LAST_ERROR_FROM_REQ(req);
  1198. return req->result;
  1199. }
  1200. }
  1201. int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
  1202. uv_fs_req_init(loop, req, UV_FS_CLOSE, cb);
  1203. req->fd = fd;
  1204. if (cb) {
  1205. QUEUE_FS_TP_JOB(loop, req);
  1206. return 0;
  1207. } else {
  1208. fs__close(req);
  1209. SET_UV_LAST_ERROR_FROM_REQ(req);
  1210. return req->result;
  1211. }
  1212. }
  1213. int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file fd, void* buf,
  1214. size_t length, int64_t offset, uv_fs_cb cb) {
  1215. uv_fs_req_init(loop, req, UV_FS_READ, cb);
  1216. req->fd = fd;
  1217. req->buf = buf;
  1218. req->length = length;
  1219. req->offset = offset;
  1220. if (cb) {
  1221. QUEUE_FS_TP_JOB(loop, req);
  1222. return 0;
  1223. } else {
  1224. fs__read(req);
  1225. SET_UV_LAST_ERROR_FROM_REQ(req);
  1226. return req->result;
  1227. }
  1228. }
  1229. int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file fd, void* buf,
  1230. size_t length, int64_t offset, uv_fs_cb cb) {
  1231. uv_fs_req_init(loop, req, UV_FS_WRITE, cb);
  1232. req->fd = fd;
  1233. req->buf = buf;
  1234. req->length = length;
  1235. req->offset = offset;
  1236. if (cb) {
  1237. QUEUE_FS_TP_JOB(loop, req);
  1238. return 0;
  1239. } else {
  1240. fs__write(req);
  1241. SET_UV_LAST_ERROR_FROM_REQ(req);
  1242. return req->result;
  1243. }
  1244. }
  1245. int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
  1246. uv_fs_cb cb) {
  1247. uv_fs_req_init(loop, req, UV_FS_UNLINK, cb);
  1248. if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
  1249. return -1;
  1250. }
  1251. if (cb) {
  1252. QUEUE_FS_TP_JOB(loop, req);
  1253. return 0;
  1254. } else {
  1255. fs__unlink(req);
  1256. SET_UV_LAST_ERROR_FROM_REQ(req);
  1257. return req->result;
  1258. }
  1259. }
  1260. int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
  1261. uv_fs_cb cb) {
  1262. uv_fs_req_init(loop, req, UV_FS_MKDIR, cb);
  1263. if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
  1264. return -1;
  1265. }
  1266. req->mode = mode;
  1267. if (cb) {
  1268. QUEUE_FS_TP_JOB(loop, req);
  1269. return 0;
  1270. } else {
  1271. fs__mkdir(req);
  1272. SET_UV_LAST_ERROR_FROM_REQ(req);
  1273. return req->result;
  1274. }
  1275. }
  1276. int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
  1277. uv_fs_req_init(loop, req, UV_FS_RMDIR, cb);
  1278. if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
  1279. return -1;
  1280. }
  1281. if (cb) {
  1282. QUEUE_FS_TP_JOB(loop, req);
  1283. return 0;
  1284. } else {
  1285. fs__rmdir(req);
  1286. SET_UV_LAST_ERROR_FROM_REQ(req);
  1287. return req->result;
  1288. }
  1289. }
  1290. int uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
  1291. uv_fs_cb cb) {
  1292. uv_fs_req_init(loop, req, UV_FS_READDIR, cb);
  1293. if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
  1294. return -1;
  1295. }
  1296. req->file_flags;
  1297. if (cb) {
  1298. QUEUE_FS_TP_JOB(loop, req);
  1299. return 0;
  1300. } else {
  1301. fs__readdir(req);
  1302. SET_UV_LAST_ERROR_FROM_REQ(req);
  1303. return req->result;
  1304. }
  1305. }
  1306. int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path,
  1307. const char* new_path, uv_fs_cb cb) {
  1308. uv_fs_req_init(loop, req, UV_FS_LINK, cb);
  1309. if (fs__capture_path(loop, req, path, new_path, cb != NULL) < 0) {
  1310. return -1;
  1311. }
  1312. if (cb) {
  1313. QUEUE_FS_TP_JOB(loop, req);
  1314. return 0;
  1315. } else {
  1316. fs__link(req);
  1317. SET_UV_LAST_ERROR_FROM_REQ(req);
  1318. return req->result;
  1319. }
  1320. }
  1321. int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
  1322. const char* new_path, int flags, uv_fs_cb cb) {
  1323. uv_fs_req_init(loop, req, UV_FS_SYMLINK, cb);
  1324. if (fs__capture_path(loop, req, path, new_path, cb != NULL) < 0) {
  1325. return -1;
  1326. }
  1327. req->file_flags = flags;
  1328. if (cb) {
  1329. QUEUE_FS_TP_JOB(loop, req);
  1330. return 0;
  1331. } else {
  1332. fs__symlink(req);
  1333. SET_UV_LAST_ERROR_FROM_REQ(req);
  1334. return req->result;
  1335. }
  1336. }
  1337. int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
  1338. uv_fs_cb cb) {
  1339. uv_fs_req_init(loop, req, UV_FS_READLINK, cb);
  1340. if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
  1341. return -1;
  1342. }
  1343. if (cb) {
  1344. QUEUE_FS_TP_JOB(loop, req);
  1345. return 0;
  1346. } else {
  1347. fs__readlink(req);
  1348. SET_UV_LAST_ERROR_FROM_REQ(req);
  1349. return req->result;
  1350. }
  1351. }
  1352. int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, int uid,
  1353. int gid, uv_fs_cb cb) {
  1354. uv_fs_req_init(loop, req, UV_FS_CHOWN, cb);
  1355. if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
  1356. return -1;
  1357. }
  1358. if (cb) {
  1359. QUEUE_FS_TP_JOB(loop, req);
  1360. return 0;
  1361. } else {
  1362. fs__chown(req);
  1363. SET_UV_LAST_ERROR_FROM_REQ(req);
  1364. return req->result;
  1365. }
  1366. }
  1367. int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int uid,
  1368. int gid, uv_fs_cb cb) {
  1369. uv_fs_req_init(loop, req, UV_FS_FCHOWN, cb);
  1370. if (cb) {
  1371. QUEUE_FS_TP_JOB(loop, req);
  1372. return 0;
  1373. } else {
  1374. fs__fchown(req);
  1375. SET_UV_LAST_ERROR_FROM_REQ(req);
  1376. return req->result;
  1377. }
  1378. }
  1379. int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
  1380. uv_fs_req_init(loop, req, UV_FS_STAT, cb);
  1381. if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
  1382. return -1;
  1383. }
  1384. if (cb) {
  1385. QUEUE_FS_TP_JOB(loop, req);
  1386. return 0;
  1387. } else {
  1388. fs__stat(req);
  1389. SET_UV_LAST_ERROR_FROM_REQ(req);
  1390. return req->result;
  1391. }
  1392. }
  1393. int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
  1394. uv_fs_req_init(loop, req, UV_FS_LSTAT, cb);
  1395. if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
  1396. return -1;
  1397. }
  1398. if (cb) {
  1399. QUEUE_FS_TP_JOB(loop, req);
  1400. return 0;
  1401. } else {
  1402. fs__lstat(req);
  1403. SET_UV_LAST_ERROR_FROM_REQ(req);
  1404. return req->result;
  1405. }
  1406. }
  1407. int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
  1408. uv_fs_req_init(loop, req, UV_FS_FSTAT, cb);
  1409. req->fd = fd;
  1410. if (cb) {
  1411. QUEUE_FS_TP_JOB(loop, req);
  1412. return 0;
  1413. } else {
  1414. fs__fstat(req);
  1415. SET_UV_LAST_ERROR_FROM_REQ(req);
  1416. return req->result;
  1417. }
  1418. }
  1419. int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path,
  1420. const char* new_path, uv_fs_cb cb) {
  1421. uv_fs_req_init(loop, req, UV_FS_RENAME, cb);
  1422. if (fs__capture_path(loop, req, path, new_path, cb != NULL) < 0) {
  1423. return -1;
  1424. }
  1425. if (cb) {
  1426. QUEUE_FS_TP_JOB(loop, req);
  1427. return 0;
  1428. } else {
  1429. fs__rename(req);
  1430. SET_UV_LAST_ERROR_FROM_REQ(req);
  1431. return req->result;
  1432. }
  1433. }
  1434. int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
  1435. uv_fs_req_init(loop, req, UV_FS_FSYNC, cb);
  1436. req->fd = fd;
  1437. if (cb) {
  1438. QUEUE_FS_TP_JOB(loop, req);
  1439. return 0;
  1440. } else {
  1441. fs__fsync(req);
  1442. SET_UV_LAST_ERROR_FROM_REQ(req);
  1443. return req->result;
  1444. }
  1445. }
  1446. int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
  1447. uv_fs_req_init(loop, req, UV_FS_FDATASYNC, cb);
  1448. req->fd = fd;
  1449. if (cb) {
  1450. QUEUE_FS_TP_JOB(loop, req);
  1451. return 0;
  1452. } else {
  1453. fs__fdatasync(req);
  1454. SET_UV_LAST_ERROR_FROM_REQ(req);
  1455. return req->result;
  1456. }
  1457. }
  1458. int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file fd,
  1459. int64_t offset, uv_fs_cb cb) {
  1460. uv_fs_req_init(loop, req, UV_FS_FTRUNCATE, cb);
  1461. req->fd = fd;
  1462. req->offset = offset;
  1463. if (cb) {
  1464. QUEUE_FS_TP_JOB(loop, req);
  1465. return 0;
  1466. } else {
  1467. fs__ftruncate(req);
  1468. SET_UV_LAST_ERROR_FROM_REQ(req);
  1469. return req->result;
  1470. }
  1471. }
  1472. int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file fd_out,
  1473. uv_file fd_in, int64_t in_offset, size_t length, uv_fs_cb cb) {
  1474. uv_fs_req_init(loop, req, UV_FS_SENDFILE, cb);
  1475. req->fd = fd_in;
  1476. req->fd_out = fd_out;
  1477. req->offset = in_offset;
  1478. req->length = length;
  1479. if (cb) {
  1480. QUEUE_FS_TP_JOB(loop, req);
  1481. return 0;
  1482. } else {
  1483. fs__sendfile(req);
  1484. SET_UV_LAST_ERROR_FROM_REQ(req);
  1485. return req->result;
  1486. }
  1487. }
  1488. int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
  1489. uv_fs_cb cb) {
  1490. uv_fs_req_init(loop, req, UV_FS_CHMOD, cb);
  1491. if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
  1492. return -1;
  1493. }
  1494. req->mode = mode;
  1495. if (cb) {
  1496. QUEUE_FS_TP_JOB(loop, req);
  1497. return 0;
  1498. } else {
  1499. fs__chmod(req);
  1500. SET_UV_LAST_ERROR_FROM_REQ(req);
  1501. return req->result;
  1502. }
  1503. }
  1504. int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int mode,
  1505. uv_fs_cb cb) {
  1506. uv_fs_req_init(loop, req, UV_FS_FCHMOD, cb);
  1507. req->fd = fd;
  1508. req->mode = mode;
  1509. if (cb) {
  1510. QUEUE_FS_TP_JOB(loop, req);
  1511. return 0;
  1512. } else {
  1513. fs__fchmod(req);
  1514. SET_UV_LAST_ERROR_FROM_REQ(req);
  1515. return req->result;
  1516. }
  1517. }
  1518. int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
  1519. double mtime, uv_fs_cb cb) {
  1520. uv_fs_req_init(loop, req, UV_FS_UTIME, cb);
  1521. if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) {
  1522. return -1;
  1523. }
  1524. req->atime = atime;
  1525. req->mtime = mtime;
  1526. if (cb) {
  1527. QUEUE_FS_TP_JOB(loop, req);
  1528. return 0;
  1529. } else {
  1530. fs__utime(req);
  1531. SET_UV_LAST_ERROR_FROM_REQ(req);
  1532. return req->result;
  1533. }
  1534. }
  1535. int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime,
  1536. double mtime, uv_fs_cb cb) {
  1537. uv_fs_req_init(loop, req, UV_FS_FUTIME, cb);
  1538. req->fd = fd;
  1539. req->atime = atime;
  1540. req->mtime = mtime;
  1541. if (cb) {
  1542. QUEUE_FS_TP_JOB(loop, req);
  1543. return 0;
  1544. } else {
  1545. fs__futime(req);
  1546. SET_UV_LAST_ERROR_FROM_REQ(req);
  1547. return req->result;
  1548. }
  1549. }
  1550. void uv_process_fs_req(uv_loop_t* loop, uv_fs_t* req) {
  1551. assert(req->cb);
  1552. uv__req_unregister(loop, req);
  1553. SET_UV_LAST_ERROR_FROM_REQ(req);
  1554. req->cb(req);
  1555. }
  1556. void uv_fs_req_cleanup(uv_fs_t* req) {
  1557. if (req->flags & UV_FS_CLEANEDUP)
  1558. return;
  1559. if (req->flags & UV_FS_FREE_PATHS)
  1560. free(req->pathw);
  1561. if (req->flags & UV_FS_FREE_PTR)
  1562. free(req->ptr);
  1563. req->path = NULL;
  1564. req->pathw = NULL;
  1565. req->new_pathw = NULL;
  1566. req->ptr = NULL;
  1567. req->flags |= UV_FS_CLEANEDUP;
  1568. }