make retrieveKeyFile and retrieveKeyFileCheap throw exceptions
Converted retrieveKeyFileCheap to a Maybe, to avoid needing to throw a exception when a remote doesn't support it.
This commit is contained in:
		
					parent
					
						
							
								a6adea4aaf
							
						
					
				
			
			
				commit
				
					
						d9c7f81ba4
					
				
			
		
					 32 changed files with 247 additions and 245 deletions
				
			
		| 
						 | 
				
			
			@ -26,7 +26,7 @@ git-annex (8.20200502) UNRELEASED; urgency=medium
 | 
			
		|||
    the current directory.
 | 
			
		||||
  * Display a warning message when asked to operate on a file inside a
 | 
			
		||||
    directory that's a symbolic link to elsewhere.
 | 
			
		||||
  * When storing content on remote fails, always display a reason why.
 | 
			
		||||
  * When accessing a remote fails, always display a reason why.
 | 
			
		||||
 | 
			
		||||
 -- Joey Hess <id@joeyh.name>  Mon, 04 May 2020 12:46:11 -0400
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -189,15 +189,19 @@ downloadRemoteFile addunlockedmatcher r o uri file sz = checkCanAdd file $ do
 | 
			
		|||
			-- so that the remote knows what url it
 | 
			
		||||
			-- should use to download it.
 | 
			
		||||
			setTempUrl urlkey loguri
 | 
			
		||||
			let downloader = \dest p -> fst 
 | 
			
		||||
				<$> Remote.retrieveKeyFile r urlkey
 | 
			
		||||
					(AssociatedFile (Just (toRawFilePath file))) dest p
 | 
			
		||||
			let downloader = \dest p ->
 | 
			
		||||
				tryNonAsync (Remote.retrieveKeyFile r urlkey af dest p) >>= \case
 | 
			
		||||
					Right _ -> return True
 | 
			
		||||
					Left e -> do
 | 
			
		||||
						warning (show e)
 | 
			
		||||
						return False
 | 
			
		||||
			ret <- downloadWith addunlockedmatcher downloader urlkey (Remote.uuid r) loguri file
 | 
			
		||||
			removeTempUrl urlkey
 | 
			
		||||
			return ret
 | 
			
		||||
		)
 | 
			
		||||
  where
 | 
			
		||||
	loguri = setDownloader uri OtherDownloader
 | 
			
		||||
	af = AssociatedFile (Just (toRawFilePath file))
 | 
			
		||||
 | 
			
		||||
startWeb :: AddUnlockedMatcher -> AddUrlOptions -> URLString -> CommandStart
 | 
			
		||||
startWeb addunlockedmatcher o urlstring = go $ fromMaybe bad $ parseURI urlstring
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -41,6 +41,7 @@ import Data.Time.Clock.POSIX
 | 
			
		|||
import System.Posix.Types (EpochTime)
 | 
			
		||||
import qualified Data.Set as S
 | 
			
		||||
import qualified Data.Map as M
 | 
			
		||||
import Data.Either
 | 
			
		||||
 | 
			
		||||
cmd :: Command
 | 
			
		||||
cmd = withGlobalOptions [jobsOption, jsonOptions, annexedMatchingOptions] $
 | 
			
		||||
