packages feed

cautious-file 0.1.2 → 0.1.3

raw patch · 5 files changed

+108/−60 lines, 5 filesdep +bytestringPVP ok

version bump matches the API change (PVP)

Dependencies added: bytestring

API changes (from Hackage documentation)

+ System.IO.Cautious: writeFileL :: FilePath -> ByteString -> IO ()
+ System.IO.Cautious: writeFileWithBackupL :: IO () -> FilePath -> ByteString -> IO ()
+ System.Posix.ByteLevel: fdWrite :: Fd -> CStringLen -> IO ByteCount
+ System.Posix.ByteLevel: fdWriteB :: Fd -> ByteString -> IO Int
+ System.Posix.ByteLevel: writeAllB :: Fd -> ByteString -> IO ()
+ System.Posix.ByteLevel: writeAllL :: Fd -> ByteString -> IO ()
+ System.Posix.Fsync: fsync :: Fd -> IO ()

Files

− System/IO/Cautious.hs
@@ -1,58 +0,0 @@-{-# LANGUAGE CPP #-}--- | It is recommended to write------ import Prelude hiding (writeFile)------ when importing this module.-module System.IO.Cautious-  ( writeFile-  , writeFileWithBackup-  ) where--import Prelude hiding (writeFile)--import System.Directory (canonicalizePath, renameFile)-import System.FilePath (splitFileName)-import System.IO (openTempFile)-#ifdef _POSIX-import Control.Monad (unless)-import Data.Function (fix)-import Data.List (genericDrop)-import System.Posix.IO (closeFd, FdOption (SynchronousWrites), fdWrite, handleToFd, setFdOption)-import System.Posix.Types (Fd)---- | Don't bother to split into two writes if the string to write is shorter than this-splitLimit :: Int-splitLimit = 65536---- | Write the entire contents of a string to a file descriptor. Assumes blocking mode.-writeAll :: Fd -> String -> IO ()-writeAll fd = fix $ \me s -> unless (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 ()---- | Backs up the old version of the file with "backup". "backup" must not fail if there is no--- old version of the file.-writeFileWithBackup :: IO () -> FilePath -> String -> IO ()-writeFileWithBackup backup fp text = do-    cfp <- canonicalizePath fp-    (tempFP, handle) <- uncurry openTempFile $ splitFileName cfp-#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 cfp
cautious-file.cabal view
@@ -1,5 +1,5 @@ name:                cautious-file-version:             0.1.2+version:             0.1.3 Cabal-Version:	     >= 1.6 synopsis:            Ways to write a file cautiously, to reduce the chances of problems such as data loss due to crashes or power failures description:         If the posix flag is enabled, posix-specific functions are used to reduce the chance of data loss further@@ -24,9 +24,11 @@     default: True  Library-  build-Depends:	base >= 4, base < 5, directory, filepath+  hs-source-dirs:       src+  build-Depends:	base >= 4, base < 5, directory, filepath, bytestring   if flag(posix)     cpp-options: -D_POSIX     build-Depends: unix+    exposed-modules:    System.Posix.ByteLevel, System.Posix.Fsync   exposed-modules:      System.IO.Cautious   ghc-options:          -Wall
+ src/System/IO/Cautious.hs view
@@ -0,0 +1,56 @@+{-# LANGUAGE CPP #-}+-- | It is recommended to write+--+-- import Prelude hiding (writeFile)+--+-- when importing this module.+module System.IO.Cautious+  ( writeFile+  , writeFileL+  , writeFileWithBackup+  , writeFileWithBackupL+  ) where++import Prelude hiding (writeFile)++import Data.ByteString.Lazy.Char8 (ByteString, pack)+import System.Directory (canonicalizePath, renameFile)+import System.FilePath (splitFileName)+import System.IO (openTempFile)+#ifdef _POSIX+import System.Posix.ByteLevel (writeAllL)+import System.Posix.Fsync (fsync)+import System.Posix.IO (closeFd, handleToFd)+#else+import Data.ByteString.Lazy (hPut)+import System.IO (hClose)+#endif++writeFile :: FilePath -> String -> IO ()+writeFile = writeFileWithBackup $ return ()++writeFileL :: FilePath -> ByteString -> IO ()+writeFileL = writeFileWithBackupL $ return ()++-- | Backs up the old version of the file with "backup". "backup" must not fail if there is no+-- old version of the file.+writeFileWithBackup :: IO () -> FilePath -> String -> IO ()+writeFileWithBackup backup fp = writeFileWithBackupL backup fp . pack++-- | Backs up the old version of the file with "backup". "backup" must not fail if there is no+-- old version of the file.+writeFileWithBackupL :: IO () -> FilePath -> ByteString -> IO ()+writeFileWithBackupL backup fp bs = do+    cfp <- canonicalizePath fp+    (tempFP, handle) <- uncurry openTempFile $ splitFileName cfp+#ifdef _POSIX+    fd <- handleToFd handle+    writeAllL fd bs+    fsync fd+    closeFd fd+#else+    hPut handle bs+    hClose handle+#endif+    backup+    renameFile tempFP cfp
+ src/System/Posix/ByteLevel.hsc view
@@ -0,0 +1,34 @@+{-# LANGUAGE ForeignFunctionInterface #-}+module System.Posix.ByteLevel (fdWrite, fdWriteB, writeAllB, writeAllL) where++import Control.Applicative ((<$>))+import Control.Monad (unless)+import qualified Data.ByteString as Strict+import Data.ByteString.Lazy (ByteString, toChunks)+import Data.ByteString.Unsafe (unsafeUseAsCStringLen)+import Data.Function (fix)+import Foreign.C.Error (throwErrnoIfMinus1Retry)+import Foreign.C.String (CString, CStringLen)+import Foreign.C.Types (CInt, CSize)+import System.Posix.Types (ByteCount, Fd(..))++#include <unistd.h>++foreign import ccall "write"+       c_write :: CInt -> CString -> CSize -> IO CSize++fdWrite :: Fd -> CStringLen -> IO ByteCount+fdWrite (Fd fd) (cs, l) =  throwErrnoIfMinus1Retry "write" . c_write fd cs $ fromIntegral l++fdWriteB :: Fd -> Strict.ByteString -> IO Int+fdWriteB fd bs = fromIntegral <$> unsafeUseAsCStringLen bs (fdWrite fd)++-- | Write the entire contents of the strict bytestring. Assumes blocking mode.+writeAllB :: Fd -> Strict.ByteString -> IO ()+writeAllB fd = fix $ \me s -> unless (Strict.null s) $ do+    count <- fdWriteB fd s+    me $ Strict.drop (fromIntegral count) s++-- | Write the entire contents of the lazy bytestring. Assumes blocking mode.+writeAllL :: Fd -> ByteString -> IO ()+writeAllL fd = mapM_ (writeAllB fd) . toChunks
+ src/System/Posix/Fsync.hsc view
@@ -0,0 +1,14 @@+{-# LANGUAGE ForeignFunctionInterface #-}+module System.Posix.Fsync (fsync) where++import Foreign.C.Error (throwErrnoIfMinus1_)+import Foreign.C.Types (CInt)+import System.Posix.Types (Fd(..))++#include <unistd.h>++foreign import ccall "fsync"+       c_fsync :: CInt -> IO CInt++fsync :: Fd -> IO ()+fsync (Fd fd) =  throwErrnoIfMinus1_ "fsync" $ c_fsync fd