module Data.Conduit.SafeWrite
( safeSinkFile
) where
import qualified Data.Conduit as C
import qualified Data.Conduit.Combinators as CC
import qualified Data.ByteString as B
import Data.IORef (newIORef, writeIORef, readIORef)
import System.FilePath (takeDirectory)
import System.IO (hClose, openTempFile)
import System.Directory (renameFile, removeFile)
import Control.Monad (unless)
import Control.Monad.Trans.Resource
import Control.Monad.IO.Class (liftIO)
import System.IO.SafeWrite (syncFile)
safeSinkFile :: (MonadResource m) =>
FilePath
-> C.Sink B.ByteString m ()
safeSinkFile finalname = C.bracketP
acquire
deleteTempOnError
writeMove
where
acquire = do
(tname, th) <- openTempFile (takeDirectory finalname) finalname
completed <- newIORef False
return (tname, th, completed)
writeMove (tname, th, completed) = do
CC.sinkHandle th
liftIO $ do
hClose th
syncFile tname
renameFile tname finalname
writeIORef completed True
deleteTempOnError (tname, th, completed) = do
completed' <- readIORef completed
unless completed' $ do
hClose th
removeFile tname