aboutsummaryrefslogtreecommitdiff
path: root/Backend
diff options
context:
space:
mode:
authorGravatar Joey Hess <joeyh@joeyh.name>2015-05-27 15:58:32 -0400
committerGravatar Joey Hess <joeyh@joeyh.name>2015-05-27 15:58:32 -0400
commit70fbb08468ba893812e5c78d60984c91aff27fdd (patch)
tree0f67926da38687096c084acb5587aecee02b7556 /Backend
parent53414931906dd5307f16601566cf8e860f7ebe2a (diff)
if external hash command fails for any reason, fall back to internal hashing
This way, if a system's sha1sum etc is broken, it will be tried if git-annex was built to use it, but at least it will fall back to using internal hashing when it fails. A side benefit of this is that hashFile consistently throws an IOError if the file is unable to be read. In particular, if the disk is failing with IO errors, and external hash command is used, it used to throw a user error with the error message from externalSHA. Now, the external hash command will fail, that message will be printed as a warning, and it'll fall back to the internal hash command. If the disk IO error is not intermittent, it will re-occur, and so an IOError will be thrown. Of course, this can mean it reads a file twice, but only in edge cases.
Diffstat (limited to 'Backend')
-rw-r--r--Backend/Hash.hs28
1 files changed, 18 insertions, 10 deletions
diff --git a/Backend/Hash.hs b/Backend/Hash.hs
index f1b9d592d..1175af0bd 100644
--- a/Backend/Hash.hs
+++ b/Backend/Hash.hs
@@ -146,17 +146,25 @@ trivialMigrate oldkey newbackend afile
| otherwise = Nothing
hashFile :: Hash -> FilePath -> Integer -> Annex String
-hashFile hash file filesize = liftIO $ go hash
+hashFile hash file filesize = go hash
where
go (SHAHash hashsize) = case shaHasher hashsize filesize of
- Left sha -> sha <$> L.readFile file
- Right command ->
- either error return
- =<< externalSHA command hashsize file
- go (SkeinHash hashsize) = skeinHasher hashsize <$> L.readFile file
- go MD5Hash = md5Hasher <$> L.readFile file
-
-shaHasher :: HashSize -> Integer -> Either (L.ByteString -> String) String
+ Left sha -> use sha
+ Right (external, internal) -> do
+ v <- liftIO $ externalSHA external hashsize file
+ case v of
+ Right r -> return r
+ Left e -> do
+ warning e
+ -- fall back to internal since
+ -- external command failed
+ use internal
+ go (SkeinHash hashsize) = use (skeinHasher hashsize)
+ go MD5Hash = use md5Hasher
+
+ use hasher = liftIO $ hasher <$> L.readFile file
+
+shaHasher :: HashSize -> Integer -> Either (L.ByteString -> String) (String, L.ByteString -> String)
shaHasher hashsize filesize
| hashsize == 1 = use SysConfig.sha1 sha1
| hashsize == 256 = use SysConfig.sha256 sha256
@@ -173,7 +181,7 @@ shaHasher hashsize filesize
- and system. So there is no point forking an external
- process unless the file is large. -}
| filesize < 1048576 = use Nothing hasher
- | otherwise = Right c
+ | otherwise = Right (c, show . hasher)
skeinHasher :: HashSize -> (L.ByteString -> String)
skeinHasher hashsize