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 | |
| 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>
| -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 */ |
