atomic-write-0.2.0.7: src/System/AtomicWrite/Internal.hs
-- |
-- Module : System.AtomicWrite.Internal
-- Copyright : © 2015-2019 Stack Builders Inc.
-- License : MIT
--
-- Maintainer : Stack Builders <hackage@stackbuilders.com>
-- Stability : experimental
-- Portability : portable
--
-- Provides functionality to create a temporary file with correct permissions
-- atomically.
module System.AtomicWrite.Internal where
import System.Directory (doesFileExist, renameFile)
import System.FilePath (takeDirectory)
import System.IO (Handle, hClose, hSetBinaryMode,
openTempFile,
openTempFileWithDefaultPermissions)
import System.Posix.Types (FileMode)
import System.PosixCompat.Files (fileMode, getFileStatus, setFileMode)
-- | Returns a temporary file with permissions correctly set. Chooses
-- either previously-set permissions if the file that we're writing
-- to existed, or permissions following the current umask.
tempFileFor ::
FilePath -- ^ The target filepath that we will replace atomically.
-> IO (FilePath, Handle)
tempFileFor targetFilePath =
doesFileExist targetFilePath >>=
tmpFile targetFilePath (takeDirectory targetFilePath) "atomic.write"
where
tmpFile :: FilePath -> FilePath -> String -> Bool -> IO (FilePath, Handle)
tmpFile targetPath workingDirectory template previousExisted =
if previousExisted then
openTempFile workingDirectory template >>=
\(tmpPath, handle) ->
getFileStatus targetPath >>= setFileMode tmpPath . fileMode >>
return (tmpPath, handle)
else
openTempFileWithDefaultPermissions workingDirectory template
closeAndRename :: Handle -> FilePath -> FilePath -> IO ()
closeAndRename tmpHandle tempFile destFile =
hClose tmpHandle >> renameFile tempFile destFile
maybeSetFileMode :: FilePath -> Maybe FileMode -> IO ()
maybeSetFileMode path =
maybe
( return () )
( \mode -> setFileMode path mode )
-- Helper Function
atomicWriteFileMaybeModeText ::
Maybe FileMode -- ^ The mode to set the file to
-> FilePath -- ^ The path where the file will be updated or created
-> (Handle -> a -> IO ()) -- ^ The function to use to write on the file
-> a -- ^ The content to write to the file
-> IO ()
atomicWriteFileMaybeModeText mmode path hF text =
tempFileFor path >>= \(tmpPath, h) -> hSetBinaryMode h False
>> hF h text
>> closeAndRename h tmpPath path
>> maybeSetFileMode path mmode
-- Helper Function
atomicWriteFileMaybeModeBinary ::
Maybe FileMode -- ^ The mode to set the file to
-> FilePath -- ^ The path where the file will be updated or created
-> (Handle -> a -> IO ()) -- ^ The function to use to write on the file
-> a -- ^ The content to write to the file
-> IO ()
atomicWriteFileMaybeModeBinary mmode path hF text =
tempFileFor path >>= \(tmpPath, h) -> hSetBinaryMode h True
>> hF h text
>> closeAndRename h tmpPath path
>> maybeSetFileMode path mmode