Skip to content

Commit 050adae

Browse files
committed
Add File internals that work directly with Path
1 parent f8e8e54 commit 050adae

5 files changed

Lines changed: 1166 additions & 0 deletions

File tree

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
module Streamly.Internal.FileSystem.File.Utils
2+
( openFile
3+
, withFile
4+
) where
5+
6+
-------------------------------------------------------------------------------
7+
-- Imports
8+
-------------------------------------------------------------------------------
9+
10+
import Control.Exception (mask, onException, try)
11+
import Control.Monad (when)
12+
import GHC.IO (catchException, unsafePerformIO)
13+
import GHC.IO.Exception (IOException(..))
14+
import GHC.IO.Handle.Internals (handleFinalizer)
15+
import Streamly.Internal.FileSystem.Path (Path)
16+
import System.IO (IOMode(..), Handle, hSetBinaryMode, hClose)
17+
18+
#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
19+
import qualified Streamly.Internal.FileSystem.Windows.File as Platform
20+
#else
21+
import qualified Streamly.Internal.FileSystem.Posix.File as Platform
22+
#endif
23+
24+
import qualified Streamly.Internal.FileSystem.Path as Path
25+
26+
#if MIN_VERSION_base(4,16,0)
27+
import GHC.IO.Handle.Internals (addHandleFinalizer)
28+
#else
29+
import Control.Concurrent.MVar (MVar, addMVarFinalizer)
30+
import GHC.IO.Handle.Internals (debugIO)
31+
import GHC.IO.Handle.Types (Handle__, Handle(..))
32+
#endif
33+
34+
-------------------------------------------------------------------------------
35+
-- Utils
36+
-------------------------------------------------------------------------------
37+
38+
#if !(MIN_VERSION_base(4,16,0))
39+
type HandleFinalizer = FilePath -> MVar Handle__ -> IO ()
40+
41+
-- | Add a finalizer to a 'Handle'. Specifically, the finalizer
42+
-- will be added to the 'MVar' of a file handle or the write-side
43+
-- 'MVar' of a duplex handle. See Handle Finalizers for details.
44+
addHandleFinalizer :: Handle -> HandleFinalizer -> IO ()
45+
addHandleFinalizer handle finalizer = do
46+
debugIO $ "Registering finalizer: " ++ show filepath
47+
addMVarFinalizer mv (finalizer filepath mv)
48+
where
49+
!(filepath, !mv) = case handle of
50+
FileHandle fp m -> (fp, m)
51+
DuplexHandle fp _ write_m -> (fp, write_m)
52+
#endif
53+
54+
addFilePathToIOError :: String -> Path -> IOException -> IOException
55+
addFilePathToIOError fun fp ioe = unsafePerformIO $ do
56+
let fp' = Path.toString fp
57+
-- XXX Why is this important?
58+
-- deepseq will be introduced dependency because of this
59+
-- fp'' <- evaluate $ force fp'
60+
pure $ ioe{ ioe_location = fun, ioe_filename = Just fp' }
61+
62+
augmentError :: String -> Path -> IO a -> IO a
63+
augmentError str osfp = flip catchException (ioError . addFilePathToIOError str osfp)
64+
65+
withOpenFile'
66+
:: Path
67+
-> IOMode -> Bool -> Bool -> Bool
68+
-> (Handle -> IO r) -> Bool -> IO r
69+
withOpenFile' fp iomode binary existing cloExec action close_finally =
70+
mask $ \restore -> do
71+
hndl <- case (existing, cloExec) of
72+
(True, False) -> Platform.openExistingFile fp iomode
73+
(False, False) -> Platform.openFile fp iomode
74+
(True, True) -> Platform.openExistingFileWithCloseOnExec fp iomode
75+
(False, True) -> Platform.openFileWithCloseOnExec fp iomode
76+
addHandleFinalizer hndl handleFinalizer
77+
when binary $ hSetBinaryMode hndl True
78+
r <- restore (action hndl) `onException` hClose hndl
79+
when close_finally $ hClose hndl
80+
pure r
81+
82+
-- | Open a file and return the 'Handle'.
83+
openFile :: Path -> IOMode -> IO Handle
84+
openFile osfp iomode =
85+
augmentError "openFile" osfp $ withOpenFile' osfp iomode False False False pure False
86+
87+
-- | Run an action on a file.
88+
--
89+
-- The 'Handle' is automatically closed afther the action.
90+
withFile :: Path -> IOMode -> (Handle -> IO r) -> IO r
91+
withFile osfp iomode act = (augmentError "withFile" osfp
92+
$ withOpenFile' osfp iomode False False False (try . act) True)
93+
>>= either ioError pure

0 commit comments

Comments
 (0)