Using only low-level POSIX I/O (i.e. no CRT FILE*-related functions), I've got this problem: I open a file in non-blocking mode:
Then I perform a read operation on it:Code:
int fd = ::open(filename, O_RDONLY | O_NONBLOCK);
OK, now there might be various results. First, the function might return -1. Then I check errno. Most of the values aren't interesting: EBADF, EFAULT and some cases of EINVAL are programming errors, EISDIR and the remaining EINVAL errors user errors. EIO is the Murphy case. So far, so good.Code:
ssize_t count = ::read(fd, buffer, buffersize);
EINTR is problematic because it's unpredictable, but on non-blocking I/O, it shouldn't be very common. If it is returned, the read position of the file isn't exactly defined, which is bad, but I can't do anything about it.
EAGAIN is returned if there is no data available for reading, but EOF hasn't been reached. (We're still in non-blocking mode.) That's the best error case, because I know exactly what happened, and it's good.
OR the function might return 0. That's good, too: EOF is reached, no data was available.
OR the function might return a value == buffersize. That's good too, because the operation completed.
OR the function might return a value between 0 and buffersize. And that's bad. It might be because EOF has been reached before buffersize bytes could be read. Or it might be because no more data was available, so it would have blocked, but a bit of data has been read. Or it might be because a signal interrupted the call after some data had been read. (The POSIX spec allows the function to succeed with a partial read in such cases.) But how do I tell which happened? I need to inform the caller whether he should expect more data in the future, or whether EOF has really been reached. I cannot issue another read: some data sources don't support seeking, and I don't want to implement buffering of a character just for this.
Basically, I'd like a low-level equivalent of feof(), but it seems there is none.
I'm currently inclined to just claim that there might be more data available - since you can't know, the program must be able to handle a total failure of the next read anyway. But I'd like to know if there's a better way.