diff options
| author | Hristo Venev <hristo@venev.name> | 2022-05-07 20:07:00 +0300 | 
|---|---|---|
| committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2022-12-19 16:13:58 +0100 | 
| commit | 852cb3b0e267dd2ddfd2eeef6275435098c606e7 (patch) | |
| tree | 1f2c04d6da8bbb1064e18aa1b83cc14c2203c333 | |
| parent | global: use release_commit_memory() (diff) | |
| download | cgit-852cb3b0e267dd2ddfd2eeef6275435098c606e7.tar.gz cgit-852cb3b0e267dd2ddfd2eeef6275435098c606e7.tar.bz2 cgit-852cb3b0e267dd2ddfd2eeef6275435098c606e7.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 '')
| -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)  /* Print the content of the active cache slot (but skip the key). */  static int print_slot(struct cache_slot *slot)  { +	off_t off;  #ifdef HAVE_LINUX_SENDFILE -	off_t start_off; -	int ret; +	off_t size; +#endif + +	off = slot->keylen + 1; -	start_off = slot->keylen + 1; +#ifdef HAVE_LINUX_SENDFILE +	size = slot->cache_st.st_size;  	do { -		ret = sendfile(STDOUT_FILENO, slot->cache_fd, &start_off, -				slot->cache_st.st_size - start_off); +		ssize_t ret; +		ret = sendfile(STDOUT_FILENO, slot->cache_fd, &off, size - off);  		if (ret < 0) {  			if (errno == EAGAIN || errno == EINTR)  				continue; +			/* Fall back to read/write on EINVAL or ENOSYS */ +			if (errno == EINVAL || errno == ENOSYS) +				break;  			return errno;  		} -		return 0; +		if (off == size) +			return 0;  	} while (1); -#else -	ssize_t i, j; +#endif -	i = lseek(slot->cache_fd, slot->keylen + 1, SEEK_SET); -	if (i != slot->keylen + 1) +	if (lseek(slot->cache_fd, off, SEEK_SET) != off)  		return errno;  	do { -		i = j = xread(slot->cache_fd, slot->buf, sizeof(slot->buf)); -		if (i > 0) -			j = xwrite(STDOUT_FILENO, slot->buf, i); -	} while (i > 0 && j == i); - -	if (i < 0 || j != i) -		return errno; -	else -		return 0; -#endif +		ssize_t ret; +		ret = xread(slot->cache_fd, slot->buf, sizeof(slot->buf)); +		if (ret < 0) +			return errno; +		if (ret == 0) +			return 0; +		if (write_in_full(STDOUT_FILENO, slot->buf, ret) < 0) +			return errno; +	} while (1);  }  /* Check if the slot has expired */ | 
