xref: /libuv/src/win/fs.c (revision 8a499e13)
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 <stdlib.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 
35 /* <winioctl.h> requires <windows.h>, included via "uv.h" above, but needs to
36    be included before our "winapi.h", included via "internal.h" below. */
37 #include <winioctl.h>
38 
39 #include "internal.h"
40 #include "req-inl.h"
41 #include "handle-inl.h"
42 #include "fs-fd-hash-inl.h"
43 
44 
45 #define UV_FS_FREE_PATHS         0x0002
46 #define UV_FS_FREE_PTR           0x0008
47 #define UV_FS_CLEANEDUP          0x0010
48 
49 
50 #define INIT(subtype)                                                         \
51   do {                                                                        \
52     if (req == NULL)                                                          \
53       return UV_EINVAL;                                                       \
54     uv__fs_req_init(loop, req, subtype, cb);                                  \
55   }                                                                           \
56   while (0)
57 
58 #define POST                                                                  \
59   do {                                                                        \
60     if (cb != NULL) {                                                         \
61       uv__req_register(loop, req);                                            \
62       uv__work_submit(loop,                                                   \
63                       &req->work_req,                                         \
64                       UV__WORK_FAST_IO,                                       \
65                       uv__fs_work,                                            \
66                       uv__fs_done);                                           \
67       return 0;                                                               \
68     } else {                                                                  \
69       uv__fs_work(&req->work_req);                                            \
70       return req->result;                                                     \
71     }                                                                         \
72   }                                                                           \
73   while (0)
74 
75 #define SET_REQ_RESULT(req, result_value)                                   \
76   do {                                                                      \
77     req->result = (result_value);                                           \
78     assert(req->result != -1);                                              \
79   } while (0)
80 
81 #define SET_REQ_WIN32_ERROR(req, sys_errno)                                 \
82   do {                                                                      \
83     req->sys_errno_ = (sys_errno);                                          \
84     req->result = uv_translate_sys_error(req->sys_errno_);                  \
85   } while (0)
86 
87 #define SET_REQ_UV_ERROR(req, uv_errno, sys_errno)                          \
88   do {                                                                      \
89     req->result = (uv_errno);                                               \
90     req->sys_errno_ = (sys_errno);                                          \
91   } while (0)
92 
93 #define VERIFY_FD(fd, req)                                                  \
94   if (fd == -1) {                                                           \
95     req->result = UV_EBADF;                                                 \
96     req->sys_errno_ = ERROR_INVALID_HANDLE;                                 \
97     return;                                                                 \
98   }
99 
100 #define MILLION ((int64_t) 1000 * 1000)
101 #define BILLION ((int64_t) 1000 * 1000 * 1000)
102 
uv__filetime_to_timespec(uv_timespec_t * ts,int64_t filetime)103 static void uv__filetime_to_timespec(uv_timespec_t *ts, int64_t filetime) {
104   filetime -= 116444736 * BILLION;
105   ts->tv_sec = (long) (filetime / (10 * MILLION));
106   ts->tv_nsec = (long) ((filetime - ts->tv_sec * 10 * MILLION) * 100U);
107   if (ts->tv_nsec < 0) {
108     ts->tv_sec -= 1;
109     ts->tv_nsec += 1e9;
110   }
111 }
112 
113 #define TIME_T_TO_FILETIME(time, filetime_ptr)                              \
114   do {                                                                      \
115     int64_t bigtime = ((time) * 10 * MILLION + 116444736 * BILLION);        \
116     (filetime_ptr)->dwLowDateTime = (uint64_t) bigtime & 0xFFFFFFFF;        \
117     (filetime_ptr)->dwHighDateTime = (uint64_t) bigtime >> 32;              \
118   } while(0)
119 
120 #define IS_SLASH(c) ((c) == L'\\' || (c) == L'/')
121 #define IS_LETTER(c) (((c) >= L'a' && (c) <= L'z') || \
122   ((c) >= L'A' && (c) <= L'Z'))
123 
124 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
125 
126 const WCHAR JUNCTION_PREFIX[] = L"\\??\\";
127 const WCHAR JUNCTION_PREFIX_LEN = 4;
128 
129 const WCHAR LONG_PATH_PREFIX[] = L"\\\\?\\";
130 const WCHAR LONG_PATH_PREFIX_LEN = 4;
131 
132 const WCHAR UNC_PATH_PREFIX[] = L"\\\\?\\UNC\\";
133 const WCHAR UNC_PATH_PREFIX_LEN = 8;
134 
135 static int uv__file_symlink_usermode_flag = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
136 
137 static DWORD uv__allocation_granularity;
138 
139 
uv__fs_init(void)140 void uv__fs_init(void) {
141   SYSTEM_INFO system_info;
142 
143   GetSystemInfo(&system_info);
144   uv__allocation_granularity = system_info.dwAllocationGranularity;
145 
146   uv__fd_hash_init();
147 }
148 
149 
fs__readlink_handle(HANDLE handle,char ** target_ptr,size_t * target_len_ptr)150 INLINE static int fs__readlink_handle(HANDLE handle,
151                                       char** target_ptr,
152                                       size_t* target_len_ptr) {
153   char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
154   REPARSE_DATA_BUFFER* reparse_data = (REPARSE_DATA_BUFFER*) buffer;
155   WCHAR* w_target;
156   DWORD w_target_len;
157   DWORD bytes;
158   size_t i;
159   size_t len;
160 
161   if (!DeviceIoControl(handle,
162                        FSCTL_GET_REPARSE_POINT,
163                        NULL,
164                        0,
165                        buffer,
166                        sizeof buffer,
167                        &bytes,
168                        NULL)) {
169     return -1;
170   }
171 
172   if (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
173     /* Real symlink */
174     w_target = reparse_data->SymbolicLinkReparseBuffer.PathBuffer +
175         (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset /
176         sizeof(WCHAR));
177     w_target_len =
178         reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength /
179         sizeof(WCHAR);
180 
181     /* Real symlinks can contain pretty much everything, but the only thing we
182      * really care about is undoing the implicit conversion to an NT namespaced
183      * path that CreateSymbolicLink will perform on absolute paths. If the path
184      * is win32-namespaced then the user must have explicitly made it so, and
185      * we better just return the unmodified reparse data. */
186     if (w_target_len >= 4 &&
187         w_target[0] == L'\\' &&
188         w_target[1] == L'?' &&
189         w_target[2] == L'?' &&
190         w_target[3] == L'\\') {
191       /* Starts with \??\ */
192       if (w_target_len >= 6 &&
193           ((w_target[4] >= L'A' && w_target[4] <= L'Z') ||
194            (w_target[4] >= L'a' && w_target[4] <= L'z')) &&
195           w_target[5] == L':' &&
196           (w_target_len == 6 || w_target[6] == L'\\')) {
197         /* \??\<drive>:\ */
198         w_target += 4;
199         w_target_len -= 4;
200 
201       } else if (w_target_len >= 8 &&
202                  (w_target[4] == L'U' || w_target[4] == L'u') &&
203                  (w_target[5] == L'N' || w_target[5] == L'n') &&
204                  (w_target[6] == L'C' || w_target[6] == L'c') &&
205                  w_target[7] == L'\\') {
206         /* \??\UNC\<server>\<share>\ - make sure the final path looks like
207          * \\<server>\<share>\ */
208         w_target += 6;
209         w_target[0] = L'\\';
210         w_target_len -= 6;
211       }
212     }
213 
214   } else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
215     /* Junction. */
216     w_target = reparse_data->MountPointReparseBuffer.PathBuffer +
217         (reparse_data->MountPointReparseBuffer.SubstituteNameOffset /
218         sizeof(WCHAR));
219     w_target_len = reparse_data->MountPointReparseBuffer.SubstituteNameLength /
220         sizeof(WCHAR);
221 
222     /* Only treat junctions that look like \??\<drive>:\ as symlink. Junctions
223      * can also be used as mount points, like \??\Volume{<guid>}, but that's
224      * confusing for programs since they wouldn't be able to actually
225      * understand such a path when returned by uv_readlink(). UNC paths are
226      * never valid for junctions so we don't care about them. */
227     if (!(w_target_len >= 6 &&
228           w_target[0] == L'\\' &&
229           w_target[1] == L'?' &&
230           w_target[2] == L'?' &&
231           w_target[3] == L'\\' &&
232           ((w_target[4] >= L'A' && w_target[4] <= L'Z') ||
233            (w_target[4] >= L'a' && w_target[4] <= L'z')) &&
234           w_target[5] == L':' &&
235           (w_target_len == 6 || w_target[6] == L'\\'))) {
236       SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
237       return -1;
238     }
239 
240     /* Remove leading \??\ */
241     w_target += 4;
242     w_target_len -= 4;
243 
244   } else if (reparse_data->ReparseTag == IO_REPARSE_TAG_APPEXECLINK) {
245     /* String #3 in the list has the target filename. */
246     if (reparse_data->AppExecLinkReparseBuffer.StringCount < 3) {
247       SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
248       return -1;
249     }
250     w_target = reparse_data->AppExecLinkReparseBuffer.StringList;
251     /* The StringList buffer contains a list of strings separated by "\0",   */
252     /* with "\0\0" terminating the list. Move to the 3rd string in the list: */
253     for (i = 0; i < 2; ++i) {
254       len = wcslen(w_target);
255       if (len == 0) {
256         SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
257         return -1;
258       }
259       w_target += len + 1;
260     }
261     w_target_len = wcslen(w_target);
262     if (w_target_len == 0) {
263       SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
264       return -1;
265     }
266     /* Make sure it is an absolute path. */
267     if (!(w_target_len >= 3 &&
268          ((w_target[0] >= L'a' && w_target[0] <= L'z') ||
269           (w_target[0] >= L'A' && w_target[0] <= L'Z')) &&
270          w_target[1] == L':' &&
271          w_target[2] == L'\\')) {
272       SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
273       return -1;
274     }
275 
276   } else {
277     /* Reparse tag does not indicate a symlink. */
278     SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
279     return -1;
280   }
281 
282   assert(target_ptr == NULL || *target_ptr == NULL);
283   return uv_utf16_to_wtf8(w_target, w_target_len, target_ptr, target_len_ptr);
284 }
285 
286 
fs__capture_path(uv_fs_t * req,const char * path,const char * new_path,const int copy_path)287 INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
288     const char* new_path, const int copy_path) {
289   WCHAR* buf;
290   WCHAR* pos;
291   size_t buf_sz = 0;
292   size_t path_len = 0;
293   ssize_t pathw_len = 0;
294   ssize_t new_pathw_len = 0;
295 
296   /* new_path can only be set if path is also set. */
297   assert(new_path == NULL || path != NULL);
298 
299   if (path != NULL) {
300     pathw_len = uv_wtf8_length_as_utf16(path);
301     if (pathw_len < 0)
302       return ERROR_INVALID_NAME;
303     buf_sz += pathw_len * sizeof(WCHAR);
304   }
305 
306   if (path != NULL && copy_path) {
307     path_len = 1 + strlen(path);
308     buf_sz += path_len;
309   }
310 
311   if (new_path != NULL) {
312     new_pathw_len = uv_wtf8_length_as_utf16(new_path);
313     if (new_pathw_len < 0)
314       return ERROR_INVALID_NAME;
315     buf_sz += new_pathw_len * sizeof(WCHAR);
316   }
317 
318 
319   if (buf_sz == 0) {
320     req->file.pathw = NULL;
321     req->fs.info.new_pathw = NULL;
322     req->path = NULL;
323     return 0;
324   }
325 
326   buf = uv__malloc(buf_sz);
327   if (buf == NULL) {
328     return ERROR_OUTOFMEMORY;
329   }
330 
331   pos = buf;
332 
333   if (path != NULL) {
334     uv_wtf8_to_utf16(path, pos, pathw_len);
335     req->file.pathw = pos;
336     pos += pathw_len;
337   } else {
338     req->file.pathw = NULL;
339   }
340 
341   if (new_path != NULL) {
342     uv_wtf8_to_utf16(new_path, pos, new_pathw_len);
343     req->fs.info.new_pathw = pos;
344     pos += new_pathw_len;
345   } else {
346     req->fs.info.new_pathw = NULL;
347   }
348 
349   req->path = path;
350   if (path != NULL && copy_path) {
351     memcpy(pos, path, path_len);
352     assert(path_len == buf_sz - (pos - buf) * sizeof(WCHAR));
353     req->path = (char*) pos;
354   }
355 
356   req->flags |= UV_FS_FREE_PATHS;
357 
358   return 0;
359 }
360 
361 
uv__fs_req_init(uv_loop_t * loop,uv_fs_t * req,uv_fs_type fs_type,const uv_fs_cb cb)362 INLINE static void uv__fs_req_init(uv_loop_t* loop, uv_fs_t* req,
363     uv_fs_type fs_type, const uv_fs_cb cb) {
364   uv__once_init();
365   UV_REQ_INIT(req, UV_FS);
366   req->loop = loop;
367   req->flags = 0;
368   req->fs_type = fs_type;
369   req->sys_errno_ = 0;
370   req->result = 0;
371   req->ptr = NULL;
372   req->path = NULL;
373   req->cb = cb;
374   memset(&req->fs, 0, sizeof(req->fs));
375 }
376 
377 
fs__open(uv_fs_t * req)378 void fs__open(uv_fs_t* req) {
379   DWORD access;
380   DWORD share;
381   DWORD disposition;
382   DWORD attributes = 0;
383   HANDLE file;
384   int fd, current_umask;
385   int flags = req->fs.info.file_flags;
386   struct uv__fd_info_s fd_info;
387 
388   /* Adjust flags to be compatible with the memory file mapping. Save the
389    * original flags to emulate the correct behavior. */
390   if (flags & UV_FS_O_FILEMAP) {
391     fd_info.flags = flags;
392     fd_info.current_pos.QuadPart = 0;
393 
394     if ((flags & (UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR)) ==
395         UV_FS_O_WRONLY) {
396       /* CreateFileMapping always needs read access */
397       flags = (flags & ~UV_FS_O_WRONLY) | UV_FS_O_RDWR;
398     }
399 
400     if (flags & UV_FS_O_APPEND) {
401       /* Clear the append flag and ensure RDRW mode */
402       flags &= ~UV_FS_O_APPEND;
403       flags &= ~(UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR);
404       flags |= UV_FS_O_RDWR;
405     }
406   }
407 
408   /* Obtain the active umask. umask() never fails and returns the previous
409    * umask. */
410   current_umask = _umask(0);
411   _umask(current_umask);
412 
413   /* convert flags and mode to CreateFile parameters */
414   switch (flags & (UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR)) {
415   case UV_FS_O_RDONLY:
416     access = FILE_GENERIC_READ;
417     break;
418   case UV_FS_O_WRONLY:
419     access = FILE_GENERIC_WRITE;
420     break;
421   case UV_FS_O_RDWR:
422     access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
423     break;
424   default:
425     goto einval;
426   }
427 
428   if (flags & UV_FS_O_APPEND) {
429     access &= ~FILE_WRITE_DATA;
430     access |= FILE_APPEND_DATA;
431   }
432 
433   /*
434    * Here is where we deviate significantly from what CRT's _open()
435    * does. We indiscriminately use all the sharing modes, to match
436    * UNIX semantics. In particular, this ensures that the file can
437    * be deleted even whilst it's open, fixing issue
438    * https://github.com/nodejs/node-v0.x-archive/issues/1449.
439    * We still support exclusive sharing mode, since it is necessary
440    * for opening raw block devices, otherwise Windows will prevent
441    * any attempt to write past the master boot record.
442    */
443   if (flags & UV_FS_O_EXLOCK) {
444     share = 0;
445   } else {
446     share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
447   }
448 
449   switch (flags & (UV_FS_O_CREAT | UV_FS_O_EXCL | UV_FS_O_TRUNC)) {
450   case 0:
451   case UV_FS_O_EXCL:
452     disposition = OPEN_EXISTING;
453     break;
454   case UV_FS_O_CREAT:
455     disposition = OPEN_ALWAYS;
456     break;
457   case UV_FS_O_CREAT | UV_FS_O_EXCL:
458   case UV_FS_O_CREAT | UV_FS_O_TRUNC | UV_FS_O_EXCL:
459     disposition = CREATE_NEW;
460     break;
461   case UV_FS_O_TRUNC:
462   case UV_FS_O_TRUNC | UV_FS_O_EXCL:
463     disposition = TRUNCATE_EXISTING;
464     break;
465   case UV_FS_O_CREAT | UV_FS_O_TRUNC:
466     disposition = CREATE_ALWAYS;
467     break;
468   default:
469     goto einval;
470   }
471 
472   attributes |= FILE_ATTRIBUTE_NORMAL;
473   if (flags & UV_FS_O_CREAT) {
474     if (!((req->fs.info.mode & ~current_umask) & _S_IWRITE)) {
475       attributes |= FILE_ATTRIBUTE_READONLY;
476     }
477   }
478 
479   if (flags & UV_FS_O_TEMPORARY ) {
480     attributes |= FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY;
481     access |= DELETE;
482   }
483 
484   if (flags & UV_FS_O_SHORT_LIVED) {
485     attributes |= FILE_ATTRIBUTE_TEMPORARY;
486   }
487 
488   switch (flags & (UV_FS_O_SEQUENTIAL | UV_FS_O_RANDOM)) {
489   case 0:
490     break;
491   case UV_FS_O_SEQUENTIAL:
492     attributes |= FILE_FLAG_SEQUENTIAL_SCAN;
493     break;
494   case UV_FS_O_RANDOM:
495     attributes |= FILE_FLAG_RANDOM_ACCESS;
496     break;
497   default:
498     goto einval;
499   }
500 
501   if (flags & UV_FS_O_DIRECT) {
502     /*
503      * FILE_APPEND_DATA and FILE_FLAG_NO_BUFFERING are mutually exclusive.
504      * Windows returns 87, ERROR_INVALID_PARAMETER if these are combined.
505      *
506      * FILE_APPEND_DATA is included in FILE_GENERIC_WRITE:
507      *
508      * FILE_GENERIC_WRITE = STANDARD_RIGHTS_WRITE |
509      *                      FILE_WRITE_DATA |
510      *                      FILE_WRITE_ATTRIBUTES |
511      *                      FILE_WRITE_EA |
512      *                      FILE_APPEND_DATA |
513      *                      SYNCHRONIZE
514      *
515      * Note: Appends are also permitted by FILE_WRITE_DATA.
516      *
517      * In order for direct writes and direct appends to succeed, we therefore
518      * exclude FILE_APPEND_DATA if FILE_WRITE_DATA is specified, and otherwise
519      * fail if the user's sole permission is a direct append, since this
520      * particular combination is invalid.
521      */
522     if (access & FILE_APPEND_DATA) {
523       if (access & FILE_WRITE_DATA) {
524         access &= ~FILE_APPEND_DATA;
525       } else {
526         goto einval;
527       }
528     }
529     attributes |= FILE_FLAG_NO_BUFFERING;
530   }
531 
532   switch (flags & (UV_FS_O_DSYNC | UV_FS_O_SYNC)) {
533   case 0:
534     break;
535   case UV_FS_O_DSYNC:
536   case UV_FS_O_SYNC:
537     attributes |= FILE_FLAG_WRITE_THROUGH;
538     break;
539   default:
540     goto einval;
541   }
542 
543   /* Setting this flag makes it possible to open a directory. */
544   attributes |= FILE_FLAG_BACKUP_SEMANTICS;
545 
546   file = CreateFileW(req->file.pathw,
547                      access,
548                      share,
549                      NULL,
550                      disposition,
551                      attributes,
552                      NULL);
553   if (file == INVALID_HANDLE_VALUE) {
554     DWORD error = GetLastError();
555     if (error == ERROR_FILE_EXISTS && (flags & UV_FS_O_CREAT) &&
556         !(flags & UV_FS_O_EXCL)) {
557       /* Special case: when ERROR_FILE_EXISTS happens and UV_FS_O_CREAT was
558        * specified, it means the path referred to a directory. */
559       SET_REQ_UV_ERROR(req, UV_EISDIR, error);
560     } else {
561       SET_REQ_WIN32_ERROR(req, GetLastError());
562     }
563     return;
564   }
565 
566   fd = _open_osfhandle((intptr_t) file, flags);
567   if (fd < 0) {
568     /* The only known failure mode for _open_osfhandle() is EMFILE, in which
569      * case GetLastError() will return zero. However we'll try to handle other
570      * errors as well, should they ever occur.
571      */
572     if (errno == EMFILE)
573       SET_REQ_UV_ERROR(req, UV_EMFILE, ERROR_TOO_MANY_OPEN_FILES);
574     else if (GetLastError() != ERROR_SUCCESS)
575       SET_REQ_WIN32_ERROR(req, GetLastError());
576     else
577       SET_REQ_WIN32_ERROR(req, (DWORD) UV_UNKNOWN);
578     CloseHandle(file);
579     return;
580   }
581 
582   if (flags & UV_FS_O_FILEMAP) {
583     FILE_STANDARD_INFO file_info;
584     if (!GetFileInformationByHandleEx(file,
585                                       FileStandardInfo,
586                                       &file_info,
587                                       sizeof file_info)) {
588       SET_REQ_WIN32_ERROR(req, GetLastError());
589       CloseHandle(file);
590       return;
591     }
592     fd_info.is_directory = file_info.Directory;
593 
594     if (fd_info.is_directory) {
595       fd_info.size.QuadPart = 0;
596       fd_info.mapping = INVALID_HANDLE_VALUE;
597     } else {
598       if (!GetFileSizeEx(file, &fd_info.size)) {
599         SET_REQ_WIN32_ERROR(req, GetLastError());
600         CloseHandle(file);
601         return;
602       }
603 
604       if (fd_info.size.QuadPart == 0) {
605         fd_info.mapping = INVALID_HANDLE_VALUE;
606       } else {
607         DWORD flProtect = (fd_info.flags & (UV_FS_O_RDONLY | UV_FS_O_WRONLY |
608           UV_FS_O_RDWR)) == UV_FS_O_RDONLY ? PAGE_READONLY : PAGE_READWRITE;
609         fd_info.mapping = CreateFileMapping(file,
610                                             NULL,
611                                             flProtect,
612                                             fd_info.size.HighPart,
613                                             fd_info.size.LowPart,
614                                             NULL);
615         if (fd_info.mapping == NULL) {
616           SET_REQ_WIN32_ERROR(req, GetLastError());
617           CloseHandle(file);
618           return;
619         }
620       }
621     }
622 
623     uv__fd_hash_add(fd, &fd_info);
624   }
625 
626   SET_REQ_RESULT(req, fd);
627   return;
628 
629  einval:
630   SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
631 }
632 
fs__close(uv_fs_t * req)633 void fs__close(uv_fs_t* req) {
634   int fd = req->file.fd;
635   int result;
636   struct uv__fd_info_s fd_info;
637 
638   VERIFY_FD(fd, req);
639 
640   if (uv__fd_hash_remove(fd, &fd_info)) {
641     if (fd_info.mapping != INVALID_HANDLE_VALUE) {
642       CloseHandle(fd_info.mapping);
643     }
644   }
645 
646   if (fd > 2)
647     result = _close(fd);
648   else
649     result = 0;
650 
651   /* _close doesn't set _doserrno on failure, but it does always set errno
652    * to EBADF on failure.
653    */
654   if (result == -1) {
655     assert(errno == EBADF);
656     SET_REQ_UV_ERROR(req, UV_EBADF, ERROR_INVALID_HANDLE);
657   } else {
658     SET_REQ_RESULT(req, 0);
659   }
660 }
661 
662 
fs__filemap_ex_filter(LONG excode,PEXCEPTION_POINTERS pep,int * perror)663 LONG fs__filemap_ex_filter(LONG excode, PEXCEPTION_POINTERS pep,
664                            int* perror) {
665   if (excode != (LONG)EXCEPTION_IN_PAGE_ERROR) {
666     return EXCEPTION_CONTINUE_SEARCH;
667   }
668 
669   assert(perror != NULL);
670   if (pep != NULL && pep->ExceptionRecord != NULL &&
671       pep->ExceptionRecord->NumberParameters >= 3) {
672     NTSTATUS status = (NTSTATUS)pep->ExceptionRecord->ExceptionInformation[3];
673     *perror = pRtlNtStatusToDosError(status);
674     if (*perror != ERROR_SUCCESS) {
675       return EXCEPTION_EXECUTE_HANDLER;
676     }
677   }
678   *perror = UV_UNKNOWN;
679   return EXCEPTION_EXECUTE_HANDLER;
680 }
681 
682 
fs__read_filemap(uv_fs_t * req,struct uv__fd_info_s * fd_info)683 void fs__read_filemap(uv_fs_t* req, struct uv__fd_info_s* fd_info) {
684   int fd = req->file.fd; /* VERIFY_FD done in fs__read */
685   int rw_flags = fd_info->flags &
686     (UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR);
687   size_t read_size, done_read;
688   unsigned int index;
689   LARGE_INTEGER pos, end_pos;
690   size_t view_offset;
691   LARGE_INTEGER view_base;
692   void* view;
693 
694   if (rw_flags == UV_FS_O_WRONLY) {
695     SET_REQ_WIN32_ERROR(req, ERROR_INVALID_FLAGS);
696     return;
697   }
698   if (fd_info->is_directory) {
699     SET_REQ_WIN32_ERROR(req, ERROR_INVALID_FUNCTION);
700     return;
701   }
702 
703   if (req->fs.info.offset == -1) {
704     pos = fd_info->current_pos;
705   } else {
706     pos.QuadPart = req->fs.info.offset;
707   }
708 
709   /* Make sure we wont read past EOF. */
710   if (pos.QuadPart >= fd_info->size.QuadPart) {
711     SET_REQ_RESULT(req, 0);
712     return;
713   }
714 
715   read_size = 0;
716   for (index = 0; index < req->fs.info.nbufs; ++index) {
717     read_size += req->fs.info.bufs[index].len;
718   }
719   read_size = (size_t) MIN((LONGLONG) read_size,
720                            fd_info->size.QuadPart - pos.QuadPart);
721   if (read_size == 0) {
722     SET_REQ_RESULT(req, 0);
723     return;
724   }
725 
726   end_pos.QuadPart = pos.QuadPart + read_size;
727 
728   view_offset = pos.QuadPart % uv__allocation_granularity;
729   view_base.QuadPart = pos.QuadPart - view_offset;
730   view = MapViewOfFile(fd_info->mapping,
731                        FILE_MAP_READ,
732                        view_base.HighPart,
733                        view_base.LowPart,
734                        view_offset + read_size);
735   if (view == NULL) {
736     SET_REQ_WIN32_ERROR(req, GetLastError());
737     return;
738   }
739 
740   done_read = 0;
741   for (index = 0;
742        index < req->fs.info.nbufs && done_read < read_size;
743        ++index) {
744     size_t this_read_size = MIN(req->fs.info.bufs[index].len,
745                                 read_size - done_read);
746 #ifdef _MSC_VER
747     int err = 0;
748     __try {
749 #endif
750       memcpy(req->fs.info.bufs[index].base,
751              (char*)view + view_offset + done_read,
752              this_read_size);
753 #ifdef _MSC_VER
754     }
755     __except (fs__filemap_ex_filter(GetExceptionCode(),
756                                     GetExceptionInformation(), &err)) {
757       SET_REQ_WIN32_ERROR(req, err);
758       UnmapViewOfFile(view);
759       return;
760     }
761 #endif
762     done_read += this_read_size;
763   }
764   assert(done_read == read_size);
765 
766   if (!UnmapViewOfFile(view)) {
767     SET_REQ_WIN32_ERROR(req, GetLastError());
768     return;
769   }
770 
771   if (req->fs.info.offset == -1) {
772     fd_info->current_pos = end_pos;
773     uv__fd_hash_add(fd, fd_info);
774   }
775 
776   SET_REQ_RESULT(req, read_size);
777   return;
778 }
779 
fs__read(uv_fs_t * req)780 void fs__read(uv_fs_t* req) {
781   int fd = req->file.fd;
782   int64_t offset = req->fs.info.offset;
783   HANDLE handle;
784   OVERLAPPED overlapped, *overlapped_ptr;
785   LARGE_INTEGER offset_;
786   DWORD bytes;
787   DWORD error;
788   int result;
789   unsigned int index;
790   LARGE_INTEGER original_position;
791   LARGE_INTEGER zero_offset;
792   int restore_position;
793   struct uv__fd_info_s fd_info;
794 
795   VERIFY_FD(fd, req);
796 
797   if (uv__fd_hash_get(fd, &fd_info)) {
798     fs__read_filemap(req, &fd_info);
799     return;
800   }
801 
802   zero_offset.QuadPart = 0;
803   restore_position = 0;
804   handle = uv__get_osfhandle(fd);
805 
806   if (handle == INVALID_HANDLE_VALUE) {
807     SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
808     return;
809   }
810 
811   if (offset != -1) {
812     memset(&overlapped, 0, sizeof overlapped);
813     overlapped_ptr = &overlapped;
814     if (SetFilePointerEx(handle, zero_offset, &original_position,
815                          FILE_CURRENT)) {
816       restore_position = 1;
817     }
818   } else {
819     overlapped_ptr = NULL;
820   }
821 
822   index = 0;
823   bytes = 0;
824   do {
825     DWORD incremental_bytes;
826 
827     if (offset != -1) {
828       offset_.QuadPart = offset + bytes;
829       overlapped.Offset = offset_.LowPart;
830       overlapped.OffsetHigh = offset_.HighPart;
831     }
832 
833     result = ReadFile(handle,
834                       req->fs.info.bufs[index].base,
835                       req->fs.info.bufs[index].len,
836                       &incremental_bytes,
837                       overlapped_ptr);
838     bytes += incremental_bytes;
839     ++index;
840   } while (result && index < req->fs.info.nbufs);
841 
842   if (restore_position)
843     SetFilePointerEx(handle, original_position, NULL, FILE_BEGIN);
844 
845   if (result || bytes > 0) {
846     SET_REQ_RESULT(req, bytes);
847   } else {
848     error = GetLastError();
849     if (error == ERROR_ACCESS_DENIED) {
850       error = ERROR_INVALID_FLAGS;
851     }
852 
853     if (error == ERROR_HANDLE_EOF || error == ERROR_BROKEN_PIPE) {
854       SET_REQ_RESULT(req, bytes);
855     } else {
856       SET_REQ_WIN32_ERROR(req, error);
857     }
858   }
859 }
860 
861 
fs__write_filemap(uv_fs_t * req,HANDLE file,struct uv__fd_info_s * fd_info)862 void fs__write_filemap(uv_fs_t* req, HANDLE file,
863                        struct uv__fd_info_s* fd_info) {
864   int fd = req->file.fd; /* VERIFY_FD done in fs__write */
865   int force_append = fd_info->flags & UV_FS_O_APPEND;
866   int rw_flags = fd_info->flags &
867     (UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR);
868   size_t write_size, done_write;
869   unsigned int index;
870   LARGE_INTEGER pos, end_pos;
871   size_t view_offset;
872   LARGE_INTEGER view_base;
873   void* view;
874   FILETIME ft;
875 
876   if (rw_flags == UV_FS_O_RDONLY) {
877     SET_REQ_WIN32_ERROR(req, ERROR_INVALID_FLAGS);
878     return;
879   }
880   if (fd_info->is_directory) {
881     SET_REQ_WIN32_ERROR(req, ERROR_INVALID_FUNCTION);
882     return;
883   }
884 
885   write_size = 0;
886   for (index = 0; index < req->fs.info.nbufs; ++index) {
887     write_size += req->fs.info.bufs[index].len;
888   }
889 
890   if (write_size == 0) {
891     SET_REQ_RESULT(req, 0);
892     return;
893   }
894 
895   if (force_append) {
896     pos = fd_info->size;
897   } else if (req->fs.info.offset == -1) {
898     pos = fd_info->current_pos;
899   } else {
900     pos.QuadPart = req->fs.info.offset;
901   }
902 
903   end_pos.QuadPart = pos.QuadPart + write_size;
904 
905   /* Recreate the mapping to enlarge the file if needed */
906   if (end_pos.QuadPart > fd_info->size.QuadPart) {
907     if (fd_info->mapping != INVALID_HANDLE_VALUE) {
908       CloseHandle(fd_info->mapping);
909     }
910 
911     fd_info->mapping = CreateFileMapping(file,
912                                          NULL,
913                                          PAGE_READWRITE,
914                                          end_pos.HighPart,
915                                          end_pos.LowPart,
916                                          NULL);
917     if (fd_info->mapping == NULL) {
918       SET_REQ_WIN32_ERROR(req, GetLastError());
919       CloseHandle(file);
920       fd_info->mapping = INVALID_HANDLE_VALUE;
921       fd_info->size.QuadPart = 0;
922       fd_info->current_pos.QuadPart = 0;
923       uv__fd_hash_add(fd, fd_info);
924       return;
925     }
926 
927     fd_info->size = end_pos;
928     uv__fd_hash_add(fd, fd_info);
929   }
930 
931   view_offset = pos.QuadPart % uv__allocation_granularity;
932   view_base.QuadPart = pos.QuadPart - view_offset;
933   view = MapViewOfFile(fd_info->mapping,
934                        FILE_MAP_WRITE,
935                        view_base.HighPart,
936                        view_base.LowPart,
937                        view_offset + write_size);
938   if (view == NULL) {
939     SET_REQ_WIN32_ERROR(req, GetLastError());
940     return;
941   }
942 
943   done_write = 0;
944   for (index = 0; index < req->fs.info.nbufs; ++index) {
945 #ifdef _MSC_VER
946     int err = 0;
947     __try {
948 #endif
949       memcpy((char*)view + view_offset + done_write,
950              req->fs.info.bufs[index].base,
951              req->fs.info.bufs[index].len);
952 #ifdef _MSC_VER
953     }
954     __except (fs__filemap_ex_filter(GetExceptionCode(),
955                                     GetExceptionInformation(), &err)) {
956       SET_REQ_WIN32_ERROR(req, err);
957       UnmapViewOfFile(view);
958       return;
959     }
960 #endif
961     done_write += req->fs.info.bufs[index].len;
962   }
963   assert(done_write == write_size);
964 
965   if (!FlushViewOfFile(view, 0)) {
966     SET_REQ_WIN32_ERROR(req, GetLastError());
967     UnmapViewOfFile(view);
968     return;
969   }
970   if (!UnmapViewOfFile(view)) {
971     SET_REQ_WIN32_ERROR(req, GetLastError());
972     return;
973   }
974 
975   if (req->fs.info.offset == -1) {
976     fd_info->current_pos = end_pos;
977     uv__fd_hash_add(fd, fd_info);
978   }
979 
980   GetSystemTimeAsFileTime(&ft);
981   SetFileTime(file, NULL, NULL, &ft);
982 
983   SET_REQ_RESULT(req, done_write);
984 }
985 
fs__write(uv_fs_t * req)986 void fs__write(uv_fs_t* req) {
987   int fd = req->file.fd;
988   int64_t offset = req->fs.info.offset;
989   HANDLE handle;
990   OVERLAPPED overlapped, *overlapped_ptr;
991   LARGE_INTEGER offset_;
992   DWORD bytes;
993   DWORD error;
994   int result;
995   unsigned int index;
996   LARGE_INTEGER original_position;
997   LARGE_INTEGER zero_offset;
998   int restore_position;
999   struct uv__fd_info_s fd_info;
1000 
1001   VERIFY_FD(fd, req);
1002 
1003   zero_offset.QuadPart = 0;
1004   restore_position = 0;
1005   handle = uv__get_osfhandle(fd);
1006   if (handle == INVALID_HANDLE_VALUE) {
1007     SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
1008     return;
1009   }
1010 
1011   if (uv__fd_hash_get(fd, &fd_info)) {
1012     fs__write_filemap(req, handle, &fd_info);
1013     return;
1014   }
1015 
1016   if (offset != -1) {
1017     memset(&overlapped, 0, sizeof overlapped);
1018     overlapped_ptr = &overlapped;
1019     if (SetFilePointerEx(handle, zero_offset, &original_position,
1020                          FILE_CURRENT)) {
1021       restore_position = 1;
1022     }
1023   } else {
1024     overlapped_ptr = NULL;
1025   }
1026 
1027   index = 0;
1028   bytes = 0;
1029   do {
1030     DWORD incremental_bytes;
1031 
1032     if (offset != -1) {
1033       offset_.QuadPart = offset + bytes;
1034       overlapped.Offset = offset_.LowPart;
1035       overlapped.OffsetHigh = offset_.HighPart;
1036     }
1037 
1038     result = WriteFile(handle,
1039                        req->fs.info.bufs[index].base,
1040                        req->fs.info.bufs[index].len,
1041                        &incremental_bytes,
1042                        overlapped_ptr);
1043     bytes += incremental_bytes;
1044     ++index;
1045   } while (result && index < req->fs.info.nbufs);
1046 
1047   if (restore_position)
1048     SetFilePointerEx(handle, original_position, NULL, FILE_BEGIN);
1049 
1050   if (result || bytes > 0) {
1051     SET_REQ_RESULT(req, bytes);
1052   } else {
1053     error = GetLastError();
1054 
1055     if (error == ERROR_ACCESS_DENIED) {
1056       error = ERROR_INVALID_FLAGS;
1057     }
1058 
1059     SET_REQ_WIN32_ERROR(req, error);
1060   }
1061 }
1062 
1063 
fs__rmdir(uv_fs_t * req)1064 void fs__rmdir(uv_fs_t* req) {
1065   int result = _wrmdir(req->file.pathw);
1066   if (result == -1)
1067     SET_REQ_WIN32_ERROR(req, _doserrno);
1068   else
1069     SET_REQ_RESULT(req, 0);
1070 }
1071 
1072 
fs__unlink(uv_fs_t * req)1073 void fs__unlink(uv_fs_t* req) {
1074   const WCHAR* pathw = req->file.pathw;
1075   HANDLE handle;
1076   BY_HANDLE_FILE_INFORMATION info;
1077   FILE_DISPOSITION_INFORMATION disposition;
1078   IO_STATUS_BLOCK iosb;
1079   NTSTATUS status;
1080 
1081   handle = CreateFileW(pathw,
1082                        FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | DELETE,
1083                        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1084                        NULL,
1085                        OPEN_EXISTING,
1086                        FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
1087                        NULL);
1088 
1089   if (handle == INVALID_HANDLE_VALUE) {
1090     SET_REQ_WIN32_ERROR(req, GetLastError());
1091     return;
1092   }
1093 
1094   if (!GetFileInformationByHandle(handle, &info)) {
1095     SET_REQ_WIN32_ERROR(req, GetLastError());
1096     CloseHandle(handle);
1097     return;
1098   }
1099 
1100   if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1101     /* Do not allow deletion of directories, unless it is a symlink. When the
1102      * path refers to a non-symlink directory, report EPERM as mandated by
1103      * POSIX.1. */
1104 
1105     /* Check if it is a reparse point. If it's not, it's a normal directory. */
1106     if (!(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
1107       SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED);
1108       CloseHandle(handle);
1109       return;
1110     }
1111 
1112     /* Read the reparse point and check if it is a valid symlink. If not, don't
1113      * unlink. */
1114     if (fs__readlink_handle(handle, NULL, NULL) < 0) {
1115       DWORD error = GetLastError();
1116       if (error == ERROR_SYMLINK_NOT_SUPPORTED)
1117         error = ERROR_ACCESS_DENIED;
1118       SET_REQ_WIN32_ERROR(req, error);
1119       CloseHandle(handle);
1120       return;
1121     }
1122   }
1123 
1124   if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
1125     /* Remove read-only attribute */
1126     FILE_BASIC_INFORMATION basic = { 0 };
1127 
1128     basic.FileAttributes = (info.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY) |
1129                            FILE_ATTRIBUTE_ARCHIVE;
1130 
1131     status = pNtSetInformationFile(handle,
1132                                    &iosb,
1133                                    &basic,
1134                                    sizeof basic,
1135                                    FileBasicInformation);
1136     if (!NT_SUCCESS(status)) {
1137       SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
1138       CloseHandle(handle);
1139       return;
1140     }
1141   }
1142 
1143   /* Try to set the delete flag. */
1144   disposition.DeleteFile = TRUE;
1145   status = pNtSetInformationFile(handle,
1146                                  &iosb,
1147                                  &disposition,
1148                                  sizeof disposition,
1149                                  FileDispositionInformation);
1150   if (NT_SUCCESS(status)) {
1151     SET_REQ_SUCCESS(req);
1152   } else {
1153     SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
1154   }
1155 
1156   CloseHandle(handle);
1157 }
1158 
1159 
fs__mkdir(uv_fs_t * req)1160 void fs__mkdir(uv_fs_t* req) {
1161   /* TODO: use req->mode. */
1162   if (CreateDirectoryW(req->file.pathw, NULL)) {
1163     SET_REQ_RESULT(req, 0);
1164   } else {
1165     SET_REQ_WIN32_ERROR(req, GetLastError());
1166     if (req->sys_errno_ == ERROR_INVALID_NAME ||
1167         req->sys_errno_ == ERROR_DIRECTORY)
1168       req->result = UV_EINVAL;
1169   }
1170 }
1171 
1172 typedef int (*uv__fs_mktemp_func)(uv_fs_t* req);
1173 
1174 /* OpenBSD original: lib/libc/stdio/mktemp.c */
fs__mktemp(uv_fs_t * req,uv__fs_mktemp_func func)1175 void fs__mktemp(uv_fs_t* req, uv__fs_mktemp_func func) {
1176   static const WCHAR *tempchars =
1177     L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
1178   static const size_t num_chars = 62;
1179   static const size_t num_x = 6;
1180   WCHAR *cp, *ep;
1181   unsigned int tries, i;
1182   size_t len;
1183   uint64_t v;
1184   char* path;
1185 
1186   path = (char*)req->path;
1187   len = wcslen(req->file.pathw);
1188   ep = req->file.pathw + len;
1189   if (len < num_x || wcsncmp(ep - num_x, L"XXXXXX", num_x)) {
1190     SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
1191     goto clobber;
1192   }
1193 
1194   tries = TMP_MAX;
1195   do {
1196     if (uv__random_rtlgenrandom((void *)&v, sizeof(v)) < 0) {
1197       SET_REQ_UV_ERROR(req, UV_EIO, ERROR_IO_DEVICE);
1198       goto clobber;
1199     }
1200 
1201     cp = ep - num_x;
1202     for (i = 0; i < num_x; i++) {
1203       *cp++ = tempchars[v % num_chars];
1204       v /= num_chars;
1205     }
1206 
1207     if (func(req)) {
1208       if (req->result >= 0) {
1209         len = strlen(path);
1210         wcstombs(path + len - num_x, ep - num_x, num_x);
1211       }
1212       return;
1213     }
1214   } while (--tries);
1215 
1216   SET_REQ_WIN32_ERROR(req, GetLastError());
1217 
1218 clobber:
1219   path[0] = '\0';
1220 }
1221 
1222 
fs__mkdtemp_func(uv_fs_t * req)1223 static int fs__mkdtemp_func(uv_fs_t* req) {
1224   DWORD error;
1225   if (CreateDirectoryW(req->file.pathw, NULL)) {
1226     SET_REQ_RESULT(req, 0);
1227     return 1;
1228   }
1229   error = GetLastError();
1230   if (error != ERROR_ALREADY_EXISTS) {
1231     SET_REQ_WIN32_ERROR(req, error);
1232     return 1;
1233   }
1234 
1235   return 0;
1236 }
1237 
1238 
fs__mkdtemp(uv_fs_t * req)1239 void fs__mkdtemp(uv_fs_t* req) {
1240   fs__mktemp(req, fs__mkdtemp_func);
1241 }
1242 
1243 
fs__mkstemp_func(uv_fs_t * req)1244 static int fs__mkstemp_func(uv_fs_t* req) {
1245   HANDLE file;
1246   int fd;
1247 
1248   file = CreateFileW(req->file.pathw,
1249                      GENERIC_READ | GENERIC_WRITE,
1250                      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1251                      NULL,
1252                      CREATE_NEW,
1253                      FILE_ATTRIBUTE_NORMAL,
1254                      NULL);
1255 
1256   if (file == INVALID_HANDLE_VALUE) {
1257     DWORD error;
1258     error = GetLastError();
1259 
1260     /* If the file exists, the main fs__mktemp() function
1261        will retry. If it's another error, we want to stop. */
1262     if (error != ERROR_FILE_EXISTS) {
1263       SET_REQ_WIN32_ERROR(req, error);
1264       return 1;
1265     }
1266 
1267     return 0;
1268   }
1269 
1270   fd = _open_osfhandle((intptr_t) file, 0);
1271   if (fd < 0) {
1272     /* The only known failure mode for _open_osfhandle() is EMFILE, in which
1273      * case GetLastError() will return zero. However we'll try to handle other
1274      * errors as well, should they ever occur.
1275      */
1276     if (errno == EMFILE)
1277       SET_REQ_UV_ERROR(req, UV_EMFILE, ERROR_TOO_MANY_OPEN_FILES);
1278     else if (GetLastError() != ERROR_SUCCESS)
1279       SET_REQ_WIN32_ERROR(req, GetLastError());
1280     else
1281       SET_REQ_WIN32_ERROR(req, UV_UNKNOWN);
1282     CloseHandle(file);
1283     return 1;
1284   }
1285 
1286   SET_REQ_RESULT(req, fd);
1287 
1288   return 1;
1289 }
1290 
1291 
fs__mkstemp(uv_fs_t * req)1292 void fs__mkstemp(uv_fs_t* req) {
1293   fs__mktemp(req, fs__mkstemp_func);
1294 }
1295 
1296 
fs__scandir(uv_fs_t * req)1297 void fs__scandir(uv_fs_t* req) {
1298   static const size_t dirents_initial_size = 32;
1299 
1300   HANDLE dir_handle = INVALID_HANDLE_VALUE;
1301 
1302   uv__dirent_t** dirents = NULL;
1303   size_t dirents_size = 0;
1304   size_t dirents_used = 0;
1305 
1306   IO_STATUS_BLOCK iosb;
1307   NTSTATUS status;
1308 
1309   /* Buffer to hold directory entries returned by NtQueryDirectoryFile.
1310    * It's important that this buffer can hold at least one entry, regardless
1311    * of the length of the file names present in the enumerated directory.
1312    * A file name is at most 256 WCHARs long.
1313    * According to MSDN, the buffer must be aligned at an 8-byte boundary.
1314    */
1315 #if _MSC_VER
1316   __declspec(align(8)) char buffer[8192];
1317 #else
1318   __attribute__ ((aligned (8))) char buffer[8192];
1319 #endif
1320 
1321   STATIC_ASSERT(sizeof buffer >=
1322                 sizeof(FILE_DIRECTORY_INFORMATION) + 256 * sizeof(WCHAR));
1323 
1324   /* Open the directory. */
1325   dir_handle =
1326       CreateFileW(req->file.pathw,
1327                   FILE_LIST_DIRECTORY | SYNCHRONIZE,
1328                   FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1329                   NULL,
1330                   OPEN_EXISTING,
1331                   FILE_FLAG_BACKUP_SEMANTICS,
1332                   NULL);
1333   if (dir_handle == INVALID_HANDLE_VALUE)
1334     goto win32_error;
1335 
1336   /* Read the first chunk. */
1337   status = pNtQueryDirectoryFile(dir_handle,
1338                                  NULL,
1339                                  NULL,
1340                                  NULL,
1341                                  &iosb,
1342                                  &buffer,
1343                                  sizeof buffer,
1344                                  FileDirectoryInformation,
1345                                  FALSE,
1346                                  NULL,
1347                                  TRUE);
1348 
1349   /* If the handle is not a directory, we'll get STATUS_INVALID_PARAMETER.
1350    * This should be reported back as UV_ENOTDIR.
1351    */
1352   if (status == (NTSTATUS)STATUS_INVALID_PARAMETER)
1353     goto not_a_directory_error;
1354 
1355   while (NT_SUCCESS(status)) {
1356     char* position = buffer;
1357     size_t next_entry_offset = 0;
1358 
1359     do {
1360       FILE_DIRECTORY_INFORMATION* info;
1361       uv__dirent_t* dirent;
1362 
1363       size_t wchar_len;
1364       size_t wtf8_len;
1365       char* wtf8;
1366 
1367       /* Obtain a pointer to the current directory entry. */
1368       position += next_entry_offset;
1369       info = (FILE_DIRECTORY_INFORMATION*) position;
1370 
1371       /* Fetch the offset to the next directory entry. */
1372       next_entry_offset = info->NextEntryOffset;
1373 
1374       /* Compute the length of the filename in WCHARs. */
1375       wchar_len = info->FileNameLength / sizeof info->FileName[0];
1376 
1377       /* Skip over '.' and '..' entries.  It has been reported that
1378        * the SharePoint driver includes the terminating zero byte in
1379        * the filename length.  Strip those first.
1380        */
1381       while (wchar_len > 0 && info->FileName[wchar_len - 1] == L'\0')
1382         wchar_len -= 1;
1383 
1384       if (wchar_len == 0)
1385         continue;
1386       if (wchar_len == 1 && info->FileName[0] == L'.')
1387         continue;
1388       if (wchar_len == 2 && info->FileName[0] == L'.' &&
1389           info->FileName[1] == L'.')
1390         continue;
1391 
1392       /* Compute the space required to store the filename as WTF-8. */
1393       wtf8_len = uv_utf16_length_as_wtf8(&info->FileName[0], wchar_len);
1394 
1395       /* Resize the dirent array if needed. */
1396       if (dirents_used >= dirents_size) {
1397         size_t new_dirents_size =
1398             dirents_size == 0 ? dirents_initial_size : dirents_size << 1;
1399         uv__dirent_t** new_dirents =
1400             uv__realloc(dirents, new_dirents_size * sizeof *dirents);
1401 
1402         if (new_dirents == NULL)
1403           goto out_of_memory_error;
1404 
1405         dirents_size = new_dirents_size;
1406         dirents = new_dirents;
1407       }
1408 
1409       /* Allocate space for the uv dirent structure. The dirent structure
1410        * includes room for the first character of the filename, but `utf8_len`
1411        * doesn't count the NULL terminator at this point.
1412        */
1413       dirent = uv__malloc(sizeof *dirent + wtf8_len);
1414       if (dirent == NULL)
1415         goto out_of_memory_error;
1416 
1417       dirents[dirents_used++] = dirent;
1418 
1419       /* Convert file name to UTF-8. */
1420       wtf8 = &dirent->d_name[0];
1421       if (uv_utf16_to_wtf8(&info->FileName[0], wchar_len, &wtf8, &wtf8_len) != 0)
1422         goto out_of_memory_error;
1423 
1424       /* Fill out the type field. */
1425       if (info->FileAttributes & FILE_ATTRIBUTE_DEVICE)
1426         dirent->d_type = UV__DT_CHAR;
1427       else if (info->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
1428         dirent->d_type = UV__DT_LINK;
1429       else if (info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1430         dirent->d_type = UV__DT_DIR;
1431       else
1432         dirent->d_type = UV__DT_FILE;
1433     } while (next_entry_offset != 0);
1434 
1435     /* Read the next chunk. */
1436     status = pNtQueryDirectoryFile(dir_handle,
1437                                    NULL,
1438                                    NULL,
1439                                    NULL,
1440                                    &iosb,
1441                                    &buffer,
1442                                    sizeof buffer,
1443                                    FileDirectoryInformation,
1444                                    FALSE,
1445                                    NULL,
1446                                    FALSE);
1447 
1448     /* After the first pNtQueryDirectoryFile call, the function may return
1449      * STATUS_SUCCESS even if the buffer was too small to hold at least one
1450      * directory entry.
1451      */
1452     if (status == STATUS_SUCCESS && iosb.Information == 0)
1453       status = STATUS_BUFFER_OVERFLOW;
1454   }
1455 
1456   if (status != STATUS_NO_MORE_FILES)
1457     goto nt_error;
1458 
1459   CloseHandle(dir_handle);
1460 
1461   /* Store the result in the request object. */
1462   req->ptr = dirents;
1463   if (dirents != NULL)
1464     req->flags |= UV_FS_FREE_PTR;
1465 
1466   SET_REQ_RESULT(req, dirents_used);
1467 
1468   /* `nbufs` will be used as index by uv_fs_scandir_next. */
1469   req->fs.info.nbufs = 0;
1470 
1471   return;
1472 
1473 nt_error:
1474   SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
1475   goto cleanup;
1476 
1477 win32_error:
1478   SET_REQ_WIN32_ERROR(req, GetLastError());
1479   goto cleanup;
1480 
1481 not_a_directory_error:
1482   SET_REQ_UV_ERROR(req, UV_ENOTDIR, ERROR_DIRECTORY);
1483   goto cleanup;
1484 
1485 out_of_memory_error:
1486   SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
1487   goto cleanup;
1488 
1489 cleanup:
1490   if (dir_handle != INVALID_HANDLE_VALUE)
1491     CloseHandle(dir_handle);
1492   while (dirents_used > 0)
1493     uv__free(dirents[--dirents_used]);
1494   if (dirents != NULL)
1495     uv__free(dirents);
1496 }
1497 
fs__opendir(uv_fs_t * req)1498 void fs__opendir(uv_fs_t* req) {
1499   WCHAR* pathw;
1500   size_t len;
1501   const WCHAR* fmt;
1502   WCHAR* find_path;
1503   uv_dir_t* dir;
1504 
1505   pathw = req->file.pathw;
1506   dir = NULL;
1507   find_path = NULL;
1508 
1509   /* Figure out whether path is a file or a directory. */
1510   if (!(GetFileAttributesW(pathw) & FILE_ATTRIBUTE_DIRECTORY)) {
1511     SET_REQ_UV_ERROR(req, UV_ENOTDIR, ERROR_DIRECTORY);
1512     goto error;
1513   }
1514 
1515   dir = uv__malloc(sizeof(*dir));
1516   if (dir == NULL) {
1517     SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
1518     goto error;
1519   }
1520 
1521   len = wcslen(pathw);
1522 
1523   if (len == 0)
1524     fmt = L"./*";
1525   else if (IS_SLASH(pathw[len - 1]))
1526     fmt = L"%s*";
1527   else
1528     fmt = L"%s\\*";
1529 
1530   find_path = uv__malloc(sizeof(WCHAR) * (len + 4));
1531   if (find_path == NULL) {
1532     SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
1533     goto error;
1534   }
1535 
1536   _snwprintf(find_path, len + 3, fmt, pathw);
1537   dir->dir_handle = FindFirstFileW(find_path, &dir->find_data);
1538   uv__free(find_path);
1539   find_path = NULL;
1540   if (dir->dir_handle == INVALID_HANDLE_VALUE &&
1541       GetLastError() != ERROR_FILE_NOT_FOUND) {
1542     SET_REQ_WIN32_ERROR(req, GetLastError());
1543     goto error;
1544   }
1545 
1546   dir->need_find_call = FALSE;
1547   req->ptr = dir;
1548   SET_REQ_RESULT(req, 0);
1549   return;
1550 
1551 error:
1552   uv__free(dir);
1553   uv__free(find_path);
1554   req->ptr = NULL;
1555 }
1556 
fs__readdir(uv_fs_t * req)1557 void fs__readdir(uv_fs_t* req) {
1558   uv_dir_t* dir;
1559   uv_dirent_t* dirents;
1560   uv__dirent_t dent;
1561   unsigned int dirent_idx;
1562   PWIN32_FIND_DATAW find_data;
1563   unsigned int i;
1564   int r;
1565 
1566   req->flags |= UV_FS_FREE_PTR;
1567   dir = req->ptr;
1568   dirents = dir->dirents;
1569   memset(dirents, 0, dir->nentries * sizeof(*dir->dirents));
1570   find_data = &dir->find_data;
1571   dirent_idx = 0;
1572 
1573   while (dirent_idx < dir->nentries) {
1574     if (dir->need_find_call && FindNextFileW(dir->dir_handle, find_data) == 0) {
1575       if (GetLastError() == ERROR_NO_MORE_FILES)
1576         break;
1577       goto error;
1578     }
1579 
1580     /* Skip "." and ".." entries. */
1581     if (find_data->cFileName[0] == L'.' &&
1582         (find_data->cFileName[1] == L'\0' ||
1583         (find_data->cFileName[1] == L'.' &&
1584         find_data->cFileName[2] == L'\0'))) {
1585       dir->need_find_call = TRUE;
1586       continue;
1587     }
1588 
1589     r = uv__convert_utf16_to_utf8((const WCHAR*) &find_data->cFileName,
1590                                   -1,
1591                                   (char**) &dirents[dirent_idx].name);
1592     if (r != 0)
1593       goto error;
1594 
1595     /* Copy file type. */
1596     if ((find_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
1597       dent.d_type = UV__DT_DIR;
1598     else if ((find_data->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0)
1599       dent.d_type = UV__DT_LINK;
1600     else if ((find_data->dwFileAttributes & FILE_ATTRIBUTE_DEVICE) != 0)
1601       dent.d_type = UV__DT_CHAR;
1602     else
1603       dent.d_type = UV__DT_FILE;
1604 
1605     dirents[dirent_idx].type = uv__fs_get_dirent_type(&dent);
1606     dir->need_find_call = TRUE;
1607     ++dirent_idx;
1608   }
1609 
1610   SET_REQ_RESULT(req, dirent_idx);
1611   return;
1612 
1613 error:
1614   SET_REQ_WIN32_ERROR(req, GetLastError());
1615   for (i = 0; i < dirent_idx; ++i) {
1616     uv__free((char*) dirents[i].name);
1617     dirents[i].name = NULL;
1618   }
1619 }
1620 
fs__closedir(uv_fs_t * req)1621 void fs__closedir(uv_fs_t* req) {
1622   uv_dir_t* dir;
1623 
1624   dir = req->ptr;
1625   FindClose(dir->dir_handle);
1626   uv__free(req->ptr);
1627   SET_REQ_RESULT(req, 0);
1628 }
1629 
fs__stat_handle(HANDLE handle,uv_stat_t * statbuf,int do_lstat)1630 INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf,
1631     int do_lstat) {
1632   size_t target_length = 0;
1633   FILE_FS_DEVICE_INFORMATION device_info;
1634   FILE_ALL_INFORMATION file_info;
1635   FILE_FS_VOLUME_INFORMATION volume_info;
1636   NTSTATUS nt_status;
1637   IO_STATUS_BLOCK io_status;
1638 
1639   nt_status = pNtQueryVolumeInformationFile(handle,
1640                                             &io_status,
1641                                             &device_info,
1642                                             sizeof device_info,
1643                                             FileFsDeviceInformation);
1644 
1645   /* Buffer overflow (a warning status code) is expected here. */
1646   if (NT_ERROR(nt_status)) {
1647     SetLastError(pRtlNtStatusToDosError(nt_status));
1648     return -1;
1649   }
1650 
1651   /* If it's NUL device set fields as reasonable as possible and return. */
1652   if (device_info.DeviceType == FILE_DEVICE_NULL) {
1653     memset(statbuf, 0, sizeof(uv_stat_t));
1654     statbuf->st_mode = _S_IFCHR;
1655     statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) |
1656                         ((_S_IREAD | _S_IWRITE) >> 6);
1657     statbuf->st_nlink = 1;
1658     statbuf->st_blksize = 4096;
1659     statbuf->st_rdev = FILE_DEVICE_NULL << 16;
1660     return 0;
1661   }
1662 
1663   nt_status = pNtQueryInformationFile(handle,
1664                                       &io_status,
1665                                       &file_info,
1666                                       sizeof file_info,
1667                                       FileAllInformation);
1668 
1669   /* Buffer overflow (a warning status code) is expected here. */
1670   if (NT_ERROR(nt_status)) {
1671     SetLastError(pRtlNtStatusToDosError(nt_status));
1672     return -1;
1673   }
1674 
1675   nt_status = pNtQueryVolumeInformationFile(handle,
1676                                             &io_status,
1677                                             &volume_info,
1678                                             sizeof volume_info,
1679                                             FileFsVolumeInformation);
1680 
1681   /* Buffer overflow (a warning status code) is expected here. */
1682   if (io_status.Status == STATUS_NOT_IMPLEMENTED) {
1683     statbuf->st_dev = 0;
1684   } else if (NT_ERROR(nt_status)) {
1685     SetLastError(pRtlNtStatusToDosError(nt_status));
1686     return -1;
1687   } else {
1688     statbuf->st_dev = volume_info.VolumeSerialNumber;
1689   }
1690 
1691   /* Todo: st_mode should probably always be 0666 for everyone. We might also
1692    * want to report 0777 if the file is a .exe or a directory.
1693    *
1694    * Currently it's based on whether the 'readonly' attribute is set, which
1695    * makes little sense because the semantics are so different: the 'read-only'
1696    * flag is just a way for a user to protect against accidental deletion, and
1697    * serves no security purpose. Windows uses ACLs for that.
1698    *
1699    * Also people now use uv_fs_chmod() to take away the writable bit for good
1700    * reasons. Windows however just makes the file read-only, which makes it
1701    * impossible to delete the file afterwards, since read-only files can't be
1702    * deleted.
1703    *
1704    * IOW it's all just a clusterfuck and we should think of something that
1705    * makes slightly more sense.
1706    *
1707    * And uv_fs_chmod should probably just fail on windows or be a total no-op.
1708    * There's nothing sensible it can do anyway.
1709    */
1710   statbuf->st_mode = 0;
1711 
1712   /*
1713   * On Windows, FILE_ATTRIBUTE_REPARSE_POINT is a general purpose mechanism
1714   * by which filesystem drivers can intercept and alter file system requests.
1715   *
1716   * The only reparse points we care about are symlinks and mount points, both
1717   * of which are treated as POSIX symlinks. Further, we only care when
1718   * invoked via lstat, which seeks information about the link instead of its
1719   * target. Otherwise, reparse points must be treated as regular files.
1720   */
1721   if (do_lstat &&
1722       (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
1723     /*
1724      * If reading the link fails, the reparse point is not a symlink and needs
1725      * to be treated as a regular file. The higher level lstat function will
1726      * detect this failure and retry without do_lstat if appropriate.
1727      */
1728     if (fs__readlink_handle(handle, NULL, &target_length) != 0)
1729       return -1;
1730     statbuf->st_mode |= S_IFLNK;
1731     statbuf->st_size = target_length;
1732   }
1733 
1734   if (statbuf->st_mode == 0) {
1735     if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1736       statbuf->st_mode |= _S_IFDIR;
1737       statbuf->st_size = 0;
1738     } else {
1739       statbuf->st_mode |= _S_IFREG;
1740       statbuf->st_size = file_info.StandardInformation.EndOfFile.QuadPart;
1741     }
1742   }
1743 
1744   if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_READONLY)
1745     statbuf->st_mode |= _S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6);
1746   else
1747     statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) |
1748                         ((_S_IREAD | _S_IWRITE) >> 6);
1749 
1750   uv__filetime_to_timespec(&statbuf->st_atim,
1751                            file_info.BasicInformation.LastAccessTime.QuadPart);
1752   uv__filetime_to_timespec(&statbuf->st_ctim,
1753                            file_info.BasicInformation.ChangeTime.QuadPart);
1754   uv__filetime_to_timespec(&statbuf->st_mtim,
1755                            file_info.BasicInformation.LastWriteTime.QuadPart);
1756   uv__filetime_to_timespec(&statbuf->st_birthtim,
1757                            file_info.BasicInformation.CreationTime.QuadPart);
1758 
1759   statbuf->st_ino = file_info.InternalInformation.IndexNumber.QuadPart;
1760 
1761   /* st_blocks contains the on-disk allocation size in 512-byte units. */
1762   statbuf->st_blocks =
1763       (uint64_t) file_info.StandardInformation.AllocationSize.QuadPart >> 9;
1764 
1765   statbuf->st_nlink = file_info.StandardInformation.NumberOfLinks;
1766 
1767   /* The st_blksize is supposed to be the 'optimal' number of bytes for reading
1768    * and writing to the disk. That is, for any definition of 'optimal' - it's
1769    * supposed to at least avoid read-update-write behavior when writing to the
1770    * disk.
1771    *
1772    * However nobody knows this and even fewer people actually use this value,
1773    * and in order to fill it out we'd have to make another syscall to query the
1774    * volume for FILE_FS_SECTOR_SIZE_INFORMATION.
1775    *
1776    * Therefore we'll just report a sensible value that's quite commonly okay
1777    * on modern hardware.
1778    *
1779    * 4096 is the minimum required to be compatible with newer Advanced Format
1780    * drives (which have 4096 bytes per physical sector), and to be backwards
1781    * compatible with older drives (which have 512 bytes per physical sector).
1782    */
1783   statbuf->st_blksize = 4096;
1784 
1785   /* Todo: set st_flags to something meaningful. Also provide a wrapper for
1786    * chattr(2).
1787    */
1788   statbuf->st_flags = 0;
1789 
1790   /* Windows has nothing sensible to say about these values, so they'll just
1791    * remain empty.
1792    */
1793   statbuf->st_gid = 0;
1794   statbuf->st_uid = 0;
1795   statbuf->st_rdev = 0;
1796   statbuf->st_gen = 0;
1797 
1798   return 0;
1799 }
1800 
1801 
fs__stat_prepare_path(WCHAR * pathw)1802 INLINE static void fs__stat_prepare_path(WCHAR* pathw) {
1803   size_t len = wcslen(pathw);
1804 
1805   /* TODO: ignore namespaced paths. */
1806   if (len > 1 && pathw[len - 2] != L':' &&
1807       (pathw[len - 1] == L'\\' || pathw[len - 1] == L'/')) {
1808     pathw[len - 1] = '\0';
1809   }
1810 }
1811 
1812 
fs__stat_impl_from_path(WCHAR * path,int do_lstat,uv_stat_t * statbuf)1813 INLINE static DWORD fs__stat_impl_from_path(WCHAR* path,
1814                                             int do_lstat,
1815                                             uv_stat_t* statbuf) {
1816   HANDLE handle;
1817   DWORD flags;
1818   DWORD ret;
1819 
1820   flags = FILE_FLAG_BACKUP_SEMANTICS;
1821   if (do_lstat)
1822     flags |= FILE_FLAG_OPEN_REPARSE_POINT;
1823 
1824   handle = CreateFileW(path,
1825                        FILE_READ_ATTRIBUTES,
1826                        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1827                        NULL,
1828                        OPEN_EXISTING,
1829                        flags,
1830                        NULL);
1831 
1832   if (handle == INVALID_HANDLE_VALUE)
1833     return GetLastError();
1834 
1835   if (fs__stat_handle(handle, statbuf, do_lstat) != 0)
1836     ret = GetLastError();
1837   else
1838     ret = 0;
1839 
1840   CloseHandle(handle);
1841   return ret;
1842 }
1843 
1844 
fs__stat_impl(uv_fs_t * req,int do_lstat)1845 INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) {
1846   DWORD error;
1847 
1848   error = fs__stat_impl_from_path(req->file.pathw, do_lstat, &req->statbuf);
1849   if (error != 0) {
1850     if (do_lstat &&
1851         (error == ERROR_SYMLINK_NOT_SUPPORTED ||
1852          error == ERROR_NOT_A_REPARSE_POINT)) {
1853       /* We opened a reparse point but it was not a symlink. Try again. */
1854       fs__stat_impl(req, 0);
1855     } else {
1856       /* Stat failed. */
1857       SET_REQ_WIN32_ERROR(req, error);
1858     }
1859 
1860     return;
1861   }
1862 
1863   req->ptr = &req->statbuf;
1864   SET_REQ_RESULT(req, 0);
1865 }
1866 
1867 
fs__fstat_handle(int fd,HANDLE handle,uv_stat_t * statbuf)1868 INLINE static int fs__fstat_handle(int fd, HANDLE handle, uv_stat_t* statbuf) {
1869   DWORD file_type;
1870 
1871   /* Each file type is processed differently. */
1872   file_type = uv_guess_handle(fd);
1873   switch (file_type) {
1874   /* Disk files use the existing logic from fs__stat_handle. */
1875   case UV_FILE:
1876     return fs__stat_handle(handle, statbuf, 0);
1877 
1878   /* Devices and pipes are processed identically. There is no more information
1879    * for them from any API. Fields are set as reasonably as possible and the
1880    * function returns. */
1881   case UV_TTY:
1882   case UV_NAMED_PIPE:
1883     memset(statbuf, 0, sizeof(uv_stat_t));
1884     statbuf->st_mode = file_type == UV_TTY ? _S_IFCHR : _S_IFIFO;
1885     statbuf->st_nlink = 1;
1886     statbuf->st_rdev = (file_type == UV_TTY ? FILE_DEVICE_CONSOLE : FILE_DEVICE_NAMED_PIPE) << 16;
1887     statbuf->st_ino = (uintptr_t) handle;
1888     return 0;
1889 
1890   /* If file type is unknown it is an error. */
1891   case UV_UNKNOWN_HANDLE:
1892   default:
1893     SetLastError(ERROR_INVALID_HANDLE);
1894     return -1;
1895   }
1896 }
1897 
1898 
fs__stat(uv_fs_t * req)1899 static void fs__stat(uv_fs_t* req) {
1900   fs__stat_prepare_path(req->file.pathw);
1901   fs__stat_impl(req, 0);
1902 }
1903 
1904 
fs__lstat(uv_fs_t * req)1905 static void fs__lstat(uv_fs_t* req) {
1906   fs__stat_prepare_path(req->file.pathw);
1907   fs__stat_impl(req, 1);
1908 }
1909 
1910 
fs__fstat(uv_fs_t * req)1911 static void fs__fstat(uv_fs_t* req) {
1912   int fd = req->file.fd;
1913   HANDLE handle;
1914 
1915   VERIFY_FD(fd, req);
1916 
1917   handle = uv__get_osfhandle(fd);
1918 
1919   if (handle == INVALID_HANDLE_VALUE) {
1920     SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
1921     return;
1922   }
1923 
1924   if (fs__fstat_handle(fd, handle, &req->statbuf) != 0) {
1925     SET_REQ_WIN32_ERROR(req, GetLastError());
1926     return;
1927   }
1928 
1929   req->ptr = &req->statbuf;
1930   SET_REQ_RESULT(req, 0);
1931 }
1932 
1933 
fs__rename(uv_fs_t * req)1934 static void fs__rename(uv_fs_t* req) {
1935   if (!MoveFileExW(req->file.pathw, req->fs.info.new_pathw, MOVEFILE_REPLACE_EXISTING)) {
1936     SET_REQ_WIN32_ERROR(req, GetLastError());
1937     return;
1938   }
1939 
1940   SET_REQ_RESULT(req, 0);
1941 }
1942 
1943 
fs__sync_impl(uv_fs_t * req)1944 INLINE static void fs__sync_impl(uv_fs_t* req) {
1945   int fd = req->file.fd;
1946   int result;
1947 
1948   VERIFY_FD(fd, req);
1949 
1950   result = FlushFileBuffers(uv__get_osfhandle(fd)) ? 0 : -1;
1951   if (result == -1) {
1952     SET_REQ_WIN32_ERROR(req, GetLastError());
1953   } else {
1954     SET_REQ_RESULT(req, result);
1955   }
1956 }
1957 
1958 
fs__fsync(uv_fs_t * req)1959 static void fs__fsync(uv_fs_t* req) {
1960   fs__sync_impl(req);
1961 }
1962 
1963 
fs__fdatasync(uv_fs_t * req)1964 static void fs__fdatasync(uv_fs_t* req) {
1965   fs__sync_impl(req);
1966 }
1967 
1968 
fs__ftruncate(uv_fs_t * req)1969 static void fs__ftruncate(uv_fs_t* req) {
1970   int fd = req->file.fd;
1971   HANDLE handle;
1972   struct uv__fd_info_s fd_info = { 0 };
1973   NTSTATUS status;
1974   IO_STATUS_BLOCK io_status;
1975   FILE_END_OF_FILE_INFORMATION eof_info;
1976 
1977   VERIFY_FD(fd, req);
1978 
1979   handle = uv__get_osfhandle(fd);
1980 
1981   if (uv__fd_hash_get(fd, &fd_info)) {
1982     if (fd_info.is_directory) {
1983       SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED);
1984       return;
1985     }
1986 
1987     if (fd_info.mapping != INVALID_HANDLE_VALUE) {
1988       CloseHandle(fd_info.mapping);
1989     }
1990   }
1991 
1992   eof_info.EndOfFile.QuadPart = req->fs.info.offset;
1993 
1994   status = pNtSetInformationFile(handle,
1995                                  &io_status,
1996                                  &eof_info,
1997                                  sizeof eof_info,
1998                                  FileEndOfFileInformation);
1999 
2000   if (NT_SUCCESS(status)) {
2001     SET_REQ_RESULT(req, 0);
2002   } else {
2003     SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
2004 
2005     if (fd_info.flags) {
2006       CloseHandle(handle);
2007       fd_info.mapping = INVALID_HANDLE_VALUE;
2008       fd_info.size.QuadPart = 0;
2009       fd_info.current_pos.QuadPart = 0;
2010       uv__fd_hash_add(fd, &fd_info);
2011       return;
2012     }
2013   }
2014 
2015   if (fd_info.flags) {
2016     fd_info.size = eof_info.EndOfFile;
2017 
2018     if (fd_info.size.QuadPart == 0) {
2019       fd_info.mapping = INVALID_HANDLE_VALUE;
2020     } else {
2021       DWORD flProtect = (fd_info.flags & (UV_FS_O_RDONLY | UV_FS_O_WRONLY |
2022         UV_FS_O_RDWR)) == UV_FS_O_RDONLY ? PAGE_READONLY : PAGE_READWRITE;
2023       fd_info.mapping = CreateFileMapping(handle,
2024                                           NULL,
2025                                           flProtect,
2026                                           fd_info.size.HighPart,
2027                                           fd_info.size.LowPart,
2028                                           NULL);
2029       if (fd_info.mapping == NULL) {
2030         SET_REQ_WIN32_ERROR(req, GetLastError());
2031         CloseHandle(handle);
2032         fd_info.mapping = INVALID_HANDLE_VALUE;
2033         fd_info.size.QuadPart = 0;
2034         fd_info.current_pos.QuadPart = 0;
2035         uv__fd_hash_add(fd, &fd_info);
2036         return;
2037       }
2038     }
2039 
2040     uv__fd_hash_add(fd, &fd_info);
2041   }
2042 }
2043 
2044 
fs__copyfile(uv_fs_t * req)2045 static void fs__copyfile(uv_fs_t* req) {
2046   int flags;
2047   int overwrite;
2048   uv_stat_t statbuf;
2049   uv_stat_t new_statbuf;
2050 
2051   flags = req->fs.info.file_flags;
2052 
2053   if (flags & UV_FS_COPYFILE_FICLONE_FORCE) {
2054     SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED);
2055     return;
2056   }
2057 
2058   overwrite = flags & UV_FS_COPYFILE_EXCL;
2059 
2060   if (CopyFileW(req->file.pathw, req->fs.info.new_pathw, overwrite) != 0) {
2061     SET_REQ_RESULT(req, 0);
2062     return;
2063   }
2064 
2065   SET_REQ_WIN32_ERROR(req, GetLastError());
2066   if (req->result != UV_EBUSY)
2067     return;
2068 
2069   /* if error UV_EBUSY check if src and dst file are the same */
2070   if (fs__stat_impl_from_path(req->file.pathw, 0, &statbuf) != 0 ||
2071       fs__stat_impl_from_path(req->fs.info.new_pathw, 0, &new_statbuf) != 0) {
2072     return;
2073   }
2074 
2075   if (statbuf.st_dev == new_statbuf.st_dev &&
2076       statbuf.st_ino == new_statbuf.st_ino) {
2077     SET_REQ_RESULT(req, 0);
2078   }
2079 }
2080 
2081 
fs__sendfile(uv_fs_t * req)2082 static void fs__sendfile(uv_fs_t* req) {
2083   int fd_in = req->file.fd, fd_out = req->fs.info.fd_out;
2084   size_t length = req->fs.info.bufsml[0].len;
2085   int64_t offset = req->fs.info.offset;
2086   const size_t max_buf_size = 65536;
2087   size_t buf_size = length < max_buf_size ? length : max_buf_size;
2088   int n, result = 0;
2089   int64_t result_offset = 0;
2090   char* buf = (char*) uv__malloc(buf_size);
2091   if (!buf) {
2092     uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
2093   }
2094 
2095   if (offset != -1) {
2096     result_offset = _lseeki64(fd_in, offset, SEEK_SET);
2097   }
2098 
2099   if (result_offset == -1) {
2100     result = -1;
2101   } else {
2102     while (length > 0) {
2103       n = _read(fd_in, buf, length < buf_size ? length : buf_size);
2104       if (n == 0) {
2105         break;
2106       } else if (n == -1) {
2107         result = -1;
2108         break;
2109       }
2110 
2111       length -= n;
2112 
2113       n = _write(fd_out, buf, n);
2114       if (n == -1) {
2115         result = -1;
2116         break;
2117       }
2118 
2119       result += n;
2120     }
2121   }
2122 
2123   uv__free(buf);
2124 
2125   SET_REQ_RESULT(req, result);
2126 }
2127 
2128 
fs__access(uv_fs_t * req)2129 static void fs__access(uv_fs_t* req) {
2130   DWORD attr = GetFileAttributesW(req->file.pathw);
2131 
2132   if (attr == INVALID_FILE_ATTRIBUTES) {
2133     SET_REQ_WIN32_ERROR(req, GetLastError());
2134     return;
2135   }
2136 
2137   /*
2138    * Access is possible if
2139    * - write access wasn't requested,
2140    * - or the file isn't read-only,
2141    * - or it's a directory.
2142    * (Directories cannot be read-only on Windows.)
2143    */
2144   if (!(req->fs.info.mode & W_OK) ||
2145       !(attr & FILE_ATTRIBUTE_READONLY) ||
2146       (attr & FILE_ATTRIBUTE_DIRECTORY)) {
2147     SET_REQ_RESULT(req, 0);
2148   } else {
2149     SET_REQ_WIN32_ERROR(req, UV_EPERM);
2150   }
2151 
2152 }
2153 
2154 
fs__chmod(uv_fs_t * req)2155 static void fs__chmod(uv_fs_t* req) {
2156   int result = _wchmod(req->file.pathw, req->fs.info.mode);
2157   if (result == -1)
2158     SET_REQ_WIN32_ERROR(req, _doserrno);
2159   else
2160     SET_REQ_RESULT(req, 0);
2161 }
2162 
2163 
fs__fchmod(uv_fs_t * req)2164 static void fs__fchmod(uv_fs_t* req) {
2165   int fd = req->file.fd;
2166   int clear_archive_flag;
2167   HANDLE handle;
2168   NTSTATUS nt_status;
2169   IO_STATUS_BLOCK io_status;
2170   FILE_BASIC_INFORMATION file_info;
2171 
2172   VERIFY_FD(fd, req);
2173 
2174   handle = ReOpenFile(uv__get_osfhandle(fd), FILE_WRITE_ATTRIBUTES, 0, 0);
2175   if (handle == INVALID_HANDLE_VALUE) {
2176     SET_REQ_WIN32_ERROR(req, GetLastError());
2177     return;
2178   }
2179 
2180   nt_status = pNtQueryInformationFile(handle,
2181                                       &io_status,
2182                                       &file_info,
2183                                       sizeof file_info,
2184                                       FileBasicInformation);
2185 
2186   if (!NT_SUCCESS(nt_status)) {
2187     SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
2188     goto fchmod_cleanup;
2189   }
2190 
2191   /* Test if the Archive attribute is cleared */
2192   if ((file_info.FileAttributes & FILE_ATTRIBUTE_ARCHIVE) == 0) {
2193       /* Set Archive flag, otherwise setting or clearing the read-only
2194          flag will not work */
2195       file_info.FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
2196       nt_status = pNtSetInformationFile(handle,
2197                                         &io_status,
2198                                         &file_info,
2199                                         sizeof file_info,
2200                                         FileBasicInformation);
2201       if (!NT_SUCCESS(nt_status)) {
2202         SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
2203         goto fchmod_cleanup;
2204       }
2205       /* Remember to clear the flag later on */
2206       clear_archive_flag = 1;
2207   } else {
2208       clear_archive_flag = 0;
2209   }
2210 
2211   if (req->fs.info.mode & _S_IWRITE) {
2212     file_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY;
2213   } else {
2214     file_info.FileAttributes |= FILE_ATTRIBUTE_READONLY;
2215   }
2216 
2217   nt_status = pNtSetInformationFile(handle,
2218                                     &io_status,
2219                                     &file_info,
2220                                     sizeof file_info,
2221                                     FileBasicInformation);
2222 
2223   if (!NT_SUCCESS(nt_status)) {
2224     SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
2225     goto fchmod_cleanup;
2226   }
2227 
2228   if (clear_archive_flag) {
2229       file_info.FileAttributes &= ~FILE_ATTRIBUTE_ARCHIVE;
2230       if (file_info.FileAttributes == 0) {
2231           file_info.FileAttributes = FILE_ATTRIBUTE_NORMAL;
2232       }
2233       nt_status = pNtSetInformationFile(handle,
2234                                         &io_status,
2235                                         &file_info,
2236                                         sizeof file_info,
2237                                         FileBasicInformation);
2238       if (!NT_SUCCESS(nt_status)) {
2239         SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
2240         goto fchmod_cleanup;
2241       }
2242   }
2243 
2244   SET_REQ_SUCCESS(req);
2245 fchmod_cleanup:
2246   CloseHandle(handle);
2247 }
2248 
2249 
fs__utime_handle(HANDLE handle,double atime,double mtime)2250 INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) {
2251   FILETIME filetime_a, filetime_m;
2252 
2253   TIME_T_TO_FILETIME(atime, &filetime_a);
2254   TIME_T_TO_FILETIME(mtime, &filetime_m);
2255 
2256   if (!SetFileTime(handle, NULL, &filetime_a, &filetime_m)) {
2257     return -1;
2258   }
2259 
2260   return 0;
2261 }
2262 
fs__utime_impl_from_path(WCHAR * path,double atime,double mtime,int do_lutime)2263 INLINE static DWORD fs__utime_impl_from_path(WCHAR* path,
2264                                              double atime,
2265                                              double mtime,
2266                                              int do_lutime) {
2267   HANDLE handle;
2268   DWORD flags;
2269   DWORD ret;
2270 
2271   flags = FILE_FLAG_BACKUP_SEMANTICS;
2272   if (do_lutime) {
2273     flags |= FILE_FLAG_OPEN_REPARSE_POINT;
2274   }
2275 
2276   handle = CreateFileW(path,
2277                        FILE_WRITE_ATTRIBUTES,
2278                        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2279                        NULL,
2280                        OPEN_EXISTING,
2281                        flags,
2282                        NULL);
2283 
2284   if (handle == INVALID_HANDLE_VALUE)
2285     return GetLastError();
2286 
2287   if (fs__utime_handle(handle, atime, mtime) != 0)
2288     ret = GetLastError();
2289   else
2290     ret = 0;
2291 
2292   CloseHandle(handle);
2293   return ret;
2294 }
2295 
fs__utime_impl(uv_fs_t * req,int do_lutime)2296 INLINE static void fs__utime_impl(uv_fs_t* req, int do_lutime) {
2297   DWORD error;
2298 
2299   error = fs__utime_impl_from_path(req->file.pathw,
2300                                    req->fs.time.atime,
2301                                    req->fs.time.mtime,
2302                                    do_lutime);
2303 
2304   if (error != 0) {
2305     if (do_lutime &&
2306         (error == ERROR_SYMLINK_NOT_SUPPORTED ||
2307          error == ERROR_NOT_A_REPARSE_POINT)) {
2308       /* Opened file is a reparse point but not a symlink. Try again. */
2309       fs__utime_impl(req, 0);
2310     } else {
2311       /* utime failed. */
2312       SET_REQ_WIN32_ERROR(req, error);
2313     }
2314 
2315     return;
2316   }
2317 
2318   SET_REQ_RESULT(req, 0);
2319 }
2320 
fs__utime(uv_fs_t * req)2321 static void fs__utime(uv_fs_t* req) {
2322   fs__utime_impl(req, /* do_lutime */ 0);
2323 }
2324 
2325 
fs__futime(uv_fs_t * req)2326 static void fs__futime(uv_fs_t* req) {
2327   int fd = req->file.fd;
2328   HANDLE handle;
2329   VERIFY_FD(fd, req);
2330 
2331   handle = uv__get_osfhandle(fd);
2332 
2333   if (handle == INVALID_HANDLE_VALUE) {
2334     SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
2335     return;
2336   }
2337 
2338   if (fs__utime_handle(handle, req->fs.time.atime, req->fs.time.mtime) != 0) {
2339     SET_REQ_WIN32_ERROR(req, GetLastError());
2340     return;
2341   }
2342 
2343   SET_REQ_RESULT(req, 0);
2344 }
2345 
fs__lutime(uv_fs_t * req)2346 static void fs__lutime(uv_fs_t* req) {
2347   fs__utime_impl(req, /* do_lutime */ 1);
2348 }
2349 
2350 
fs__link(uv_fs_t * req)2351 static void fs__link(uv_fs_t* req) {
2352   DWORD r = CreateHardLinkW(req->fs.info.new_pathw, req->file.pathw, NULL);
2353   if (r == 0)
2354     SET_REQ_WIN32_ERROR(req, GetLastError());
2355   else
2356     SET_REQ_RESULT(req, 0);
2357 }
2358 
2359 
fs__create_junction(uv_fs_t * req,const WCHAR * path,const WCHAR * new_path)2360 static void fs__create_junction(uv_fs_t* req, const WCHAR* path,
2361     const WCHAR* new_path) {
2362   HANDLE handle = INVALID_HANDLE_VALUE;
2363   REPARSE_DATA_BUFFER *buffer = NULL;
2364   int created = 0;
2365   int target_len;
2366   int is_absolute, is_long_path;
2367   int needed_buf_size, used_buf_size, used_data_size, path_buf_len;
2368   int start, len, i;
2369   int add_slash;
2370   DWORD bytes;
2371   WCHAR* path_buf;
2372 
2373   target_len = wcslen(path);
2374   is_long_path = wcsncmp(path, LONG_PATH_PREFIX, LONG_PATH_PREFIX_LEN) == 0;
2375 
2376   if (is_long_path) {
2377     is_absolute = 1;
2378   } else {
2379     is_absolute = target_len >= 3 && IS_LETTER(path[0]) &&
2380       path[1] == L':' && IS_SLASH(path[2]);
2381   }
2382 
2383   if (!is_absolute) {
2384     /* Not supporting relative paths */
2385     SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_NOT_SUPPORTED);
2386     return;
2387   }
2388 
2389   /* Do a pessimistic calculation of the required buffer size */
2390   needed_buf_size =
2391       FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) +
2392       JUNCTION_PREFIX_LEN * sizeof(WCHAR) +
2393       2 * (target_len + 2) * sizeof(WCHAR);
2394 
2395   /* Allocate the buffer */
2396   buffer = (REPARSE_DATA_BUFFER*)uv__malloc(needed_buf_size);
2397   if (!buffer) {
2398     uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
2399   }
2400 
2401   /* Grab a pointer to the part of the buffer where filenames go */
2402   path_buf = (WCHAR*)&(buffer->MountPointReparseBuffer.PathBuffer);
2403   path_buf_len = 0;
2404 
2405   /* Copy the substitute (internal) target path */
2406   start = path_buf_len;
2407 
2408   wcsncpy((WCHAR*)&path_buf[path_buf_len], JUNCTION_PREFIX,
2409     JUNCTION_PREFIX_LEN);
2410   path_buf_len += JUNCTION_PREFIX_LEN;
2411 
2412   add_slash = 0;
2413   for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) {
2414     if (IS_SLASH(path[i])) {
2415       add_slash = 1;
2416       continue;
2417     }
2418 
2419     if (add_slash) {
2420       path_buf[path_buf_len++] = L'\\';
2421       add_slash = 0;
2422     }
2423 
2424     path_buf[path_buf_len++] = path[i];
2425   }
2426   path_buf[path_buf_len++] = L'\\';
2427   len = path_buf_len - start;
2428 
2429   /* Set the info about the substitute name */
2430   buffer->MountPointReparseBuffer.SubstituteNameOffset = start * sizeof(WCHAR);
2431   buffer->MountPointReparseBuffer.SubstituteNameLength = len * sizeof(WCHAR);
2432 
2433   /* Insert null terminator */
2434   path_buf[path_buf_len++] = L'\0';
2435 
2436   /* Copy the print name of the target path */
2437   start = path_buf_len;
2438   add_slash = 0;
2439   for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) {
2440     if (IS_SLASH(path[i])) {
2441       add_slash = 1;
2442       continue;
2443     }
2444 
2445     if (add_slash) {
2446       path_buf[path_buf_len++] = L'\\';
2447       add_slash = 0;
2448     }
2449 
2450     path_buf[path_buf_len++] = path[i];
2451   }
2452   len = path_buf_len - start;
2453   if (len == 2) {
2454     path_buf[path_buf_len++] = L'\\';
2455     len++;
2456   }
2457 
2458   /* Set the info about the print name */
2459   buffer->MountPointReparseBuffer.PrintNameOffset = start * sizeof(WCHAR);
2460   buffer->MountPointReparseBuffer.PrintNameLength = len * sizeof(WCHAR);
2461 
2462   /* Insert another null terminator */
2463   path_buf[path_buf_len++] = L'\0';
2464 
2465   /* Calculate how much buffer space was actually used */
2466   used_buf_size = FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) +
2467     path_buf_len * sizeof(WCHAR);
2468   used_data_size = used_buf_size -
2469     FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer);
2470 
2471   /* Put general info in the data buffer */
2472   buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
2473   buffer->ReparseDataLength = used_data_size;
2474   buffer->Reserved = 0;
2475 
2476   /* Create a new directory */
2477   if (!CreateDirectoryW(new_path, NULL)) {
2478     SET_REQ_WIN32_ERROR(req, GetLastError());
2479     goto error;
2480   }
2481   created = 1;
2482 
2483   /* Open the directory */
2484   handle = CreateFileW(new_path,
2485                        GENERIC_WRITE,
2486                        0,
2487                        NULL,
2488                        OPEN_EXISTING,
2489                        FILE_FLAG_BACKUP_SEMANTICS |
2490                          FILE_FLAG_OPEN_REPARSE_POINT,
2491                        NULL);
2492   if (handle == INVALID_HANDLE_VALUE) {
2493     SET_REQ_WIN32_ERROR(req, GetLastError());
2494     goto error;
2495   }
2496 
2497   /* Create the actual reparse point */
2498   if (!DeviceIoControl(handle,
2499                        FSCTL_SET_REPARSE_POINT,
2500                        buffer,
2501                        used_buf_size,
2502                        NULL,
2503                        0,
2504                        &bytes,
2505                        NULL)) {
2506     SET_REQ_WIN32_ERROR(req, GetLastError());
2507     goto error;
2508   }
2509 
2510   /* Clean up */
2511   CloseHandle(handle);
2512   uv__free(buffer);
2513 
2514   SET_REQ_RESULT(req, 0);
2515   return;
2516 
2517 error:
2518   uv__free(buffer);
2519 
2520   if (handle != INVALID_HANDLE_VALUE) {
2521     CloseHandle(handle);
2522   }
2523 
2524   if (created) {
2525     RemoveDirectoryW(new_path);
2526   }
2527 }
2528 
2529 
fs__symlink(uv_fs_t * req)2530 static void fs__symlink(uv_fs_t* req) {
2531   WCHAR* pathw;
2532   WCHAR* new_pathw;
2533   int flags;
2534   int err;
2535 
2536   pathw = req->file.pathw;
2537   new_pathw = req->fs.info.new_pathw;
2538 
2539   if (req->fs.info.file_flags & UV_FS_SYMLINK_JUNCTION) {
2540     fs__create_junction(req, pathw, new_pathw);
2541     return;
2542   }
2543 
2544   if (req->fs.info.file_flags & UV_FS_SYMLINK_DIR)
2545     flags = SYMBOLIC_LINK_FLAG_DIRECTORY | uv__file_symlink_usermode_flag;
2546   else
2547     flags = uv__file_symlink_usermode_flag;
2548 
2549   if (CreateSymbolicLinkW(new_pathw, pathw, flags)) {
2550     SET_REQ_RESULT(req, 0);
2551     return;
2552   }
2553 
2554   /* Something went wrong. We will test if it is because of user-mode
2555    * symlinks.
2556    */
2557   err = GetLastError();
2558   if (err == ERROR_INVALID_PARAMETER &&
2559       flags & SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) {
2560     /* This system does not support user-mode symlinks. We will clear the
2561      * unsupported flag and retry.
2562      */
2563     uv__file_symlink_usermode_flag = 0;
2564     fs__symlink(req);
2565   } else {
2566     SET_REQ_WIN32_ERROR(req, err);
2567   }
2568 }
2569 
2570 
fs__readlink(uv_fs_t * req)2571 static void fs__readlink(uv_fs_t* req) {
2572   HANDLE handle;
2573 
2574   handle = CreateFileW(req->file.pathw,
2575                        0,
2576                        0,
2577                        NULL,
2578                        OPEN_EXISTING,
2579                        FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
2580                        NULL);
2581 
2582   if (handle == INVALID_HANDLE_VALUE) {
2583     SET_REQ_WIN32_ERROR(req, GetLastError());
2584     return;
2585   }
2586 
2587   assert(req->ptr == NULL);
2588   if (fs__readlink_handle(handle, (char**) &req->ptr, NULL) != 0) {
2589     DWORD error = GetLastError();
2590     SET_REQ_WIN32_ERROR(req, error);
2591     if (error == ERROR_NOT_A_REPARSE_POINT)
2592       req->result = UV_EINVAL;
2593     CloseHandle(handle);
2594     return;
2595   }
2596 
2597   req->flags |= UV_FS_FREE_PTR;
2598   SET_REQ_RESULT(req, 0);
2599 
2600   CloseHandle(handle);
2601 }
2602 
2603 
fs__realpath_handle(HANDLE handle,char ** realpath_ptr)2604 static ssize_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) {
2605   int r;
2606   DWORD w_realpath_len;
2607   WCHAR* w_realpath_ptr = NULL;
2608   WCHAR* w_realpath_buf;
2609 
2610   w_realpath_len = GetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS);
2611   if (w_realpath_len == 0) {
2612     return -1;
2613   }
2614 
2615   w_realpath_buf = uv__malloc((w_realpath_len + 1) * sizeof(WCHAR));
2616   if (w_realpath_buf == NULL) {
2617     SetLastError(ERROR_OUTOFMEMORY);
2618     return -1;
2619   }
2620   w_realpath_ptr = w_realpath_buf;
2621 
2622   if (GetFinalPathNameByHandleW(
2623           handle, w_realpath_ptr, w_realpath_len, VOLUME_NAME_DOS) == 0) {
2624     uv__free(w_realpath_buf);
2625     SetLastError(ERROR_INVALID_HANDLE);
2626     return -1;
2627   }
2628 
2629   /* convert UNC path to long path */
2630   if (wcsncmp(w_realpath_ptr,
2631               UNC_PATH_PREFIX,
2632               UNC_PATH_PREFIX_LEN) == 0) {
2633     w_realpath_ptr += 6;
2634     *w_realpath_ptr = L'\\';
2635     w_realpath_len -= 6;
2636   } else if (wcsncmp(w_realpath_ptr,
2637                       LONG_PATH_PREFIX,
2638                       LONG_PATH_PREFIX_LEN) == 0) {
2639     w_realpath_ptr += 4;
2640     w_realpath_len -= 4;
2641   } else {
2642     uv__free(w_realpath_buf);
2643     SetLastError(ERROR_INVALID_HANDLE);
2644     return -1;
2645   }
2646 
2647   assert(*realpath_ptr == NULL);
2648   r = uv_utf16_to_wtf8(w_realpath_ptr, w_realpath_len, realpath_ptr, NULL);
2649   uv__free(w_realpath_buf);
2650   return r;
2651 }
2652 
fs__realpath(uv_fs_t * req)2653 static void fs__realpath(uv_fs_t* req) {
2654   HANDLE handle;
2655 
2656   handle = CreateFileW(req->file.pathw,
2657                        0,
2658                        0,
2659                        NULL,
2660                        OPEN_EXISTING,
2661                        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS,
2662                        NULL);
2663   if (handle == INVALID_HANDLE_VALUE) {
2664     SET_REQ_WIN32_ERROR(req, GetLastError());
2665     return;
2666   }
2667 
2668   assert(req->ptr == NULL);
2669   if (fs__realpath_handle(handle, (char**) &req->ptr) == -1) {
2670     CloseHandle(handle);
2671     SET_REQ_WIN32_ERROR(req, GetLastError());
2672     return;
2673   }
2674 
2675   CloseHandle(handle);
2676   req->flags |= UV_FS_FREE_PTR;
2677   SET_REQ_RESULT(req, 0);
2678 }
2679 
2680 
fs__chown(uv_fs_t * req)2681 static void fs__chown(uv_fs_t* req) {
2682   SET_REQ_RESULT(req, 0);
2683 }
2684 
2685 
fs__fchown(uv_fs_t * req)2686 static void fs__fchown(uv_fs_t* req) {
2687   SET_REQ_RESULT(req, 0);
2688 }
2689 
2690 
fs__lchown(uv_fs_t * req)2691 static void fs__lchown(uv_fs_t* req) {
2692   SET_REQ_RESULT(req, 0);
2693 }
2694 
2695 
fs__statfs(uv_fs_t * req)2696 static void fs__statfs(uv_fs_t* req) {
2697   uv_statfs_t* stat_fs;
2698   DWORD sectors_per_cluster;
2699   DWORD bytes_per_sector;
2700   DWORD free_clusters;
2701   DWORD total_clusters;
2702   WCHAR* pathw;
2703 
2704   pathw = req->file.pathw;
2705 retry_get_disk_free_space:
2706   if (0 == GetDiskFreeSpaceW(pathw,
2707                              &sectors_per_cluster,
2708                              &bytes_per_sector,
2709                              &free_clusters,
2710                              &total_clusters)) {
2711     DWORD err;
2712     WCHAR* fpart;
2713     size_t len;
2714     DWORD ret;
2715     BOOL is_second;
2716 
2717     err = GetLastError();
2718     is_second = pathw != req->file.pathw;
2719     if (err != ERROR_DIRECTORY || is_second) {
2720       if (is_second)
2721         uv__free(pathw);
2722 
2723       SET_REQ_WIN32_ERROR(req, err);
2724       return;
2725     }
2726 
2727     len = MAX_PATH + 1;
2728     pathw = uv__malloc(len * sizeof(*pathw));
2729     if (pathw == NULL) {
2730       SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
2731       return;
2732     }
2733 retry_get_full_path_name:
2734     ret = GetFullPathNameW(req->file.pathw,
2735                            len,
2736                            pathw,
2737                            &fpart);
2738     if (ret == 0) {
2739       uv__free(pathw);
2740       SET_REQ_WIN32_ERROR(req, err);
2741       return;
2742     } else if (ret > len) {
2743       len = ret;
2744       pathw = uv__reallocf(pathw, len * sizeof(*pathw));
2745       if (pathw == NULL) {
2746         SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
2747         return;
2748       }
2749       goto retry_get_full_path_name;
2750     }
2751     if (fpart != 0)
2752       *fpart = L'\0';
2753 
2754     goto retry_get_disk_free_space;
2755   }
2756   if (pathw != req->file.pathw) {
2757     uv__free(pathw);
2758   }
2759 
2760   stat_fs = uv__malloc(sizeof(*stat_fs));
2761   if (stat_fs == NULL) {
2762     SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
2763     return;
2764   }
2765 
2766   stat_fs->f_type = 0;
2767   stat_fs->f_bsize = bytes_per_sector * sectors_per_cluster;
2768   stat_fs->f_blocks = total_clusters;
2769   stat_fs->f_bfree = free_clusters;
2770   stat_fs->f_bavail = free_clusters;
2771   stat_fs->f_files = 0;
2772   stat_fs->f_ffree = 0;
2773   req->ptr = stat_fs;
2774   req->flags |= UV_FS_FREE_PTR;
2775   SET_REQ_RESULT(req, 0);
2776 }
2777 
2778 
uv__fs_work(struct uv__work * w)2779 static void uv__fs_work(struct uv__work* w) {
2780   uv_fs_t* req;
2781 
2782   req = container_of(w, uv_fs_t, work_req);
2783   assert(req->type == UV_FS);
2784 
2785 #define XX(uc, lc)  case UV_FS_##uc: fs__##lc(req); break;
2786   switch (req->fs_type) {
2787     XX(OPEN, open)
2788     XX(CLOSE, close)
2789     XX(READ, read)
2790     XX(WRITE, write)
2791     XX(COPYFILE, copyfile)
2792     XX(SENDFILE, sendfile)
2793     XX(STAT, stat)
2794     XX(LSTAT, lstat)
2795     XX(FSTAT, fstat)
2796     XX(FTRUNCATE, ftruncate)
2797     XX(UTIME, utime)
2798     XX(FUTIME, futime)
2799     XX(LUTIME, lutime)
2800     XX(ACCESS, access)
2801     XX(CHMOD, chmod)
2802     XX(FCHMOD, fchmod)
2803     XX(FSYNC, fsync)
2804     XX(FDATASYNC, fdatasync)
2805     XX(UNLINK, unlink)
2806     XX(RMDIR, rmdir)
2807     XX(MKDIR, mkdir)
2808     XX(MKDTEMP, mkdtemp)
2809     XX(MKSTEMP, mkstemp)
2810     XX(RENAME, rename)
2811     XX(SCANDIR, scandir)
2812     XX(READDIR, readdir)
2813     XX(OPENDIR, opendir)
2814     XX(CLOSEDIR, closedir)
2815     XX(LINK, link)
2816     XX(SYMLINK, symlink)
2817     XX(READLINK, readlink)
2818     XX(REALPATH, realpath)
2819     XX(CHOWN, chown)
2820     XX(FCHOWN, fchown)
2821     XX(LCHOWN, lchown)
2822     XX(STATFS, statfs)
2823     default:
2824       assert(!"bad uv_fs_type");
2825   }
2826 }
2827 
2828 
uv__fs_done(struct uv__work * w,int status)2829 static void uv__fs_done(struct uv__work* w, int status) {
2830   uv_fs_t* req;
2831 
2832   req = container_of(w, uv_fs_t, work_req);
2833   uv__req_unregister(req->loop, req);
2834 
2835   if (status == UV_ECANCELED) {
2836     assert(req->result == 0);
2837     SET_REQ_UV_ERROR(req, UV_ECANCELED, 0);
2838   }
2839 
2840   req->cb(req);
2841 }
2842 
2843 
uv_fs_req_cleanup(uv_fs_t * req)2844 void uv_fs_req_cleanup(uv_fs_t* req) {
2845   if (req == NULL)
2846     return;
2847 
2848   if (req->flags & UV_FS_CLEANEDUP)
2849     return;
2850 
2851   if (req->flags & UV_FS_FREE_PATHS)
2852     uv__free(req->file.pathw);
2853 
2854   if (req->flags & UV_FS_FREE_PTR) {
2855     if (req->fs_type == UV_FS_SCANDIR && req->ptr != NULL)
2856       uv__fs_scandir_cleanup(req);
2857     else if (req->fs_type == UV_FS_READDIR)
2858       uv__fs_readdir_cleanup(req);
2859     else
2860       uv__free(req->ptr);
2861   }
2862 
2863   if (req->fs.info.bufs != req->fs.info.bufsml)
2864     uv__free(req->fs.info.bufs);
2865 
2866   req->path = NULL;
2867   req->file.pathw = NULL;
2868   req->fs.info.new_pathw = NULL;
2869   req->fs.info.bufs = NULL;
2870   req->ptr = NULL;
2871 
2872   req->flags |= UV_FS_CLEANEDUP;
2873 }
2874 
2875 
uv_fs_open(uv_loop_t * loop,uv_fs_t * req,const char * path,int flags,int mode,uv_fs_cb cb)2876 int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
2877     int mode, uv_fs_cb cb) {
2878   int err;
2879 
2880   INIT(UV_FS_OPEN);
2881   err = fs__capture_path(req, path, NULL, cb != NULL);
2882   if (err) {
2883     SET_REQ_WIN32_ERROR(req, err);
2884     return req->result;
2885   }
2886 
2887   req->fs.info.file_flags = flags;
2888   req->fs.info.mode = mode;
2889   POST;
2890 }
2891 
2892 
uv_fs_close(uv_loop_t * loop,uv_fs_t * req,uv_file fd,uv_fs_cb cb)2893 int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
2894   INIT(UV_FS_CLOSE);
2895   req->file.fd = fd;
2896   POST;
2897 }
2898 
2899 
uv_fs_read(uv_loop_t * loop,uv_fs_t * req,uv_file fd,const uv_buf_t bufs[],unsigned int nbufs,int64_t offset,uv_fs_cb cb)2900 int uv_fs_read(uv_loop_t* loop,
2901                uv_fs_t* req,
2902                uv_file fd,
2903                const uv_buf_t bufs[],
2904                unsigned int nbufs,
2905                int64_t offset,
2906                uv_fs_cb cb) {
2907   INIT(UV_FS_READ);
2908 
2909   if (bufs == NULL || nbufs == 0) {
2910     SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
2911     return UV_EINVAL;
2912   }
2913 
2914   req->file.fd = fd;
2915 
2916   req->fs.info.nbufs = nbufs;
2917   req->fs.info.bufs = req->fs.info.bufsml;
2918   if (nbufs > ARRAY_SIZE(req->fs.info.bufsml))
2919     req->fs.info.bufs = uv__malloc(nbufs * sizeof(*bufs));
2920 
2921   if (req->fs.info.bufs == NULL) {
2922     SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
2923     return UV_ENOMEM;
2924   }
2925 
2926   memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs));
2927 
2928   req->fs.info.offset = offset;
2929   POST;
2930 }
2931 
2932 
uv_fs_write(uv_loop_t * loop,uv_fs_t * req,uv_file fd,const uv_buf_t bufs[],unsigned int nbufs,int64_t offset,uv_fs_cb cb)2933 int uv_fs_write(uv_loop_t* loop,
2934                 uv_fs_t* req,
2935                 uv_file fd,
2936                 const uv_buf_t bufs[],
2937                 unsigned int nbufs,
2938                 int64_t offset,
2939                 uv_fs_cb cb) {
2940   INIT(UV_FS_WRITE);
2941 
2942   if (bufs == NULL || nbufs == 0) {
2943     SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
2944     return UV_EINVAL;
2945   }
2946 
2947   req->file.fd = fd;
2948 
2949   req->fs.info.nbufs = nbufs;
2950   req->fs.info.bufs = req->fs.info.bufsml;
2951   if (nbufs > ARRAY_SIZE(req->fs.info.bufsml))
2952     req->fs.info.bufs = uv__malloc(nbufs * sizeof(*bufs));
2953 
2954   if (req->fs.info.bufs == NULL) {
2955     SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
2956     return UV_ENOMEM;
2957   }
2958 
2959   memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs));
2960 
2961   req->fs.info.offset = offset;
2962   POST;
2963 }
2964 
2965 
uv_fs_unlink(uv_loop_t * loop,uv_fs_t * req,const char * path,uv_fs_cb cb)2966 int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
2967     uv_fs_cb cb) {
2968   int err;
2969 
2970   INIT(UV_FS_UNLINK);
2971   err = fs__capture_path(req, path, NULL, cb != NULL);
2972   if (err) {
2973     SET_REQ_WIN32_ERROR(req, err);
2974     return req->result;
2975   }
2976 
2977   POST;
2978 }
2979 
2980 
uv_fs_mkdir(uv_loop_t * loop,uv_fs_t * req,const char * path,int mode,uv_fs_cb cb)2981 int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
2982     uv_fs_cb cb) {
2983   int err;
2984 
2985   INIT(UV_FS_MKDIR);
2986   err = fs__capture_path(req, path, NULL, cb != NULL);
2987   if (err) {
2988     SET_REQ_WIN32_ERROR(req, err);
2989     return req->result;
2990   }
2991 
2992   req->fs.info.mode = mode;
2993   POST;
2994 }
2995 
2996 
uv_fs_mkdtemp(uv_loop_t * loop,uv_fs_t * req,const char * tpl,uv_fs_cb cb)2997 int uv_fs_mkdtemp(uv_loop_t* loop,
2998                   uv_fs_t* req,
2999                   const char* tpl,
3000                   uv_fs_cb cb) {
3001   int err;
3002 
3003   INIT(UV_FS_MKDTEMP);
3004   err = fs__capture_path(req, tpl, NULL, TRUE);
3005   if (err) {
3006     SET_REQ_WIN32_ERROR(req, err);
3007     return req->result;
3008   }
3009 
3010   POST;
3011 }
3012 
3013 
uv_fs_mkstemp(uv_loop_t * loop,uv_fs_t * req,const char * tpl,uv_fs_cb cb)3014 int uv_fs_mkstemp(uv_loop_t* loop,
3015                   uv_fs_t* req,
3016                   const char* tpl,
3017                   uv_fs_cb cb) {
3018   int err;
3019 
3020   INIT(UV_FS_MKSTEMP);
3021   err = fs__capture_path(req, tpl, NULL, TRUE);
3022   if (err) {
3023     SET_REQ_WIN32_ERROR(req, err);
3024     return req->result;
3025   }
3026 
3027   POST;
3028 }
3029 
3030 
uv_fs_rmdir(uv_loop_t * loop,uv_fs_t * req,const char * path,uv_fs_cb cb)3031 int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
3032   int err;
3033 
3034   INIT(UV_FS_RMDIR);
3035   err = fs__capture_path(req, path, NULL, cb != NULL);
3036   if (err) {
3037     SET_REQ_WIN32_ERROR(req, err);
3038     return req->result;
3039   }
3040 
3041   POST;
3042 }
3043 
3044 
uv_fs_scandir(uv_loop_t * loop,uv_fs_t * req,const char * path,int flags,uv_fs_cb cb)3045 int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
3046     uv_fs_cb cb) {
3047   int err;
3048 
3049   INIT(UV_FS_SCANDIR);
3050   err = fs__capture_path(req, path, NULL, cb != NULL);
3051   if (err) {
3052     SET_REQ_WIN32_ERROR(req, err);
3053     return req->result;
3054   }
3055 
3056   req->fs.info.file_flags = flags;
3057   POST;
3058 }
3059 
uv_fs_opendir(uv_loop_t * loop,uv_fs_t * req,const char * path,uv_fs_cb cb)3060 int uv_fs_opendir(uv_loop_t* loop,
3061                   uv_fs_t* req,
3062                   const char* path,
3063                   uv_fs_cb cb) {
3064   int err;
3065 
3066   INIT(UV_FS_OPENDIR);
3067   err = fs__capture_path(req, path, NULL, cb != NULL);
3068   if (err) {
3069     SET_REQ_WIN32_ERROR(req, err);
3070     return req->result;
3071   }
3072   POST;
3073 }
3074 
uv_fs_readdir(uv_loop_t * loop,uv_fs_t * req,uv_dir_t * dir,uv_fs_cb cb)3075 int uv_fs_readdir(uv_loop_t* loop,
3076                   uv_fs_t* req,
3077                   uv_dir_t* dir,
3078                   uv_fs_cb cb) {
3079   INIT(UV_FS_READDIR);
3080 
3081   if (dir == NULL ||
3082       dir->dirents == NULL ||
3083       dir->dir_handle == INVALID_HANDLE_VALUE) {
3084     SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
3085     return UV_EINVAL;
3086   }
3087 
3088   req->ptr = dir;
3089   POST;
3090 }
3091 
uv_fs_closedir(uv_loop_t * loop,uv_fs_t * req,uv_dir_t * dir,uv_fs_cb cb)3092 int uv_fs_closedir(uv_loop_t* loop,
3093                    uv_fs_t* req,
3094                    uv_dir_t* dir,
3095                    uv_fs_cb cb) {
3096   INIT(UV_FS_CLOSEDIR);
3097   if (dir == NULL) {
3098     SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
3099     return UV_EINVAL;
3100   }
3101   req->ptr = dir;
3102   POST;
3103 }
3104 
uv_fs_link(uv_loop_t * loop,uv_fs_t * req,const char * path,const char * new_path,uv_fs_cb cb)3105 int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path,
3106     const char* new_path, uv_fs_cb cb) {
3107   int err;
3108 
3109   INIT(UV_FS_LINK);
3110   err = fs__capture_path(req, path, new_path, cb != NULL);
3111   if (err) {
3112     SET_REQ_WIN32_ERROR(req, err);
3113     return req->result;
3114   }
3115 
3116   POST;
3117 }
3118 
3119 
uv_fs_symlink(uv_loop_t * loop,uv_fs_t * req,const char * path,const char * new_path,int flags,uv_fs_cb cb)3120 int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
3121     const char* new_path, int flags, uv_fs_cb cb) {
3122   int err;
3123 
3124   INIT(UV_FS_SYMLINK);
3125   err = fs__capture_path(req, path, new_path, cb != NULL);
3126   if (err) {
3127     SET_REQ_WIN32_ERROR(req, err);
3128     return req->result;
3129   }
3130 
3131   req->fs.info.file_flags = flags;
3132   POST;
3133 }
3134 
3135 
uv_fs_readlink(uv_loop_t * loop,uv_fs_t * req,const char * path,uv_fs_cb cb)3136 int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
3137     uv_fs_cb cb) {
3138   int err;
3139 
3140   INIT(UV_FS_READLINK);
3141   err = fs__capture_path(req, path, NULL, cb != NULL);
3142   if (err) {
3143     SET_REQ_WIN32_ERROR(req, err);
3144     return req->result;
3145   }
3146 
3147   POST;
3148 }
3149 
3150 
uv_fs_realpath(uv_loop_t * loop,uv_fs_t * req,const char * path,uv_fs_cb cb)3151 int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path,
3152     uv_fs_cb cb) {
3153   int err;
3154 
3155   INIT(UV_FS_REALPATH);
3156 
3157   if (!path) {
3158     SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
3159     return UV_EINVAL;
3160   }
3161 
3162   err = fs__capture_path(req, path, NULL, cb != NULL);
3163   if (err) {
3164     SET_REQ_WIN32_ERROR(req, err);
3165     return req->result;
3166   }
3167 
3168   POST;
3169 }
3170 
3171 
uv_fs_chown(uv_loop_t * loop,uv_fs_t * req,const char * path,uv_uid_t uid,uv_gid_t gid,uv_fs_cb cb)3172 int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid,
3173     uv_gid_t gid, uv_fs_cb cb) {
3174   int err;
3175 
3176   INIT(UV_FS_CHOWN);
3177   err = fs__capture_path(req, path, NULL, cb != NULL);
3178   if (err) {
3179     SET_REQ_WIN32_ERROR(req, err);
3180     return req->result;
3181   }
3182 
3183   POST;
3184 }
3185 
3186 
uv_fs_fchown(uv_loop_t * loop,uv_fs_t * req,uv_file fd,uv_uid_t uid,uv_gid_t gid,uv_fs_cb cb)3187 int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_uid_t uid,
3188     uv_gid_t gid, uv_fs_cb cb) {
3189   INIT(UV_FS_FCHOWN);
3190   POST;
3191 }
3192 
3193 
uv_fs_lchown(uv_loop_t * loop,uv_fs_t * req,const char * path,uv_uid_t uid,uv_gid_t gid,uv_fs_cb cb)3194 int uv_fs_lchown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid,
3195     uv_gid_t gid, uv_fs_cb cb) {
3196   int err;
3197 
3198   INIT(UV_FS_LCHOWN);
3199   err = fs__capture_path(req, path, NULL, cb != NULL);
3200   if (err) {
3201     SET_REQ_WIN32_ERROR(req, err);
3202     return req->result;
3203   }
3204 
3205   POST;
3206 }
3207 
3208 
uv_fs_stat(uv_loop_t * loop,uv_fs_t * req,const char * path,uv_fs_cb cb)3209 int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
3210   int err;
3211 
3212   INIT(UV_FS_STAT);
3213   err = fs__capture_path(req, path, NULL, cb != NULL);
3214   if (err) {
3215     SET_REQ_WIN32_ERROR(req, err);
3216     return req->result;
3217   }
3218 
3219   POST;
3220 }
3221 
3222 
uv_fs_lstat(uv_loop_t * loop,uv_fs_t * req,const char * path,uv_fs_cb cb)3223 int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
3224   int err;
3225 
3226   INIT(UV_FS_LSTAT);
3227   err = fs__capture_path(req, path, NULL, cb != NULL);
3228   if (err) {
3229     SET_REQ_WIN32_ERROR(req, err);
3230     return req->result;
3231   }
3232 
3233   POST;
3234 }
3235 
3236 
uv_fs_fstat(uv_loop_t * loop,uv_fs_t * req,uv_file fd,uv_fs_cb cb)3237 int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
3238   INIT(UV_FS_FSTAT);
3239   req->file.fd = fd;
3240   POST;
3241 }
3242 
3243 
uv_fs_rename(uv_loop_t * loop,uv_fs_t * req,const char * path,const char * new_path,uv_fs_cb cb)3244 int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path,
3245     const char* new_path, uv_fs_cb cb) {
3246   int err;
3247 
3248   INIT(UV_FS_RENAME);
3249   err = fs__capture_path(req, path, new_path, cb != NULL);
3250   if (err) {
3251     SET_REQ_WIN32_ERROR(req, err);
3252     return req->result;
3253   }
3254 
3255   POST;
3256 }
3257 
3258 
uv_fs_fsync(uv_loop_t * loop,uv_fs_t * req,uv_file fd,uv_fs_cb cb)3259 int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
3260   INIT(UV_FS_FSYNC);
3261   req->file.fd = fd;
3262   POST;
3263 }
3264 
3265 
uv_fs_fdatasync(uv_loop_t * loop,uv_fs_t * req,uv_file fd,uv_fs_cb cb)3266 int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
3267   INIT(UV_FS_FDATASYNC);
3268   req->file.fd = fd;
3269   POST;
3270 }
3271 
3272 
uv_fs_ftruncate(uv_loop_t * loop,uv_fs_t * req,uv_file fd,int64_t offset,uv_fs_cb cb)3273 int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file fd,
3274     int64_t offset, uv_fs_cb cb) {
3275   INIT(UV_FS_FTRUNCATE);
3276   req->file.fd = fd;
3277   req->fs.info.offset = offset;
3278   POST;
3279 }
3280 
3281 
uv_fs_copyfile(uv_loop_t * loop,uv_fs_t * req,const char * path,const char * new_path,int flags,uv_fs_cb cb)3282 int uv_fs_copyfile(uv_loop_t* loop,
3283                    uv_fs_t* req,
3284                    const char* path,
3285                    const char* new_path,
3286                    int flags,
3287                    uv_fs_cb cb) {
3288   int err;
3289 
3290   INIT(UV_FS_COPYFILE);
3291 
3292   if (flags & ~(UV_FS_COPYFILE_EXCL |
3293                 UV_FS_COPYFILE_FICLONE |
3294                 UV_FS_COPYFILE_FICLONE_FORCE)) {
3295     SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
3296     return UV_EINVAL;
3297   }
3298 
3299   err = fs__capture_path(req, path, new_path, cb != NULL);
3300   if (err) {
3301     SET_REQ_WIN32_ERROR(req, err);
3302     return req->result;
3303   }
3304 
3305   req->fs.info.file_flags = flags;
3306   POST;
3307 }
3308 
3309 
uv_fs_sendfile(uv_loop_t * loop,uv_fs_t * req,uv_file fd_out,uv_file fd_in,int64_t in_offset,size_t length,uv_fs_cb cb)3310 int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file fd_out,
3311     uv_file fd_in, int64_t in_offset, size_t length, uv_fs_cb cb) {
3312   INIT(UV_FS_SENDFILE);
3313   req->file.fd = fd_in;
3314   req->fs.info.fd_out = fd_out;
3315   req->fs.info.offset = in_offset;
3316   req->fs.info.bufsml[0].len = length;
3317   POST;
3318 }
3319 
3320 
uv_fs_access(uv_loop_t * loop,uv_fs_t * req,const char * path,int flags,uv_fs_cb cb)3321 int uv_fs_access(uv_loop_t* loop,
3322                  uv_fs_t* req,
3323                  const char* path,
3324                  int flags,
3325                  uv_fs_cb cb) {
3326   int err;
3327 
3328   INIT(UV_FS_ACCESS);
3329   err = fs__capture_path(req, path, NULL, cb != NULL);
3330   if (err) {
3331     SET_REQ_WIN32_ERROR(req, err);
3332     return req->result;
3333   }
3334 
3335   req->fs.info.mode = flags;
3336   POST;
3337 }
3338 
3339 
uv_fs_chmod(uv_loop_t * loop,uv_fs_t * req,const char * path,int mode,uv_fs_cb cb)3340 int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
3341     uv_fs_cb cb) {
3342   int err;
3343 
3344   INIT(UV_FS_CHMOD);
3345   err = fs__capture_path(req, path, NULL, cb != NULL);
3346   if (err) {
3347     SET_REQ_WIN32_ERROR(req, err);
3348     return req->result;
3349   }
3350 
3351   req->fs.info.mode = mode;
3352   POST;
3353 }
3354 
3355 
uv_fs_fchmod(uv_loop_t * loop,uv_fs_t * req,uv_file fd,int mode,uv_fs_cb cb)3356 int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int mode,
3357     uv_fs_cb cb) {
3358   INIT(UV_FS_FCHMOD);
3359   req->file.fd = fd;
3360   req->fs.info.mode = mode;
3361   POST;
3362 }
3363 
3364 
uv_fs_utime(uv_loop_t * loop,uv_fs_t * req,const char * path,double atime,double mtime,uv_fs_cb cb)3365 int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
3366     double mtime, uv_fs_cb cb) {
3367   int err;
3368 
3369   INIT(UV_FS_UTIME);
3370   err = fs__capture_path(req, path, NULL, cb != NULL);
3371   if (err) {
3372     SET_REQ_WIN32_ERROR(req, err);
3373     return req->result;
3374   }
3375 
3376   req->fs.time.atime = atime;
3377   req->fs.time.mtime = mtime;
3378   POST;
3379 }
3380 
3381 
uv_fs_futime(uv_loop_t * loop,uv_fs_t * req,uv_file fd,double atime,double mtime,uv_fs_cb cb)3382 int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime,
3383     double mtime, uv_fs_cb cb) {
3384   INIT(UV_FS_FUTIME);
3385   req->file.fd = fd;
3386   req->fs.time.atime = atime;
3387   req->fs.time.mtime = mtime;
3388   POST;
3389 }
3390 
uv_fs_lutime(uv_loop_t * loop,uv_fs_t * req,const char * path,double atime,double mtime,uv_fs_cb cb)3391 int uv_fs_lutime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
3392     double mtime, uv_fs_cb cb) {
3393   int err;
3394 
3395   INIT(UV_FS_LUTIME);
3396   err = fs__capture_path(req, path, NULL, cb != NULL);
3397   if (err) {
3398     SET_REQ_WIN32_ERROR(req, err);
3399     return req->result;
3400   }
3401 
3402   req->fs.time.atime = atime;
3403   req->fs.time.mtime = mtime;
3404   POST;
3405 }
3406 
3407 
uv_fs_statfs(uv_loop_t * loop,uv_fs_t * req,const char * path,uv_fs_cb cb)3408 int uv_fs_statfs(uv_loop_t* loop,
3409                  uv_fs_t* req,
3410                  const char* path,
3411                  uv_fs_cb cb) {
3412   int err;
3413 
3414   INIT(UV_FS_STATFS);
3415   err = fs__capture_path(req, path, NULL, cb != NULL);
3416   if (err) {
3417     SET_REQ_WIN32_ERROR(req, err);
3418     return req->result;
3419   }
3420 
3421   POST;
3422 }
3423 
uv_fs_get_system_error(const uv_fs_t * req)3424 int uv_fs_get_system_error(const uv_fs_t* req) {
3425   return req->sys_errno_;
3426 }
3427