fix stall while storing encrypted data in bup
Forking a new process rather than relying on a thread to feed gpg. The feeder thread was stalling, probably when the main thread got to the point it was wait()ing on the gpg to exit.
This commit is contained in:
parent
11da36e48f
commit
d996637fd6
2 changed files with 41 additions and 32 deletions
42
Crypto.hs
42
Crypto.hs
|
@ -17,6 +17,7 @@ module Crypto (
|
||||||
extractCipher,
|
extractCipher,
|
||||||
decryptCipher,
|
decryptCipher,
|
||||||
encryptKey,
|
encryptKey,
|
||||||
|
withEncryptedContentHandle,
|
||||||
withEncryptedContent,
|
withEncryptedContent,
|
||||||
withDecryptedContent,
|
withDecryptedContent,
|
||||||
) where
|
) where
|
||||||
|
@ -33,8 +34,10 @@ import Data.Bits.Utils
|
||||||
import System.IO
|
import System.IO
|
||||||
import System.Posix.IO
|
import System.Posix.IO
|
||||||
import System.Posix.Types
|
import System.Posix.Types
|
||||||
|
import System.Posix.Process
|
||||||
import Control.Concurrent
|
import Control.Concurrent
|
||||||
import Control.Exception
|
import Control.Exception
|
||||||
|
import System.Exit
|
||||||
|
|
||||||
import Types
|
import Types
|
||||||
import Key
|
import Key
|
||||||
|
@ -116,6 +119,11 @@ encryptKey (Cipher c) k =
|
||||||
keyMtime = Nothing -- to avoid leaking data
|
keyMtime = Nothing -- to avoid leaking data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{- Runs an action passing it a handle from which it can
|
||||||
|
- stream encrypted content. -}
|
||||||
|
withEncryptedContentHandle :: Cipher -> L.ByteString -> (Handle -> IO a) -> IO a
|
||||||
|
withEncryptedContentHandle = gpgCipherHandle [Params "--symmetric --force-mdc"]
|
||||||
|
|
||||||
{- Streams encrypted content to an action. -}
|
{- Streams encrypted content to an action. -}
|
||||||
withEncryptedContent :: Cipher -> L.ByteString -> (L.ByteString -> IO a) -> IO a
|
withEncryptedContent :: Cipher -> L.ByteString -> (L.ByteString -> IO a) -> IO a
|
||||||
withEncryptedContent = gpgCipher [Params "--symmetric --force-mdc"]
|
withEncryptedContent = gpgCipher [Params "--symmetric --force-mdc"]
|
||||||
|
@ -142,17 +150,10 @@ gpgPipeStrict params input = do
|
||||||
forceSuccess pid
|
forceSuccess pid
|
||||||
return output
|
return output
|
||||||
|
|
||||||
gpgPipeBytes :: [CommandParam] -> L.ByteString -> IO (PipeHandle, L.ByteString)
|
|
||||||
gpgPipeBytes params input = do
|
|
||||||
(pid, fromh, toh) <- hPipeBoth "gpg" (gpgParams params)
|
|
||||||
_ <- forkIO $ finally (L.hPut toh input) (hClose toh)
|
|
||||||
output <- L.hGetContents fromh
|
|
||||||
return (pid, output)
|
|
||||||
|
|
||||||
{- Runs gpg with a cipher and some parameters, feeding it an input,
|
{- Runs gpg with a cipher and some parameters, feeding it an input,
|
||||||
- and piping its output lazily to an action. -}
|
- and passing a handle to its output to an action. -}
|
||||||
gpgCipher :: [CommandParam] -> Cipher -> L.ByteString -> (L.ByteString -> IO a) -> IO a
|
gpgCipherHandle :: [CommandParam] -> Cipher -> L.ByteString -> (Handle -> IO a) -> IO a
|
||||||
gpgCipher params (Cipher c) input a = do
|
gpgCipherHandle params (Cipher c) input a = do
|
||||||
-- pipe the passphrase into gpg on a fd
|
-- pipe the passphrase into gpg on a fd
|
||||||
(frompipe, topipe) <- createPipe
|
(frompipe, topipe) <- createPipe
|
||||||
_ <- forkIO $ do
|
_ <- forkIO $ do
|
||||||
|
@ -161,16 +162,29 @@ gpgCipher params (Cipher c) input a = do
|
||||||
hClose toh
|
hClose toh
|
||||||
let Fd passphrasefd = frompipe
|
let Fd passphrasefd = frompipe
|
||||||
let passphrase = [Param "--passphrase-fd", Param $ show passphrasefd]
|
let passphrase = [Param "--passphrase-fd", Param $ show passphrasefd]
|
||||||
(pid, output) <- gpgPipeBytes (passphrase ++ params) input
|
|
||||||
|
(pid, fromh, toh) <- hPipeBoth "gpg" $
|
||||||
ret <- a output
|
gpgParams $ passphrase ++ params
|
||||||
|
_ <- forkProcess $ do
|
||||||
|
L.hPut toh input
|
||||||
|
hClose toh
|
||||||
|
exitSuccess
|
||||||
|
hClose toh
|
||||||
|
ret <- a fromh
|
||||||
|
|
||||||
-- cleanup
|
-- cleanup
|
||||||
forceSuccess pid
|
forceSuccess pid
|
||||||
closeFd frompipe
|
closeFd frompipe
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
{- Runs gpg with a cipher and some parameters, feeding it an input,
|
||||||
|
- and piping its output lazily to an action. -}
|
||||||
|
gpgCipher :: [CommandParam] -> Cipher -> L.ByteString -> (L.ByteString -> IO a) -> IO a
|
||||||
|
gpgCipher params c input a = do
|
||||||
|
gpgCipherHandle params c input $ \h -> do
|
||||||
|
content <- L.hGetContents h
|
||||||
|
a content
|
||||||
|
|
||||||
configKeyIds :: RemoteConfig -> IO KeyIds
|
configKeyIds :: RemoteConfig -> IO KeyIds
|
||||||
configKeyIds c = do
|
configKeyIds c = do
|
||||||
let k = configGet c "encryption"
|
let k = configGet c "encryption"
|
||||||
|
|
|
@ -17,7 +17,6 @@ import System.Process
|
||||||
import System.Exit
|
import System.Exit
|
||||||
import System.FilePath
|
import System.FilePath
|
||||||
import Data.List.Utils
|
import Data.List.Utils
|
||||||
import System.Cmd.Utils
|
|
||||||
|
|
||||||
import RemoteClass
|
import RemoteClass
|
||||||
import Types
|
import Types
|
||||||
|
@ -96,6 +95,15 @@ bup command buprepo params = do
|
||||||
showProgress -- make way for bup output
|
showProgress -- make way for bup output
|
||||||
liftIO $ boolSystem "bup" $ bupParams command buprepo params
|
liftIO $ boolSystem "bup" $ bupParams command buprepo params
|
||||||
|
|
||||||
|
pipeBup :: [CommandParam] -> Maybe Handle -> Maybe Handle -> IO Bool
|
||||||
|
pipeBup params inh outh = do
|
||||||
|
p <- runProcess "bup" (toCommand params)
|
||||||
|
Nothing Nothing inh outh Nothing
|
||||||
|
ok <- waitForProcess p
|
||||||
|
case ok of
|
||||||
|
ExitSuccess -> return True
|
||||||
|
_ -> return False
|
||||||
|
|
||||||
bupSplitParams :: Git.Repo -> BupRepo -> Key -> CommandParam -> Annex [CommandParam]
|
bupSplitParams :: Git.Repo -> BupRepo -> Key -> CommandParam -> Annex [CommandParam]
|
||||||
bupSplitParams r buprepo k src = do
|
bupSplitParams r buprepo k src = do
|
||||||
o <- getConfig r "bup-split-options" ""
|
o <- getConfig r "bup-split-options" ""
|
||||||
|
@ -118,28 +126,15 @@ storeEncrypted r buprepo (cipher, enck) k = do
|
||||||
params <- bupSplitParams r buprepo enck (Param "-")
|
params <- bupSplitParams r buprepo enck (Param "-")
|
||||||
liftIO $ flip catch (const $ return False) $ do
|
liftIO $ flip catch (const $ return False) $ do
|
||||||
content <- L.readFile src
|
content <- L.readFile src
|
||||||
-- FIXME hangs after a while
|
withEncryptedContentHandle cipher content $ \h -> do
|
||||||
(pid, h) <- hPipeTo "bup" (toCommand params)
|
pipeBup params (Just h) Nothing
|
||||||
withEncryptedContent cipher content $ L.hPut h
|
|
||||||
hClose h
|
|
||||||
forceSuccess pid
|
|
||||||
return True
|
|
||||||
|
|
||||||
retrieve :: BupRepo -> Key -> FilePath -> Annex Bool
|
retrieve :: BupRepo -> Key -> FilePath -> Annex Bool
|
||||||
retrieve buprepo k f = do
|
retrieve buprepo k f = do
|
||||||
let params = bupParams "join" buprepo [Param $ show k]
|
let params = bupParams "join" buprepo [Param $ show k]
|
||||||
ret <- liftIO $ try $ do
|
liftIO $ flip catch (const $ return False) $ do
|
||||||
-- pipe bup's stdout directly to file
|
|
||||||
tofile <- openFile f WriteMode
|
tofile <- openFile f WriteMode
|
||||||
p <- runProcess "bup" (toCommand params)
|
pipeBup params Nothing (Just tofile)
|
||||||
Nothing Nothing Nothing (Just tofile) Nothing
|
|
||||||
r <- waitForProcess p
|
|
||||||
case r of
|
|
||||||
ExitSuccess -> return True
|
|
||||||
_ -> return False
|
|
||||||
case ret of
|
|
||||||
Right r -> return r
|
|
||||||
Left _ -> return False
|
|
||||||
|
|
||||||
retrieveEncrypted :: BupRepo -> (Cipher, Key) -> FilePath -> Annex Bool
|
retrieveEncrypted :: BupRepo -> (Cipher, Key) -> FilePath -> Annex Bool
|
||||||
retrieveEncrypted bupreoo (cipher, enck) f = do
|
retrieveEncrypted bupreoo (cipher, enck) f = do
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue