Question

I am writing a wrapper around generic file operations and do not know how to handle the case when write returns a smaller size written then provided.

The man page for write says:

The number of bytes written may be less than count if, for example, there is insufficient space on the underlying physical medium, or the RLIMIT_FSIZE resource limit is encountered (see setrlimit(2)), or the call was interrupted by a signal handler after having written less than count bytes. (See also pipe(7).)

From my understanding of the above, it's a mixture of errors (medium full) and incitation to come back (interrupted call). If my file descriptors are all non-blocking, I should not get the interrupt case and then the only reason would be an error. Am I right ?

Code example:

int size_written = write(fd, str, count);
if (size_written == -1) {
  if (errno == EAGAIN) {
    // poll on fd and come back later
  } else {
    // throw an error
  }
} else if (size_written < count) {
  // ***************
  // what should I do here ?
  // throw an error ?
  // ***************
}
Was it helpful?

Solution

You need to use the raw I/O functions in a loop:

ssize_t todo = count;

for (ssize_t n; todo > 0; )
{
    n = write(fd, str, todo);
    if (n == -1 && errno != EINTR)
    {
        // error
        break;
    }
    str += n;
    todo -= n;
}

if (todo != 0) { /* error */ }

The special condition concerning EINTR allows the write call to be interrupted by a signal without causing the entire operation to fail. Otherwise, we expect to be able to write all data eventually.

If you can't finish writing all data because your file descriptor is non-blocking and cannot accept any data at the moment, you have to store the remaining data and try again later when the file descriptor has signalled that it's ready for writing again.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top