| 
						 | 
				
			
			@ -174,17 +175,20 @@ performRemote key afile backend numcopies remote =
 | 
			
		|||
		cleanup
 | 
			
		||||
		cleanup `after` a tmp
 | 
			
		||||
	getfile tmp = ifM (checkDiskSpace (Just (takeDirectory tmp)) key 0 True)
 | 
			
		||||
		( ifM (Remote.retrieveKeyFileCheap remote key afile tmp)
 | 
			
		||||
		( ifM (getcheap tmp)
 | 
			
		||||
			( return (Just True)
 | 
			
		||||
			, ifM (Annex.getState Annex.fast)
 | 
			
		||||
				( return Nothing
 | 
			
		||||
				, Just . fst <$>
 | 
			
		||||
					Remote.retrieveKeyFile remote key (AssociatedFile Nothing) tmp dummymeter
 | 
			
		||||
				, Just . isRight <$> tryNonAsync (getfile' tmp)
 | 
			
		||||
				)
 | 
			
		||||
			)
 | 
			
		||||
		, return (Just False)
 | 
			
		||||
		)
 | 
			
		||||
	getfile' tmp = Remote.retrieveKeyFile remote key (AssociatedFile Nothing) tmp dummymeter
 | 
			
		||||
	dummymeter _ = noop
 | 
			
		||||
	getcheap tmp = case Remote.retrieveKeyFileCheap remote of
 | 
			
		||||
		Just a -> isRight <$> tryNonAsync (a key afile tmp)
 | 
			
		||||
		Nothing -> return False
 | 
			
		||||
 | 
			
		||||
startKey :: Maybe Remote -> Incremental -> (Key, ActionItem) -> NumCopies -> CommandStart
 | 
			
		||||
startKey from inc (key, ai) numcopies =
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -112,5 +112,9 @@ getKey' key afile = dispatch
 | 
			
		|||
		download (Remote.uuid r) key afile stdRetry
 | 
			
		||||
			(\p -> do
 | 
			
		||||
				showAction $ "from " ++ Remote.name r
 | 
			
		||||
				Remote.retrieveKeyFile r key afile dest p
 | 
			
		||||
				tryNonAsync (Remote.retrieveKeyFile r key afile dest p) >>= \case
 | 
			
		||||
					Right v -> return (True, v)
 | 
			
		||||
					Left e -> do
 | 
			
		||||
						warning (show e)
 | 
			
		||||
						return (False, UnVerified)
 | 
			
		||||
			) witness
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -207,7 +207,11 @@ fromPerform src removewhen key afile = do
 | 
			
		|||
	go = notifyTransfer Download afile $ 
 | 
			
		||||
		download (Remote.uuid src) key afile stdRetry $ \p ->
 | 
			
		||||
			getViaTmp (Remote.retrievalSecurityPolicy src) (RemoteVerify src) key $ \t ->
 | 
			
		||||
				Remote.retrieveKeyFile src key afile t p
 | 
			
		||||
				tryNonAsync (Remote.retrieveKeyFile src key afile t p) >>= \case
 | 
			
		||||
					Right v -> return (True, v)
 | 
			
		||||
					Left e -> do
 | 
			
		||||
						warning (show e)
 | 
			
		||||
						return (False, UnVerified)
 | 
			
		||||
	dispatch _ _ False = stop -- failed
 | 
			
		||||
	dispatch RemoveNever _ True = next $ return True -- copy complete
 | 
			
		||||
	dispatch RemoveSafe deststartedwithcopy True = lockContentShared key $ \_lck -> do
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -274,8 +274,9 @@ test runannex mkr mkk =
 | 
			
		|||
			Nothing -> return True
 | 
			
		||||
			Just verifier -> verifier k (serializeKey k)
 | 
			
		||||
	get r k = getViaTmp (Remote.retrievalSecurityPolicy r) (RemoteVerify r) k $ \dest ->
 | 
			
		||||
		Remote.retrieveKeyFile r k (AssociatedFile Nothing)
 | 
			
		||||
			dest nullMeterUpdate
 | 
			
		||||
		tryNonAsync (Remote.retrieveKeyFile r k (AssociatedFile Nothing) dest nullMeterUpdate) >>= \case
 | 
			
		||||
			Right v -> return (True, v)
 | 
			
		||||
			Left _ -> return (False, UnVerified)
 | 
			
		||||
	store r k = Remote.storeKey r k (AssociatedFile Nothing) nullMeterUpdate
 | 
			
		||||
	remove r k = Remote.removeKey r k
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -348,10 +349,14 @@ testUnavailable runannex mkr mkk =
 | 
			
		|||
		Remote.checkPresent r k
 | 
			
		||||
	, check (== Right False) "retrieveKeyFile" $ \r k ->
 | 
			
		||||
		getViaTmp (Remote.retrievalSecurityPolicy r) (RemoteVerify r) k $ \dest ->
 | 
			
		||||
			Remote.retrieveKeyFile r k (AssociatedFile Nothing) dest nullMeterUpdate
 | 
			
		||||
	, check (== Right False) "retrieveKeyFileCheap" $ \r k ->
 | 
			
		||||
		getViaTmp (Remote.retrievalSecurityPolicy r) (RemoteVerify r) k $ \dest -> unVerified $
 | 
			
		||||
			Remote.retrieveKeyFileCheap r k (AssociatedFile Nothing) dest
 | 
			
		||||
			tryNonAsync (Remote.retrieveKeyFile r k (AssociatedFile Nothing) dest nullMeterUpdate) >>= \case
 | 
			
		||||
				Right v -> return (True, v)
 | 
			
		||||
				Left _ -> return (False, UnVerified)
 | 
			
		||||
	, check (== Right False) "retrieveKeyFileCheap" $ \r k -> case Remote.retrieveKeyFileCheap r of
 | 
			
		||||
		Nothing -> return False
 | 
			
		||||
		Just a -> getViaTmp (Remote.retrievalSecurityPolicy r) (RemoteVerify r) k $ \dest -> 
 | 
			
		||||
			unVerified $ isRight
 | 
			
		||||
				<$> tryNonAsync (a k (AssociatedFile Nothing) dest)
 | 
			
		||||
	]
 | 
			
		||||
  where
 | 
			
		||||
	check checkval desc a = testCase desc $ 
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -53,18 +53,22 @@ toPerform :: Key -> AssociatedFile -> Remote -> CommandPerform
 | 
			
		|||
toPerform key file remote = go Upload file $
 | 
			
		||||
	upload (uuid remote) key file stdRetry $ \p -> do
 | 
			
		||||
		tryNonAsync (Remote.storeKey remote key file p) >>= \case
 | 
			
		||||
			Left e -> do
 | 
			
		||||
				warning (show e)
 | 
			
		||||
				return False
 | 
			
		||||
			Right () -> do
 | 
			
		||||
				Remote.logStatus remote key InfoPresent
 | 
			
		||||
				return True
 | 
			
		||||
			Left e -> do
 | 
			
		||||
				warning (show e)
 | 
			
		||||
				return False
 | 
			
		||||
 | 
			
		||||
fromPerform :: Key -> AssociatedFile -> Remote -> CommandPerform
 | 
			
		||||
fromPerform key file remote = go Upload file $
 | 
			
		||||
	download (uuid remote) key file stdRetry $ \p ->
 | 
			
		||||
		getViaTmp (retrievalSecurityPolicy remote) (RemoteVerify remote) key $ 
 | 
			
		||||
			\t -> Remote.retrieveKeyFile remote key file t p
 | 
			
		||||
		getViaTmp (retrievalSecurityPolicy remote) (RemoteVerify remote) key $ \t ->
 | 
			
		||||
			tryNonAsync (Remote.retrieveKeyFile remote key file t p) >>= \case
 | 
			
		||||
				Right v -> return (True, v)	
 | 
			
		||||
				Left e -> do
 | 
			
		||||
					warning (show e)
 | 
			
		||||
					return (False, UnVerified)
 | 
			
		||||
 | 
			
		||||
go :: Direction -> AssociatedFile -> (NotifyWitness -> Annex Bool) -> CommandPerform
 | 
			
		||||
go direction file a = notifyTransfer direction file a >>= liftIO . exitBool
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,7 +48,11 @@ start = do
 | 
			
		|||
		| otherwise = notifyTransfer direction file $
 | 
			
		||||
			download (Remote.uuid remote) key file stdRetry $ \p ->
 | 
			
		||||
				getViaTmp (Remote.retrievalSecurityPolicy remote) (RemoteVerify remote) key $ \t -> do
 | 
			
		||||
					r <- Remote.retrieveKeyFile remote key file t p
 | 
			
		||||
					r <- tryNonAsync (Remote.retrieveKeyFile remote key file t p) >>= \case
 | 
			
		||||
						Left e -> do
 | 
			
		||||
							warning (show e)
 | 
			
		||||
							return (False, UnVerified)
 | 
			
		||||
						Right v -> return (True, v)
 | 
			
		||||
					-- Make sure we get the current
 | 
			
		||||
					-- associated files data for the key,
 | 
			
		||||
					-- not old cached data.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -64,8 +64,8 @@ gen r u rc gc rs = do
 | 
			
		|||
		, cost = semiExpensiveRemoteCost
 | 
			
		||||
		, name = Git.repoDescribe r
 | 
			
		||||
		, storeKey = storeKeyDummy
 | 
			
		||||
		, retrieveKeyFile = retreiveKeyFileDummy
 | 
			
		||||
		, retrieveKeyFileCheap = \_ _ _ -> return False
 | 
			
		||||
		, retrieveKeyFile = retrieveKeyFileDummy
 | 
			
		||||
		, retrieveKeyFileCheap = Nothing
 | 
			
		||||
		, retrievalSecurityPolicy = RetrievalAllKeysSecure
 | 
			
		||||
		, removeKey = removeKeyDummy
 | 
			
		||||
		, lockContent = Nothing
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -64,7 +64,7 @@ gen r _ rc gc rs = do
 | 
			
		|||
		, name = Git.repoDescribe r
 | 
			
		||||
		, storeKey = uploadKey
 | 
			
		||||
		, retrieveKeyFile = downloadKey
 | 
			
		||||
		, retrieveKeyFileCheap = downloadKeyCheap
 | 
			
		||||
		, retrieveKeyFileCheap = Nothing
 | 
			
		||||
		-- Bittorrent does its own hash checks.
 | 
			
		||||
		, retrievalSecurityPolicy = RetrievalAllKeysSecure
 | 
			
		||||
		, removeKey = dropKey
 | 
			
		||||
| 
						 | 
				
			
			@ -91,25 +91,23 @@ gen r _ rc gc rs = do
 | 
			
		|||
		, remoteStateHandle = rs
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
downloadKey :: Key -> AssociatedFile -> FilePath -> MeterUpdate -> Annex (Bool, Verification)
 | 
			
		||||
downloadKey key _file dest p = unVerified $
 | 
			
		||||
downloadKey :: Key -> AssociatedFile -> FilePath -> MeterUpdate -> Annex Verification
 | 
			
		||||
downloadKey key _file dest p = do
 | 
			
		||||
	get . map (torrentUrlNum . fst . getDownloader) =<< getBitTorrentUrls key
 | 
			
		||||
	return UnVerified
 | 
			
		||||
  where
 | 
			
		||||
	get [] = do
 | 
			
		||||
		warning "could not download torrent"
 | 
			
		||||
		return False
 | 
			
		||||
	get [] = giveup "could not download torrent"
 | 
			
		||||
	get urls = do
 | 
			
		||||
		showOutput -- make way for download progress bar
 | 
			
		||||
		untilTrue urls $ \(u, filenum) -> do
 | 
			
		||||
		ok <- untilTrue urls $ \(u, filenum) -> do
 | 
			
		||||
			registerTorrentCleanup u
 | 
			
		||||
			checkDependencies
 | 
			
		||||
			ifM (downloadTorrentFile u)
 | 
			
		||||
				( downloadTorrentContent key u dest filenum p
 | 
			
		||||
				, return False
 | 
			
		||||
				)
 | 
			
		||||
 | 
			
		||||
downloadKeyCheap :: Key -> AssociatedFile -> FilePath -> Annex Bool
 | 
			
		||||
downloadKeyCheap _ _ _ = return False
 | 
			
		||||
		unless ok $
 | 
			
		||||
			get []
 | 
			
		||||
 | 
			
		||||
uploadKey :: Key -> AssociatedFile -> MeterUpdate -> Annex ()
 | 
			
		||||
uploadKey _ _ _ = giveup "upload to bittorrent not supported"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -70,8 +70,8 @@ gen r u rc gc rs = do
 | 
			
		|||
		, cost = cst
 | 
			
		||||
		, name = Git.repoDescribe r
 | 
			
		||||
		, storeKey = storeKeyDummy
 | 
			
		||||
		, retrieveKeyFile = retreiveKeyFileDummy
 | 
			
		||||
		, retrieveKeyFileCheap = retrieveCheap buprepo
 | 
			
		||||
		, retrieveKeyFile = retrieveKeyFileDummy
 | 
			
		||||
		, retrieveKeyFileCheap = Nothing
 | 
			
		||||
		-- Bup uses git, which cryptographically verifies content
 | 
			
		||||
		-- (with SHA1, but sufficiently for this).
 | 
			
		||||
		, retrievalSecurityPolicy = RetrievalAllKeysSecure
 | 
			
		||||
| 
						 | 
				
			
			@ -169,9 +169,6 @@ retrieve buprepo = byteRetriever $ \k sink -> do
 | 
			
		|||
	liftIO (hClose h >> forceSuccessProcess p pid)
 | 
			
		||||
		`after` (sink =<< liftIO (L.hGetContents h))
 | 
			
		||||
 | 
			
		||||
retrieveCheap :: BupRepo -> Key -> AssociatedFile -> FilePath -> Annex Bool
 | 
			
		||||
retrieveCheap _ _ _ _ = return False
 | 
			
		||||
 | 
			
		||||
{- Cannot revert having stored a key in bup, but at least the data for the
 | 
			
		||||
 - key will be used for deltaing data of other keys stored later.
 | 
			
		||||
 -
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -71,8 +71,8 @@ gen r u rc gc rs = do
 | 
			
		|||
		, cost = cst
 | 
			
		||||
		, name = Git.repoDescribe r
 | 
			
		||||
		, storeKey = storeKeyDummy
 | 
			
		||||
		, retrieveKeyFile = retreiveKeyFileDummy
 | 
			
		||||
		, retrieveKeyFileCheap = retrieveCheap
 | 
			
		||||
		, retrieveKeyFile = retrieveKeyFileDummy
 | 
			
		||||
		, retrieveKeyFileCheap = Nothing
 | 
			
		||||
		-- ddar communicates over ssh, not subject to http redirect
 | 
			
		||||
		-- type attacks
 | 
			
		||||
		, retrievalSecurityPolicy = RetrievalAllKeysSecure
 | 
			
		||||
| 
						 | 
				
			
			@ -162,9 +162,6 @@ retrieve ddarrepo = byteRetriever $ \k sink -> do
 | 
			
		|||
	liftIO (hClose h >> forceSuccessProcess p pid)
 | 
			
		||||
		`after` (sink =<< liftIO (L.hGetContents h))
 | 
			
		||||
 | 
			
		||||
retrieveCheap :: Key -> AssociatedFile -> FilePath -> Annex Bool
 | 
			
		||||
retrieveCheap _ _ _ = return False
 | 
			
		||||
 | 
			
		||||
remove :: DdarRepo -> Remover
 | 
			
		||||
remove ddarrepo key = do
 | 
			
		||||
	(cmd, params) <- ddarRemoteCall NoConsumeStdin ddarrepo 'd'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -69,7 +69,7 @@ gen r u rc gc rs = do
 | 
			
		|||
			, cost = cst
 | 
			
		||||
			, name = Git.repoDescribe r
 | 
			
		||||
			, storeKey = storeKeyDummy
 | 
			
		||||
			, retrieveKeyFile = retreiveKeyFileDummy
 | 
			
		||||
			, retrieveKeyFile = retrieveKeyFileDummy
 | 
			
		||||
			, retrieveKeyFileCheap = retrieveKeyFileCheapM dir chunkconfig
 | 
			
		||||
			, retrievalSecurityPolicy = RetrievalAllKeysSecure
 | 
			
		||||
			, removeKey = removeKeyDummy
 | 
			
		||||
| 
						 | 
				
			
			@ -205,21 +205,19 @@ retrieveKeyFileM d (LegacyChunks _) = Legacy.retrieve locations d
 | 
			
		|||
retrieveKeyFileM d _ = byteRetriever $ \k sink ->
 | 
			
		||||
	sink =<< liftIO (L.readFile =<< getLocation d k)
 | 
			
		||||
 | 
			
		||||
retrieveKeyFileCheapM :: FilePath -> ChunkConfig -> Key -> AssociatedFile -> FilePath -> Annex Bool
 | 
			
		||||
retrieveKeyFileCheapM :: FilePath -> ChunkConfig -> Maybe (Key -> AssociatedFile -> FilePath -> Annex ())
 | 
			
		||||
-- no cheap retrieval possible for chunks
 | 
			
		||||
retrieveKeyFileCheapM _ (UnpaddedChunks _) _ _ _ = return False
 | 
			
		||||
retrieveKeyFileCheapM _ (LegacyChunks _) _ _ _ = return False
 | 
			
		||||
retrieveKeyFileCheapM _ (UnpaddedChunks _) = Nothing
 | 
			
		||||
retrieveKeyFileCheapM _ (LegacyChunks _) = Nothing
 | 
			
		||||
#ifndef mingw32_HOST_OS
 | 
			
		||||
retrieveKeyFileCheapM d NoChunks k _af f = liftIO $ catchBoolIO $ do
 | 
			
		||||
retrieveKeyFileCheapM d NoChunks = Just $ \k _af f -> liftIO $ do
 | 
			
		||||
	file <- absPath =<< getLocation d k
 | 
			
		||||
	ifM (doesFileExist file)
 | 
			
		||||
		( do
 | 
			
		||||
			createSymbolicLink file f
 | 
			
		||||
			return True
 | 
			
		||||
		, return False
 | 
			
		||||
		( createSymbolicLink file f
 | 
			
		||||
		, giveup "content file not present in remote"
 | 
			
		||||
		)
 | 
			
		||||
#else
 | 
			
		||||
retrieveKeyFileCheapM _ _ _ _ _ = return False
 | 
			
		||||
retrieveKeyFileCheapM _ _ = Nothing
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
removeKeyM :: FilePath -> Remover
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -121,8 +121,8 @@ gen r u rc gc rs
 | 
			
		|||
			, cost = cst
 | 
			
		||||
			, name = Git.repoDescribe r
 | 
			
		||||
			, storeKey = storeKeyDummy
 | 
			
		||||
			, retrieveKeyFile = retreiveKeyFileDummy
 | 
			
		||||
			, retrieveKeyFileCheap = \_ _ _ -> return False
 | 
			
		||||
			, retrieveKeyFile = retrieveKeyFileDummy
 | 
			
		||||
			, retrieveKeyFileCheap = Nothing
 | 
			
		||||
			-- External special remotes use many http libraries
 | 
			
		||||
			-- and have no protection against redirects to
 | 
			
		||||
			-- local private web servers, or in some cases
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -132,8 +132,8 @@ gen' r u c gc rs = do
 | 
			
		|||
		, cost = cst
 | 
			
		||||
		, name = Git.repoDescribe r
 | 
			
		||||
		, storeKey = storeKeyDummy
 | 
			
		||||
		, retrieveKeyFile = retreiveKeyFileDummy
 | 
			
		||||
		, retrieveKeyFileCheap = \_ _ _ -> return False
 | 
			
		||||
		, retrieveKeyFile = retrieveKeyFileDummy
 | 
			
		||||
		, retrieveKeyFileCheap = Nothing
 | 
			
		||||
		, retrievalSecurityPolicy = RetrievalAllKeysSecure
 | 
			
		||||
		, removeKey = removeKeyDummy
 | 
			
		||||
		, lockContent = Nothing
 | 
			
		||||
| 
						 | 
				
			
			@ -393,7 +393,7 @@ retrieve r rsyncopts k p sink = do
 | 
			
		|||
retrieve' :: Git.Repo -> Remote -> Remote.Rsync.RsyncOpts -> Retriever
 | 
			
		||||
retrieve' repo r rsyncopts
 | 
			
		||||
	| not $ Git.repoIsUrl repo = byteRetriever $ \k sink ->
 | 
			
		||||
		guardUsable repo (return False) $
 | 
			
		||||
		guardUsable repo (giveup "cannot access remote") $
 | 
			
		||||
			sink =<< liftIO (L.readFile $ gCryptLocation repo k)
 | 
			
		||||
	| Git.repoIsSsh repo = if accessShell r
 | 
			
		||||
		then fileRetriever $ \f k p -> do
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -183,7 +183,7 @@ gen r u rc gc rs
 | 
			
		|||
			, name = Git.repoDescribe r
 | 
			
		||||
			, storeKey = copyToRemote new st
 | 
			
		||||
			, retrieveKeyFile = copyFromRemote new st
 | 
			
		||||
			, retrieveKeyFileCheap = copyFromRemoteCheap new st
 | 
			
		||||
			, retrieveKeyFileCheap = copyFromRemoteCheap new st r
 | 
			
		||||
			, retrievalSecurityPolicy = RetrievalAllKeysSecure
 | 
			
		||||
			, removeKey = dropKey new st
 | 
			
		||||
			, lockContent = Just (lockKey new st)
 | 
			
		||||
| 
						 | 
				
			
			@ -515,50 +515,55 @@ lockKey' repo r st@(State connpool duc _ _ _) key callback
 | 
			
		|||
	failedlock = giveup "can't lock content"
 | 
			
		||||
 | 
			
		||||
{- Tries to copy a key's content from a remote's annex to a file. -}
 | 
			
		||||
copyFromRemote :: Remote -> State -> Key -> AssociatedFile -> FilePath -> MeterUpdate -> Annex (Bool, Verification)
 | 
			
		||||
copyFromRemote :: Remote -> State -> Key -> AssociatedFile -> FilePath -> MeterUpdate -> Annex Verification
 | 
			
		||||
copyFromRemote = copyFromRemote' False
 | 
			
		||||
 | 
			
		||||
copyFromRemote' :: Bool -> Remote -> State -> Key -> AssociatedFile -> FilePath -> MeterUpdate -> Annex (Bool, Verification)
 | 
			
		||||
copyFromRemote' :: Bool -> Remote -> State -> Key -> AssociatedFile -> FilePath -> MeterUpdate -> Annex Verification
 | 
			
		||||
copyFromRemote' forcersync r st key file dest meterupdate = do
 | 
			
		||||
	repo <- getRepo r
 | 
			
		||||
	copyFromRemote'' repo forcersync r st key file dest meterupdate
 | 
			
		||||
 | 
			
		||||
copyFromRemote'' :: Git.Repo -> Bool -> Remote -> State -> Key -> AssociatedFile -> FilePath -> MeterUpdate -> Annex (Bool, Verification)
 | 
			
		||||
copyFromRemote'' :: Git.Repo -> Bool -> Remote -> State -> Key -> AssociatedFile -> FilePath -> MeterUpdate -> Annex Verification
 | 
			
		||||
copyFromRemote'' repo forcersync r st@(State connpool _ _ _ _) key file dest meterupdate
 | 
			
		||||
	| Git.repoIsHttp repo = unVerified $ do
 | 
			
		||||
	| Git.repoIsHttp repo = do
 | 
			
		||||
		gc <- Annex.getGitConfig
 | 
			
		||||
		Url.withUrlOptionsPromptingCreds $
 | 
			
		||||
		ok <- Url.withUrlOptionsPromptingCreds $
 | 
			
		||||
			Annex.Content.downloadUrl key meterupdate (keyUrls gc repo r key) dest
 | 
			
		||||
	| not $ Git.repoIsUrl repo = guardUsable repo (unVerified (return False)) $ do
 | 
			
		||||
		unless ok $
 | 
			
		||||
			giveup "failed to download content"
 | 
			
		||||
		return UnVerified
 | 
			
		||||
	| not $ Git.repoIsUrl repo = guardUsable repo (giveup "cannot access remote") $ do
 | 
			
		||||
		params <- Ssh.rsyncParams r Download
 | 
			
		||||
		u <- getUUID
 | 
			
		||||
		hardlink <- wantHardLink
 | 
			
		||||
		-- run copy from perspective of remote
 | 
			
		||||
		onLocalFast st $ do
 | 
			
		||||
			v <- Annex.Content.prepSendAnnex key
 | 
			
		||||
			case v of
 | 
			
		||||
				Nothing -> do
 | 
			
		||||
					warning "content is not present in remote"
 | 
			
		||||
					return (False, UnVerified)
 | 
			
		||||
				Just (object, checksuccess) -> do
 | 
			
		||||
					copier <- mkCopier hardlink st params
 | 
			
		||||
					runTransfer (Transfer Download u (fromKey id key))
 | 
			
		||||
						file stdRetry $ \p ->
 | 
			
		||||
							metered (Just (combineMeterUpdate p meterupdate)) key $ \_ p' -> 
 | 
			
		||||
								copier object dest p' checksuccess
 | 
			
		||||
		onLocalFast st $ Annex.Content.prepSendAnnex key >>= \case
 | 
			
		||||
			Just (object, checksuccess) -> do
 | 
			
		||||
				copier <- mkCopier hardlink st params
 | 
			
		||||
				(ok, v) <- runTransfer (Transfer Download u (fromKey id key))
 | 
			
		||||
					file stdRetry $ \p ->
 | 
			
		||||
						metered (Just (combineMeterUpdate p meterupdate)) key $ \_ p' -> 
 | 
			
		||||
							copier object dest p' checksuccess
 | 
			
		||||
				if ok
 | 
			
		||||
					then return v
 | 
			
		||||
					else giveup "failed to retrieve content from remote"
 | 
			
		||||
			Nothing -> giveup "content is not present in remote"
 | 
			
		||||
	| Git.repoIsSsh repo = if forcersync
 | 
			
		||||
		then fallback meterupdate
 | 
			
		||||
		then do
 | 
			
		||||
			(ok, v) <- fallback meterupdate
 | 
			
		||||
			if ok
 | 
			
		||||
				then return v
 | 
			
		||||
				else giveup "failed to retrieve content from remote"
 | 
			
		||||
		else P2PHelper.retrieve
 | 
			
		||||
			(\p -> Ssh.runProto r connpool (return (False, UnVerified)) (fallback p))
 | 
			
		||||
			key file dest meterupdate
 | 
			
		||||
	| otherwise = do
 | 
			
		||||
		warning "copying from non-ssh, non-http remote not supported"
 | 
			
		||||
		unVerified (return False)
 | 
			
		||||
	| otherwise = giveup "copying from non-ssh, non-http remote not supported"
 | 
			
		||||
  where
 | 
			
		||||
	fallback p = unVerified $ feedprogressback $ \p' -> do
 | 
			
		||||
		oh <- mkOutputHandlerQuiet
 | 
			
		||||
		Ssh.rsyncHelper oh (Just (combineMeterUpdate p' p))
 | 
			
		||||
			=<< Ssh.rsyncParamsRemote False r Download key dest file
 | 
			
		||||
 | 
			
		||||
	{- Feed local rsync's progress info back to the remote,
 | 
			
		||||
	 - by forking a feeder thread that runs
 | 
			
		||||
	 - git-annex-shell transferinfo at the same time
 | 
			
		||||
| 
						 | 
				
			
			@ -619,33 +624,26 @@ copyFromRemote'' repo forcersync r st@(State connpool _ _ _ _) key file dest met
 | 
			
		|||
					=<< tryTakeMVar pidv
 | 
			
		||||
		bracketIO noop (const cleanup) (const $ a feeder)
 | 
			
		||||
 | 
			
		||||
copyFromRemoteCheap :: Remote -> State -> Key -> AssociatedFile -> FilePath -> Annex Bool
 | 
			
		||||
copyFromRemoteCheap r st key af file = do
 | 
			
		||||
	repo <- getRepo r
 | 
			
		||||
	copyFromRemoteCheap' repo r st key af file
 | 
			
		||||
 | 
			
		||||
copyFromRemoteCheap' :: Git.Repo -> Remote -> State -> Key -> AssociatedFile -> FilePath -> Annex Bool
 | 
			
		||||
copyFromRemoteCheap :: Remote -> State -> Git.Repo -> Maybe (Key -> AssociatedFile -> FilePath -> Annex ())
 | 
			
		||||
copyFromRemoteCheap r st repo
 | 
			
		||||
#ifndef mingw32_HOST_OS
 | 
			
		||||
copyFromRemoteCheap' repo r st key af file
 | 
			
		||||
	| not $ Git.repoIsUrl repo = guardUsable repo (return False) $ do
 | 
			
		||||
	| not $ Git.repoIsUrl repo = Just $ \key _af file -> guardUsable repo (giveup "cannot access remote") $ do
 | 
			
		||||
		gc <- getGitConfigFromState st
 | 
			
		||||
		loc <- liftIO $ gitAnnexLocation key repo gc
 | 
			
		||||
		liftIO $ ifM (R.doesPathExist loc)
 | 
			
		||||
			( do
 | 
			
		||||
				absloc <- absPath (fromRawFilePath loc)
 | 
			
		||||
				catchBoolIO $ do
 | 
			
		||||
					createSymbolicLink absloc file
 | 
			
		||||
					return True
 | 
			
		||||
			, return False
 | 
			
		||||
				createSymbolicLink absloc file
 | 
			
		||||
			, giveup "remote does not contain key"
 | 
			
		||||
			)
 | 
			
		||||
	| Git.repoIsSsh repo =
 | 
			
		||||
	| Git.repoIsSsh repo = Just $ \key af file ->
 | 
			
		||||
		ifM (Annex.Content.preseedTmp key file)
 | 
			
		||||
			( fst <$> copyFromRemote' True r st key af file nullMeterUpdate
 | 
			
		||||
			, return False
 | 
			
		||||
			( void $ copyFromRemote' True r st key af file nullMeterUpdate
 | 
			
		||||
			, giveup "cannot preseed rsync with existing content"
 | 
			
		||||
			)
 | 
			
		||||
	| otherwise = return False
 | 
			
		||||
	| otherwise = Nothing
 | 
			
		||||
#else
 | 
			
		||||
copyFromRemoteCheap' _ _ _ _ _ _ = return False
 | 
			
		||||
copyFromRemoteCheap' _ _ _ = Nothing
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
{- Tries to copy a key's content to a remote's annex. -}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -102,8 +102,8 @@ gen r u rc gc rs = do
 | 
			
		|||
		, cost = cst
 | 
			
		||||
		, name = Git.repoDescribe r
 | 
			
		||||
		, storeKey = storeKeyDummy
 | 
			
		||||
		, retrieveKeyFile = retreiveKeyFileDummy
 | 
			
		||||
		, retrieveKeyFileCheap = retrieveCheap
 | 
			
		||||
		, retrieveKeyFile = retrieveKeyFileDummy
 | 
			
		||||
		, retrieveKeyFileCheap = Nothing
 | 
			
		||||
		-- content stored on git-lfs is hashed with SHA256
 | 
			
		||||
		-- no matter what git-annex key it's for, and the hash
 | 
			
		||||
		-- is checked on download
 | 
			
		||||
| 
						 | 
				
			
			@ -525,9 +525,6 @@ checkKey rs h key = getLFSEndpoint LFS.RequestDownload h >>= \case
 | 
			
		|||
					giveup "git-lfs server replied with other object than the one we requested"
 | 
			
		||||
				| otherwise -> return True
 | 
			
		||||
 | 
			
		||||
retrieveCheap :: Key -> AssociatedFile -> FilePath -> Annex Bool
 | 
			
		||||
retrieveCheap _ _ _ = return False
 | 
			
		||||
 | 
			
		||||
remove :: TVar LFSHandle -> Remover
 | 
			
		||||
remove _h _key = do
 | 
			
		||||
	warning "git-lfs does not support removing content"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -76,8 +76,8 @@ gen r u rc gc rs = new
 | 
			
		|||
			, cost = cst
 | 
			
		||||
			, name = Git.repoDescribe r
 | 
			
		||||
			, storeKey = storeKeyDummy
 | 
			
		||||
			, retrieveKeyFile = retreiveKeyFileDummy
 | 
			
		||||
			, retrieveKeyFileCheap = retrieveCheap this
 | 
			
		||||
			, retrieveKeyFile = retrieveKeyFileDummy
 | 
			
		||||
			, retrieveKeyFileCheap = Nothing
 | 
			
		||||
			-- glacier-cli does not follow redirects and does
 | 
			
		||||
			-- not support file://, as far as we know, but
 | 
			
		||||
			-- there's no guarantee that will continue to be
 | 
			
		||||
| 
						 | 
				
			
			@ -169,7 +169,7 @@ store' r k b p = go =<< glacierEnv c gc u
 | 
			
		|||
retrieve :: Remote -> Retriever
 | 
			
		||||
retrieve = byteRetriever . retrieve'
 | 
			
		||||
 | 
			
		||||
retrieve' :: Remote -> Key -> (L.ByteString -> Annex Bool) -> Annex Bool
 | 
			
		||||
retrieve' :: Remote -> Key -> (L.ByteString -> Annex ()) -> Annex ()
 | 
			
		||||
retrieve' r k sink = go =<< glacierEnv c gc u
 | 
			
		||||
  where
 | 
			
		||||
	c = config r
 | 
			
		||||
| 
						 | 
				
			
			@ -183,26 +183,22 @@ retrieve' r k sink = go =<< glacierEnv c gc u
 | 
			
		|||
		, Param $ archive r k
 | 
			
		||||
		]
 | 
			
		||||
	go Nothing = giveup "cannot retrieve from glacier"
 | 
			
		||||
	go (Just e) = do
 | 
			
		||||
	go (Just environ) = do
 | 
			
		||||
		let cmd = (proc "glacier" (toCommand params))
 | 
			
		||||
			{ env = Just e
 | 
			
		||||
			{ env = Just environ
 | 
			
		||||
			, std_out = CreatePipe
 | 
			
		||||
			}
 | 
			
		||||
		(_, Just h, _, pid) <- liftIO $ createProcess cmd
 | 
			
		||||
		-- Glacier cannot store empty files, so if the output is
 | 
			
		||||
		-- empty, the content is not available yet.
 | 
			
		||||
		ok <- ifM (liftIO $ hIsEOF h)
 | 
			
		||||
			( return False
 | 
			
		||||
			, sink =<< liftIO (L.hGetContents h)
 | 
			
		||||
			)
 | 
			
		||||
		liftIO $ hClose h
 | 
			
		||||
		liftIO $ forceSuccessProcess cmd pid
 | 
			
		||||
		unless ok $ do
 | 
			
		||||
			showLongNote "Recommend you wait up to 4 hours, and then run this command again."
 | 
			
		||||
		return ok
 | 
			
		||||
 | 
			
		||||
retrieveCheap :: Remote -> Key -> AssociatedFile -> FilePath -> Annex Bool
 | 
			
		||||
retrieveCheap _ _ _ _ = return False
 | 
			
		||||
		let cleanup = liftIO $ do
 | 
			
		||||
			hClose h
 | 
			
		||||
			forceSuccessProcess cmd pid
 | 
			
		||||
		flip finally cleanup $ do
 | 
			
		||||
			-- Glacier cannot store empty files, so if
 | 
			
		||||
			-- the output is empty, the content is not
 | 
			
		||||
			-- available yet.
 | 
			
		||||
			whenM (liftIO $ hIsEOF h) $
 | 
			
		||||
				giveup "Content is not available from glacier yet. Recommend you wait up to 4 hours, and then run this command again."
 | 
			
		||||
			sink =<< liftIO (L.hGetContents h)
 | 
			
		||||
 | 
			
		||||
remove :: Remote -> Remover
 | 
			
		||||
remove r k = glacierAction r
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -221,8 +221,8 @@ removeChunks remover u chunkconfig encryptor k = do
 | 
			
		|||
 - other chunks in the list is fed to the sink.
 | 
			
		||||
 -
 | 
			
		||||
 - If retrival of one of the subsequent chunks throws an exception,
 | 
			
		||||
 - gives up and returns False. Note that partial data may have been
 | 
			
		||||
 - written to the sink in this case.
 | 
			
		||||
 - gives up. Note that partial data may have been written to the sink
 | 
			
		||||
 - in this case.
 | 
			
		||||
 -
 | 
			
		||||
 - Resuming is supported when using chunks. When the destination file
 | 
			
		||||
 - already exists, it skips to the next chunked key that would be needed
 | 
			
		||||
| 
						 | 
				
			
			@ -236,8 +236,8 @@ retrieveChunks
 | 
			
		|||
	-> Key
 | 
			
		||||
	-> FilePath
 | 
			
		||||
	-> MeterUpdate
 | 
			
		||||
	-> (Maybe Handle -> Maybe MeterUpdate -> ContentSource -> Annex Bool)
 | 
			
		||||
	-> Annex Bool
 | 
			
		||||
	-> (Maybe Handle -> Maybe MeterUpdate -> ContentSource -> Annex ())
 | 
			
		||||
	-> Annex ()
 | 
			
		||||
retrieveChunks retriever u chunkconfig encryptor basek dest basep sink
 | 
			
		||||
	| noChunks chunkconfig =
 | 
			
		||||
		-- Optimisation: Try the unchunked key first, to avoid
 | 
			
		||||
| 
						 | 
				
			
			@ -251,14 +251,10 @@ retrieveChunks retriever u chunkconfig encryptor basek dest basep sink
 | 
			
		|||
		currsize <- liftIO $ catchMaybeIO $ getFileSize dest
 | 
			
		||||
		let ls' = maybe ls (setupResume ls) currsize
 | 
			
		||||
		if any null ls'
 | 
			
		||||
			then return True -- dest is already complete
 | 
			
		||||
			else firstavail currsize ls' `catchNonAsync` unable
 | 
			
		||||
			then noop -- dest is already complete
 | 
			
		||||
			else firstavail currsize ls'
 | 
			
		||||
 | 
			
		||||
	unable e = do
 | 
			
		||||
		warning (show e)
 | 
			
		||||
		return False
 | 
			
		||||
 | 
			
		||||
	firstavail _ [] = return False
 | 
			
		||||
	firstavail _ [] = giveup "chunk retrieval failed"
 | 
			
		||||
	firstavail currsize ([]:ls) = firstavail currsize ls
 | 
			
		||||
	firstavail currsize ((k:ks):ls)
 | 
			
		||||
		| k == basek = getunchunked
 | 
			
		||||
| 
						 | 
				
			
			@ -271,25 +267,22 @@ retrieveChunks retriever u chunkconfig encryptor basek dest basep sink
 | 
			
		|||
			v <- tryNonAsync $
 | 
			
		||||
				retriever (encryptor k) p $ \content ->
 | 
			
		||||
					bracketIO (maybe opennew openresume offset) hClose $ \h -> do
 | 
			
		||||
						void $ tosink (Just h) p content
 | 
			
		||||
						tosink (Just h) p content
 | 
			
		||||
						let sz = toBytesProcessed $
 | 
			
		||||
							fromMaybe 0 $ fromKey keyChunkSize k
 | 
			
		||||
						getrest p h sz sz ks
 | 
			
		||||
							`catchNonAsync` unable
 | 
			
		||||
			case v of
 | 
			
		||||
				Left e
 | 
			
		||||
					| null ls -> unable e
 | 
			
		||||
					| null ls -> throwM e
 | 
			
		||||
					| otherwise -> firstavail currsize ls
 | 
			
		||||
				Right r -> return r
 | 
			
		||||
 | 
			
		||||
	getrest _ _ _ _ [] = return True
 | 
			
		||||
	getrest _ _ _ _ [] = noop
 | 
			
		||||
	getrest p h sz bytesprocessed (k:ks) = do
 | 
			
		||||
		let p' = offsetMeterUpdate p bytesprocessed
 | 
			
		||||
		liftIO $ p' zeroBytesProcessed
 | 
			
		||||
		ifM (retriever (encryptor k) p' $ tosink (Just h) p')
 | 
			
		||||
			( getrest p h sz (addBytesProcessed bytesprocessed sz) ks
 | 
			
		||||
			, unable "chunk retrieval failed"
 | 
			
		||||
			)
 | 
			
		||||
		retriever (encryptor k) p' $ tosink (Just h) p'
 | 
			
		||||
		getrest p h sz (addBytesProcessed bytesprocessed sz) ks
 | 
			
		||||
 | 
			
		||||
	getunchunked = retriever (encryptor basek) basep $ tosink Nothing basep
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -202,15 +202,12 @@ adjustExportImport r rs = case getRemoteConfigValue exportTreeField (config r) o
 | 
			
		|||
		, retrieveKeyFile = \k af dest p ->
 | 
			
		||||
			let retrieveexport = retrieveKeyFileFromExport dbv k af dest p
 | 
			
		||||
			in if appendonly r
 | 
			
		||||
				then do
 | 
			
		||||
					ret@(ok, _v) <- retrieveKeyFile r k af dest p
 | 
			
		||||
					if ok
 | 
			
		||||
						then return ret
 | 
			
		||||
						else retrieveexport
 | 
			
		||||
				then retrieveKeyFile r k af dest p
 | 
			
		||||
					`catchNonAsync` const retrieveexport
 | 
			
		||||
				else retrieveexport
 | 
			
		||||
		, retrieveKeyFileCheap = if appendonly r
 | 
			
		||||
			then retrieveKeyFileCheap r
 | 
			
		||||
			else \_ _ _ -> return False
 | 
			
		||||
			else Nothing
 | 
			
		||||
		-- Removing a key from an export would need to
 | 
			
		||||
		-- change the tree in the export log to not include
 | 
			
		||||
		-- the file. Otherwise, conflicts when removing
 | 
			
		||||
| 
						 | 
				
			
			@ -318,18 +315,16 @@ adjustExportImport r rs = case getRemoteConfigValue exportTreeField (config r) o
 | 
			
		|||
		db <- getexportdb dbv
 | 
			
		||||
		liftIO $ Export.getExportTree db k
 | 
			
		||||
 | 
			
		||||
	retrieveKeyFileFromExport dbv k _af dest p = unVerified $
 | 
			
		||||
		if maybe False (isJust . verifyKeyContent) (maybeLookupBackendVariety (fromKey keyVariety k))
 | 
			
		||||
			then do
 | 
			
		||||
				locs <- getexportlocs dbv k
 | 
			
		||||
				case locs of
 | 
			
		||||
					[] -> do
 | 
			
		||||
						ifM (liftIO $ atomically $ readTVar $ getexportinconflict dbv)
 | 
			
		||||
							( warning "unknown export location, likely due to the export conflict"
 | 
			
		||||
							, warning "unknown export location"
 | 
			
		||||
							)
 | 
			
		||||
						return False
 | 
			
		||||
					(l:_) -> retrieveExport (exportActions r) k l dest p
 | 
			
		||||
			else do
 | 
			
		||||
				warning $ "exported content cannot be verified due to using the " ++ decodeBS (formatKeyVariety (fromKey keyVariety k)) ++ " backend"
 | 
			
		||||
				return False
 | 
			
		||||
	retrieveKeyFileFromExport dbv k _af dest p
 | 
			
		||||
		| maybe False (isJust . verifyKeyContent) (maybeLookupBackendVariety (fromKey keyVariety k)) = do
 | 
			
		||||
			locs <- getexportlocs dbv k
 | 
			
		||||
			case locs of
 | 
			
		||||
				[] -> ifM (liftIO $ atomically $ readTVar $ getexportinconflict dbv)
 | 
			
		||||
					( giveup "unknown export location, likely due to the export conflict"
 | 
			
		||||
					, giveup "unknown export location"
 | 
			
		||||
					)
 | 
			
		||||
				(l:_) -> do
 | 
			
		||||
					unlessM (retrieveExport (exportActions r) k l dest p) $
 | 
			
		||||
						giveup "retrieving from export failed"
 | 
			
		||||
					return UnVerified
 | 
			
		||||
		| otherwise = giveup $ "exported content cannot be verified due to using the " ++ decodeBS (formatKeyVariety (fromKey keyVariety k)) ++ " backend"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,7 +34,9 @@ addHooks' r starthook stophook = r'
 | 
			
		|||
	r' = r
 | 
			
		||||
		{ storeKey = \k f p -> wrapper $ storeKey r k f p
 | 
			
		||||
		, retrieveKeyFile = \k f d p -> wrapper $ retrieveKeyFile r k f d p
 | 
			
		||||
		, retrieveKeyFileCheap = \k af f -> wrapper $ retrieveKeyFileCheap r k af f
 | 
			
		||||
		, retrieveKeyFileCheap = case retrieveKeyFileCheap r of
 | 
			
		||||
			Just a -> Just $ \k af f -> wrapper $ a k af f
 | 
			
		||||
			Nothing -> Nothing
 | 
			
		||||
		, removeKey = wrapper . removeKey r
 | 
			
		||||
		, checkPresent = wrapper . checkPresent r
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,11 +39,13 @@ store runner k af p = do
 | 
			
		|||
			Just False -> giveup "transfer failed"
 | 
			
		||||
			Nothing -> giveup "can't connect to remote"
 | 
			
		||||
 | 
			
		||||
retrieve :: (MeterUpdate -> ProtoRunner (Bool, Verification)) -> Key -> AssociatedFile -> FilePath -> MeterUpdate -> Annex (Bool, Verification)
 | 
			
		||||
retrieve :: (MeterUpdate -> ProtoRunner (Bool, Verification)) -> Key -> AssociatedFile -> FilePath -> MeterUpdate -> Annex Verification
 | 
			
		||||
retrieve runner k af dest p =
 | 
			
		||||
	metered (Just p) k $ \m p' -> 
 | 
			
		||||
		fromMaybe (False, UnVerified)
 | 
			
		||||
			<$> runner p' (P2P.get dest k af m p')
 | 
			
		||||
		runner p' (P2P.get dest k af m p') >>= \case
 | 
			
		||||
			Just (True, v) -> return v
 | 
			
		||||
			Just (False, _) -> giveup "transfer failed"
 | 
			
		||||
			Nothing -> giveup "can't connec to remote"
 | 
			
		||||
 | 
			
		||||
remove :: ProtoRunner Bool -> Key -> Annex Bool
 | 
			
		||||
remove runner k = fromMaybe False <$> runner (P2P.remove k)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,7 @@ module Remote.Helper.Special (
 | 
			
		|||
	fileRetriever,
 | 
			
		||||
	byteRetriever,
 | 
			
		||||
	storeKeyDummy,
 | 
			
		||||
	retreiveKeyFileDummy,
 | 
			
		||||
	retrieveKeyFileDummy,
 | 
			
		||||
	removeKeyDummy,
 | 
			
		||||
	checkPresentDummy,
 | 
			
		||||
	SpecialRemoteCfg(..),
 | 
			
		||||
| 
						 | 
				
			
			@ -112,7 +112,7 @@ fileRetriever a k m callback = do
 | 
			
		|||
-- A Retriever that generates a lazy ByteString containing the Key's
 | 
			
		||||
-- content, and passes it to a callback action which will fully consume it
 | 
			
		||||
-- before returning.
 | 
			
		||||
byteRetriever :: (Key -> (L.ByteString -> Annex Bool) -> Annex Bool) -> Retriever
 | 
			
		||||
byteRetriever :: (Key -> (L.ByteString -> Annex ()) -> Annex ()) -> Retriever
 | 
			
		||||
byteRetriever a k _m callback = a k (callback . ByteContent)
 | 
			
		||||
 | 
			
		||||
{- The base Remote that is provided to specialRemote needs to have
 | 
			
		||||
| 
						 | 
				
			
			@ -122,8 +122,8 @@ byteRetriever a k _m callback = a k (callback . ByteContent)
 | 
			
		|||
 -}
 | 
			
		||||
storeKeyDummy :: Key -> AssociatedFile -> MeterUpdate -> Annex ()
 | 
			
		||||
storeKeyDummy _ _ _ = error "missing storeKey implementation"
 | 
			
		||||
retreiveKeyFileDummy :: Key -> AssociatedFile -> FilePath -> MeterUpdate -> Annex (Bool, Verification)
 | 
			
		||||
retreiveKeyFileDummy _ _ _ _ = unVerified (return False)
 | 
			
		||||
retrieveKeyFileDummy :: Key -> AssociatedFile -> FilePath -> MeterUpdate -> Annex Verification
 | 
			
		||||
retrieveKeyFileDummy _ _ _ _ = error "missing retrieveKeyFile implementation"
 | 
			
		||||
removeKeyDummy :: Key -> Annex Bool
 | 
			
		||||
removeKeyDummy _ = return False
 | 
			
		||||
checkPresentDummy :: Key -> Annex Bool
 | 
			
		||||
| 
						 | 
				
			
			@ -168,11 +168,13 @@ specialRemote' cfg c storer retriever remover checkpresent baser = encr
 | 
			
		|||
  where
 | 
			
		||||
	encr = baser
 | 
			
		||||
		{ storeKey = \k _f p -> cip >>= storeKeyGen k p
 | 
			
		||||
		, retrieveKeyFile = \k _f d p -> cip >>= unVerified . retrieveKeyFileGen k d p
 | 
			
		||||
		, retrieveKeyFileCheap = \k f d -> cip >>= maybe
 | 
			
		||||
			(retrieveKeyFileCheap baser k f d)
 | 
			
		||||
			-- retrieval of encrypted keys is never cheap
 | 
			
		||||
			(\_ -> return False)
 | 
			
		||||
		, retrieveKeyFile = \k _f d p -> cip >>= retrieveKeyFileGen k d p
 | 
			
		||||
		, retrieveKeyFileCheap = case retrieveKeyFileCheap baser of
 | 
			
		||||
			Nothing -> Nothing
 | 
			
		||||
			Just a
 | 
			
		||||
				-- retrieval of encrypted keys is never cheap
 | 
			
		||||
				| isencrypted -> Nothing
 | 
			
		||||
				| otherwise -> Just $ \k f d -> a k f d
 | 
			
		||||
		-- When encryption is used, the remote could provide
 | 
			
		||||
		-- some other content encrypted by the user, and trick
 | 
			
		||||
		-- git-annex into decrypting it, leaking the decryption
 | 
			
		||||
| 
						 | 
				
			
			@ -226,10 +228,11 @@ specialRemote' cfg c storer retriever remover checkpresent baser = encr
 | 
			
		|||
					storer (enck k) (ByteContent encb) p
 | 
			
		||||
 | 
			
		||||
	-- call retriever to get chunks; decrypt them; stream to dest file
 | 
			
		||||
	retrieveKeyFileGen k dest p enc = safely $
 | 
			
		||||
	retrieveKeyFileGen k dest p enc = do
 | 
			
		||||
		displayprogress p k Nothing $ \p' ->
 | 
			
		||||
			retrieveChunks retriever (uuid baser) chunkconfig
 | 
			
		||||
				enck k dest p' (sink dest enc encr)
 | 
			
		||||
		return UnVerified
 | 
			
		||||
	  where
 | 
			
		||||
		enck = maybe id snd enc
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -268,27 +271,25 @@ sink
 | 
			
		|||
	-> Maybe Handle
 | 
			
		||||
	-> Maybe MeterUpdate
 | 
			
		||||
	-> ContentSource
 | 
			
		||||
	-> Annex Bool
 | 
			
		||||
sink dest enc c mh mp content = do
 | 
			
		||||
	case (enc, mh, content) of
 | 
			
		||||
		(Nothing, Nothing, FileContent f)
 | 
			
		||||
			| f == dest -> noop
 | 
			
		||||
			| otherwise -> liftIO $ moveFile f dest
 | 
			
		||||
		(Just (cipher, _), _, ByteContent b) -> do
 | 
			
		||||
			cmd <- gpgCmd <$> Annex.getGitConfig
 | 
			
		||||
	-> Annex ()
 | 
			
		||||
sink dest enc c mh mp content = case (enc, mh, content) of
 | 
			
		||||
	(Nothing, Nothing, FileContent f)
 | 
			
		||||
		| f == dest -> noop
 | 
			
		||||
		| otherwise -> liftIO $ moveFile f dest
 | 
			
		||||
	(Just (cipher, _), _, ByteContent b) -> do
 | 
			
		||||
		cmd <- gpgCmd <$> Annex.getGitConfig
 | 
			
		||||
		decrypt cmd c cipher (feedBytes b) $
 | 
			
		||||
			readBytes write
 | 
			
		||||
	(Just (cipher, _), _, FileContent f) -> do
 | 
			
		||||
		cmd <- gpgCmd <$> Annex.getGitConfig
 | 
			
		||||
		withBytes content $ \b ->
 | 
			
		||||
			decrypt cmd c cipher (feedBytes b) $
 | 
			
		||||
				readBytes write
 | 
			
		||||
		(Just (cipher, _), _, FileContent f) -> do
 | 
			
		||||
			cmd <- gpgCmd <$> Annex.getGitConfig
 | 
			
		||||
			withBytes content $ \b ->
 | 
			
		||||
				decrypt cmd c cipher (feedBytes b) $
 | 
			
		||||
					readBytes write
 | 
			
		||||
			liftIO $ nukeFile f
 | 
			
		||||
		(Nothing, _, FileContent f) -> do
 | 
			
		||||
			withBytes content write
 | 
			
		||||
			liftIO $ nukeFile f
 | 
			
		||||
		(Nothing, _, ByteContent b) -> write b
 | 
			
		||||
	return True
 | 
			
		||||
		liftIO $ nukeFile f
 | 
			
		||||
	(Nothing, _, FileContent f) -> do
 | 
			
		||||
		withBytes content write
 | 
			
		||||
		liftIO $ nukeFile f
 | 
			
		||||
	(Nothing, _, ByteContent b) -> write b
 | 
			
		||||
  where
 | 
			
		||||
	write b = case mh of
 | 
			
		||||
		Just h -> liftIO $ b `streamto` h
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -59,8 +59,8 @@ gen r u rc gc rs = do
 | 
			
		|||
			, cost = cst
 | 
			
		||||
			, name = Git.repoDescribe r
 | 
			
		||||
			, storeKey = storeKeyDummy
 | 
			
		||||
			, retrieveKeyFile = retreiveKeyFileDummy
 | 
			
		||||
			, retrieveKeyFileCheap = retrieveCheap hooktype
 | 
			
		||||
			, retrieveKeyFile = retrieveKeyFileDummy
 | 
			
		||||
			, retrieveKeyFileCheap = Nothing
 | 
			
		||||
			-- A hook could use http and be vulnerable to
 | 
			
		||||
			-- redirect to file:// attacks, etc.
 | 
			
		||||
			, retrievalSecurityPolicy = mkRetrievalVerifiableKeysSecure gc
 | 
			
		||||
| 
						 | 
				
			
			@ -162,9 +162,6 @@ retrieve h = fileRetriever $ \d k _p ->
 | 
			
		|||
	unlessM (runHook' h "retrieve" k (Just d) $ return True) $
 | 
			
		||||
		giveup "failed to retrieve content"
 | 
			
		||||
 | 
			
		||||
retrieveCheap :: HookName -> Key -> AssociatedFile -> FilePath -> Annex Bool
 | 
			
		||||
retrieveCheap _ _ _ _ = return False
 | 
			
		||||
 | 
			
		||||
remove :: HookName -> Remover
 | 
			
		||||
remove h k = runHook' h "remove" k Nothing $ return True
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -56,7 +56,7 @@ chainGen addr r u rc gc rs = do
 | 
			
		|||
		, name = Git.repoDescribe r
 | 
			
		||||
		, storeKey = store (const protorunner)
 | 
			
		||||
		, retrieveKeyFile = retrieve (const protorunner)
 | 
			
		||||
		, retrieveKeyFileCheap = \_ _ _ -> return False
 | 
			
		||||
		, retrieveKeyFileCheap = Nothing
 | 
			
		||||
		, retrievalSecurityPolicy = RetrievalAllKeysSecure
 | 
			
		||||
		, removeKey = remove protorunner
 | 
			
		||||
		, lockContent = Just $ lock withconn runProtoConn u 
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -89,8 +89,8 @@ gen r u rc gc rs = do
 | 
			
		|||
			, cost = cst
 | 
			
		||||
			, name = Git.repoDescribe r
 | 
			
		||||
			, storeKey = storeKeyDummy
 | 
			
		||||
			, retrieveKeyFile = retreiveKeyFileDummy
 | 
			
		||||
			, retrieveKeyFileCheap = retrieveCheap o
 | 
			
		||||
			, retrieveKeyFile = retrieveKeyFileDummy
 | 
			
		||||
			, retrieveKeyFileCheap = Just (retrieveCheap o)
 | 
			
		||||
			, retrievalSecurityPolicy = RetrievalAllKeysSecure
 | 
			
		||||
			, removeKey = removeKeyDummy
 | 
			
		||||
			, lockContent = Nothing
 | 
			
		||||
| 
						 | 
				
			
			@ -237,12 +237,13 @@ storeGeneric' o meterupdate basedest populatedest = withRsyncScratchDir $ \tmp -
 | 
			
		|||
		else return False
 | 
			
		||||
 | 
			
		||||
retrieve :: RsyncOpts -> FilePath -> Key -> MeterUpdate -> Annex ()
 | 
			
		||||
retrieve o f k p = 
 | 
			
		||||
	unlessM (rsyncRetrieveKey o k f (Just p)) $
 | 
			
		||||
		giveup "rsync failed"
 | 
			
		||||
retrieve o f k p = rsyncRetrieveKey o k f (Just p)
 | 
			
		||||
 | 
			
		||||
retrieveCheap :: RsyncOpts -> Key -> AssociatedFile -> FilePath -> Annex Bool
 | 
			
		||||
retrieveCheap o k _af f = ifM (preseedTmp k f) ( rsyncRetrieveKey o k f Nothing , return False )
 | 
			
		||||
retrieveCheap :: RsyncOpts -> Key -> AssociatedFile -> FilePath -> Annex ()
 | 
			
		||||
retrieveCheap o k _af f = ifM (preseedTmp k f)
 | 
			
		||||
	( rsyncRetrieveKey o k f Nothing
 | 
			
		||||
	, giveup "cannot preseed rsync with existing content"
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
remove :: RsyncOpts -> Remover
 | 
			
		||||
remove o k = removeGeneric o includes
 | 
			
		||||
| 
						 | 
				
			
			@ -358,8 +359,10 @@ rsyncRetrieve o rsyncurls dest meterupdate =
 | 
			
		|||
		, File dest
 | 
			
		||||
		]
 | 
			
		||||
 | 
			
		||||
rsyncRetrieveKey :: RsyncOpts -> Key -> FilePath -> Maybe MeterUpdate -> Annex Bool
 | 
			
		||||
rsyncRetrieveKey o k dest meterupdate = rsyncRetrieve o (rsyncUrls o k) dest meterupdate
 | 
			
		||||
rsyncRetrieveKey :: RsyncOpts -> Key -> FilePath -> Maybe MeterUpdate -> Annex ()
 | 
			
		||||
rsyncRetrieveKey o k dest meterupdate =
 | 
			
		||||
	unlessM (rsyncRetrieve o (rsyncUrls o k) dest meterupdate) $
 | 
			
		||||
		giveup "rsync failed"
 | 
			
		||||
 | 
			
		||||
showResumable :: Annex Bool -> Annex Bool
 | 
			
		||||
showResumable a = ifM a
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -193,8 +193,8 @@ gen r u rc gc rs = do
 | 
			
		|||
			, cost = cst
 | 
			
		||||
			, name = Git.repoDescribe r
 | 
			
		||||
			, storeKey = storeKeyDummy
 | 
			
		||||
			, retrieveKeyFile = retreiveKeyFileDummy
 | 
			
		||||
			, retrieveKeyFileCheap = retrieveCheap
 | 
			
		||||
			, retrieveKeyFile = retrieveKeyFileDummy
 | 
			
		||||
			, retrieveKeyFileCheap = Nothing
 | 
			
		||||
			-- HttpManagerRestricted is used here, so this is
 | 
			
		||||
			-- secure.
 | 
			
		||||
			, retrievalSecurityPolicy = RetrievalAllKeysSecure
 | 
			
		||||
| 
						 | 
				
			
			@ -418,9 +418,6 @@ retrieveHelper' h f p req = liftIO $ runResourceT $ do
 | 
			
		|||
	S3.GetObjectResponse { S3.gorResponse = rsp } <- sendS3Handle h req
 | 
			
		||||
	Url.sinkResponseFile p zeroBytesProcessed f WriteMode rsp
 | 
			
		||||
 | 
			
		||||
retrieveCheap :: Key -> AssociatedFile -> FilePath -> Annex Bool
 | 
			
		||||
retrieveCheap _ _ _ = return False
 | 
			
		||||
 | 
			
		||||
remove :: S3HandleVar -> Remote -> S3Info -> Remover
 | 
			
		||||
remove hv r info k = withS3HandleOrFail (uuid r) hv $ \h -> liftIO $ runResourceT $ do
 | 
			
		||||
	res <- tryNonAsync $ sendS3Handle h $
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -87,7 +87,7 @@ gen r u rc gc rs = do
 | 
			
		|||
		, name = Git.repoDescribe r
 | 
			
		||||
		, storeKey = store rs hdl
 | 
			
		||||
		, retrieveKeyFile = retrieve rs hdl
 | 
			
		||||
		, retrieveKeyFileCheap = \_ _ _ -> return False
 | 
			
		||||
		, retrieveKeyFileCheap = Nothing
 | 
			
		||||
		-- Tahoe cryptographically verifies content.
 | 
			
		||||
		, retrievalSecurityPolicy = RetrievalAllKeysSecure
 | 
			
		||||
		, removeKey = remove
 | 
			
		||||
| 
						 | 
				
			
			@ -141,11 +141,14 @@ store rs hdl k _f _p = sendAnnex k noop $ \src ->
 | 
			
		|||
		(giveup "tahoe failed to store content")
 | 
			
		||||
		(\cap -> storeCapability rs k cap)
 | 
			
		||||
 | 
			
		||||
retrieve :: RemoteStateHandle -> TahoeHandle -> Key -> AssociatedFile -> FilePath -> MeterUpdate -> Annex (Bool, Verification)
 | 
			
		||||
retrieve rs hdl k _f d _p = unVerified $ go =<< getCapability rs k
 | 
			
		||||
retrieve :: RemoteStateHandle -> TahoeHandle -> Key -> AssociatedFile -> FilePath -> MeterUpdate -> Annex Verification
 | 
			
		||||
retrieve rs hdl k _f d _p = do
 | 
			
		||||
	go =<< getCapability rs k
 | 
			
		||||
	return UnVerified
 | 
			
		||||
  where
 | 
			
		||||
	go Nothing = return False
 | 
			
		||||
	go (Just cap) = liftIO $ requestTahoe hdl "get" [Param cap, File d]
 | 
			
		||||
	go Nothing = giveup "tahoe capability is not known"
 | 
			
		||||
	go (Just cap) = unlessM (liftIO $ requestTahoe hdl "get" [Param cap, File d]) $
 | 
			
		||||
		giveup "tahoe failed to reteieve content"
 | 
			
		||||
 | 
			
		||||
remove :: Key -> Annex Bool
 | 
			
		||||
remove _k = do
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -52,7 +52,7 @@ gen r _ rc gc rs = do
 | 
			
		|||
		, name = Git.repoDescribe r
 | 
			
		||||
		, storeKey = uploadKey
 | 
			
		||||
		, retrieveKeyFile = downloadKey
 | 
			
		||||
		, retrieveKeyFileCheap = downloadKeyCheap
 | 
			
		||||
		, retrieveKeyFileCheap = Nothing
 | 
			
		||||
		-- HttpManagerRestricted is used here, so this is
 | 
			
		||||
		-- secure.
 | 
			
		||||
		, retrievalSecurityPolicy = RetrievalAllKeysSecure
 | 
			
		||||
| 
						 | 
				
			
			@ -80,22 +80,22 @@ gen r _ rc gc rs = do
 | 
			
		|||
		, remoteStateHandle = rs
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
downloadKey :: Key -> AssociatedFile -> FilePath -> MeterUpdate -> Annex (Bool, Verification)
 | 
			
		||||
downloadKey key _af dest p = unVerified $ get =<< getWebUrls key
 | 
			
		||||
downloadKey :: Key -> AssociatedFile -> FilePath -> MeterUpdate -> Annex Verification
 | 
			
		||||
downloadKey key _af dest p = do
 | 
			
		||||
	get =<< getWebUrls key
 | 
			
		||||
	return UnVerified
 | 
			
		||||
  where
 | 
			
		||||
	get [] = do
 | 
			
		||||
		warning "no known url"
 | 
			
		||||
		return False
 | 
			
		||||
	get urls = untilTrue urls $ \u -> do
 | 
			
		||||
		let (u', downloader) = getDownloader u
 | 
			
		||||
		case downloader of
 | 
			
		||||
			YoutubeDownloader -> do
 | 
			
		||||
				showOutput
 | 
			
		||||
				youtubeDlTo key u' dest
 | 
			
		||||
			_ -> Url.withUrlOptions $ downloadUrl key p [u'] dest
 | 
			
		||||
 | 
			
		||||
downloadKeyCheap :: Key -> AssociatedFile -> FilePath -> Annex Bool
 | 
			
		||||
downloadKeyCheap _ _ _ = return False
 | 
			
		||||
	get [] = giveup "no known url"
 | 
			
		||||
	get urls = do
 | 
			
		||||
		r <- untilTrue urls $ \u -> do
 | 
			
		||||
			let (u', downloader) = getDownloader u
 | 
			
		||||
			case downloader of
 | 
			
		||||
				YoutubeDownloader -> do
 | 
			
		||||
					showOutput
 | 
			
		||||
					youtubeDlTo key u' dest
 | 
			
		||||
				_ -> Url.withUrlOptions $ downloadUrl key p [u'] dest
 | 
			
		||||
		unless r $
 | 
			
		||||
			giveup "download failed"
 | 
			
		||||
 | 
			
		||||
uploadKey :: Key -> AssociatedFile -> MeterUpdate -> Annex ()
 | 
			
		||||
uploadKey _ _ _ = giveup "upload to web not supported"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -84,8 +84,8 @@ gen r u rc gc rs = do
 | 
			
		|||
			, cost = cst
 | 
			
		||||
			, name = Git.repoDescribe r
 | 
			
		||||
			, storeKey = storeKeyDummy
 | 
			
		||||
			, retrieveKeyFile = retreiveKeyFileDummy
 | 
			
		||||
			, retrieveKeyFileCheap = retrieveCheap
 | 
			
		||||
			, retrieveKeyFile = retrieveKeyFileDummy
 | 
			
		||||
			, retrieveKeyFileCheap = Nothing
 | 
			
		||||
			-- HttpManagerRestricted is used here, so this is
 | 
			
		||||
			-- secure.
 | 
			
		||||
			, retrievalSecurityPolicy = RetrievalAllKeysSecure
 | 
			
		||||
| 
						 | 
				
			
			@ -162,9 +162,6 @@ finalizeStore dav tmp dest = do
 | 
			
		|||
	maybe noop (void . mkColRecursive) (locationParent dest)
 | 
			
		||||
	moveDAV (baseURL dav) tmp dest
 | 
			
		||||
 | 
			
		||||
retrieveCheap :: Key -> AssociatedFile -> FilePath -> Annex Bool
 | 
			
		||||
retrieveCheap _ _ _ = return False
 | 
			
		||||
 | 
			
		||||
retrieve :: DavHandleVar -> ChunkConfig -> Retriever
 | 
			
		||||
retrieve hv cc = fileRetriever $ \d k p ->
 | 
			
		||||
	withDavHandle hv $ \dav -> case cc of
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -89,10 +89,12 @@ data RemoteA a = Remote
 | 
			
		|||
	-- Retrieves a key's contents to a file.
 | 
			
		||||
	-- (The MeterUpdate does not need to be used if it writes
 | 
			
		||||
	-- sequentially to the file.)
 | 
			
		||||
	, retrieveKeyFile :: Key -> AssociatedFile -> FilePath -> MeterUpdate -> a (Bool, Verification)
 | 
			
		||||
	-- Throws exception on failure.
 | 
			
		||||
	, retrieveKeyFile :: Key -> AssociatedFile -> FilePath -> MeterUpdate -> a Verification
 | 
			
		||||
	-- Retrieves a key's contents to a tmp file, if it can be done cheaply.
 | 
			
		||||
	-- It's ok to create a symlink or hardlink.
 | 
			
		||||
	, retrieveKeyFileCheap :: Key -> AssociatedFile -> FilePath -> a Bool
 | 
			
		||||
	-- Throws exception on failure.
 | 
			
		||||
	, retrieveKeyFileCheap :: Maybe (Key -> AssociatedFile -> FilePath -> a ())
 | 
			
		||||
	-- Security policy for reteiving keys from this remote.
 | 
			
		||||
	, retrievalSecurityPolicy :: RetrievalSecurityPolicy
 | 
			
		||||
	-- Removes a key's contents (succeeds if the contents are not present)
 | 
			
		||||
| 
						 | 
				
			
			@ -186,7 +188,7 @@ data Verification
 | 
			
		|||
	-- ^ Content likely to have been altered during transfer,
 | 
			
		||||
	-- verify even if verification is normally disabled
 | 
			
		||||
 | 
			
		||||
unVerified :: Monad m => m Bool -> m (Bool, Verification)
 | 
			
		||||
unVerified :: Monad m => m a -> m (a, Verification)
 | 
			
		||||
unVerified a = do
 | 
			
		||||
	ok <- a
 | 
			
		||||
	return (ok, UnVerified)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,7 +28,7 @@ type Storer = Key -> ContentSource -> MeterUpdate -> Annex ()
 | 
			
		|||
-- Action that retrieves a Key's content from a remote, passing it to a
 | 
			
		||||
-- callback, which will fully consume the content before returning.
 | 
			
		||||
-- Throws exception if key is not present, or remote is not accessible.
 | 
			
		||||
type Retriever = Key -> MeterUpdate -> (ContentSource -> Annex Bool) -> Annex Bool
 | 
			
		||||
type Retriever = Key -> MeterUpdate -> (ContentSource -> Annex ()) -> Annex ()
 | 
			
		||||
 | 
			
		||||
-- Action that removes a Key's content from a remote.
 | 
			
		||||
-- Succeeds if key is already not present; never throws exceptions.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue