22

I'm looking at the read syscall in Unix, which (at least in Linux) has this signature: [1]

ssize_t read(int fd, void* buf, size_t count);

Let's assume that the call succeeds (i.e. no negative return values) and that count > 0 (i.e. the buffer actually can store a nonzero amount of bytes). Under which circumstances would read() return 0? I can think of the following:

  • When fd refers to a regular file and the end of the file has been reached.
  • When fd refers to the receiving end of a pipe, socket or FIFO, the sending end has been closed and the pipe's/socket's/FIFO's own buffer has been exhausted.
  • When fd refers to the slave side of a terminal device that is in ICANON and Ctrl-D has been sent into the master side while the line buffer was empty.

I'm curious if there are any other situations that I'm not aware of, where read() would return with a result of 0. I'm especially interested (because of reasons) in situations like the last one in the list above, where read() returns 0 once, but subsequent calls to read() on the same FD could return a nonzero result. If an answer only applies to a certain flavor of Unix, I'm still interested in hearing it.

[1] I know this signature is for the libc wrapper, not the actual syscall, but that's not important right now.

Stefan Majewsky
  • 5,427
  • 2
  • 28
  • 51
  • 2
    It happens for regular files if the file has been appended to since the previous read returned 0. – that other guy Jul 18 '18 at 21:57
  • `0` is always considered to be "end of file". It's just that for some types of streams, this can be a temporary condition. – Barmar Jul 18 '18 at 22:03
  • "In the absence of errors, or if error detection is not performed, the read() function shall return zero and have no other results."[1](http://pubs.opengroup.org/onlinepubs/009695399/functions/read.html) – vv01f Jul 18 '18 at 22:06
  • 1
    @vv01f That's only if `nbyte == 0` – Barmar Jul 18 '18 at 22:08
  • indeed, the document names other cases for "shall return 0" – vv01f Jul 18 '18 at 22:11
  • 1
    In z/OS: (1) If the Physical File System does not support simple reads from directories, read() will return 0 if it is used for a directory. (2) If the starting position for the read operation is at the end of the file or **beyond**, read() returns 0. [doc](https://www.ibm.com/support/knowledgecenter/en/SSLTBW_2.3.0/com.ibm.zos.v2r3.bpxbd00/rtrea.htm) – DaBler Jul 23 '18 at 08:30

2 Answers2

8
  • If the Physical File System does not support simple reads from directories, read() will return 0 if it is used for a directory.
  • If no process has the pipe open for writing, read() returns 0 to indicate the end of the file.
  • If the connection is broken on a stream socket, but no data is available, then the read() function returns 0 bytes as EOF.
VishnuVS
  • 1,055
  • 2
  • 14
  • 29
  • The only thing here that I didn't mention yet is the empty read on fds backed by directories (which, as far as I've been told, is also not portable; some obscure Unices return stuff from read() on directories). So sorry, but that's not worth the +200 bounty IMO. – Stefan Majewsky Jul 30 '18 at 12:49
  • @StefanMajewsky I don't think there are any other cases other than special conditions of your points #2 and #3. – VishnuVS Jul 30 '18 at 13:51
  • I don't disagree. – Stefan Majewsky Jul 31 '18 at 08:09
  • You missed: if `read` from a regular file whose file pointer is at 0 bytes from `SEEK_END` – MirkoBanchi Feb 24 '23 at 15:13
0

Normally a return value of 0 always means end-of-file. However, if you specify 0 as the number of bytes to read, it will always return 0 unless there's an error detected.

Terminal devices are a special case. If the terminal is in cooked mode, typing Control-d tells the device driver to return from any pending read() immediately with whatever is in the input editing buffer, rather than waiting for the user to enter a newline. If the buffer is empty, this results in a zero-length read. This is how typing the EOF character at the beginning of a line is automatically treated as EOF by applications.

Barmar
  • 741,623
  • 53
  • 500
  • 612