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