dte test coverage


Directory: ./
File: src/util/fd.c
Date: 2025-12-03 13:13:24
Coverage Exec Excl Total
Lines: 54.7% 29 0 53
Functions: 62.5% 5 0 8
Branches: 11.3% 6 0 53

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 5 → 6 not taken.
✓ Branch 5 → 22 taken 42 times.
✗ Branch 6 → 7 not taken.
✗ Branch 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 5 → 6 not taken.
✓ Branch 5 → 7 taken 63 times.
✗ Branch 6 → 4 not taken.
✗ Branch 6 → 7 not taken.
63 } while (unlikely(fd < 0 && errno == EINTR));
50
51
1/4
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 17 taken 63 times.
✗ Branch 8 → 9 not taken.
✗ Branch 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 4 → 5 not taken.
✓ Branch 4 → 6 taken 2 times.
✗ Branch 5 → 3 not taken.
✗ Branch 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 4 → 5 not taken.
✓ Branch 4 → 6 taken 21 times.
✗ Branch 5 → 3 not taken.
✗ Branch 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 4 → 5 not taken.
✓ Branch 4 → 6 taken 21 times.
✗ Branch 5 → 3 not taken.
✗ Branch 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