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