diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,12 @@
 
 This project adheres to the [Haskell Package Versioning Policy](https://pvp.haskell.org/).
 
+## [0.6.1.0] - 2023-08-14
+
+- Add `uninterruptibleWriteBytesCompletelyErrno`
+- Add `writeBytesCompletelyErrno`
+- Add `uninterruptibleAccept4_`
+
 ## [0.6.0.1] - 2023-07-13
 
 - Fix mistake in header file that caused builds to fail
diff --git a/cbits/HaskellPosix.c b/cbits/HaskellPosix.c
--- a/cbits/HaskellPosix.c
+++ b/cbits/HaskellPosix.c
@@ -26,13 +26,15 @@
 // way to support providing an offset (without just copying the bytes
 // into pinned memory) is to use a wrapper.
 
-ssize_t write_offset_loop(int fd, const char *message, HsInt offset, size_t length){
+// This returns an error code, not a length of written bytes. The error
+// code zero means "no error".
+int write_offset_loop(int fd, const char *message, HsInt offset, size_t length){
   ssize_t r;
   size_t bytesSent;
   const char* buf = message + offset;
   while(length > 0){
     if ((r = write(fd, (const void*)buf, length)) == -1) {
-      return (-1);
+      return errno;
     } else {
       bytesSent = (size_t)r;
       buf = buf + bytesSent;
diff --git a/posix-api.cabal b/posix-api.cabal
--- a/posix-api.cabal
+++ b/posix-api.cabal
@@ -1,6 +1,6 @@
 cabal-version: 2.2
 name: posix-api
-version: 0.6.0.1
+version: 0.6.1.0
 synopsis: posix bindings
 description:
   This library provides a very thin wrapper around POSIX APIs. It can be
diff --git a/src/Linux/Socket.hs b/src/Linux/Socket.hs
--- a/src/Linux/Socket.hs
+++ b/src/Linux/Socket.hs
@@ -12,6 +12,7 @@
   , uninterruptibleReceiveMultipleMessageC
   , uninterruptibleReceiveMultipleMessageD
   , uninterruptibleAccept4
+  , uninterruptibleAccept4_
     -- * Types
   , SocketFlags(..)
     -- * Option Names
@@ -49,26 +50,28 @@
 
 import Control.Monad (when)
 import Data.Bits ((.|.))
-import Data.Primitive.Addr (Addr(..),plusAddr,nullAddr)
 import Data.Primitive (MutableByteArray(..),ByteArray(..),MutablePrimArray(..))
+import Data.Primitive.Addr (Addr(..),plusAddr,nullAddr)
 import Data.Primitive.Unlifted.Array (MutableUnliftedArray,UnliftedArray)
 import Data.Primitive.Unlifted.Array (MutableUnliftedArray_(MutableUnliftedArray))
+import Data.Primitive.Unlifted.Array.Primops (MutableUnliftedArray#(MutableUnliftedArray#))
+import Data.Void (Void)
 import Data.Word (Word8)
 import Foreign.C.Error (Errno,getErrno)
 import Foreign.C.Types (CInt(..),CSize(..),CUInt(..))
+import Foreign.Ptr (nullPtr)
 import GHC.Exts (Ptr(..),RealWorld,MutableArray#,MutableByteArray#,Addr#,Int(I#))
 import GHC.Exts (shrinkMutableByteArray#,touch#,nullAddr#)
 import GHC.IO (IO(..))
 import Linux.Socket.Types (SocketFlags(..))
 import Posix.Socket (Type(..),MessageFlags(..),Message(Receive),SocketAddress(..))
 import System.Posix.Types (Fd(..),CSsize(..))
-import Data.Primitive.Unlifted.Array.Primops (MutableUnliftedArray#(MutableUnliftedArray#))
 
+import qualified Control.Monad.Primitive as PM
 import qualified Data.Primitive as PM
 import qualified Data.Primitive.Unlifted.Array as PM
-import qualified Control.Monad.Primitive as PM
-import qualified Posix.Socket as S
 import qualified Linux.Socket.Types as LST
+import qualified Posix.Socket as S
 
 foreign import ccall unsafe "sys/socket.h recvmmsg"
   c_unsafe_addr_recvmmsg :: Fd
@@ -85,6 +88,17 @@
                    -> SocketFlags
                    -> IO Fd
 
+-- Variant of c_unsafe_ptr_accept4 that uses Ptr instead of MutableByteArray.
+-- Currently, we expect that the two pointers are set to NULL.
+-- This is only used internally.
+foreign import ccall unsafe "sys/socket.h accept4"
+  c_unsafe_ptr_accept4 ::
+        Fd
+     -> Ptr Void -- SocketAddress
+     -> Ptr Void -- Ptr CInt
+     -> SocketFlags
+     -> IO Fd
+
 foreign import ccall unsafe "HaskellPosix.h recvmmsg_sockaddr_in"
   c_unsafe_recvmmsg_sockaddr_in ::
        Fd
@@ -366,6 +380,19 @@
         else pure ()
       sockAddr <- PM.unsafeFreezeByteArray sockAddrBuf
       pure (Right (sz,SocketAddress sockAddr,r))
+    else fmap Left getErrno
+
+-- | Variant of 'uninterruptibleAccept4' that requests that the kernel not
+-- include the socket address in its reponse.
+uninterruptibleAccept4_ ::
+     Fd -- ^ Listening socket
+  -> SocketFlags -- ^ Set non-blocking and close-on-exec without extra syscall
+  -> IO (Either Errno Fd) -- ^ Connected socket
+{-# inline uninterruptibleAccept4_ #-}
+uninterruptibleAccept4_ !sock !flags = do
+  r <- c_unsafe_ptr_accept4 sock nullPtr nullPtr flags
+  if r > (-1)
+    then pure (Right r)
     else fmap Left getErrno
 
 cintToInt :: CInt -> Int
diff --git a/src/Posix/File.hs b/src/Posix/File.hs
--- a/src/Posix/File.hs
+++ b/src/Posix/File.hs
@@ -1,5 +1,6 @@
 {-# language BangPatterns #-}
 {-# language BinaryLiterals #-}
+{-# language LambdaCase #-}
 {-# language MagicHash #-}
 {-# language TypeApplications #-}
 {-# language UnliftedFFITypes #-}
@@ -11,6 +12,8 @@
   , uninterruptibleWriteByteArray
   , uninterruptibleWriteBytes
   , uninterruptibleWriteBytesCompletely
+  , uninterruptibleWriteBytesCompletelyErrno
+  , writeBytesCompletelyErrno
   , uninterruptibleOpen
   , uninterruptibleOpenMode
   , writeByteArray
@@ -44,7 +47,7 @@
 import Assertion (assertByteArrayPinned,assertMutableByteArrayPinned)
 import Data.Bits ((.&.),(.|.))
 import Data.Primitive (ByteArray(..))
-import Foreign.C.Error (Errno,getErrno)
+import Foreign.C.Error (Errno(Errno),getErrno,eOK)
 import Foreign.C.String.Managed (ManagedCString(..))
 import Foreign.C.Types (CInt(..),CSize(..))
 import GHC.Exts (ByteArray#,MutableByteArray#,RealWorld)
@@ -76,8 +79,11 @@
   c_unsafe_bytearray_write :: Fd -> ByteArray# -> Int -> CSize -> IO CSsize
 
 foreign import ccall unsafe "HaskellPosix.h write_offset_loop"
-  c_unsafe_bytearray_write_loop :: Fd -> ByteArray# -> Int -> CSize -> IO CInt
+  c_unsafe_bytearray_write_loop :: Fd -> ByteArray# -> Int -> CSize -> IO Errno
 
+foreign import ccall safe "HaskellPosix.h write_offset_loop"
+  c_safe_bytearray_write_loop :: Fd -> ByteArray# -> Int -> CSize -> IO Errno
+
 foreign import ccall safe "HaskellPosix.h write_offset"
   c_safe_bytearray_write :: Fd -> ByteArray# -> Int -> CSize -> IO CSsize
 
@@ -137,11 +143,32 @@
      Fd -- ^ File descriptor
   -> Bytes -- ^ Source bytes
   -> IO (Either Errno ())
-uninterruptibleWriteBytesCompletely !fd (Bytes (ByteArray buf) off len) =
+uninterruptibleWriteBytesCompletely !fd !b = do
+  e <- uninterruptibleWriteBytesCompletelyErrno fd b
+  if e == eOK
+    then pure (Right ())
+    else pure (Left e)
+
+-- | Variant of 'uninterruptibleWriteBytesCompletely' that uses errno 0
+-- to communicate success.
+uninterruptibleWriteBytesCompletelyErrno ::
+     Fd -- ^ File descriptor
+  -> Bytes -- ^ Source bytes
+  -> IO Errno
+uninterruptibleWriteBytesCompletelyErrno !fd (Bytes (ByteArray buf) off len) =
   c_unsafe_bytearray_write_loop fd buf off (fromIntegral @Int @CSize len)
-    >>= errorsFromInt_
 
 -- | Wrapper for @write(2)@ that takes a slice of bytes and an offset.
+-- The byte array backing the slice must be pinned.
+writeBytesCompletelyErrno ::
+     Fd -- ^ File descriptor
+  -> Bytes -- ^ Source bytes
+  -> IO Errno
+writeBytesCompletelyErrno !fd (Bytes buf0 off len) =
+  let !(ByteArray buf1) = assertByteArrayPinned buf0
+   in c_safe_bytearray_write_loop fd buf1 off (fromIntegral @Int @CSize len)
+
+-- | Wrapper for @write(2)@ that takes a slice of bytes and an offset.
 -- The byte array backing the slice does not need to be pinned.
 uninterruptibleWriteBytes ::
      Fd -- ^ File descriptor
@@ -173,6 +200,8 @@
 writeByteArray !fd !buf0 !off !len =
   let !(ByteArray buf1) = assertByteArrayPinned buf0
    in c_safe_bytearray_write fd buf1 off len >>= errorsFromSize
+
+-- writeByteArrayCompletely ::
 
 -- | Variant of 'writeByteArray' that operates on mutable byte array.
 -- Uses @safe@ FFI. The byte array must be pinned.
