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/* Caveat emptor: this file deviates from the libuv convention of returning
23 * negated errno codes. Most uv_fs_*() functions map directly to the system
24 * call of the same name. For more complex wrappers, it's easier to just
25 * return -1 with errno set. The dispatcher in uv__fs_work() takes care of
26 * getting the errno to the right place (req->result or as the return value.)
27 */
28
29#include "uv.h"
30#include "internal.h"
31
32#include <errno.h>
33#include <dlfcn.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <limits.h> /* PATH_MAX */
38
39#include <sys/types.h>
40#include <sys/socket.h>
41#include <sys/stat.h>
42#include <sys/time.h>
43#include <sys/uio.h>
44#include <pthread.h>
45#include <unistd.h>
46#include <fcntl.h>
47#include <poll.h>
48
49#if defined(__DragonFly__)        ||                                      \
50    defined(__FreeBSD__)          ||                                      \
51    defined(__FreeBSD_kernel__)   ||                                      \
52    defined(__OpenBSD__)          ||                                      \
53    defined(__NetBSD__)
54# define HAVE_PREADV 1
55#else
56# define HAVE_PREADV 0
57#endif
58
59#if defined(__linux__)
60# include "sys/utsname.h"
61#endif
62
63#if defined(__linux__) || defined(__sun)
64# include <sys/sendfile.h>
65# include <sys/sysmacros.h>
66#endif
67
68#if defined(__APPLE__)
69# include <sys/sysctl.h>
70#elif defined(__linux__) && !defined(FICLONE)
71# include <sys/ioctl.h>
72# define FICLONE _IOW(0x94, 9, int)
73#endif
74
75#if defined(_AIX) && !defined(_AIX71)
76# include <utime.h>
77#endif
78
79#if defined(__APPLE__)            ||                                      \
80    defined(__DragonFly__)        ||                                      \
81    defined(__FreeBSD__)          ||                                      \
82    defined(__FreeBSD_kernel__)   ||                                      \
83    defined(__OpenBSD__)          ||                                      \
84    defined(__NetBSD__)
85# include <sys/param.h>
86# include <sys/mount.h>
87#elif defined(__sun)      || \
88      defined(__MVS__)    || \
89      defined(__NetBSD__) || \
90      defined(__HAIKU__)  || \
91      defined(__QNX__)
92# include <sys/statvfs.h>
93#else
94# include <sys/statfs.h>
95#endif
96
97#if defined(_AIX) && _XOPEN_SOURCE <= 600
98extern char *mkdtemp(char *template); /* See issue #740 on AIX < 7 */
99#endif
100
101#define INIT(subtype)                                                         \
102  do {                                                                        \
103    if (req == NULL)                                                          \
104      return UV_EINVAL;                                                       \
105    UV_REQ_INIT(req, UV_FS);                                                  \
106    req->fs_type = UV_FS_ ## subtype;                                         \
107    req->result = 0;                                                          \
108    req->ptr = NULL;                                                          \
109    req->loop = loop;                                                         \
110    req->path = NULL;                                                         \
111    req->new_path = NULL;                                                     \
112    req->bufs = NULL;                                                         \
113    req->cb = cb;                                                             \
114  }                                                                           \
115  while (0)
116
117#define PATH                                                                  \
118  do {                                                                        \
119    assert(path != NULL);                                                     \
120    if (cb == NULL) {                                                         \
121      req->path = path;                                                       \
122    } else {                                                                  \
123      req->path = uv__strdup(path);                                           \
124      if (req->path == NULL)                                                  \
125        return UV_ENOMEM;                                                     \
126    }                                                                         \
127  }                                                                           \
128  while (0)
129
130#define PATH2                                                                 \
131  do {                                                                        \
132    if (cb == NULL) {                                                         \
133      req->path = path;                                                       \
134      req->new_path = new_path;                                               \
135    } else {                                                                  \
136      size_t path_len;                                                        \
137      size_t new_path_len;                                                    \
138      path_len = strlen(path) + 1;                                            \
139      new_path_len = strlen(new_path) + 1;                                    \
140      req->path = uv__malloc(path_len + new_path_len);                        \
141      if (req->path == NULL)                                                  \
142        return UV_ENOMEM;                                                     \
143      req->new_path = req->path + path_len;                                   \
144      memcpy((void*) req->path, path, path_len);                              \
145      memcpy((void*) req->new_path, new_path, new_path_len);                  \
146    }                                                                         \
147  }                                                                           \
148  while (0)
149
150#define POST                                                                  \
151  do {                                                                        \
152    if (cb != NULL) {                                                         \
153      uv__req_register(loop, req);                                            \
154      uv__work_submit(loop,                                                   \
155                      &req->work_req,                                         \
156                      UV__WORK_FAST_IO,                                       \
157                      uv__fs_work,                                            \
158                      uv__fs_done);                                           \
159      return 0;                                                               \
160    }                                                                         \
161    else {                                                                    \
162      uv__fs_work(&req->work_req);                                            \
163      return req->result;                                                     \
164    }                                                                         \
165  }                                                                           \
166  while (0)
167
168
169static int uv__fs_close(int fd) {
170  int rc;
171
172  rc = uv__close_nocancel(fd);
173  if (rc == -1)
174    if (errno == EINTR || errno == EINPROGRESS)
175      rc = 0;  /* The close is in progress, not an error. */
176
177  return rc;
178}
179
180
181static ssize_t uv__fs_fsync(uv_fs_t* req) {
182#if defined(__APPLE__)
183  /* Apple's fdatasync and fsync explicitly do NOT flush the drive write cache
184   * to the drive platters. This is in contrast to Linux's fdatasync and fsync
185   * which do, according to recent man pages. F_FULLFSYNC is Apple's equivalent
186   * for flushing buffered data to permanent storage. If F_FULLFSYNC is not
187   * supported by the file system we fall back to F_BARRIERFSYNC or fsync().
188   * This is the same approach taken by sqlite, except sqlite does not issue
189   * an F_BARRIERFSYNC call.
190   */
191  int r;
192
193  r = fcntl(req->file, F_FULLFSYNC);
194  if (r != 0)
195    r = fcntl(req->file, 85 /* F_BARRIERFSYNC */);  /* fsync + barrier */
196  if (r != 0)
197    r = fsync(req->file);
198  return r;
199#else
200  return fsync(req->file);
201#endif
202}
203
204
205static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
206#if defined(__linux__) || defined(__sun) || defined(__NetBSD__)
207  return fdatasync(req->file);
208#elif defined(__APPLE__)
209  /* See the comment in uv__fs_fsync. */
210  return uv__fs_fsync(req);
211#else
212  return fsync(req->file);
213#endif
214}
215
216
217UV_UNUSED(static struct timespec uv__fs_to_timespec(double time)) {
218  struct timespec ts;
219  ts.tv_sec  = time;
220  ts.tv_nsec = (time - ts.tv_sec) * 1e9;
221
222 /* TODO(bnoordhuis) Remove this. utimesat() has nanosecond resolution but we
223  * stick to microsecond resolution for the sake of consistency with other
224  * platforms. I'm the original author of this compatibility hack but I'm
225  * less convinced it's useful nowadays.
226  */
227  ts.tv_nsec -= ts.tv_nsec % 1000;
228
229  if (ts.tv_nsec < 0) {
230    ts.tv_nsec += 1e9;
231    ts.tv_sec -= 1;
232  }
233  return ts;
234}
235
236UV_UNUSED(static struct timeval uv__fs_to_timeval(double time)) {
237  struct timeval tv;
238  tv.tv_sec  = time;
239  tv.tv_usec = (time - tv.tv_sec) * 1e6;
240  if (tv.tv_usec < 0) {
241    tv.tv_usec += 1e6;
242    tv.tv_sec -= 1;
243  }
244  return tv;
245}
246
247static ssize_t uv__fs_futime(uv_fs_t* req) {
248#if defined(__linux__)                                                        \
249    || defined(_AIX71)                                                        \
250    || defined(__HAIKU__)                                                     \
251    || defined(__GNU__)
252  struct timespec ts[2];
253  ts[0] = uv__fs_to_timespec(req->atime);
254  ts[1] = uv__fs_to_timespec(req->mtime);
255  return futimens(req->file, ts);
256#elif defined(__APPLE__)                                                      \
257    || defined(__DragonFly__)                                                 \
258    || defined(__FreeBSD__)                                                   \
259    || defined(__FreeBSD_kernel__)                                            \
260    || defined(__NetBSD__)                                                    \
261    || defined(__OpenBSD__)                                                   \
262    || defined(__sun)
263  struct timeval tv[2];
264  tv[0] = uv__fs_to_timeval(req->atime);
265  tv[1] = uv__fs_to_timeval(req->mtime);
266# if defined(__sun)
267  return futimesat(req->file, NULL, tv);
268# else
269  return futimes(req->file, tv);
270# endif
271#elif defined(__MVS__)
272  attrib_t atr;
273  memset(&atr, 0, sizeof(atr));
274  atr.att_mtimechg = 1;
275  atr.att_atimechg = 1;
276  atr.att_mtime = req->mtime;
277  atr.att_atime = req->atime;
278  return __fchattr(req->file, &atr, sizeof(atr));
279#else
280  errno = ENOSYS;
281  return -1;
282#endif
283}
284
285
286static ssize_t uv__fs_mkdtemp(uv_fs_t* req) {
287  return mkdtemp((char*) req->path) ? 0 : -1;
288}
289
290
291static int (*uv__mkostemp)(char*, int);
292
293
294static void uv__mkostemp_initonce(void) {
295  /* z/os doesn't have RTLD_DEFAULT but that's okay
296   * because it doesn't have mkostemp(O_CLOEXEC) either.
297   */
298#ifdef RTLD_DEFAULT
299  uv__mkostemp = (int (*)(char*, int)) dlsym(RTLD_DEFAULT, "mkostemp");
300
301  /* We don't care about errors, but we do want to clean them up.
302   * If there has been no error, then dlerror() will just return
303   * NULL.
304   */
305  dlerror();
306#endif  /* RTLD_DEFAULT */
307}
308
309
310static int uv__fs_mkstemp(uv_fs_t* req) {
311  static uv_once_t once = UV_ONCE_INIT;
312  int r;
313#ifdef O_CLOEXEC
314  static int no_cloexec_support;
315#endif
316  static const char pattern[] = "XXXXXX";
317  static const size_t pattern_size = sizeof(pattern) - 1;
318  char* path;
319  size_t path_length;
320
321  path = (char*) req->path;
322  path_length = strlen(path);
323
324  /* EINVAL can be returned for 2 reasons:
325      1. The template's last 6 characters were not XXXXXX
326      2. open() didn't support O_CLOEXEC
327     We want to avoid going to the fallback path in case
328     of 1, so it's manually checked before. */
329  if (path_length < pattern_size ||
330      strcmp(path + path_length - pattern_size, pattern)) {
331    errno = EINVAL;
332    r = -1;
333    goto clobber;
334  }
335
336  uv_once(&once, uv__mkostemp_initonce);
337
338#ifdef O_CLOEXEC
339  if (uv__load_relaxed(&no_cloexec_support) == 0 && uv__mkostemp != NULL) {
340    r = uv__mkostemp(path, O_CLOEXEC);
341
342    if (r >= 0)
343      return r;
344
345    /* If mkostemp() returns EINVAL, it means the kernel doesn't
346       support O_CLOEXEC, so we just fallback to mkstemp() below. */
347    if (errno != EINVAL)
348      goto clobber;
349
350    /* We set the static variable so that next calls don't even
351       try to use mkostemp. */
352    uv__store_relaxed(&no_cloexec_support, 1);
353  }
354#endif  /* O_CLOEXEC */
355
356  if (req->cb != NULL)
357    uv_rwlock_rdlock(&req->loop->cloexec_lock);
358
359  r = mkstemp(path);
360
361  /* In case of failure `uv__cloexec` will leave error in `errno`,
362   * so it is enough to just set `r` to `-1`.
363   */
364  if (r >= 0 && uv__cloexec(r, 1) != 0) {
365    r = uv__close(r);
366    if (r != 0)
367      abort();
368    r = -1;
369  }
370
371  if (req->cb != NULL)
372    uv_rwlock_rdunlock(&req->loop->cloexec_lock);
373
374clobber:
375  if (r < 0)
376    path[0] = '\0';
377  return r;
378}
379
380
381static ssize_t uv__fs_open(uv_fs_t* req) {
382#ifdef O_CLOEXEC
383  return open(req->path, req->flags | O_CLOEXEC, req->mode);
384#else  /* O_CLOEXEC */
385  int r;
386
387  if (req->cb != NULL)
388    uv_rwlock_rdlock(&req->loop->cloexec_lock);
389
390  r = open(req->path, req->flags, req->mode);
391
392  /* In case of failure `uv__cloexec` will leave error in `errno`,
393   * so it is enough to just set `r` to `-1`.
394   */
395  if (r >= 0 && uv__cloexec(r, 1) != 0) {
396    r = uv__close(r);
397    if (r != 0)
398      abort();
399    r = -1;
400  }
401
402  if (req->cb != NULL)
403    uv_rwlock_rdunlock(&req->loop->cloexec_lock);
404
405  return r;
406#endif  /* O_CLOEXEC */
407}
408
409
410#if !HAVE_PREADV
411static ssize_t uv__fs_preadv(uv_file fd,
412                             uv_buf_t* bufs,
413                             unsigned int nbufs,
414                             off_t off) {
415  uv_buf_t* buf;
416  uv_buf_t* end;
417  ssize_t result;
418  ssize_t rc;
419  size_t pos;
420
421  assert(nbufs > 0);
422
423  result = 0;
424  pos = 0;
425  buf = bufs + 0;
426  end = bufs + nbufs;
427
428  for (;;) {
429    do
430      rc = pread(fd, buf->base + pos, buf->len - pos, off + result);
431    while (rc == -1 && errno == EINTR);
432
433    if (rc == 0)
434      break;
435
436    if (rc == -1 && result == 0)
437      return UV__ERR(errno);
438
439    if (rc == -1)
440      break;  /* We read some data so return that, ignore the error. */
441
442    pos += rc;
443    result += rc;
444
445    if (pos < buf->len)
446      continue;
447
448    pos = 0;
449    buf += 1;
450
451    if (buf == end)
452      break;
453  }
454
455  return result;
456}
457#endif
458
459
460static ssize_t uv__fs_read(uv_fs_t* req) {
461#if defined(__linux__)
462  static int no_preadv;
463#endif
464  unsigned int iovmax;
465  ssize_t result;
466
467  iovmax = uv__getiovmax();
468  if (req->nbufs > iovmax)
469    req->nbufs = iovmax;
470
471  if (req->off < 0) {
472    if (req->nbufs == 1)
473      result = read(req->file, req->bufs[0].base, req->bufs[0].len);
474    else
475      result = readv(req->file, (struct iovec*) req->bufs, req->nbufs);
476  } else {
477    if (req->nbufs == 1) {
478      result = pread(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
479      goto done;
480    }
481
482#if HAVE_PREADV
483    result = preadv(req->file, (struct iovec*) req->bufs, req->nbufs, req->off);
484#else
485# if defined(__linux__)
486    if (uv__load_relaxed(&no_preadv)) retry:
487# endif
488    {
489      result = uv__fs_preadv(req->file, req->bufs, req->nbufs, req->off);
490    }
491# if defined(__linux__)
492    else {
493      result = uv__preadv(req->file,
494                          (struct iovec*)req->bufs,
495                          req->nbufs,
496                          req->off);
497      if (result == -1 && errno == ENOSYS) {
498        uv__store_relaxed(&no_preadv, 1);
499        goto retry;
500      }
501    }
502# endif
503#endif
504  }
505
506done:
507  /* Early cleanup of bufs allocation, since we're done with it. */
508  if (req->bufs != req->bufsml)
509    uv__free(req->bufs);
510
511  req->bufs = NULL;
512  req->nbufs = 0;
513
514#ifdef __PASE__
515  /* PASE returns EOPNOTSUPP when reading a directory, convert to EISDIR */
516  if (result == -1 && errno == EOPNOTSUPP) {
517    struct stat buf;
518    ssize_t rc;
519    rc = fstat(req->file, &buf);
520    if (rc == 0 && S_ISDIR(buf.st_mode)) {
521      errno = EISDIR;
522    }
523  }
524#endif
525
526  return result;
527}
528
529
530#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_8)
531#define UV_CONST_DIRENT uv__dirent_t
532#else
533#define UV_CONST_DIRENT const uv__dirent_t
534#endif
535
536
537static int uv__fs_scandir_filter(UV_CONST_DIRENT* dent) {
538  return strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0;
539}
540
541
542static int uv__fs_scandir_sort(UV_CONST_DIRENT** a, UV_CONST_DIRENT** b) {
543  return strcmp((*a)->d_name, (*b)->d_name);
544}
545
546
547static ssize_t uv__fs_scandir(uv_fs_t* req) {
548  uv__dirent_t** dents;
549  int n;
550
551  dents = NULL;
552  n = scandir(req->path, &dents, uv__fs_scandir_filter, uv__fs_scandir_sort);
553
554  /* NOTE: We will use nbufs as an index field */
555  req->nbufs = 0;
556
557  if (n == 0) {
558    /* OS X still needs to deallocate some memory.
559     * Memory was allocated using the system allocator, so use free() here.
560     */
561    free(dents);
562    dents = NULL;
563  } else if (n == -1) {
564    return n;
565  }
566
567  req->ptr = dents;
568
569  return n;
570}
571
572static int uv__fs_opendir(uv_fs_t* req) {
573  uv_dir_t* dir;
574
575  dir = uv__malloc(sizeof(*dir));
576  if (dir == NULL)
577    goto error;
578
579  dir->dir = opendir(req->path);
580  if (dir->dir == NULL)
581    goto error;
582
583  req->ptr = dir;
584  return 0;
585
586error:
587  uv__free(dir);
588  req->ptr = NULL;
589  return -1;
590}
591
592static int uv__fs_readdir(uv_fs_t* req) {
593  uv_dir_t* dir;
594  uv_dirent_t* dirent;
595  struct dirent* res;
596  unsigned int dirent_idx;
597  unsigned int i;
598
599  dir = req->ptr;
600  dirent_idx = 0;
601
602  while (dirent_idx < dir->nentries) {
603    /* readdir() returns NULL on end of directory, as well as on error. errno
604       is used to differentiate between the two conditions. */
605    errno = 0;
606    res = readdir(dir->dir);
607
608    if (res == NULL) {
609      if (errno != 0)
610        goto error;
611      break;
612    }
613
614    if (strcmp(res->d_name, ".") == 0 || strcmp(res->d_name, "..") == 0)
615      continue;
616
617    dirent = &dir->dirents[dirent_idx];
618    dirent->name = uv__strdup(res->d_name);
619
620    if (dirent->name == NULL)
621      goto error;
622
623    dirent->type = uv__fs_get_dirent_type(res);
624    ++dirent_idx;
625  }
626
627  return dirent_idx;
628
629error:
630  for (i = 0; i < dirent_idx; ++i) {
631    uv__free((char*) dir->dirents[i].name);
632    dir->dirents[i].name = NULL;
633  }
634
635  return -1;
636}
637
638static int uv__fs_closedir(uv_fs_t* req) {
639  uv_dir_t* dir;
640
641  dir = req->ptr;
642
643  if (dir->dir != NULL) {
644    closedir(dir->dir);
645    dir->dir = NULL;
646  }
647
648  uv__free(req->ptr);
649  req->ptr = NULL;
650  return 0;
651}
652
653static int uv__fs_statfs(uv_fs_t* req) {
654  uv_statfs_t* stat_fs;
655#if defined(__sun)      || \
656    defined(__MVS__)    || \
657    defined(__NetBSD__) || \
658    defined(__HAIKU__)  || \
659    defined(__QNX__)
660  struct statvfs buf;
661
662  if (0 != statvfs(req->path, &buf))
663#else
664  struct statfs buf;
665
666  if (0 != statfs(req->path, &buf))
667#endif /* defined(__sun) */
668    return -1;
669
670  stat_fs = uv__malloc(sizeof(*stat_fs));
671  if (stat_fs == NULL) {
672    errno = ENOMEM;
673    return -1;
674  }
675
676#if defined(__sun)        || \
677    defined(__MVS__)      || \
678    defined(__OpenBSD__)  || \
679    defined(__NetBSD__)   || \
680    defined(__HAIKU__)    || \
681    defined(__QNX__)
682  stat_fs->f_type = 0;  /* f_type is not supported. */
683#else
684  stat_fs->f_type = buf.f_type;
685#endif
686  stat_fs->f_bsize = buf.f_bsize;
687  stat_fs->f_blocks = buf.f_blocks;
688  stat_fs->f_bfree = buf.f_bfree;
689  stat_fs->f_bavail = buf.f_bavail;
690  stat_fs->f_files = buf.f_files;
691  stat_fs->f_ffree = buf.f_ffree;
692  req->ptr = stat_fs;
693  return 0;
694}
695
696static ssize_t uv__fs_pathmax_size(const char* path) {
697  ssize_t pathmax;
698
699  pathmax = pathconf(path, _PC_PATH_MAX);
700
701  if (pathmax == -1)
702    pathmax = UV__PATH_MAX;
703
704  return pathmax;
705}
706
707static ssize_t uv__fs_readlink(uv_fs_t* req) {
708  ssize_t maxlen;
709  ssize_t len;
710  char* buf;
711
712#if defined(_POSIX_PATH_MAX) || defined(PATH_MAX)
713  maxlen = uv__fs_pathmax_size(req->path);
714#else
715  /* We may not have a real PATH_MAX.  Read size of link.  */
716  struct stat st;
717  int ret;
718  ret = lstat(req->path, &st);
719  if (ret != 0)
720    return -1;
721  if (!S_ISLNK(st.st_mode)) {
722    errno = EINVAL;
723    return -1;
724  }
725
726  maxlen = st.st_size;
727
728  /* According to readlink(2) lstat can report st_size == 0
729     for some symlinks, such as those in /proc or /sys.  */
730  if (maxlen == 0)
731    maxlen = uv__fs_pathmax_size(req->path);
732#endif
733
734  buf = uv__malloc(maxlen);
735
736  if (buf == NULL) {
737    errno = ENOMEM;
738    return -1;
739  }
740
741#if defined(__MVS__)
742  len = os390_readlink(req->path, buf, maxlen);
743#else
744  len = readlink(req->path, buf, maxlen);
745#endif
746
747  if (len == -1) {
748    uv__free(buf);
749    return -1;
750  }
751
752  /* Uncommon case: resize to make room for the trailing nul byte. */
753  if (len == maxlen) {
754    buf = uv__reallocf(buf, len + 1);
755
756    if (buf == NULL)
757      return -1;
758  }
759
760  buf[len] = '\0';
761  req->ptr = buf;
762
763  return 0;
764}
765
766static ssize_t uv__fs_realpath(uv_fs_t* req) {
767  char* buf;
768
769#if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L
770  buf = realpath(req->path, NULL);
771  if (buf == NULL)
772    return -1;
773#else
774  ssize_t len;
775
776  len = uv__fs_pathmax_size(req->path);
777  buf = uv__malloc(len + 1);
778
779  if (buf == NULL) {
780    errno = ENOMEM;
781    return -1;
782  }
783
784  if (realpath(req->path, buf) == NULL) {
785    uv__free(buf);
786    return -1;
787  }
788#endif
789
790  req->ptr = buf;
791
792  return 0;
793}
794
795static ssize_t uv__fs_sendfile_emul(uv_fs_t* req) {
796  struct pollfd pfd;
797  int use_pread;
798  off_t offset;
799  ssize_t nsent;
800  ssize_t nread;
801  ssize_t nwritten;
802  size_t buflen;
803  size_t len;
804  ssize_t n;
805  int in_fd;
806  int out_fd;
807  char buf[8192];
808
809  len = req->bufsml[0].len;
810  in_fd = req->flags;
811  out_fd = req->file;
812  offset = req->off;
813  use_pread = 1;
814
815  /* Here are the rules regarding errors:
816   *
817   * 1. Read errors are reported only if nsent==0, otherwise we return nsent.
818   *    The user needs to know that some data has already been sent, to stop
819   *    them from sending it twice.
820   *
821   * 2. Write errors are always reported. Write errors are bad because they
822   *    mean data loss: we've read data but now we can't write it out.
823   *
824   * We try to use pread() and fall back to regular read() if the source fd
825   * doesn't support positional reads, for example when it's a pipe fd.
826   *
827   * If we get EAGAIN when writing to the target fd, we poll() on it until
828   * it becomes writable again.
829   *
830   * FIXME: If we get a write error when use_pread==1, it should be safe to
831   *        return the number of sent bytes instead of an error because pread()
832   *        is, in theory, idempotent. However, special files in /dev or /proc
833   *        may support pread() but not necessarily return the same data on
834   *        successive reads.
835   *
836   * FIXME: There is no way now to signal that we managed to send *some* data
837   *        before a write error.
838   */
839  for (nsent = 0; (size_t) nsent < len; ) {
840    buflen = len - nsent;
841
842    if (buflen > sizeof(buf))
843      buflen = sizeof(buf);
844
845    do
846      if (use_pread)
847        nread = pread(in_fd, buf, buflen, offset);
848      else
849        nread = read(in_fd, buf, buflen);
850    while (nread == -1 && errno == EINTR);
851
852    if (nread == 0)
853      goto out;
854
855    if (nread == -1) {
856      if (use_pread && nsent == 0 && (errno == EIO || errno == ESPIPE)) {
857        use_pread = 0;
858        continue;
859      }
860
861      if (nsent == 0)
862        nsent = -1;
863
864      goto out;
865    }
866
867    for (nwritten = 0; nwritten < nread; ) {
868      do
869        n = write(out_fd, buf + nwritten, nread - nwritten);
870      while (n == -1 && errno == EINTR);
871
872      if (n != -1) {
873        nwritten += n;
874        continue;
875      }
876
877      if (errno != EAGAIN && errno != EWOULDBLOCK) {
878        nsent = -1;
879        goto out;
880      }
881
882      pfd.fd = out_fd;
883      pfd.events = POLLOUT;
884      pfd.revents = 0;
885
886      do
887        n = poll(&pfd, 1, -1);
888      while (n == -1 && errno == EINTR);
889
890      if (n == -1 || (pfd.revents & ~POLLOUT) != 0) {
891        errno = EIO;
892        nsent = -1;
893        goto out;
894      }
895    }
896
897    offset += nread;
898    nsent += nread;
899  }
900
901out:
902  if (nsent != -1)
903    req->off = offset;
904
905  return nsent;
906}
907
908
909#ifdef __linux__
910static unsigned uv__kernel_version(void) {
911  static unsigned cached_version;
912  struct utsname u;
913  unsigned version;
914  unsigned major;
915  unsigned minor;
916  unsigned patch;
917
918  version = uv__load_relaxed(&cached_version);
919  if (version != 0)
920    return version;
921
922  if (-1 == uname(&u))
923    return 0;
924
925  if (3 != sscanf(u.release, "%u.%u.%u", &major, &minor, &patch))
926    return 0;
927
928  version = major * 65536 + minor * 256 + patch;
929  uv__store_relaxed(&cached_version, version);
930
931  return version;
932}
933
934
935/* Pre-4.20 kernels have a bug where CephFS uses the RADOS copy-from command
936 * in copy_file_range() when it shouldn't. There is no workaround except to
937 * fall back to a regular copy.
938 */
939static int uv__is_buggy_cephfs(int fd) {
940  struct statfs s;
941
942  if (-1 == fstatfs(fd, &s))
943    return 0;
944
945  if (s.f_type != /* CephFS */ 0xC36400)
946    return 0;
947
948  return uv__kernel_version() < /* 4.20.0 */ 0x041400;
949}
950
951
952static int uv__is_cifs_or_smb(int fd) {
953  struct statfs s;
954
955  if (-1 == fstatfs(fd, &s))
956    return 0;
957
958  switch ((unsigned) s.f_type) {
959  case 0x0000517Bu:  /* SMB */
960  case 0xFE534D42u:  /* SMB2 */
961  case 0xFF534D42u:  /* CIFS */
962    return 1;
963  }
964
965  return 0;
966}
967
968
969static ssize_t uv__fs_try_copy_file_range(int in_fd, off_t* off,
970                                          int out_fd, size_t len) {
971  static int no_copy_file_range_support;
972  ssize_t r;
973
974  if (uv__load_relaxed(&no_copy_file_range_support)) {
975    errno = ENOSYS;
976    return -1;
977  }
978
979  r = uv__fs_copy_file_range(in_fd, off, out_fd, NULL, len, 0);
980
981  if (r != -1)
982    return r;
983
984  switch (errno) {
985  case EACCES:
986    /* Pre-4.20 kernels have a bug where CephFS uses the RADOS
987     * copy-from command when it shouldn't.
988     */
989    if (uv__is_buggy_cephfs(in_fd))
990      errno = ENOSYS;  /* Use fallback. */
991    break;
992  case ENOSYS:
993    uv__store_relaxed(&no_copy_file_range_support, 1);
994    break;
995  case EPERM:
996    /* It's been reported that CIFS spuriously fails.
997     * Consider it a transient error.
998     */
999    if (uv__is_cifs_or_smb(out_fd))
1000      errno = ENOSYS;  /* Use fallback. */
1001    break;
1002  case ENOTSUP:
1003  case EXDEV:
1004    /* ENOTSUP - it could work on another file system type.
1005     * EXDEV - it will not work when in_fd and out_fd are not on the same
1006     *         mounted filesystem (pre Linux 5.3)
1007     */
1008    errno = ENOSYS;  /* Use fallback. */
1009    break;
1010  }
1011
1012  return -1;
1013}
1014
1015#endif  /* __linux__ */
1016
1017
1018static ssize_t uv__fs_sendfile(uv_fs_t* req) {
1019  int in_fd;
1020  int out_fd;
1021
1022  in_fd = req->flags;
1023  out_fd = req->file;
1024
1025#if defined(__linux__) || defined(__sun)
1026  {
1027    off_t off;
1028    ssize_t r;
1029    size_t len;
1030    int try_sendfile;
1031
1032    off = req->off;
1033    len = req->bufsml[0].len;
1034    try_sendfile = 1;
1035
1036#ifdef __linux__
1037    r = uv__fs_try_copy_file_range(in_fd, &off, out_fd, len);
1038    try_sendfile = (r == -1 && errno == ENOSYS);
1039#endif
1040
1041    if (try_sendfile)
1042      r = sendfile(out_fd, in_fd, &off, len);
1043
1044    /* sendfile() on SunOS returns EINVAL if the target fd is not a socket but
1045     * it still writes out data. Fortunately, we can detect it by checking if
1046     * the offset has been updated.
1047     */
1048    if (r != -1 || off > req->off) {
1049      r = off - req->off;
1050      req->off = off;
1051      return r;
1052    }
1053
1054    if (errno == EINVAL ||
1055        errno == EIO ||
1056        errno == ENOTSOCK ||
1057        errno == EXDEV) {
1058      errno = 0;
1059      return uv__fs_sendfile_emul(req);
1060    }
1061
1062    return -1;
1063  }
1064#elif defined(__APPLE__)           || \
1065      defined(__DragonFly__)       || \
1066      defined(__FreeBSD__)         || \
1067      defined(__FreeBSD_kernel__)
1068  {
1069    off_t len;
1070    ssize_t r;
1071
1072    /* sendfile() on FreeBSD and Darwin returns EAGAIN if the target fd is in
1073     * non-blocking mode and not all data could be written. If a non-zero
1074     * number of bytes have been sent, we don't consider it an error.
1075     */
1076
1077#if defined(__FreeBSD__) || defined(__DragonFly__)
1078#if defined(__FreeBSD__)
1079    off_t off;
1080
1081    off = req->off;
1082    r = uv__fs_copy_file_range(in_fd, &off, out_fd, NULL, req->bufsml[0].len, 0);
1083    if (r >= 0) {
1084        r = off - req->off;
1085        req->off = off;
1086        return r;
1087    }
1088#endif
1089    len = 0;
1090    r = sendfile(in_fd, out_fd, req->off, req->bufsml[0].len, NULL, &len, 0);
1091#elif defined(__FreeBSD_kernel__)
1092    len = 0;
1093    r = bsd_sendfile(in_fd,
1094                     out_fd,
1095                     req->off,
1096                     req->bufsml[0].len,
1097                     NULL,
1098                     &len,
1099                     0);
1100#else
1101    /* The darwin sendfile takes len as an input for the length to send,
1102     * so make sure to initialize it with the caller's value. */
1103    len = req->bufsml[0].len;
1104    r = sendfile(in_fd, out_fd, req->off, &len, NULL, 0);
1105#endif
1106
1107     /*
1108     * The man page for sendfile(2) on DragonFly states that `len` contains
1109     * a meaningful value ONLY in case of EAGAIN and EINTR.
1110     * Nothing is said about it's value in case of other errors, so better
1111     * not depend on the potential wrong assumption that is was not modified
1112     * by the syscall.
1113     */
1114    if (r == 0 || ((errno == EAGAIN || errno == EINTR) && len != 0)) {
1115      req->off += len;
1116      return (ssize_t) len;
1117    }
1118
1119    if (errno == EINVAL ||
1120        errno == EIO ||
1121        errno == ENOTSOCK ||
1122        errno == EXDEV) {
1123      errno = 0;
1124      return uv__fs_sendfile_emul(req);
1125    }
1126
1127    return -1;
1128  }
1129#else
1130  /* Squelch compiler warnings. */
1131  (void) &in_fd;
1132  (void) &out_fd;
1133
1134  return uv__fs_sendfile_emul(req);
1135#endif
1136}
1137
1138
1139static ssize_t uv__fs_utime(uv_fs_t* req) {
1140#if defined(__linux__)                                                         \
1141    || defined(_AIX71)                                                         \
1142    || defined(__sun)                                                          \
1143    || defined(__HAIKU__)
1144  struct timespec ts[2];
1145  ts[0] = uv__fs_to_timespec(req->atime);
1146  ts[1] = uv__fs_to_timespec(req->mtime);
1147  return utimensat(AT_FDCWD, req->path, ts, 0);
1148#elif defined(__APPLE__)                                                      \
1149    || defined(__DragonFly__)                                                 \
1150    || defined(__FreeBSD__)                                                   \
1151    || defined(__FreeBSD_kernel__)                                            \
1152    || defined(__NetBSD__)                                                    \
1153    || defined(__OpenBSD__)
1154  struct timeval tv[2];
1155  tv[0] = uv__fs_to_timeval(req->atime);
1156  tv[1] = uv__fs_to_timeval(req->mtime);
1157  return utimes(req->path, tv);
1158#elif defined(_AIX)                                                           \
1159    && !defined(_AIX71)
1160  struct utimbuf buf;
1161  buf.actime = req->atime;
1162  buf.modtime = req->mtime;
1163  return utime(req->path, &buf);
1164#elif defined(__MVS__)
1165  attrib_t atr;
1166  memset(&atr, 0, sizeof(atr));
1167  atr.att_mtimechg = 1;
1168  atr.att_atimechg = 1;
1169  atr.att_mtime = req->mtime;
1170  atr.att_atime = req->atime;
1171  return __lchattr((char*) req->path, &atr, sizeof(atr));
1172#else
1173  errno = ENOSYS;
1174  return -1;
1175#endif
1176}
1177
1178
1179static ssize_t uv__fs_lutime(uv_fs_t* req) {
1180#if defined(__linux__)            ||                                           \
1181    defined(_AIX71)               ||                                           \
1182    defined(__sun)                ||                                           \
1183    defined(__HAIKU__)            ||                                           \
1184    defined(__GNU__)              ||                                           \
1185    defined(__OpenBSD__)
1186  struct timespec ts[2];
1187  ts[0] = uv__fs_to_timespec(req->atime);
1188  ts[1] = uv__fs_to_timespec(req->mtime);
1189  return utimensat(AT_FDCWD, req->path, ts, AT_SYMLINK_NOFOLLOW);
1190#elif defined(__APPLE__)          ||                                          \
1191      defined(__DragonFly__)      ||                                          \
1192      defined(__FreeBSD__)        ||                                          \
1193      defined(__FreeBSD_kernel__) ||                                          \
1194      defined(__NetBSD__)
1195  struct timeval tv[2];
1196  tv[0] = uv__fs_to_timeval(req->atime);
1197  tv[1] = uv__fs_to_timeval(req->mtime);
1198  return lutimes(req->path, tv);
1199#else
1200  errno = ENOSYS;
1201  return -1;
1202#endif
1203}
1204
1205
1206static ssize_t uv__fs_write(uv_fs_t* req) {
1207#if defined(__linux__)
1208  static int no_pwritev;
1209#endif
1210  ssize_t r;
1211
1212  /* Serialize writes on OS X, concurrent write() and pwrite() calls result in
1213   * data loss. We can't use a per-file descriptor lock, the descriptor may be
1214   * a dup().
1215   */
1216#if defined(__APPLE__)
1217  static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
1218
1219  if (pthread_mutex_lock(&lock))
1220    abort();
1221#endif
1222
1223  if (req->off < 0) {
1224    if (req->nbufs == 1)
1225      r = write(req->file, req->bufs[0].base, req->bufs[0].len);
1226    else
1227      r = writev(req->file, (struct iovec*) req->bufs, req->nbufs);
1228  } else {
1229    if (req->nbufs == 1) {
1230      r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
1231      goto done;
1232    }
1233#if HAVE_PREADV
1234    r = pwritev(req->file, (struct iovec*) req->bufs, req->nbufs, req->off);
1235#else
1236# if defined(__linux__)
1237    if (no_pwritev) retry:
1238# endif
1239    {
1240      r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
1241    }
1242# if defined(__linux__)
1243    else {
1244      r = uv__pwritev(req->file,
1245                      (struct iovec*) req->bufs,
1246                      req->nbufs,
1247                      req->off);
1248      if (r == -1 && errno == ENOSYS) {
1249        no_pwritev = 1;
1250        goto retry;
1251      }
1252    }
1253# endif
1254#endif
1255  }
1256
1257done:
1258#if defined(__APPLE__)
1259  if (pthread_mutex_unlock(&lock))
1260    abort();
1261#endif
1262
1263  return r;
1264}
1265
1266static ssize_t uv__fs_copyfile(uv_fs_t* req) {
1267  uv_fs_t fs_req;
1268  uv_file srcfd;
1269  uv_file dstfd;
1270  struct stat src_statsbuf;
1271  struct stat dst_statsbuf;
1272  int dst_flags;
1273  int result;
1274  int err;
1275  off_t bytes_to_send;
1276  off_t in_offset;
1277  off_t bytes_written;
1278  size_t bytes_chunk;
1279
1280  dstfd = -1;
1281  err = 0;
1282
1283  /* Open the source file. */
1284  srcfd = uv_fs_open(NULL, &fs_req, req->path, O_RDONLY, 0, NULL);
1285  uv_fs_req_cleanup(&fs_req);
1286
1287  if (srcfd < 0)
1288    return srcfd;
1289
1290  /* Get the source file's mode. */
1291  if (fstat(srcfd, &src_statsbuf)) {
1292    err = UV__ERR(errno);
1293    goto out;
1294  }
1295
1296  dst_flags = O_WRONLY | O_CREAT;
1297
1298  if (req->flags & UV_FS_COPYFILE_EXCL)
1299    dst_flags |= O_EXCL;
1300
1301  /* Open the destination file. */
1302  dstfd = uv_fs_open(NULL,
1303                     &fs_req,
1304                     req->new_path,
1305                     dst_flags,
1306                     src_statsbuf.st_mode,
1307                     NULL);
1308  uv_fs_req_cleanup(&fs_req);
1309
1310  if (dstfd < 0) {
1311    err = dstfd;
1312    goto out;
1313  }
1314
1315  /* If the file is not being opened exclusively, verify that the source and
1316     destination are not the same file. If they are the same, bail out early. */
1317  if ((req->flags & UV_FS_COPYFILE_EXCL) == 0) {
1318    /* Get the destination file's mode. */
1319    if (fstat(dstfd, &dst_statsbuf)) {
1320      err = UV__ERR(errno);
1321      goto out;
1322    }
1323
1324    /* Check if srcfd and dstfd refer to the same file */
1325    if (src_statsbuf.st_dev == dst_statsbuf.st_dev &&
1326        src_statsbuf.st_ino == dst_statsbuf.st_ino) {
1327      goto out;
1328    }
1329
1330    /* Truncate the file in case the destination already existed. */
1331    if (ftruncate(dstfd, 0) != 0) {
1332      err = UV__ERR(errno);
1333      goto out;
1334    }
1335  }
1336
1337  if (fchmod(dstfd, src_statsbuf.st_mode) == -1) {
1338    err = UV__ERR(errno);
1339#ifdef __linux__
1340    /* fchmod() on CIFS shares always fails with EPERM unless the share is
1341     * mounted with "noperm". As fchmod() is a meaningless operation on such
1342     * shares anyway, detect that condition and squelch the error.
1343     */
1344    if (err != UV_EPERM)
1345      goto out;
1346
1347    if (!uv__is_cifs_or_smb(dstfd))
1348      goto out;
1349
1350    err = 0;
1351#else  /* !__linux__ */
1352    goto out;
1353#endif  /* !__linux__ */
1354  }
1355
1356#ifdef FICLONE
1357  if (req->flags & UV_FS_COPYFILE_FICLONE ||
1358      req->flags & UV_FS_COPYFILE_FICLONE_FORCE) {
1359    if (ioctl(dstfd, FICLONE, srcfd) == 0) {
1360      /* ioctl() with FICLONE succeeded. */
1361      goto out;
1362    }
1363    /* If an error occurred and force was set, return the error to the caller;
1364     * fall back to sendfile() when force was not set. */
1365    if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) {
1366      err = UV__ERR(errno);
1367      goto out;
1368    }
1369  }
1370#else
1371  if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) {
1372    err = UV_ENOSYS;
1373    goto out;
1374  }
1375#endif
1376
1377  bytes_to_send = src_statsbuf.st_size;
1378  in_offset = 0;
1379  while (bytes_to_send != 0) {
1380    bytes_chunk = SSIZE_MAX;
1381    if (bytes_to_send < (off_t) bytes_chunk)
1382      bytes_chunk = bytes_to_send;
1383    uv_fs_sendfile(NULL, &fs_req, dstfd, srcfd, in_offset, bytes_chunk, NULL);
1384    bytes_written = fs_req.result;
1385    uv_fs_req_cleanup(&fs_req);
1386
1387    if (bytes_written < 0) {
1388      err = bytes_written;
1389      break;
1390    }
1391
1392    bytes_to_send -= bytes_written;
1393    in_offset += bytes_written;
1394  }
1395
1396out:
1397  if (err < 0)
1398    result = err;
1399  else
1400    result = 0;
1401
1402  /* Close the source file. */
1403  err = uv__close_nocheckstdio(srcfd);
1404
1405  /* Don't overwrite any existing errors. */
1406  if (err != 0 && result == 0)
1407    result = err;
1408
1409  /* Close the destination file if it is open. */
1410  if (dstfd >= 0) {
1411    err = uv__close_nocheckstdio(dstfd);
1412
1413    /* Don't overwrite any existing errors. */
1414    if (err != 0 && result == 0)
1415      result = err;
1416
1417    /* Remove the destination file if something went wrong. */
1418    if (result != 0) {
1419      uv_fs_unlink(NULL, &fs_req, req->new_path, NULL);
1420      /* Ignore the unlink return value, as an error already happened. */
1421      uv_fs_req_cleanup(&fs_req);
1422    }
1423  }
1424
1425  if (result == 0)
1426    return 0;
1427
1428  errno = UV__ERR(result);
1429  return -1;
1430}
1431
1432static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
1433  dst->st_dev = src->st_dev;
1434  dst->st_mode = src->st_mode;
1435  dst->st_nlink = src->st_nlink;
1436  dst->st_uid = src->st_uid;
1437  dst->st_gid = src->st_gid;
1438  dst->st_rdev = src->st_rdev;
1439  dst->st_ino = src->st_ino;
1440  dst->st_size = src->st_size;
1441  dst->st_blksize = src->st_blksize;
1442  dst->st_blocks = src->st_blocks;
1443
1444#if defined(__APPLE__)
1445  dst->st_atim.tv_sec = src->st_atimespec.tv_sec;
1446  dst->st_atim.tv_nsec = src->st_atimespec.tv_nsec;
1447  dst->st_mtim.tv_sec = src->st_mtimespec.tv_sec;
1448  dst->st_mtim.tv_nsec = src->st_mtimespec.tv_nsec;
1449  dst->st_ctim.tv_sec = src->st_ctimespec.tv_sec;
1450  dst->st_ctim.tv_nsec = src->st_ctimespec.tv_nsec;
1451  dst->st_birthtim.tv_sec = src->st_birthtimespec.tv_sec;
1452  dst->st_birthtim.tv_nsec = src->st_birthtimespec.tv_nsec;
1453  dst->st_flags = src->st_flags;
1454  dst->st_gen = src->st_gen;
1455#elif defined(__ANDROID__)
1456  dst->st_atim.tv_sec = src->st_atime;
1457  dst->st_atim.tv_nsec = src->st_atimensec;
1458  dst->st_mtim.tv_sec = src->st_mtime;
1459  dst->st_mtim.tv_nsec = src->st_mtimensec;
1460  dst->st_ctim.tv_sec = src->st_ctime;
1461  dst->st_ctim.tv_nsec = src->st_ctimensec;
1462  dst->st_birthtim.tv_sec = src->st_ctime;
1463  dst->st_birthtim.tv_nsec = src->st_ctimensec;
1464  dst->st_flags = 0;
1465  dst->st_gen = 0;
1466#elif !defined(_AIX) &&         \
1467    !defined(__MVS__) && (      \
1468    defined(__DragonFly__)   || \
1469    defined(__FreeBSD__)     || \
1470    defined(__OpenBSD__)     || \
1471    defined(__NetBSD__)      || \
1472    defined(_GNU_SOURCE)     || \
1473    defined(_BSD_SOURCE)     || \
1474    defined(_SVID_SOURCE)    || \
1475    defined(_XOPEN_SOURCE)   || \
1476    defined(_DEFAULT_SOURCE))
1477  dst->st_atim.tv_sec = src->st_atim.tv_sec;
1478  dst->st_atim.tv_nsec = src->st_atim.tv_nsec;
1479  dst->st_mtim.tv_sec = src->st_mtim.tv_sec;
1480  dst->st_mtim.tv_nsec = src->st_mtim.tv_nsec;
1481  dst->st_ctim.tv_sec = src->st_ctim.tv_sec;
1482  dst->st_ctim.tv_nsec = src->st_ctim.tv_nsec;
1483# if defined(__FreeBSD__)    || \
1484     defined(__NetBSD__)
1485  dst->st_birthtim.tv_sec = src->st_birthtim.tv_sec;
1486  dst->st_birthtim.tv_nsec = src->st_birthtim.tv_nsec;
1487  dst->st_flags = src->st_flags;
1488  dst->st_gen = src->st_gen;
1489# else
1490  dst->st_birthtim.tv_sec = src->st_ctim.tv_sec;
1491  dst->st_birthtim.tv_nsec = src->st_ctim.tv_nsec;
1492  dst->st_flags = 0;
1493  dst->st_gen = 0;
1494# endif
1495#else
1496  dst->st_atim.tv_sec = src->st_atime;
1497  dst->st_atim.tv_nsec = 0;
1498  dst->st_mtim.tv_sec = src->st_mtime;
1499  dst->st_mtim.tv_nsec = 0;
1500  dst->st_ctim.tv_sec = src->st_ctime;
1501  dst->st_ctim.tv_nsec = 0;
1502  dst->st_birthtim.tv_sec = src->st_ctime;
1503  dst->st_birthtim.tv_nsec = 0;
1504  dst->st_flags = 0;
1505  dst->st_gen = 0;
1506#endif
1507}
1508
1509
1510static int uv__fs_statx(int fd,
1511                        const char* path,
1512                        int is_fstat,
1513                        int is_lstat,
1514                        uv_stat_t* buf) {
1515  STATIC_ASSERT(UV_ENOSYS != -1);
1516#ifdef __linux__
1517  static int no_statx;
1518  struct uv__statx statxbuf;
1519  int dirfd;
1520  int flags;
1521  int mode;
1522  int rc;
1523
1524  if (uv__load_relaxed(&no_statx))
1525    return UV_ENOSYS;
1526
1527  dirfd = AT_FDCWD;
1528  flags = 0; /* AT_STATX_SYNC_AS_STAT */
1529  mode = 0xFFF; /* STATX_BASIC_STATS + STATX_BTIME */
1530
1531  if (is_fstat) {
1532    dirfd = fd;
1533    flags |= 0x1000; /* AT_EMPTY_PATH */
1534  }
1535
1536  if (is_lstat)
1537    flags |= AT_SYMLINK_NOFOLLOW;
1538
1539  rc = uv__statx(dirfd, path, flags, mode, &statxbuf);
1540
1541  switch (rc) {
1542  case 0:
1543    break;
1544  case -1:
1545    /* EPERM happens when a seccomp filter rejects the system call.
1546     * Has been observed with libseccomp < 2.3.3 and docker < 18.04.
1547     * EOPNOTSUPP is used on DVS exported filesystems
1548     */
1549    if (errno != EINVAL && errno != EPERM && errno != ENOSYS && errno != EOPNOTSUPP)
1550      return -1;
1551    /* Fall through. */
1552  default:
1553    /* Normally on success, zero is returned and On error, -1 is returned.
1554     * Observed on S390 RHEL running in a docker container with statx not
1555     * implemented, rc might return 1 with 0 set as the error code in which
1556     * case we return ENOSYS.
1557     */
1558    uv__store_relaxed(&no_statx, 1);
1559    return UV_ENOSYS;
1560  }
1561
1562  buf->st_dev = makedev(statxbuf.stx_dev_major, statxbuf.stx_dev_minor);
1563  buf->st_mode = statxbuf.stx_mode;
1564  buf->st_nlink = statxbuf.stx_nlink;
1565  buf->st_uid = statxbuf.stx_uid;
1566  buf->st_gid = statxbuf.stx_gid;
1567  buf->st_rdev = makedev(statxbuf.stx_rdev_major, statxbuf.stx_rdev_minor);
1568  buf->st_ino = statxbuf.stx_ino;
1569  buf->st_size = statxbuf.stx_size;
1570  buf->st_blksize = statxbuf.stx_blksize;
1571  buf->st_blocks = statxbuf.stx_blocks;
1572  buf->st_atim.tv_sec = statxbuf.stx_atime.tv_sec;
1573  buf->st_atim.tv_nsec = statxbuf.stx_atime.tv_nsec;
1574  buf->st_mtim.tv_sec = statxbuf.stx_mtime.tv_sec;
1575  buf->st_mtim.tv_nsec = statxbuf.stx_mtime.tv_nsec;
1576  buf->st_ctim.tv_sec = statxbuf.stx_ctime.tv_sec;
1577  buf->st_ctim.tv_nsec = statxbuf.stx_ctime.tv_nsec;
1578  buf->st_birthtim.tv_sec = statxbuf.stx_btime.tv_sec;
1579  buf->st_birthtim.tv_nsec = statxbuf.stx_btime.tv_nsec;
1580  buf->st_flags = 0;
1581  buf->st_gen = 0;
1582
1583  return 0;
1584#else
1585  return UV_ENOSYS;
1586#endif /* __linux__ */
1587}
1588
1589
1590static int uv__fs_stat(const char *path, uv_stat_t *buf) {
1591  struct stat pbuf;
1592  int ret;
1593
1594  ret = uv__fs_statx(-1, path, /* is_fstat */ 0, /* is_lstat */ 0, buf);
1595  if (ret != UV_ENOSYS)
1596    return ret;
1597
1598  ret = stat(path, &pbuf);
1599  if (ret == 0)
1600    uv__to_stat(&pbuf, buf);
1601
1602  return ret;
1603}
1604
1605
1606static int uv__fs_lstat(const char *path, uv_stat_t *buf) {
1607  struct stat pbuf;
1608  int ret;
1609
1610  ret = uv__fs_statx(-1, path, /* is_fstat */ 0, /* is_lstat */ 1, buf);
1611  if (ret != UV_ENOSYS)
1612    return ret;
1613
1614  ret = lstat(path, &pbuf);
1615  if (ret == 0)
1616    uv__to_stat(&pbuf, buf);
1617
1618  return ret;
1619}
1620
1621
1622static int uv__fs_fstat(int fd, uv_stat_t *buf) {
1623  struct stat pbuf;
1624  int ret;
1625
1626  ret = uv__fs_statx(fd, "", /* is_fstat */ 1, /* is_lstat */ 0, buf);
1627  if (ret != UV_ENOSYS)
1628    return ret;
1629
1630  ret = fstat(fd, &pbuf);
1631  if (ret == 0)
1632    uv__to_stat(&pbuf, buf);
1633
1634  return ret;
1635}
1636
1637static size_t uv__fs_buf_offset(uv_buf_t* bufs, size_t size) {
1638  size_t offset;
1639  /* Figure out which bufs are done */
1640  for (offset = 0; size > 0 && bufs[offset].len <= size; ++offset)
1641    size -= bufs[offset].len;
1642
1643  /* Fix a partial read/write */
1644  if (size > 0) {
1645    bufs[offset].base += size;
1646    bufs[offset].len -= size;
1647  }
1648  return offset;
1649}
1650
1651static ssize_t uv__fs_write_all(uv_fs_t* req) {
1652  unsigned int iovmax;
1653  unsigned int nbufs;
1654  uv_buf_t* bufs;
1655  ssize_t total;
1656  ssize_t result;
1657
1658  iovmax = uv__getiovmax();
1659  nbufs = req->nbufs;
1660  bufs = req->bufs;
1661  total = 0;
1662
1663  while (nbufs > 0) {
1664    req->nbufs = nbufs;
1665    if (req->nbufs > iovmax)
1666      req->nbufs = iovmax;
1667
1668    do
1669      result = uv__fs_write(req);
1670    while (result < 0 && errno == EINTR);
1671
1672    if (result <= 0) {
1673      if (total == 0)
1674        total = result;
1675      break;
1676    }
1677
1678    if (req->off >= 0)
1679      req->off += result;
1680
1681    req->nbufs = uv__fs_buf_offset(req->bufs, result);
1682    req->bufs += req->nbufs;
1683    nbufs -= req->nbufs;
1684    total += result;
1685  }
1686
1687  if (bufs != req->bufsml)
1688    uv__free(bufs);
1689
1690  req->bufs = NULL;
1691  req->nbufs = 0;
1692
1693  return total;
1694}
1695
1696
1697static void uv__fs_work(struct uv__work* w) {
1698  int retry_on_eintr;
1699  uv_fs_t* req;
1700  ssize_t r;
1701
1702  req = container_of(w, uv_fs_t, work_req);
1703  retry_on_eintr = !(req->fs_type == UV_FS_CLOSE ||
1704                     req->fs_type == UV_FS_READ);
1705
1706  do {
1707    errno = 0;
1708
1709#define X(type, action)                                                       \
1710  case UV_FS_ ## type:                                                        \
1711    r = action;                                                               \
1712    break;
1713
1714    switch (req->fs_type) {
1715    X(ACCESS, access(req->path, req->flags));
1716    X(CHMOD, chmod(req->path, req->mode));
1717    X(CHOWN, chown(req->path, req->uid, req->gid));
1718    X(CLOSE, uv__fs_close(req->file));
1719    X(COPYFILE, uv__fs_copyfile(req));
1720    X(FCHMOD, fchmod(req->file, req->mode));
1721    X(FCHOWN, fchown(req->file, req->uid, req->gid));
1722    X(LCHOWN, lchown(req->path, req->uid, req->gid));
1723    X(FDATASYNC, uv__fs_fdatasync(req));
1724    X(FSTAT, uv__fs_fstat(req->file, &req->statbuf));
1725    X(FSYNC, uv__fs_fsync(req));
1726    X(FTRUNCATE, ftruncate(req->file, req->off));
1727    X(FUTIME, uv__fs_futime(req));
1728    X(LUTIME, uv__fs_lutime(req));
1729    X(LSTAT, uv__fs_lstat(req->path, &req->statbuf));
1730    X(LINK, link(req->path, req->new_path));
1731    X(MKDIR, mkdir(req->path, req->mode));
1732    X(MKDTEMP, uv__fs_mkdtemp(req));
1733    X(MKSTEMP, uv__fs_mkstemp(req));
1734    X(OPEN, uv__fs_open(req));
1735    X(READ, uv__fs_read(req));
1736    X(SCANDIR, uv__fs_scandir(req));
1737    X(OPENDIR, uv__fs_opendir(req));
1738    X(READDIR, uv__fs_readdir(req));
1739    X(CLOSEDIR, uv__fs_closedir(req));
1740    X(READLINK, uv__fs_readlink(req));
1741    X(REALPATH, uv__fs_realpath(req));
1742    X(RENAME, rename(req->path, req->new_path));
1743    X(RMDIR, rmdir(req->path));
1744    X(SENDFILE, uv__fs_sendfile(req));
1745    X(STAT, uv__fs_stat(req->path, &req->statbuf));
1746    X(STATFS, uv__fs_statfs(req));
1747    X(SYMLINK, symlink(req->path, req->new_path));
1748    X(UNLINK, unlink(req->path));
1749    X(UTIME, uv__fs_utime(req));
1750    X(WRITE, uv__fs_write_all(req));
1751    default: abort();
1752    }
1753#undef X
1754  } while (r == -1 && errno == EINTR && retry_on_eintr);
1755
1756  if (r == -1)
1757    req->result = UV__ERR(errno);
1758  else
1759    req->result = r;
1760
1761  if (r == 0 && (req->fs_type == UV_FS_STAT ||
1762                 req->fs_type == UV_FS_FSTAT ||
1763                 req->fs_type == UV_FS_LSTAT)) {
1764    req->ptr = &req->statbuf;
1765  }
1766}
1767
1768
1769static void uv__fs_done(struct uv__work* w, int status) {
1770  uv_fs_t* req;
1771
1772  req = container_of(w, uv_fs_t, work_req);
1773  uv__req_unregister(req->loop, req);
1774
1775  if (status == UV_ECANCELED) {
1776    assert(req->result == 0);
1777    req->result = UV_ECANCELED;
1778  }
1779
1780  req->cb(req);
1781}
1782
1783
1784int uv_fs_access(uv_loop_t* loop,
1785                 uv_fs_t* req,
1786                 const char* path,
1787                 int flags,
1788                 uv_fs_cb cb) {
1789  INIT(ACCESS);
1790  PATH;
1791  req->flags = flags;
1792  POST;
1793}
1794
1795
1796int uv_fs_chmod(uv_loop_t* loop,
1797                uv_fs_t* req,
1798                const char* path,
1799                int mode,
1800                uv_fs_cb cb) {
1801  INIT(CHMOD);
1802  PATH;
1803  req->mode = mode;
1804  POST;
1805}
1806
1807
1808int uv_fs_chown(uv_loop_t* loop,
1809                uv_fs_t* req,
1810                const char* path,
1811                uv_uid_t uid,
1812                uv_gid_t gid,
1813                uv_fs_cb cb) {
1814  INIT(CHOWN);
1815  PATH;
1816  req->uid = uid;
1817  req->gid = gid;
1818  POST;
1819}
1820
1821
1822int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
1823  INIT(CLOSE);
1824  req->file = file;
1825  POST;
1826}
1827
1828
1829int uv_fs_fchmod(uv_loop_t* loop,
1830                 uv_fs_t* req,
1831                 uv_file file,
1832                 int mode,
1833                 uv_fs_cb cb) {
1834  INIT(FCHMOD);
1835  req->file = file;
1836  req->mode = mode;
1837  POST;
1838}
1839
1840
1841int uv_fs_fchown(uv_loop_t* loop,
1842                 uv_fs_t* req,
1843                 uv_file file,
1844                 uv_uid_t uid,
1845                 uv_gid_t gid,
1846                 uv_fs_cb cb) {
1847  INIT(FCHOWN);
1848  req->file = file;
1849  req->uid = uid;
1850  req->gid = gid;
1851  POST;
1852}
1853
1854
1855int uv_fs_lchown(uv_loop_t* loop,
1856                 uv_fs_t* req,
1857                 const char* path,
1858                 uv_uid_t uid,
1859                 uv_gid_t gid,
1860                 uv_fs_cb cb) {
1861  INIT(LCHOWN);
1862  PATH;
1863  req->uid = uid;
1864  req->gid = gid;
1865  POST;
1866}
1867
1868
1869int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
1870  INIT(FDATASYNC);
1871  req->file = file;
1872  POST;
1873}
1874
1875
1876int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
1877  INIT(FSTAT);
1878  req->file = file;
1879  POST;
1880}
1881
1882
1883int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
1884  INIT(FSYNC);
1885  req->file = file;
1886  POST;
1887}
1888
1889
1890int uv_fs_ftruncate(uv_loop_t* loop,
1891                    uv_fs_t* req,
1892                    uv_file file,
1893                    int64_t off,
1894                    uv_fs_cb cb) {
1895  INIT(FTRUNCATE);
1896  req->file = file;
1897  req->off = off;
1898  POST;
1899}
1900
1901
1902int uv_fs_futime(uv_loop_t* loop,
1903                 uv_fs_t* req,
1904                 uv_file file,
1905                 double atime,
1906                 double mtime,
1907                 uv_fs_cb cb) {
1908  INIT(FUTIME);
1909  req->file = file;
1910  req->atime = atime;
1911  req->mtime = mtime;
1912  POST;
1913}
1914
1915int uv_fs_lutime(uv_loop_t* loop,
1916                 uv_fs_t* req,
1917                 const char* path,
1918                 double atime,
1919                 double mtime,
1920                 uv_fs_cb cb) {
1921  INIT(LUTIME);
1922  PATH;
1923  req->atime = atime;
1924  req->mtime = mtime;
1925  POST;
1926}
1927
1928
1929int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
1930  INIT(LSTAT);
1931  PATH;
1932  POST;
1933}
1934
1935
1936int uv_fs_link(uv_loop_t* loop,
1937               uv_fs_t* req,
1938               const char* path,
1939               const char* new_path,
1940               uv_fs_cb cb) {
1941  INIT(LINK);
1942  PATH2;
1943  POST;
1944}
1945
1946
1947int uv_fs_mkdir(uv_loop_t* loop,
1948                uv_fs_t* req,
1949                const char* path,
1950                int mode,
1951                uv_fs_cb cb) {
1952  INIT(MKDIR);
1953  PATH;
1954  req->mode = mode;
1955  POST;
1956}
1957
1958
1959int uv_fs_mkdtemp(uv_loop_t* loop,
1960                  uv_fs_t* req,
1961                  const char* tpl,
1962                  uv_fs_cb cb) {
1963  INIT(MKDTEMP);
1964  req->path = uv__strdup(tpl);
1965  if (req->path == NULL)
1966    return UV_ENOMEM;
1967  POST;
1968}
1969
1970
1971int uv_fs_mkstemp(uv_loop_t* loop,
1972                  uv_fs_t* req,
1973                  const char* tpl,
1974                  uv_fs_cb cb) {
1975  INIT(MKSTEMP);
1976  req->path = uv__strdup(tpl);
1977  if (req->path == NULL)
1978    return UV_ENOMEM;
1979  POST;
1980}
1981
1982
1983int uv_fs_open(uv_loop_t* loop,
1984               uv_fs_t* req,
1985               const char* path,
1986               int flags,
1987               int mode,
1988               uv_fs_cb cb) {
1989  INIT(OPEN);
1990  PATH;
1991  req->flags = flags;
1992  req->mode = mode;
1993  POST;
1994}
1995
1996
1997int uv_fs_read(uv_loop_t* loop, uv_fs_t* req,
1998               uv_file file,
1999               const uv_buf_t bufs[],
2000               unsigned int nbufs,
2001               int64_t off,
2002               uv_fs_cb cb) {
2003  INIT(READ);
2004
2005  if (bufs == NULL || nbufs == 0)
2006    return UV_EINVAL;
2007
2008  req->file = file;
2009
2010  req->nbufs = nbufs;
2011  req->bufs = req->bufsml;
2012  if (nbufs > ARRAY_SIZE(req->bufsml))
2013    req->bufs = uv__malloc(nbufs * sizeof(*bufs));
2014
2015  if (req->bufs == NULL)
2016    return UV_ENOMEM;
2017
2018  memcpy(req->bufs, bufs, nbufs * sizeof(*bufs));
2019
2020  req->off = off;
2021  POST;
2022}
2023
2024
2025int uv_fs_scandir(uv_loop_t* loop,
2026                  uv_fs_t* req,
2027                  const char* path,
2028                  int flags,
2029                  uv_fs_cb cb) {
2030  INIT(SCANDIR);
2031  PATH;
2032  req->flags = flags;
2033  POST;
2034}
2035
2036int uv_fs_opendir(uv_loop_t* loop,
2037                  uv_fs_t* req,
2038                  const char* path,
2039                  uv_fs_cb cb) {
2040  INIT(OPENDIR);
2041  PATH;
2042  POST;
2043}
2044
2045int uv_fs_readdir(uv_loop_t* loop,
2046                  uv_fs_t* req,
2047                  uv_dir_t* dir,
2048                  uv_fs_cb cb) {
2049  INIT(READDIR);
2050
2051  if (dir == NULL || dir->dir == NULL || dir->dirents == NULL)
2052    return UV_EINVAL;
2053
2054  req->ptr = dir;
2055  POST;
2056}
2057
2058int uv_fs_closedir(uv_loop_t* loop,
2059                   uv_fs_t* req,
2060                   uv_dir_t* dir,
2061                   uv_fs_cb cb) {
2062  INIT(CLOSEDIR);
2063
2064  if (dir == NULL)
2065    return UV_EINVAL;
2066
2067  req->ptr = dir;
2068  POST;
2069}
2070
2071int uv_fs_readlink(uv_loop_t* loop,
2072                   uv_fs_t* req,
2073                   const char* path,
2074                   uv_fs_cb cb) {
2075  INIT(READLINK);
2076  PATH;
2077  POST;
2078}
2079
2080
2081int uv_fs_realpath(uv_loop_t* loop,
2082                  uv_fs_t* req,
2083                  const char * path,
2084                  uv_fs_cb cb) {
2085  INIT(REALPATH);
2086  PATH;
2087  POST;
2088}
2089
2090
2091int uv_fs_rename(uv_loop_t* loop,
2092                 uv_fs_t* req,
2093                 const char* path,
2094                 const char* new_path,
2095                 uv_fs_cb cb) {
2096  INIT(RENAME);
2097  PATH2;
2098  POST;
2099}
2100
2101
2102int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
2103  INIT(RMDIR);
2104  PATH;
2105  POST;
2106}
2107
2108
2109int uv_fs_sendfile(uv_loop_t* loop,
2110                   uv_fs_t* req,
2111                   uv_file out_fd,
2112                   uv_file in_fd,
2113                   int64_t off,
2114                   size_t len,
2115                   uv_fs_cb cb) {
2116  INIT(SENDFILE);
2117  req->flags = in_fd; /* hack */
2118  req->file = out_fd;
2119  req->off = off;
2120  req->bufsml[0].len = len;
2121  POST;
2122}
2123
2124
2125int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
2126  INIT(STAT);
2127  PATH;
2128  POST;
2129}
2130
2131
2132int uv_fs_symlink(uv_loop_t* loop,
2133                  uv_fs_t* req,
2134                  const char* path,
2135                  const char* new_path,
2136                  int flags,
2137                  uv_fs_cb cb) {
2138  INIT(SYMLINK);
2139  PATH2;
2140  req->flags = flags;
2141  POST;
2142}
2143
2144
2145int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
2146  INIT(UNLINK);
2147  PATH;
2148  POST;
2149}
2150
2151
2152int uv_fs_utime(uv_loop_t* loop,
2153                uv_fs_t* req,
2154                const char* path,
2155                double atime,
2156                double mtime,
2157                uv_fs_cb cb) {
2158  INIT(UTIME);
2159  PATH;
2160  req->atime = atime;
2161  req->mtime = mtime;
2162  POST;
2163}
2164
2165
2166int uv_fs_write(uv_loop_t* loop,
2167                uv_fs_t* req,
2168                uv_file file,
2169                const uv_buf_t bufs[],
2170                unsigned int nbufs,
2171                int64_t off,
2172                uv_fs_cb cb) {
2173  INIT(WRITE);
2174
2175  if (bufs == NULL || nbufs == 0)
2176    return UV_EINVAL;
2177
2178  req->file = file;
2179
2180  req->nbufs = nbufs;
2181  req->bufs = req->bufsml;
2182  if (nbufs > ARRAY_SIZE(req->bufsml))
2183    req->bufs = uv__malloc(nbufs * sizeof(*bufs));
2184
2185  if (req->bufs == NULL)
2186    return UV_ENOMEM;
2187
2188  memcpy(req->bufs, bufs, nbufs * sizeof(*bufs));
2189
2190  req->off = off;
2191  POST;
2192}
2193
2194
2195void uv_fs_req_cleanup(uv_fs_t* req) {
2196  if (req == NULL)
2197    return;
2198
2199  /* Only necessary for asychronous requests, i.e., requests with a callback.
2200   * Synchronous ones don't copy their arguments and have req->path and
2201   * req->new_path pointing to user-owned memory.  UV_FS_MKDTEMP and
2202   * UV_FS_MKSTEMP are the exception to the rule, they always allocate memory.
2203   */
2204  if (req->path != NULL &&
2205      (req->cb != NULL ||
2206        req->fs_type == UV_FS_MKDTEMP || req->fs_type == UV_FS_MKSTEMP))
2207    uv__free((void*) req->path);  /* Memory is shared with req->new_path. */
2208
2209  req->path = NULL;
2210  req->new_path = NULL;
2211
2212  if (req->fs_type == UV_FS_READDIR && req->ptr != NULL)
2213    uv__fs_readdir_cleanup(req);
2214
2215  if (req->fs_type == UV_FS_SCANDIR && req->ptr != NULL)
2216    uv__fs_scandir_cleanup(req);
2217
2218  if (req->bufs != req->bufsml)
2219    uv__free(req->bufs);
2220  req->bufs = NULL;
2221
2222  if (req->fs_type != UV_FS_OPENDIR && req->ptr != &req->statbuf)
2223    uv__free(req->ptr);
2224  req->ptr = NULL;
2225}
2226
2227
2228int uv_fs_copyfile(uv_loop_t* loop,
2229                   uv_fs_t* req,
2230                   const char* path,
2231                   const char* new_path,
2232                   int flags,
2233                   uv_fs_cb cb) {
2234  INIT(COPYFILE);
2235
2236  if (flags & ~(UV_FS_COPYFILE_EXCL |
2237                UV_FS_COPYFILE_FICLONE |
2238                UV_FS_COPYFILE_FICLONE_FORCE)) {
2239    return UV_EINVAL;
2240  }
2241
2242  PATH2;
2243  req->flags = flags;
2244  POST;
2245}
2246
2247
2248int uv_fs_statfs(uv_loop_t* loop,
2249                 uv_fs_t* req,
2250                 const char* path,
2251                 uv_fs_cb cb) {
2252  INIT(STATFS);
2253  PATH;
2254  POST;
2255}
2256
2257int uv_fs_get_system_error(const uv_fs_t* req) {
2258  return -req->result;
2259}
2260