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