module System.IO.SafeWrite
( withOutputFile
, syncFile
, allocateTempFile
, finalizeTempFile
) where
import System.FilePath (takeDirectory, takeBaseName)
import System.Posix.IO (openFd, defaultFileFlags, closeFd, OpenMode(..))
import System.Posix.Unistd (fileSynchronise)
import Control.Exception (bracket, bracketOnError)
import System.IO (Handle, hClose, openTempFile)
import System.Directory (renameFile, removeFile)
syncFile :: FilePath
-> IO ()
syncFile fname = do
bracket (openFd fname ReadWrite Nothing defaultFileFlags)
closeFd
fileSynchronise
bracket (openFd (takeDirectory fname) ReadOnly Nothing defaultFileFlags)
closeFd
fileSynchronise
withOutputFile ::
FilePath
-> (Handle -> IO a)
-> IO a
withOutputFile finalname act =
bracketOnError
(allocateTempFile finalname)
(finalizeTempFile finalname False)
(\tdata@(_, th) -> do
r <- act th
finalizeTempFile finalname True tdata
return r)
allocateTempFile :: FilePath -> IO (FilePath, Handle)
allocateTempFile finalname = openTempFile (takeDirectory finalname) (takeBaseName finalname)
finalizeTempFile :: FilePath -> Bool -> (FilePath, Handle) -> IO ()
finalizeTempFile finalname ok (tname, th)
| ok = do
hClose th
syncFile tname
renameFile tname finalname
| otherwise = do
hClose th
removeFile tname