openFile sets creat (O_CREAT) even for ReadOnly :: IOMode.
https://github.com/hasufell/file-io/blob/6cc5a118946611e0df030d31141814fb0d3c868a/System/File/Common.hs#L14-L15
https://github.com/hasufell/file-io/blob/6cc5a118946611e0df030d31141814fb0d3c868a/System/File/Posix.hs#L13-L21
This behavior is inconsistent with System.IO.openBinaryFile (read_flags).
Note: It might also be a good idea to use cloexec (O_CLOEXEC) to prevent child processes from inheriting the file descriptors.
I noticed this bug in directory, which caused copyFile to create the source file if it does not exist. This was fixed in haskell/directory@154a29c, along with O_CLOEXEC in haskell/directory@0ff4e13.