configure: Better checking that sha commands output in the desired format.
Run the same code git-annex used to get the sha, including its sanity checking. Much better than old grep. Should detect FreeBSD systems with sha commands that output in stange format.
This commit is contained in:
parent
cda0ed5d25
commit
d38854f3d1
4 changed files with 86 additions and 48 deletions
|
@ -12,11 +12,11 @@ import qualified Annex
|
|||
import Types.Backend
|
||||
import Types.Key
|
||||
import Types.KeySource
|
||||
import Utility.ExternalSHA
|
||||
|
||||
import qualified Build.SysConfig as SysConfig
|
||||
import Data.Digest.Pure.SHA
|
||||
import qualified Data.ByteString.Lazy as L
|
||||
import System.Process
|
||||
import Data.Char
|
||||
|
||||
type SHASize = Int
|
||||
|
@ -55,49 +55,11 @@ shaNameE size = shaName size ++ "E"
|
|||
shaN :: SHASize -> FilePath -> Integer -> Annex String
|
||||
shaN shasize file filesize = do
|
||||
showAction "checksum"
|
||||
case shaCommand shasize filesize of
|
||||
Left sha -> liftIO $ sha <$> L.readFile file
|
||||
Right command -> liftIO $
|
||||
sanitycheck command . parse command . lines <$>
|
||||
readsha command (toCommand [File file])
|
||||
where
|
||||
parse command [] = bad command
|
||||
parse command (l:_)
|
||||
| null sha = bad command
|
||||
-- sha is prefixed with \ when filename contains certian chars
|
||||
| "\\" `isPrefixOf` sha = drop 1 sha
|
||||
| otherwise = sha
|
||||
where
|
||||
sha = fst $ separate (== ' ') l
|
||||
bad command = error $ command ++ " parse error"
|
||||
|
||||
{- sha commands output the filename, so need to set fileEncoding -}
|
||||
readsha command args =
|
||||
withHandle StdoutHandle createProcessSuccess p $ \h -> do
|
||||
fileEncoding h
|
||||
output <- hGetContentsStrict h
|
||||
hClose h
|
||||
return output
|
||||
where
|
||||
p = (proc command args) { std_out = CreatePipe }
|
||||
|
||||
{- Check that we've correctly parsing the output of the command,
|
||||
- by making sure the sha we read is of the expected length. -}
|
||||
sanitycheck command sha
|
||||
| length sha /= expectedlen =
|
||||
error $ "Failed to parse the output of " ++ command
|
||||
| any (`notElem` "0123456789abcdef") sha' =
|
||||
error $ "Unexpected character in output of " ++ command ++ "\"" ++ sha ++ "\""
|
||||
| otherwise = sha'
|
||||
where
|
||||
sha' = map toLower sha
|
||||
expectedlen = case shasize of
|
||||
1 -> 40
|
||||
256 -> 64
|
||||
512 -> 128
|
||||
224 -> 56
|
||||
384 -> 96
|
||||
_ -> 0
|
||||
liftIO $ case shaCommand shasize filesize of
|
||||
Left sha -> sha <$> L.readFile file
|
||||
Right command ->
|
||||
either error return
|
||||
=<< externalSHA command shasize file
|
||||
|
||||
shaCommand :: SHASize -> Integer -> Either (L.ByteString -> String) String
|
||||
shaCommand shasize filesize
|
||||
|
|
|
@ -14,6 +14,7 @@ import Build.TestConfig
|
|||
import Utility.SafeCommand
|
||||
import Utility.Monad
|
||||
import Utility.Exception
|
||||
import Utility.ExternalSHA
|
||||
|
||||
tests :: [TestCase]
|
||||
tests =
|
||||
|
@ -45,17 +46,24 @@ tests =
|
|||
- On some systems, shaN is used instead, but on other
|
||||
- systems, it might be "hashalot", which does not produce
|
||||
- usable checksums. Only accept programs that produce
|
||||
- known-good hashes. -}
|
||||
- known-good hashes when run on files. -}
|
||||
shaTestCases :: [(Int, String)] -> [TestCase]
|
||||
shaTestCases l = map make l
|
||||
where
|
||||
make (n, knowngood) = TestCase key $ maybeSelectCmd key $
|
||||
zip (shacmds n) (repeat check)
|
||||
make (n, knowngood) = TestCase key $
|
||||
Config key . MaybeStringConfig <$> search (shacmds n)
|
||||
where
|
||||
key = "sha" ++ show n
|
||||
check = "</dev/null 2>/dev/null | grep -q '" ++ knowngood ++ "'"
|
||||
search [] = return Nothing
|
||||
search (c:cmds) = do
|
||||
sha <- externalSHA c n "/dev/null"
|
||||
if sha == Right knowngood
|
||||
then return $ Just c
|
||||
else search cmds
|
||||
|
||||
shacmds n = concatMap (\x -> [x, 'g':x, osxpath </> x]) $
|
||||
map (\x -> "sha" ++ show n ++ x) ["sum", ""]
|
||||
|
||||
{- Max OSX sometimes puts GNU tools outside PATH, so look in
|
||||
- the location it uses, and remember where to run them
|
||||
- from. -}
|
||||
|
|
67
Utility/ExternalSHA.hs
Normal file
67
Utility/ExternalSHA.hs
Normal file
|
@ -0,0 +1,67 @@
|
|||
{- Calculating a SHA checksum with an external command.
|
||||
-
|
||||
- This is often faster than using Haskell libraries.
|
||||
-
|
||||
- Copyright 2011-2013 Joey Hess <joey@kitenet.net>
|
||||
-
|
||||
- Licensed under the GNU GPL version 3 or higher.
|
||||
-}
|
||||
|
||||
module Utility.ExternalSHA (externalSHA) where
|
||||
|
||||
import Utility.SafeCommand
|
||||
import Utility.Process
|
||||
import Utility.FileSystemEncoding
|
||||
import Utility.Misc
|
||||
|
||||
import System.Process
|
||||
import Data.List
|
||||
import Data.Char
|
||||
import Control.Applicative
|
||||
import System.IO
|
||||
|
||||
externalSHA :: String -> Int -> FilePath -> IO (Either String String)
|
||||
externalSHA command shasize file = do
|
||||
ls <- lines <$> readsha (toCommand [File file])
|
||||
return $ sanitycheck =<< parse ls
|
||||
where
|
||||
{- sha commands output the filename, so need to set fileEncoding -}
|
||||
readsha args =
|
||||
withHandle StdoutHandle (createProcessChecked checkSuccessProcess) p $ \h -> do
|
||||
fileEncoding h
|
||||
output <- hGetContentsStrict h
|
||||
hClose h
|
||||
return output
|
||||
where
|
||||
p = (proc command args) { std_out = CreatePipe }
|
||||
|
||||
{- The first word of the output is taken to be the sha. -}
|
||||
parse [] = bad
|
||||
parse (l:_)
|
||||
| null sha = bad
|
||||
-- sha is prefixed with \ when filename contains certian chars
|
||||
| "\\" `isPrefixOf` sha = Right $ drop 1 sha
|
||||
| otherwise = Right sha
|
||||
where
|
||||
sha = fst $ separate (== ' ') l
|
||||
bad = Left $ command ++ " parse error"
|
||||
|
||||
{- Check that we've correctly parsing the output of the command,
|
||||
- by making sure the sha we read is of the expected length
|
||||
- and contains only the right characters. -}
|
||||
sanitycheck sha
|
||||
| length sha /= expectedSHALength shasize =
|
||||
Left $ "Failed to parse the output of " ++ command
|
||||
| any (`notElem` "0123456789abcdef") sha' =
|
||||
Left $ "Unexpected character in output of " ++ command ++ "\"" ++ sha ++ "\""
|
||||
| otherwise = Right sha'
|
||||
where
|
||||
sha' = map toLower sha
|
||||
|
||||
expectedSHALength :: Int -> Int
|
||||
expectedSHALength 1 = 40
|
||||
expectedSHALength 256 = 64
|
||||
expectedSHALength 512 = 128
|
||||
expectedSHALength 224 = 56
|
||||
expectedSHALength 384 = 96
|
||||
expectedSHALength _ = 0
|
1
debian/changelog
vendored
1
debian/changelog
vendored
|
@ -17,6 +17,7 @@ git-annex (4.20130502) UNRELEASED; urgency=low
|
|||
as received.
|
||||
* SHA: Add a runtime sanity check that sha commands output something
|
||||
that appears to be a real sha.
|
||||
* configure: Better checking that sha commands output in the desired format.
|
||||
|
||||
-- Joey Hess <joeyh@debian.org> Thu, 02 May 2013 20:39:19 -0400
|
||||
|
||||
|
|
Loading…
Reference in a new issue