From: Andre Noll Date: Sun, 11 Dec 2011 20:12:13 +0000 (+0100) Subject: fd: Let write_all() return an error on short writes. X-Git-Tag: v0.4.10~11^2~8 X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=commitdiff_plain;h=864024c003d678dbb436cdfc1148b201e4e47018;ds=sidebyside fd: Let write_all() return an error on short writes. Short writes are often ignored because most callers of write_all() do not check the return value. Rather than fixing all callers, this patch teaches write_all() to detect short writes and return the new E_SHORT_WRITE error code in this case. Currently write_all() is a wrapper for write(), similar to write_nonblock() but lacking the safety checks of the latter. To get these safety checks, write_all() is changed to call write_nonblock(). Unfortunately, this involves some code movement. --- diff --git a/error.h b/error.h index 63d4d5db..f7216ea3 100644 --- a/error.h +++ b/error.h @@ -441,6 +441,7 @@ extern const char **para_errlist[]; PARA_ERROR(FGETS, "fgets error"), \ PARA_ERROR(EOF, "end of file"), \ PARA_ERROR(READ_PATTERN, "did not read expected pattern"), \ + PARA_ERROR(SHORT_WRITE, "unexpected short write"), \ #define ALSA_WRITE_ERRORS \ diff --git a/fd.c b/fd.c index 830b15da..01c7ed8e 100644 --- a/fd.c +++ b/fd.c @@ -18,49 +18,6 @@ #include "string.h" #include "fd.h" -/** - * Write a buffer to a file descriptor, re-write on short writes. - * - * \param fd The file descriptor. - * \param buf The buffer to be sent. - * \param len The length of \a buf. - * - * \return Standard. - */ -int write_all(int fd, const char *buf, size_t len) -{ - size_t total = len; - - assert(total); - len = 0; - while (len < total) { - int ret = write(fd, buf + len, total - len); - if (ret == -1) - return -ERRNO_TO_PARA_ERROR(errno); - len += ret; - } - return len; -} - -/** - * Send a buffer given by a format string. - * - * \param fd The file descriptor. - * \param fmt A format string. - * - * \return Standard. - */ -__printf_2_3 int write_va_buffer(int fd, const char *fmt, ...) -{ - char *msg; - int ret; - - PARA_VSPRINTF(fmt, msg); - ret = write_buffer(fd, msg); - free(msg); - return ret; -} - /** * Write a buffer to a file descriptor, re-writing on short writes. * @@ -109,6 +66,48 @@ int write_nonblock(int fd, const char *buf, size_t len) return written; } +/** + * Write all data to a file descriptor. + * + * \param fd The file descriptor. + * \param buf The buffer to be sent. + * \param len The length of \a buf. + * + * This is like \ref write_nonblock() but returns \p -E_SHORT_WRITE if not + * all data could be written. + * + * \return Number of bytes written on success, negative error code else. + */ +int write_all(int fd, const char *buf, size_t len) +{ + int ret = write_nonblock(fd, buf, len); + + if (ret < 0) + return ret; + if (ret != len) + return -E_SHORT_WRITE; + return ret; +} + +/** + * Write a buffer given by a format string. + * + * \param fd The file descriptor. + * \param fmt A format string. + * + * \return The return value of the underlying call to \ref write_all(). + */ +__printf_2_3 int write_va_buffer(int fd, const char *fmt, ...) +{ + char *msg; + int ret; + + PARA_VSPRINTF(fmt, msg); + ret = write_buffer(fd, msg); + free(msg); + return ret; +} + /** * Read from a non-blocking file descriptor into multiple buffers. *