Skip to content

Commit 275a51a

Browse files
Merge pull request #32 from redneb/getcwd-exn-safe
rewrite getWorkingDirectory to use allocaBytes for exception safety
2 parents 49aede1 + 6479305 commit 275a51a

File tree

2 files changed

+30
-30
lines changed

2 files changed

+30
-30
lines changed

System/Posix/Directory.hsc

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -116,21 +116,21 @@ foreign import ccall unsafe "__hscore_d_name"
116116
-- | @getWorkingDirectory@ calls @getcwd@ to obtain the name
117117
-- of the current working directory.
118118
getWorkingDirectory :: IO FilePath
119-
getWorkingDirectory = do
120-
p <- mallocBytes long_path_size
121-
go p long_path_size
122-
where go p bytes = do
123-
p' <- c_getcwd p (fromIntegral bytes)
124-
if p' /= nullPtr
125-
then do s <- peekFilePath p'
126-
free p'
127-
return s
128-
else do errno <- getErrno
129-
if errno == eRANGE
130-
then do let bytes' = bytes * 2
131-
p'' <- reallocBytes p bytes'
132-
go p'' bytes'
133-
else throwErrno "getCurrentDirectory"
119+
getWorkingDirectory = go long_path_size
120+
where
121+
go bytes = do
122+
r <- allocaBytes bytes $ \buf -> do
123+
buf' <- c_getcwd buf (fromIntegral bytes)
124+
if buf' /= nullPtr
125+
then do s <- peekFilePath buf
126+
return (Just s)
127+
else do errno <- getErrno
128+
if errno == eRANGE
129+
-- we use Nothing to indicate that we should
130+
-- try again with a bigger buffer
131+
then return Nothing
132+
else throwErrno "getWorkingDirectory"
133+
maybe (go (2 * bytes)) return r
134134

135135
foreign import ccall unsafe "getcwd"
136136
c_getcwd :: Ptr CChar -> CSize -> IO (Ptr CChar)

System/Posix/Directory/ByteString.hsc

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -117,21 +117,21 @@ foreign import ccall unsafe "__hscore_d_name"
117117
-- | @getWorkingDirectory@ calls @getcwd@ to obtain the name
118118
-- of the current working directory.
119119
getWorkingDirectory :: IO RawFilePath
120-
getWorkingDirectory = do
121-
p <- mallocBytes long_path_size
122-
go p long_path_size
123-
where go p bytes = do
124-
p' <- c_getcwd p (fromIntegral bytes)
125-
if p' /= nullPtr
126-
then do s <- peekFilePath p'
127-
free p'
128-
return s
129-
else do errno <- getErrno
130-
if errno == eRANGE
131-
then do let bytes' = bytes * 2
132-
p'' <- reallocBytes p bytes'
133-
go p'' bytes'
134-
else throwErrno "getCurrentDirectory"
120+
getWorkingDirectory = go long_path_size
121+
where
122+
go bytes = do
123+
r <- allocaBytes bytes $ \buf -> do
124+
buf' <- c_getcwd buf (fromIntegral bytes)
125+
if buf' /= nullPtr
126+
then do s <- peekFilePath buf
127+
return (Just s)
128+
else do errno <- getErrno
129+
if errno == eRANGE
130+
-- we use Nothing to indicate that we should
131+
-- try again with a bigger buffer
132+
then return Nothing
133+
else throwErrno "getWorkingDirectory"
134+
maybe (go (2 * bytes)) return r
135135

136136
foreign import ccall unsafe "getcwd"
137137
c_getcwd :: Ptr CChar -> CSize -> IO (Ptr CChar)

0 commit comments

Comments
 (0)