dte test coverage


Directory: ./
File: src/util/fd.c
Date: 2025-09-07 23:01:39
Exec Total Coverage
Lines: 29 53 54.7%
Functions: 5 8 62.5%
Branches: 6 53 11.3%

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