More safely handle reading files

This replaces readIfFileExists, which has a race-condition and may raise
an exception, with safeReadFile, which safely reads a file and includes
the IOException if something goes wrong.
This commit is contained in:
Joshua Clayton 2016-07-02 07:08:09 -04:00
parent e1d6143161
commit d9efa11777
No known key found for this signature in database
GPG Key ID: 5B6558F77E9A8118
3 changed files with 10 additions and 15 deletions

View File

@ -10,7 +10,7 @@ import qualified System.Directory as D
import qualified Data.Char as C
import Data.Maybe (fromMaybe)
import Unused.Cache.FindArgsFromIgnoredPaths
import Unused.Util (safeHead, readIfFileExists)
import Unused.Util (safeHead, safeReadFile)
type MD5Config = ReaderT String IO
@ -43,7 +43,7 @@ md5Result r = do
liftIO $ readProcess md5exec [] r
ignoredPaths :: IO [String]
ignoredPaths = fromMaybe [] <$> (fmap lines <$> readIfFileExists ".gitignore")
ignoredPaths = either (const []) id <$> (fmap lines <$> safeReadFile ".gitignore")
md5Executable :: IO (Maybe String)
md5Executable =

View File

@ -12,7 +12,7 @@ import System.FilePath ((</>))
import System.Directory (getHomeDirectory, doesFileExist)
import Paths_unused (getDataFileName)
import Unused.ResultsClassifier.Types (LanguageConfiguration, ParseConfigError(..))
import Unused.Util (readIfFileExists)
import Unused.Util (safeReadFile)
loadConfig :: IO (Either String [LanguageConfiguration])
loadConfig = do
@ -39,10 +39,10 @@ loadAllConfigurations = do
loadConfigFromFile :: String -> IO (Either ParseConfigError [LanguageConfiguration])
loadConfigFromFile path = do
file <- fmap C.pack <$> readIfFileExists path
file <- fmap C.pack <$> safeReadFile path
return $ case file of
Nothing -> Right []
Just body -> addSourceToLeft path $ Y.decodeEither body
Left _ -> Right []
Right body -> addSourceToLeft path $ Y.decodeEither body
addSourceToLeft :: String -> Either String c -> Either ParseConfigError c
addSourceToLeft source = B.first (ParseConfigError source)

View File

@ -2,11 +2,11 @@ module Unused.Util
( groupBy
, stringToInt
, safeHead
, readIfFileExists
, safeReadFile
) where
import System.Directory (doesFileExist)
import Control.Arrow ((&&&))
import qualified Control.Exception as E
import qualified Data.List as L
import Data.Function
import Data.Char (digitToInt, isDigit)
@ -27,10 +27,5 @@ stringToInt xs
where
loop = foldl (\acc x -> acc * 10 + digitToInt x)
readIfFileExists :: String -> IO (Maybe String)
readIfFileExists path = do
exists <- doesFileExist path
if exists
then Just <$> readFile path
else return Nothing
safeReadFile :: FilePath -> IO (Either E.IOException String)
safeReadFile = E.try . readFile