From 9c8486aafba09cd6fada8ed19336419eec570a4e Mon Sep 17 00:00:00 2001 From: Eshan Kelkar Date: Mon, 24 Jul 2023 20:43:31 +0530 Subject: [PATCH] misc.c : Introduce ssh_readn() A call to read() may peform a short read from a local file even when sufficient data is present in the file. ssh_readn() can be used instead of read() to avoid such short reads. Signed-off-by: Eshan Kelkar Reviewed-by: Jakub Jelen Reviewed-by: Norbert Pocs --- include/libssh/misc.h | 18 +++++++++++++ src/misc.c | 60 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/include/libssh/misc.h b/include/libssh/misc.h index 924da533..1d84ffd6 100644 --- a/include/libssh/misc.h +++ b/include/libssh/misc.h @@ -21,6 +21,21 @@ #ifndef MISC_H_ #define MISC_H_ +#ifdef _WIN32 + +# ifdef _MSC_VER +# ifndef _SSIZE_T_DEFINED +# undef ssize_t +# include + typedef _W64 SSIZE_T ssize_t; +# define _SSIZE_T_DEFINED +# endif /* _SSIZE_T_DEFINED */ +# endif /* _MSC_VER */ + +#else +# include +#endif /* _WIN32 */ + #ifdef __cplusplus extern "C" { #endif @@ -103,6 +118,9 @@ int ssh_newline_vis(const char *string, char *buf, size_t buf_len); int ssh_tmpname(char *name); char *ssh_strreplace(const char *src, const char *pattern, const char *repl); + +ssize_t ssh_readn(int fd, void *buf, size_t nbytes); + #ifdef __cplusplus } #endif diff --git a/src/misc.c b/src/misc.c index 11db2553..bc072295 100644 --- a/src/misc.c +++ b/src/misc.c @@ -1976,4 +1976,64 @@ char *ssh_strerror(int err_num, char *buf, size_t buflen) #endif /* defined(__linux__) && defined(__GLIBC__) && defined(_GNU_SOURCE) */ } +/** + * @brief Read the requested number of bytes from a local file. + * + * A call to read() may perform a short read even when sufficient data is + * present in the file. This function can be used to avoid such short reads. + * + * This function tries to read the requested number of bytes from the file + * until one of the following occurs : + * - Requested number of bytes are read. + * - EOF is encountered before reading the requested number of bytes. + * - An error occurs. + * + * On encountering an error due to an interrupt, this function ignores that + * error and continues trying to read the data. + * + * @param[in] fd The file descriptor of the local file to read from. + * + * @param[out] buf Pointer to a buffer in which read data will be + * stored. + * + * @param[in] nbytes Number of bytes to read. + * + * @returns Number of bytes read on success, + * SSH_ERROR on error with errno set to indicate the + * error. + */ +ssize_t ssh_readn(int fd, void *buf, size_t nbytes) +{ + size_t total_bytes_read = 0; + ssize_t bytes_read; + + if (fd < 0 || buf == NULL || nbytes == 0) { + errno = EINVAL; + return SSH_ERROR; + } + + do { + bytes_read = read(fd, + ((char *)buf) + total_bytes_read, + nbytes - total_bytes_read); + if (bytes_read == -1) { + if (errno == EINTR) { + /* Ignoring errors due to signal interrupts */ + continue; + } + + return SSH_ERROR; + } + + if (bytes_read == 0) { + /* EOF encountered on the local file before reading nbytes */ + break; + } + + total_bytes_read += (size_t)bytes_read; + } while (total_bytes_read < nbytes); + + return total_bytes_read; +} + /** @} */