dte test coverage


Directory: ./
File: src/util/xreadwrite.c
Date: 2024-12-21 16:03:22
Exec Total Coverage
Lines: 43 54 79.6%
Functions: 6 6 100.0%
Branches: 15 38 39.5%

Line Branch Exec Source
1 #include <limits.h>
2 #include <unistd.h>
3 #include "xreadwrite.h"
4
5 #if defined(__APPLE__)
6 // See: https://gitlab.com/craigbarnes/dte/-/issues/201
7 #define MAX_RW_COUNT ((size_t)INT_MAX)
8 #elif defined(__linux__) && 0x7ffff000 <= SSIZE_MAX
9 // Unlike macOS, trying to read or write more than 0x7ffff000 bytes
10 // on Linux simply causes the syscall to return (at most) the upper
11 // limit, rather than indicating an error condition. Thus, using
12 // this value here is done simply because it's a more appropriate
13 // value than SSIZE_MAX, not because it's actually needed for
14 // correct functioning of xread_all().
15 // See also:
16 // • https://man7.org/linux/man-pages/man2/read.2.html#NOTES
17 // • https://man7.org/linux/man-pages/man2/write.2.html#NOTES
18 // • https://stackoverflow.com/a/70370002
19 #define MAX_RW_COUNT ((size_t)0x7ffff000)
20 #else
21 #define MAX_RW_COUNT ((size_t)SSIZE_MAX)
22 #endif
23
24 26 ssize_t xread(int fd, void *buf, size_t count)
25 {
26 26 ssize_t r;
27 52 do {
28 26 r = read(fd, buf, count);
29
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
26 } while (unlikely(r < 0 && errno == EINTR));
30 26 return r;
31 }
32
33 4 ssize_t xwrite(int fd, const void *buf, size_t count)
34 {
35 4 ssize_t r;
36 8 do {
37 4 r = write(fd, buf, count);
38
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
4 } while (unlikely(r < 0 && errno == EINTR));
39 4 return r;
40 }
41
42 114 static size_t rwsize(size_t count)
43 {
44 114 return MIN(count, MAX_RW_COUNT);
45 }
46
47 80 ssize_t xread_all(int fd, void *buf, size_t count)
48 {
49 80 char *b = buf;
50 80 size_t pos = 0;
51 82 do {
52 82 ssize_t rc = read(fd, b + pos, rwsize(count - pos));
53
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 if (unlikely(rc < 0)) {
54 if (errno == EINTR) {
55 continue;
56 }
57 return -1;
58 }
59
2/2
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 9 times.
82 if (rc == 0) {
60 // eof
61 break;
62 }
63 73 pos += rc;
64
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 71 times.
73 } while (pos < count);
65 80 return pos;
66 }
67
68 32 ssize_t xwrite_all(int fd, const void *buf, size_t count)
69 {
70 32 const char *b = buf;
71 32 const size_t count_save = count;
72 32 do {
73 32 ssize_t rc = write(fd, b, rwsize(count));
74
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 31 times.
32 if (unlikely(rc < 0)) {
75
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (errno == EINTR) {
76 continue;
77 }
78 return -1;
79 }
80 31 b += rc;
81 31 count -= rc;
82
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31 times.
31 } while (count > 0);
83 31 return count_save;
84 }
85
86 209 int xclose(int fd)
87 {
88 209 int saved_errno = errno;
89 209 int r = close(fd);
90
3/4
✓ Branch 0 taken 194 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
209 if (likely(r == 0 || (errno != EINTR && errno != EINPROGRESS))) {
91 15 goto out;
92 }
93
94 // Treat EINPROGRESS the same as r == 0
95 // (https://git.musl-libc.org/cgit/musl/commit/?id=82dc1e2e783815e00a90cd)
96 if (errno == EINPROGRESS) {
97 r = 0;
98 goto out;
99 }
100
101 // If the first close() call failed with EINTR, retry until it succeeds or
102 // fails with a different error
103 do {
104 r = close(fd);
105 } while (r && errno == EINTR);
106
107 // On some systems, when close() fails with EINTR, the descriptor
108 // still gets closed anyway and calling close() again then fails
109 // with EBADF. This is not really an "error" that can be handled
110 // meaningfully, so we just return as if successful.
111 //
112 // Note that this is only safe to do in a single-threaded context,
113 // where there's no risk of a concurrent open() call reusing the
114 // same file descriptor.
115 //
116 // • http://www.daemonology.net/blog/2011-12-17-POSIX-close-is-broken.html
117 // • https://ewontfix.com/4/
118 // • https://sourceware.org/bugzilla/show_bug.cgi?id=14627
119 // • https://www.austingroupbugs.net/view.php?id=529#c1200
120 if (r && errno == EBADF) {
121 r = 0;
122 }
123
124 out:
125
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
209 if (r == 0) {
126 194 errno = saved_errno;
127 }
128 209 return r;
129 }
130