diff options
author | Hristo Venev | 2022-05-07 20:07:00 +0300 |
---|---|---|
committer | June McEnroe | 2022-05-13 16:07:35 -0400 |
commit | 695515801c9241f106f6f99b04dc0e84439fdea5 (patch) | |
tree | 4d30ba8c55f0eb64ab6288dff16417accecf904e | |
parent | git: update to v2.36.1 (diff) | |
download | cgit-695515801c9241f106f6f99b04dc0e84439fdea5.tar.gz cgit-695515801c9241f106f6f99b04dc0e84439fdea5.zip |
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>
-rw-r--r-- | cache.c | 45 |
1 files changed, 25 insertions, 20 deletions
diff --git a/cache.c b/cache.c index 578b73b..5937254 100644 --- a/cache.c +++ b/cache.c | |||
@@ -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 */ |