| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "build-defs.h" | ||
| 2 | #include <sys/stat.h> | ||
| 3 | #include "fd.h" | ||
| 4 | #include "debug.h" | ||
| 5 | #include "xreadwrite.h" | ||
| 6 | |||
| 7 | ✗ | static bool cloexec(int fd) {return fd_set_cloexec(fd, true);} | |
| 8 | ✗ | static bool nonblock(int fd) {return fd_set_nonblock(fd, true);} | |
| 9 | |||
| 10 | 42 | int xpipe2(int fd[static 2], int flags) | |
| 11 | { | ||
| 12 | 42 | BUG_ON((flags & (O_CLOEXEC | O_NONBLOCK)) != flags); | |
| 13 | |||
| 14 | #if HAVE_PIPE2 | ||
| 15 | // If pipe2() fails with ENOSYS, it means the function is just a stub | ||
| 16 | // and not actually supported. In that case, the pure POSIX fallback | ||
| 17 | // implementation should be tried instead. In other cases, the failure | ||
| 18 | // is probably caused by a normal error condition. | ||
| 19 | 42 | int r = pipe2(fd, flags); | |
| 20 |
1/4✗ Branch 0 (5→6) not taken.
✓ Branch 1 (5→22) taken 42 times.
✗ Branch 2 (6→7) not taken.
✗ Branch 3 (6→22) not taken.
|
42 | if (likely(r == 0 || errno != ENOSYS)) { |
| 21 | return r; | ||
| 22 | } | ||
| 23 | #endif | ||
| 24 | |||
| 25 | // NOLINTNEXTLINE(android-cloexec-pipe) | ||
| 26 | ✗ | if (unlikely(pipe(fd) != 0)) { | |
| 27 | return -1; | ||
| 28 | } | ||
| 29 | |||
| 30 | ✗ | bool ok = !(flags & O_CLOEXEC) || (cloexec(fd[0]) && cloexec(fd[1])); | |
| 31 | ✗ | ok = ok && (!(flags & O_NONBLOCK) || (nonblock(fd[0]) && nonblock(fd[1]))); | |
| 32 | ✗ | if (unlikely(!ok)) { | |
| 33 | ✗ | xclose(fd[0]); | |
| 34 | ✗ | xclose(fd[1]); | |
| 35 | ✗ | return -1; | |
| 36 | } | ||
| 37 | |||
| 38 | return 0; | ||
| 39 | } | ||
| 40 | |||
| 41 | 63 | int xdup3(int oldfd, int newfd, int flags) | |
| 42 | { | ||
| 43 | 63 | BUG_ON((flags & O_CLOEXEC) != flags); | |
| 44 | 63 | int fd; | |
| 45 | |||
| 46 | #if HAVE_DUP3 | ||
| 47 | 126 | do { | |
| 48 | 63 | fd = dup3(oldfd, newfd, flags); | |
| 49 |
1/4✗ Branch 0 (5→6) not taken.
✓ Branch 1 (5→7) taken 63 times.
✗ Branch 2 (6→4) not taken.
✗ Branch 3 (6→7) not taken.
|
63 | } while (unlikely(fd < 0 && errno == EINTR)); |
| 50 | |||
| 51 |
1/4✗ Branch 0 (7→8) not taken.
✓ Branch 1 (7→17) taken 63 times.
✗ Branch 2 (8→9) not taken.
✗ Branch 3 (8→17) not taken.
|
63 | if (fd != -1 || errno != ENOSYS) { |
| 52 | return fd; | ||
| 53 | } | ||
| 54 | |||
| 55 | // If execution reaches this point, dup3() failed with ENOSYS | ||
| 56 | // ("function not supported"), so we fall through to the pure | ||
| 57 | // POSIX implementation below. | ||
| 58 | #endif | ||
| 59 | |||
| 60 | ✗ | if (unlikely(oldfd == newfd)) { | |
| 61 | // Replicate dup3() behaviour: | ||
| 62 | ✗ | errno = EINVAL; | |
| 63 | ✗ | return -1; | |
| 64 | } | ||
| 65 | |||
| 66 | ✗ | do { | |
| 67 | ✗ | fd = dup2(oldfd, newfd); | |
| 68 | ✗ | } while (unlikely(fd < 0 && errno == EINTR)); | |
| 69 | |||
| 70 | ✗ | if (fd >= 0 && (flags & O_CLOEXEC)) { | |
| 71 | ✗ | cloexec(fd); | |
| 72 | } | ||
| 73 | |||
| 74 | return fd; | ||
| 75 | } | ||
| 76 | |||
| 77 | 2 | int xfchown(int fd, uid_t owner, gid_t group) | |
| 78 | { | ||
| 79 | 2 | int r; | |
| 80 | 4 | do { | |
| 81 | 2 | r = fchown(fd, owner, group); | |
| 82 |
1/4✗ Branch 0 (4→5) not taken.
✓ Branch 1 (4→6) taken 2 times.
✗ Branch 2 (5→3) not taken.
✗ Branch 3 (5→6) not taken.
|
2 | } while (unlikely(r != 0 && errno == EINTR)); |
| 83 | 2 | return r; | |
| 84 | } | ||
| 85 | |||
| 86 | 21 | int xfchmod(int fd, mode_t mode) | |
| 87 | { | ||
| 88 | 21 | int r; | |
| 89 | 42 | do { | |
| 90 | 21 | r = fchmod(fd, mode); | |
| 91 |
1/4✗ Branch 0 (4→5) not taken.
✓ Branch 1 (4→6) taken 21 times.
✗ Branch 2 (5→3) not taken.
✗ Branch 3 (5→6) not taken.
|
21 | } while (unlikely(r != 0 && errno == EINTR)); |
| 92 | 21 | return r; | |
| 93 | } | ||
| 94 | |||
| 95 | 21 | int xftruncate(int fd, off_t length) | |
| 96 | { | ||
| 97 | 21 | int r; | |
| 98 | 42 | do { | |
| 99 | 21 | r = ftruncate(fd, length); | |
| 100 |
1/4✗ Branch 0 (4→5) not taken.
✓ Branch 1 (4→6) taken 21 times.
✗ Branch 2 (5→3) not taken.
✗ Branch 3 (5→6) not taken.
|
21 | } while (unlikely(r != 0 && errno == EINTR)); |
| 101 | 21 | return r; | |
| 102 | } | ||
| 103 | |||
| 104 | ✗ | int xfsync(int fd) | |
| 105 | { | ||
| 106 | #if HAVE_FSYNC | ||
| 107 | ✗ | retry: | |
| 108 | ✗ | if (fsync(fd) == 0) { | |
| 109 | return 0; | ||
| 110 | } | ||
| 111 | |||
| 112 | ✗ | switch (errno) { | |
| 113 | // EINVAL is ignored because it just means "operation not possible | ||
| 114 | // on this descriptor" rather than indicating an actual error | ||
| 115 | case EINVAL: | ||
| 116 | case ENOTSUP: | ||
| 117 | case ENOSYS: | ||
| 118 | return 0; | ||
| 119 | ✗ | case EINTR: | |
| 120 | ✗ | goto retry; | |
| 121 | } | ||
| 122 | |||
| 123 | ✗ | return -1; | |
| 124 | #else | ||
| 125 | (void)fd; | ||
| 126 | return 0; | ||
| 127 | #endif | ||
| 128 | } | ||
| 129 |