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