Below follows wrappers around read() and write() that retry when interrupted by a signal (the case where the return value is -1 and errno has the value EINTR), two more wrappers around write() and read() that call write() and read() in a loop respectively until size bytes have been written/read, and a function to copy file permissions from one file to another.
Code:
io.h:
#ifndef IO_H
#define IO_H 1
#include <sys/types.h>
/**
* These functions return -1 on failure, or a non-negative integer otherwise. */
/**
* Version of read() that retries when interrupted by EINTR (possibly by a
* SIGWINCH). */
[[nodiscard, gnu::nonnull]] ssize_t io_read_eintr(int fd, void *buf, size_t size);
/**
* Version of write() that retries when interrupted by EINTR (possibly
* by a SIGWINCH). */
[[nodiscard, gnu::nonnull]] ssize_t io_write_eintr(int fd,
const void *buf,
size_t size);
/**
* Version of read() that retries when interrupted by EINTR (possibly by a
* SIGWINCH). */
[[nodiscard, gnu::nonnull]] ssize_t io_read_all(int fd, void *buf, size_t size);
/**
* A wrapper around io_write_eintr() that's called in a loop until size bytes
* have been written. */
[[nodiscard, gnu::nonnull]] ssize_t io_write_all(int fd,
const void *buf,
size_t size);
/**
* Copies src_fd's mode bits to dest_fd. */
[[nodiscard]] ssize_t io_copy_file_perms(int src_fd, int dest_fd);
#endif /* IO_H */
io.c:
#undef POSIX_C_SOURCE
#undef _XOPEN_SOURCE
#define _POSIX_C_SOURCE 200819L
#define _XOPEN_SOURCE 700
#include "io.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
ssize_t io_read_eintr(int fd, void *buf, size_t size)
{
ssize_t ret = 0;
do {
errno = 0;
ret = read(fd, buf, size);
} while (ret == -1 && errno == EINTR);
return ret;
}
ssize_t io_write_eintr(int fd, const void *buf, size_t size)
{
ssize_t ret = 0;
do {
errno = 0;
ret = write(fd, buf, size);
} while (ret == -1 && errno == EINTR);
return ret;
}
ssize_t io_read_all(int fd, void *buf, size_t size)
{
size_t rcount = 0;
size_t bytes_left = size;
ssize_t ret;
for (ret = 0; rcount < size && ret != -1; rcount += (size_t) ret) {
ret = io_read_eintr(fd, (char *) buf + rcount, bytes_left);
bytes_left -= (size_t) ret;
}
return ret == -1 ? -1 : rcount;
}
ssize_t io_write_all(int fd, const void *buf, size_t size)
{
size_t wcount = 0;
size_t bytes_left = size;
ssize_t ret;
for (ret = 0; wcount < size && ret != -1; wcount += (size_t) ret) {
ret = io_write_eintr(fd, (char *) buf + wcount, bytes_left);
bytes_left -= (size_t) ret;
}
return ret == -1 ? -1 : wcount;
}
ssize_t io_copy_file_perms(int src_fd, int dest_fd)
{
struct stat st;
return fstat(src_fd, &st) != -1 && fchmod(dest_fd, st.st_mode) != -1 ? 0 : -1;
}
Review request:
Any bugs, missing error checking, et cetera.
io_copy_file_perms()return assize_twhen thereturnis really only doing abooltest? \$\endgroup\$boolpreviously. Then I changed it tossize_t for consistency with other functions in this file. \$\endgroup\$