When it’s shared between several, though, seekable streams become annoying (and difficult to impossible to use correctly). When the sharing spans process boundaries, we get the well-known bane of microkernel Unices that TFA describes—you need every file position for every Unix process to be (at least potentially) tracked by a single systemwide “Unix server”. That’s a lot of pain for not a lot of win.
My point was that I can’t think of any non-niche thing that’s naturally a seekable stream—they’re usually either nonseekable or outright random-access. Tape was the natural example when the API was invented, but it is niche now.
If the access to a file was truly read only, then trivially every reader can just have its own seekable FD tracking position locally (or permissions to access the underlying object and open new ones).
What is not a natural extension of the whole thing is that, even on an otherwise completely quiescent system,
int fd1 = open("foo", O_RDWR), fd2 = dup(fd1);
behaves very differently from int fd1 = open("foo", O_RDWR), fd2 = open("foo", O_RDWR);
(imagine these fds are then passed out to other processes or whatnot).Even with O_RDONLY, these are still not at all the same. Witness the epitome of CLI design that is OpenSSL /s :
{
openssl x509 -out "/etc/swanctl/x509/$1.pem"
while openssl x509 -out "$t" 2>/dev/null; do
fp=$(openssl x509 -in "$t" -noout -md5 -fingerprint |
sed 's/.*=//; s/://g')
mv -f -- "$t" /etc/swanctl/x509ca/$fp.pem
done
} < "/etc/ssl/uacme/$1/cert.pem"
This is how you pick apart a PEM cert bundle using OpenSSL: the shell spawns openssl, which reads a single PEM block from stdin, does its dirty deeds with it, and leaves stdin pointing to the next one, ready to be consumed by the next instance of itself that’s yet to be spawned by the shell. You can’t do that with a per-process file position, trivially or otherwise.Returning to the application side, imagine you’re making a concurrent B-tree. If one thread wants to write out page X and the other page Y, they have presumably already used some locking to make sure that’ll leave the data structure consistent, so they’re free to just issue their pwrite()s and let them happen in whatever order. On the other hand, if all they have is write() and seek(), they have to hit a global lock even if X and Y are completely unrelated.