Skip to content

Commit 65ec5c2

Browse files
committed
Make findExecutable return Nothing on absolute paths that aren't executable
Fixes #187.
1 parent 3f74c1e commit 65ec5c2

File tree

4 files changed

+37
-5
lines changed

4 files changed

+37
-5
lines changed

System/Directory/Internal/Windows.hsc

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import GHC.IO.SubSystem (IoSubSystem(IoPOSIX, IoNative), ioSubSystem)
2424
#endif
2525
import System.OsPath
2626
( (</>)
27+
, hasExtension
28+
, isExtensionOf
2729
, isPathSeparator
2830
, isRelative
2931
, pack
@@ -428,12 +430,18 @@ canonicalizePathSimplify path =
428430
pure path
429431

430432
searchPathEnvForExes :: OsString -> IO (Maybe OsPath)
431-
searchPathEnvForExes (OsString binary) = search `catch` \e ->
432-
if ioeGetErrorType e == InvalidArgument
433-
then pure Nothing
434-
else throwIO e
433+
searchPathEnvForExes binaryPath@(OsString binary) = do
434+
maybePath <- search
435+
`catch` \e ->
436+
if ioeGetErrorType e == InvalidArgument
437+
then pure Nothing
438+
else throwIO e
439+
pure (OsString <$> maybePath >>= verify)
435440
where
436-
search = (OsString <$>) <$> Win32.searchPath Nothing binary (Just (getOsString exeExtension))
441+
search = Win32.searchPath Nothing binary (Just (getOsString exeExtension))
442+
verify p
443+
| hasExtension binaryPath || exeExtension `isExtensionOf` p = Just p
444+
| otherwise = Nothing
437445

438446
findExecutablesLazyInternal :: ([OsPath] -> OsString -> ListT IO OsPath)
439447
-> OsString

directory.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ test-suite test
102102
DoesDirectoryExist001
103103
DoesPathExist
104104
FileTime
105+
FindExecutable
105106
FindFile001
106107
GetDirContents001
107108
GetDirContents002

tests/FindExecutable.hs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{-# LANGUAGE CPP #-}
2+
module FindExecutable where
3+
#include "util.inl"
4+
5+
main :: TestEnv -> IO ()
6+
main _t = do
7+
8+
-- 'find' expected to exist on both Windows and POSIX,
9+
-- though we have no idea if it's writable
10+
Just _ <- findExecutable "find"
11+
12+
T(expectEq) () Nothing =<< findExecutable "__nonexistent_binary_gbowyxcejjawf7r6__"
13+
14+
-- https://github.com/haskell/directory/issues/187
15+
T(expectEq) () Nothing =<< findExecutable "/"
16+
T(expectEq) () Nothing =<< findExecutable "//"
17+
#if !defined(mingw32_HOST_OS)
18+
T(expectEq) () Nothing =<< findExecutable "\\"
19+
T(expectEq) () Nothing =<< findExecutable "\\\\"
20+
T(expectEq) () Nothing =<< findExecutable "\\\\localhost\\c$"
21+
#endif

tests/Main.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import qualified Directory001
1111
import qualified DoesDirectoryExist001
1212
import qualified DoesPathExist
1313
import qualified FileTime
14+
import qualified FindExecutable
1415
import qualified FindFile001
1516
import qualified GetDirContents001
1617
import qualified GetDirContents002
@@ -45,6 +46,7 @@ main = T.testMain $ \ _t -> do
4546
T.isolatedRun _t "DoesDirectoryExist001" DoesDirectoryExist001.main
4647
T.isolatedRun _t "DoesPathExist" DoesPathExist.main
4748
T.isolatedRun _t "FileTime" FileTime.main
49+
T.isolatedRun _t "FindExecutable" FindExecutable.main
4850
T.isolatedRun _t "FindFile001" FindFile001.main
4951
T.isolatedRun _t "GetDirContents001" GetDirContents001.main
5052
T.isolatedRun _t "GetDirContents002" GetDirContents002.main

0 commit comments

Comments
 (0)