Coverage Report

Created: 2026-10-28 06:38

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