Given two file descriptors, one for input, one for output, the following function copies the data from the input to the output reasonably reliably.
#include <unistd.h>
/* Copy file from input file descriptor ifd to output file descriptor ofd */
extern int copy_file(int ifd, int ofd);
int copy_file(int ifd, int ofd)
{
char buffer[65536]; // Resize to suit your requirements
ssize_t i_bytes;
while ((i_bytes = read(ifd, buffer, sizeof(buffer))) > 0)
{
ssize_t bytes_left = i_bytes;
char *posn = buffer;
ssize_t o_bytes;
while ((o_bytes = write(ofd, posn, bytes_left)) > 0)
{
bytes_left -= o_bytes;
posn += o_bytes;
}
if (o_bytes < 0)
return -1;
}
if (i_bytes < 0)
return -1;
return 0;
}
A bare minimal test program might be:
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
…declaration or definition of file_copy()…
int main(void)
{
int rc = EXIT_SUCCESS;
if (copy_file(STDIN_FILENO, STDOUT_FILENO) != 0)
{
int errnum = errno;
rc = EXIT_FAILURE;
fprintf(stderr, "copy_file failed: (%d) %s\n", errnum, strerror(errnum));
}
return rc;
}
This correctly copies files from standard input to standard output. I've not definitively tested a 'short write'. It's a pretty rare scenario, and the most likely context is when the output file descriptor is a socket. Testing the error paths is harder, too. I called the program cf89
. One test was:
$ (trap '' 13; ./cf89 < /dev/zero) | (sleep 1)
copy_file failed: (32) Broken pipe
$
The trap
ignores SIGPIPE (13), so the writing blocks because nothing is reading the pipe. When the sleep
exits, the writing process gets an error from the write()
— because the signal is ignored — and it generates the error message.
As an aside, there are those who argue against reporting both the error number and the error message on security grounds — it tells the attacker too much about the system if they manage to trigger an error. I'm not in that camp; the attacker already knows the system type by the time they get to attacking a program such as this. It might be relevant in other contexts, such as perhaps a web server.