diff options
author | Hristo Venev | 2022-05-07 20:07:00 +0300 |
---|---|---|
committer | Yigit Sever | 2023-07-21 03:03:51 +0300 |
commit | 1bb668962658b4e805f56eae0e2585ade645c116 (patch) | |
tree | 74196adf2898e09a0b349449b8ba772503002c9c /cache.c | |
parent | d4d0a488eb6f9456df2fa7fc9348c5076ee7dfab (diff) | |
download | cgit-1bb668962658b4e805f56eae0e2585ade645c116.tar.gz cgit-1bb668962658b4e805f56eae0e2585ade645c116.tar.bz2 cgit-1bb668962658b4e805f56eae0e2585ade645c116.zip |
cache: tolerate short writes in print_slot
sendfile() can return after a short read/write, so we may need to call
it more than once. As suggested in the manual page, we fall back to
read/write if sendfile fails with EINVAL or ENOSYS.
On the read/write path, use write_in_full which deals with short writes.
Signed-off-by: Hristo Venev <hristo@venev.name>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'cache.c')
-rw-r--r-- | cache.c | 45 |
1 files changed, 25 insertions, 20 deletions
@@ -85,40 +85,45 @@ static int close_slot(struct cache_slot *slot) | |||
85 | /* Print the content of the active cache slot (but skip the key). */ | 85 | /* Print the content of the active cache slot (but skip the key). */ |
86 | static int print_slot(struct cache_slot *slot) | 86 | static int print_slot(struct cache_slot *slot) |
87 | { | 87 | { |
88 | off_t off; | ||
88 | #ifdef HAVE_LINUX_SENDFILE | 89 | #ifdef HAVE_LINUX_SENDFILE |
89 | off_t start_off; | 90 | off_t size; |
90 | int ret; | 91 | #endif |
92 | |||
93 | off = slot->keylen + 1; | ||
91 | 94 | ||
92 | start_off = slot->keylen + 1; | 95 | #ifdef HAVE_LINUX_SENDFILE |
96 | size = slot->cache_st.st_size; | ||
93 | 97 | ||
94 | do { | 98 | do { |
95 | ret = sendfile(STDOUT_FILENO, slot->cache_fd, &start_off, | 99 | ssize_t ret; |
96 | slot->cache_st.st_size - start_off); | 100 | ret = sendfile(STDOUT_FILENO, slot->cache_fd, &off, size - off); |
97 | if (ret < 0) { | 101 | if (ret < 0) { |
98 | if (errno == EAGAIN || errno == EINTR) | 102 | if (errno == EAGAIN || errno == EINTR) |
99 | continue; | 103 | continue; |
104 | /* Fall back to read/write on EINVAL or ENOSYS */ | ||
105 | if (errno == EINVAL || errno == ENOSYS) | ||
106 | break; | ||
100 | return errno; | 107 | return errno; |
101 | } | 108 | } |
102 | return 0; | 109 | if (off == size) |
110 | return 0; | ||
103 | } while (1); | 111 | } while (1); |
104 | #else | 112 | #endif |
105 | ssize_t i, j; | ||
106 | 113 | ||
107 | i = lseek(slot->cache_fd, slot->keylen + 1, SEEK_SET); | 114 | if (lseek(slot->cache_fd, off, SEEK_SET) != off) |
108 | if (i != slot->keylen + 1) | ||
109 | return errno; | 115 | return errno; |
110 | 116 | ||
111 | do { | 117 | do { |
112 | i = j = xread(slot->cache_fd, slot->buf, sizeof(slot->buf)); | 118 | ssize_t ret; |
113 | if (i > 0) | 119 | ret = xread(slot->cache_fd, slot->buf, sizeof(slot->buf)); |
114 | j = xwrite(STDOUT_FILENO, slot->buf, i); | 120 | if (ret < 0) |
115 | } while (i > 0 && j == i); | 121 | return errno; |
116 | 122 | if (ret == 0) | |
117 | if (i < 0 || j != i) | 123 | return 0; |
118 | return errno; | 124 | if (write_in_full(STDOUT_FILENO, slot->buf, ret) < 0) |
119 | else | 125 | return errno; |
120 | return 0; | 126 | } while (1); |
121 | #endif | ||
122 | } | 127 | } |
123 | 128 | ||
124 | /* Check if the slot has expired */ | 129 | /* Check if the slot has expired */ |