2016-05-09 14:53:31 +00:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
2016-05-29 15:29:13 +00:00
|
|
|
{-# LANGUAGE PackageImports #-}
|
|
|
|
|
2016-05-09 14:53:31 +00:00
|
|
|
|
|
|
|
module Utils where
|
|
|
|
|
|
|
|
|
2016-05-09 16:53:26 +00:00
|
|
|
import Control.Applicative
|
|
|
|
(
|
|
|
|
(<$>)
|
|
|
|
)
|
2016-05-29 15:29:13 +00:00
|
|
|
import Control.Monad
|
|
|
|
(
|
2016-06-05 12:33:53 +00:00
|
|
|
forM_
|
|
|
|
, void
|
|
|
|
)
|
2016-06-05 19:52:52 +00:00
|
|
|
import Control.Monad.IfElse
|
|
|
|
(
|
|
|
|
whenM
|
|
|
|
)
|
2016-06-05 12:33:53 +00:00
|
|
|
import qualified Data.ByteString as BS
|
|
|
|
import Data.IORef
|
|
|
|
(
|
|
|
|
newIORef
|
|
|
|
, readIORef
|
|
|
|
, writeIORef
|
|
|
|
, IORef
|
|
|
|
)
|
2016-05-09 14:53:31 +00:00
|
|
|
import HPath.IO
|
2018-04-06 15:22:22 +00:00
|
|
|
import Prelude hiding (appendFile, readFile, writeFile)
|
2016-05-09 14:53:31 +00:00
|
|
|
import Data.Maybe
|
|
|
|
(
|
|
|
|
fromJust
|
|
|
|
)
|
|
|
|
import qualified HPath as P
|
2016-06-05 12:46:45 +00:00
|
|
|
import System.IO.Unsafe
|
|
|
|
(
|
|
|
|
unsafePerformIO
|
|
|
|
)
|
2016-06-05 12:55:21 +00:00
|
|
|
import qualified System.Posix.Directory.Traversals as DT
|
2016-05-09 14:53:31 +00:00
|
|
|
import Data.ByteString
|
|
|
|
(
|
|
|
|
ByteString
|
|
|
|
)
|
2018-04-06 14:42:40 +00:00
|
|
|
import qualified Data.ByteString.Lazy as L
|
2016-05-09 14:53:31 +00:00
|
|
|
import System.Posix.Files.ByteString
|
|
|
|
(
|
|
|
|
groupExecuteMode
|
|
|
|
, groupReadMode
|
|
|
|
, nullFileMode
|
|
|
|
, otherExecuteMode
|
|
|
|
, otherReadMode
|
|
|
|
, ownerExecuteMode
|
|
|
|
, ownerReadMode
|
|
|
|
, setFileMode
|
|
|
|
, unionFileModes
|
|
|
|
)
|
|
|
|
|
2020-01-04 16:52:21 +00:00
|
|
|
baseTmpDir :: IORef (Maybe ByteString)
|
|
|
|
{-# NOINLINE baseTmpDir #-}
|
|
|
|
baseTmpDir = unsafePerformIO (newIORef Nothing)
|
2016-05-29 15:29:13 +00:00
|
|
|
|
2016-06-05 12:33:53 +00:00
|
|
|
|
2020-01-04 16:52:21 +00:00
|
|
|
tmpDir :: IORef (Maybe ByteString)
|
2016-06-05 12:33:53 +00:00
|
|
|
{-# NOINLINE tmpDir #-}
|
2020-01-04 16:52:21 +00:00
|
|
|
tmpDir = unsafePerformIO (newIORef Nothing)
|
2016-05-29 15:29:13 +00:00
|
|
|
|
2016-05-09 14:53:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
-----------------
|
|
|
|
--[ Utilities ]--
|
|
|
|
-----------------
|
|
|
|
|
|
|
|
|
2016-06-05 12:33:53 +00:00
|
|
|
setTmpDir :: ByteString -> IO ()
|
|
|
|
{-# NOINLINE setTmpDir #-}
|
2020-01-04 16:52:21 +00:00
|
|
|
setTmpDir bs = do
|
|
|
|
tmp <- fromJust <$> readIORef baseTmpDir
|
|
|
|
writeIORef tmpDir (Just (tmp `BS.append` bs))
|
2016-06-05 12:33:53 +00:00
|
|
|
|
|
|
|
|
2016-05-29 15:29:13 +00:00
|
|
|
createTmpDir :: IO ()
|
2016-06-05 12:33:53 +00:00
|
|
|
{-# NOINLINE createTmpDir #-}
|
2016-05-29 15:29:13 +00:00
|
|
|
createTmpDir = do
|
2020-01-04 16:52:21 +00:00
|
|
|
tmp <- P.parseAbs =<< (fromJust <$> readIORef tmpDir)
|
|
|
|
void $ createDir newDirPerms tmp
|
2016-05-29 15:29:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
deleteTmpDir :: IO ()
|
2016-06-05 12:33:53 +00:00
|
|
|
{-# NOINLINE deleteTmpDir #-}
|
2016-05-29 15:29:13 +00:00
|
|
|
deleteTmpDir = do
|
2020-01-04 16:52:21 +00:00
|
|
|
tmp <- P.parseAbs =<< (fromJust <$> readIORef tmpDir)
|
|
|
|
void $ deleteDir tmp
|
2016-06-05 12:33:53 +00:00
|
|
|
|
|
|
|
|
|
|
|
deleteBaseTmpDir :: IO ()
|
|
|
|
{-# NOINLINE deleteBaseTmpDir #-}
|
|
|
|
deleteBaseTmpDir = do
|
2020-01-04 16:52:21 +00:00
|
|
|
tmp <- (fromJust <$> readIORef baseTmpDir) >>= P.parseAbs
|
|
|
|
contents <- getDirsFiles tmp
|
2016-06-05 12:33:53 +00:00
|
|
|
forM_ contents deleteDir
|
2020-01-04 16:52:21 +00:00
|
|
|
void $ deleteDir tmp
|
2016-05-29 15:29:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
withRawTmpDir :: (P.Path P.Abs -> IO a) -> IO a
|
2016-06-05 12:33:53 +00:00
|
|
|
{-# NOINLINE withRawTmpDir #-}
|
2016-05-29 15:29:13 +00:00
|
|
|
withRawTmpDir f = do
|
2020-01-04 16:52:21 +00:00
|
|
|
tmp <- P.parseAbs =<< (fromJust <$> readIORef tmpDir)
|
|
|
|
f tmp
|
2016-05-29 15:29:13 +00:00
|
|
|
|
|
|
|
|
2016-06-05 12:33:53 +00:00
|
|
|
getRawTmpDir :: IO ByteString
|
|
|
|
{-# NOINLINE getRawTmpDir #-}
|
|
|
|
getRawTmpDir = withRawTmpDir (return . flip BS.append "/" . P.fromAbs)
|
|
|
|
|
|
|
|
|
2016-05-29 15:29:13 +00:00
|
|
|
withTmpDir :: ByteString -> (P.Path P.Abs -> IO a) -> IO a
|
2016-06-05 12:33:53 +00:00
|
|
|
{-# NOINLINE withTmpDir #-}
|
2016-05-29 15:29:13 +00:00
|
|
|
withTmpDir ip f = do
|
2020-01-04 16:52:21 +00:00
|
|
|
tmp <- P.parseAbs =<< (fromJust <$> readIORef tmpDir)
|
|
|
|
p <- (tmp P.</>) <$> P.parseRel ip
|
2016-05-09 14:53:31 +00:00
|
|
|
f p
|
|
|
|
|
|
|
|
|
2016-05-29 15:29:13 +00:00
|
|
|
withTmpDir' :: ByteString
|
|
|
|
-> ByteString
|
|
|
|
-> (P.Path P.Abs -> P.Path P.Abs -> IO a)
|
|
|
|
-> IO a
|
2016-06-05 12:33:53 +00:00
|
|
|
{-# NOINLINE withTmpDir' #-}
|
2016-05-29 15:29:13 +00:00
|
|
|
withTmpDir' ip1 ip2 f = do
|
2020-01-04 16:52:21 +00:00
|
|
|
tmp <- P.parseAbs =<< (fromJust <$> readIORef tmpDir)
|
|
|
|
p1 <- (tmp P.</>) <$> P.parseRel ip1
|
|
|
|
p2 <- (tmp P.</>) <$> P.parseRel ip2
|
2016-05-09 14:53:31 +00:00
|
|
|
f p1 p2
|
|
|
|
|
|
|
|
|
|
|
|
removeFileIfExists :: ByteString -> IO ()
|
2016-06-05 12:33:53 +00:00
|
|
|
{-# NOINLINE removeFileIfExists #-}
|
2016-05-09 14:53:31 +00:00
|
|
|
removeFileIfExists bs =
|
2016-05-29 15:29:13 +00:00
|
|
|
withTmpDir bs $ \p -> whenM (doesFileExist p) (deleteFile p)
|
2016-05-09 14:53:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
removeDirIfExists :: ByteString -> IO ()
|
2016-06-05 12:33:53 +00:00
|
|
|
{-# NOINLINE removeDirIfExists #-}
|
2016-05-09 14:53:31 +00:00
|
|
|
removeDirIfExists bs =
|
2016-05-29 15:29:13 +00:00
|
|
|
withTmpDir bs $ \p -> whenM (doesDirectoryExist p) (deleteDirRecursive p)
|
2016-05-09 14:53:31 +00:00
|
|
|
|
|
|
|
|
2016-06-05 01:10:28 +00:00
|
|
|
copyFile' :: ByteString -> ByteString -> CopyMode -> IO ()
|
2016-06-05 12:33:53 +00:00
|
|
|
{-# NOINLINE copyFile' #-}
|
2016-06-05 01:10:28 +00:00
|
|
|
copyFile' inputFileP outputFileP cm =
|
|
|
|
withTmpDir' inputFileP outputFileP (\p1 p2 -> copyFile p1 p2 cm)
|
2016-05-09 14:53:31 +00:00
|
|
|
|
|
|
|
|
2016-06-05 01:10:28 +00:00
|
|
|
copyDirRecursive' :: ByteString -> ByteString
|
2016-06-05 14:07:46 +00:00
|
|
|
-> CopyMode -> RecursiveErrorMode -> IO ()
|
2016-06-05 12:33:53 +00:00
|
|
|
{-# NOINLINE copyDirRecursive' #-}
|
2016-06-05 01:10:28 +00:00
|
|
|
copyDirRecursive' inputDirP outputDirP cm rm =
|
|
|
|
withTmpDir' inputDirP outputDirP (\p1 p2 -> copyDirRecursive p1 p2 cm rm)
|
2016-05-09 14:53:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
createDir' :: ByteString -> IO ()
|
2016-06-05 12:33:53 +00:00
|
|
|
{-# NOINLINE createDir' #-}
|
2016-06-05 15:46:25 +00:00
|
|
|
createDir' dest = withTmpDir dest (createDir newDirPerms)
|
2016-05-09 14:53:31 +00:00
|
|
|
|
2016-06-12 23:28:55 +00:00
|
|
|
createDirRecursive' :: ByteString -> IO ()
|
|
|
|
{-# NOINLINE createDirRecursive' #-}
|
|
|
|
createDirRecursive' dest = withTmpDir dest (createDirRecursive newDirPerms)
|
2016-05-09 14:53:31 +00:00
|
|
|
|
|
|
|
createRegularFile' :: ByteString -> IO ()
|
2016-06-05 12:33:53 +00:00
|
|
|
{-# NOINLINE createRegularFile' #-}
|
2016-06-05 15:46:25 +00:00
|
|
|
createRegularFile' dest = withTmpDir dest (createRegularFile newFilePerms)
|
2016-05-29 15:29:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
createSymlink' :: ByteString -> ByteString -> IO ()
|
2016-06-05 12:33:53 +00:00
|
|
|
{-# NOINLINE createSymlink' #-}
|
2016-05-29 15:29:13 +00:00
|
|
|
createSymlink' dest sympoint = withTmpDir dest
|
|
|
|
(\x -> createSymlink x sympoint)
|
2016-05-09 14:53:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
renameFile' :: ByteString -> ByteString -> IO ()
|
2016-06-05 12:33:53 +00:00
|
|
|
{-# NOINLINE renameFile' #-}
|
2016-05-09 14:53:31 +00:00
|
|
|
renameFile' inputFileP outputFileP =
|
2016-05-29 15:29:13 +00:00
|
|
|
withTmpDir' inputFileP outputFileP $ \i o -> do
|
2016-05-09 14:53:31 +00:00
|
|
|
renameFile i o
|
|
|
|
renameFile o i
|
|
|
|
|
|
|
|
|
2016-06-05 01:10:28 +00:00
|
|
|
moveFile' :: ByteString -> ByteString -> CopyMode -> IO ()
|
2016-06-05 12:33:53 +00:00
|
|
|
{-# NOINLINE moveFile' #-}
|
2016-06-05 01:10:28 +00:00
|
|
|
moveFile' inputFileP outputFileP cm =
|
2016-05-29 15:29:13 +00:00
|
|
|
withTmpDir' inputFileP outputFileP $ \i o -> do
|
2016-06-05 01:10:28 +00:00
|
|
|
moveFile i o cm
|
|
|
|
moveFile o i Strict
|
2016-05-09 14:53:31 +00:00
|
|
|
|
|
|
|
|
2016-06-05 01:10:28 +00:00
|
|
|
recreateSymlink' :: ByteString -> ByteString -> CopyMode -> IO ()
|
2016-06-05 12:33:53 +00:00
|
|
|
{-# NOINLINE recreateSymlink' #-}
|
2016-06-05 01:10:28 +00:00
|
|
|
recreateSymlink' inputFileP outputFileP cm =
|
|
|
|
withTmpDir' inputFileP outputFileP (\p1 p2 -> recreateSymlink p1 p2 cm)
|
2016-05-09 14:53:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
noWritableDirPerms :: ByteString -> IO ()
|
2016-06-05 12:33:53 +00:00
|
|
|
{-# NOINLINE noWritableDirPerms #-}
|
2016-05-29 15:29:13 +00:00
|
|
|
noWritableDirPerms path = withTmpDir path $ \p ->
|
2016-05-09 14:53:31 +00:00
|
|
|
setFileMode (P.fromAbs p) perms
|
|
|
|
where
|
|
|
|
perms = ownerReadMode
|
|
|
|
`unionFileModes` ownerExecuteMode
|
|
|
|
`unionFileModes` groupReadMode
|
|
|
|
`unionFileModes` groupExecuteMode
|
|
|
|
`unionFileModes` otherReadMode
|
|
|
|
`unionFileModes` otherExecuteMode
|
|
|
|
|
|
|
|
|
|
|
|
noPerms :: ByteString -> IO ()
|
2016-06-05 12:33:53 +00:00
|
|
|
{-# NOINLINE noPerms #-}
|
2016-05-29 15:29:13 +00:00
|
|
|
noPerms path = withTmpDir path $ \p -> setFileMode (P.fromAbs p) nullFileMode
|
2016-05-09 14:53:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
normalDirPerms :: ByteString -> IO ()
|
2016-06-05 12:33:53 +00:00
|
|
|
{-# NOINLINE normalDirPerms #-}
|
2016-05-09 14:53:31 +00:00
|
|
|
normalDirPerms path =
|
2016-05-29 15:29:13 +00:00
|
|
|
withTmpDir path $ \p -> setFileMode (P.fromAbs p) newDirPerms
|
2016-05-09 14:53:31 +00:00
|
|
|
|
|
|
|
|
2018-04-06 14:42:40 +00:00
|
|
|
normalFilePerms :: ByteString -> IO ()
|
|
|
|
{-# NOINLINE normalFilePerms #-}
|
|
|
|
normalFilePerms path =
|
|
|
|
withTmpDir path $ \p -> setFileMode (P.fromAbs p) newFilePerms
|
|
|
|
|
|
|
|
|
2016-05-09 14:53:31 +00:00
|
|
|
getFileType' :: ByteString -> IO FileType
|
2016-06-05 12:33:53 +00:00
|
|
|
{-# NOINLINE getFileType' #-}
|
2016-05-29 15:29:13 +00:00
|
|
|
getFileType' path = withTmpDir path getFileType
|
2016-05-09 14:53:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
getDirsFiles' :: ByteString -> IO [P.Path P.Abs]
|
2016-06-05 12:33:53 +00:00
|
|
|
{-# NOINLINE getDirsFiles' #-}
|
2016-05-29 15:29:13 +00:00
|
|
|
getDirsFiles' path = withTmpDir path getDirsFiles
|
2016-05-09 14:53:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
deleteFile' :: ByteString -> IO ()
|
2016-06-05 12:33:53 +00:00
|
|
|
{-# NOINLINE deleteFile' #-}
|
2016-05-29 15:29:13 +00:00
|
|
|
deleteFile' p = withTmpDir p deleteFile
|
2016-05-09 14:53:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
deleteDir' :: ByteString -> IO ()
|
2016-06-05 12:33:53 +00:00
|
|
|
{-# NOINLINE deleteDir' #-}
|
2016-05-29 15:29:13 +00:00
|
|
|
deleteDir' p = withTmpDir p deleteDir
|
2016-05-09 14:53:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
deleteDirRecursive' :: ByteString -> IO ()
|
2016-06-05 12:33:53 +00:00
|
|
|
{-# NOINLINE deleteDirRecursive' #-}
|
2016-05-29 15:29:13 +00:00
|
|
|
deleteDirRecursive' p = withTmpDir p deleteDirRecursive
|
2016-05-09 14:53:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
canonicalizePath' :: ByteString -> IO (P.Path P.Abs)
|
2016-06-05 12:33:53 +00:00
|
|
|
{-# NOINLINE canonicalizePath' #-}
|
2016-05-29 15:29:13 +00:00
|
|
|
canonicalizePath' p = withTmpDir p canonicalizePath
|
|
|
|
|
2016-05-09 14:53:31 +00:00
|
|
|
|
2016-05-29 15:29:13 +00:00
|
|
|
writeFile' :: ByteString -> ByteString -> IO ()
|
2016-06-05 12:33:53 +00:00
|
|
|
{-# NOINLINE writeFile' #-}
|
2016-05-29 15:29:13 +00:00
|
|
|
writeFile' ip bs =
|
2018-04-06 15:22:22 +00:00
|
|
|
withTmpDir ip $ \p -> writeFile p bs
|
|
|
|
|
|
|
|
|
|
|
|
appendFile' :: ByteString -> ByteString -> IO ()
|
|
|
|
{-# NOINLINE appendFile' #-}
|
|
|
|
appendFile' ip bs =
|
|
|
|
withTmpDir ip $ \p -> appendFile p bs
|
2016-06-05 01:10:28 +00:00
|
|
|
|
|
|
|
|
|
|
|
allDirectoryContents' :: ByteString -> IO [ByteString]
|
2016-06-05 12:33:53 +00:00
|
|
|
{-# NOINLINE allDirectoryContents' #-}
|
2016-06-05 01:10:28 +00:00
|
|
|
allDirectoryContents' ip =
|
2016-06-05 12:55:21 +00:00
|
|
|
withTmpDir ip $ \p -> DT.allDirectoryContents' (P.fromAbs p)
|
2016-06-05 01:10:28 +00:00
|
|
|
|
2018-04-06 14:42:40 +00:00
|
|
|
|
|
|
|
readFile' :: ByteString -> IO ByteString
|
|
|
|
{-# NOINLINE readFile' #-}
|
2020-01-13 22:13:21 +00:00
|
|
|
readFile' p = withTmpDir p (fmap L.toStrict . readFile)
|
2018-04-06 14:42:40 +00:00
|
|
|
|