module System.IO.Cautious
( writeFile
, writeFileWithBackup
) where
import Prelude hiding (writeFile)
import System.Directory (renameFile)
import System.FilePath (splitFileName)
import System.IO (openTempFile)
#ifdef _POSIX
import Control.Monad (when)
import Data.Function (fix)
import Data.List (genericDrop)
import System.Posix.IO (closeFd, FdOption (SynchronousWrites), fdWrite, handleToFd, setFdOption)
import System.Posix.Types (Fd)
splitLimit :: Int
splitLimit = 65536
writeAll :: Fd -> String -> IO ()
writeAll fd = fix $ \me s -> when (not $ null s) $ do
count <- fdWrite fd s
me $ genericDrop count s
#else
import System.IO (hPutStr, hClose)
#endif
writeFile :: FilePath -> String -> IO ()
writeFile = writeFileWithBackup $ return ()
writeFileWithBackup :: IO () -> FilePath -> String -> IO ()
writeFileWithBackup backup fp text = do
(tempFP, handle) <- uncurry openTempFile $ splitFileName fp
#ifdef _POSIX
fd <- handleToFd handle
let writeSync = (setFdOption fd SynchronousWrites True >>) . writeAll fd
if null $ drop splitLimit text
then writeSync text
else writeAll fd (init text) >> writeSync [last text]
closeFd fd
#else
hPutStr handle text
hClose handle
#endif
backup
renameFile tempFP fp