safe recv-key in direct mode
Checks the key's size and checksum. This is sorta expensive, but it avoids needing to add another round-trip to the protocol.
This commit is contained in:
		
					parent
					
						
							
								043c9562f3
							
						
					
				
			
			
				commit
				
					
						18a6935e42
					
				
			
		
					 7 changed files with 71 additions and 34 deletions
				
			
		| 
						 | 
					@ -14,6 +14,10 @@ import Annex.Content
 | 
				
			||||||
import Utility.Rsync
 | 
					import Utility.Rsync
 | 
				
			||||||
import Logs.Transfer
 | 
					import Logs.Transfer
 | 
				
			||||||
import Command.SendKey (fieldTransfer)
 | 
					import Command.SendKey (fieldTransfer)
 | 
				
			||||||
 | 
					import qualified Fields
 | 
				
			||||||
 | 
					import qualified Types.Key
 | 
				
			||||||
 | 
					import qualified Types.Backend
 | 
				
			||||||
 | 
					import qualified Backend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def :: [Command]
 | 
					def :: [Command]
 | 
				
			||||||
def = [noCommit $ command "recvkey" paramKey seek
 | 
					def = [noCommit $ command "recvkey" paramKey seek
 | 
				
			||||||
| 
						 | 
					@ -26,7 +30,7 @@ start :: Key -> CommandStart
 | 
				
			||||||
start key = ifM (inAnnex key)
 | 
					start key = ifM (inAnnex key)
 | 
				
			||||||
	( error "key is already present in annex"
 | 
						( error "key is already present in annex"
 | 
				
			||||||
	, fieldTransfer Download key $ \_p -> do
 | 
						, fieldTransfer Download key $ \_p -> do
 | 
				
			||||||
		ifM (getViaTmp key $ liftIO . rsyncServerReceive)
 | 
							ifM (getViaTmp key go)
 | 
				
			||||||
			( do
 | 
								( do
 | 
				
			||||||
				-- forcibly quit after receiving one key,
 | 
									-- forcibly quit after receiving one key,
 | 
				
			||||||
				-- and shutdown cleanly
 | 
									-- and shutdown cleanly
 | 
				
			||||||
| 
						 | 
					@ -35,3 +39,28 @@ start key = ifM (inAnnex key)
 | 
				
			||||||
			, return False
 | 
								, return False
 | 
				
			||||||
			)
 | 
								)
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
 | 
					  where
 | 
				
			||||||
 | 
						go tmp = ifM (liftIO $ rsyncServerReceive tmp)
 | 
				
			||||||
 | 
							( ifM (isJust <$> Fields.getField Fields.direct)
 | 
				
			||||||
 | 
								( directcheck tmp
 | 
				
			||||||
 | 
								, return True
 | 
				
			||||||
 | 
								)
 | 
				
			||||||
 | 
							, return False
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
						{- If the sending repository uses direct mode, the file
 | 
				
			||||||
 | 
						 - it sends could be modified as it's sending it. So check
 | 
				
			||||||
 | 
						 - that the right size file was received, and that the key/value
 | 
				
			||||||
 | 
						 - Backend is happy with it. -}
 | 
				
			||||||
 | 
						directcheck tmp = do
 | 
				
			||||||
 | 
							oksize <- case Types.Key.keySize key of
 | 
				
			||||||
 | 
							        Nothing -> return True
 | 
				
			||||||
 | 
							        Just size -> do
 | 
				
			||||||
 | 
									size' <- fromIntegral . fileSize
 | 
				
			||||||
 | 
					       	        	        	<$> liftIO (getFileStatus tmp)
 | 
				
			||||||
 | 
									return $ size == size'
 | 
				
			||||||
 | 
							if oksize
 | 
				
			||||||
 | 
								then case Backend.maybeLookupBackendName (Types.Key.keyBackendName key) of
 | 
				
			||||||
 | 
									Nothing -> return False
 | 
				
			||||||
 | 
									Just backend -> maybe (return True) (\a -> a key tmp)
 | 
				
			||||||
 | 
										(Types.Backend.fsckKey backend)
 | 
				
			||||||
 | 
								else return False
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,3 +30,6 @@ associatedFile :: Field
 | 
				
			||||||
associatedFile = Field "associatedfile" $ \f ->
 | 
					associatedFile = Field "associatedfile" $ \f ->
 | 
				
			||||||
	-- is the file a safe relative filename?
 | 
						-- is the file a safe relative filename?
 | 
				
			||||||
	not (isAbsolute f) && not ("../" `isPrefixOf` f)
 | 
						not (isAbsolute f) && not ("../" `isPrefixOf` f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					direct :: Field
 | 
				
			||||||
 | 
					direct = Field "direct" $ \f -> f == "1"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -122,6 +122,7 @@ checkField :: (String, String) -> Bool
 | 
				
			||||||
checkField (field, value)
 | 
					checkField (field, value)
 | 
				
			||||||
	| field == fieldName remoteUUID = fieldCheck remoteUUID value
 | 
						| field == fieldName remoteUUID = fieldCheck remoteUUID value
 | 
				
			||||||
	| field == fieldName associatedFile = fieldCheck associatedFile value
 | 
						| field == fieldName associatedFile = fieldCheck associatedFile value
 | 
				
			||||||
 | 
						| field == fieldName direct = fieldCheck direct value
 | 
				
			||||||
	| otherwise = False
 | 
						| otherwise = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
failure :: IO ()
 | 
					failure :: IO ()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -398,7 +398,9 @@ rsyncOrCopyFile rsyncparams src dest p =
 | 
				
			||||||
rsyncParamsRemote :: Remote -> Direction -> Key -> FilePath -> AssociatedFile -> Annex [CommandParam]
 | 
					rsyncParamsRemote :: Remote -> Direction -> Key -> FilePath -> AssociatedFile -> Annex [CommandParam]
 | 
				
			||||||
rsyncParamsRemote r direction key file afile = do
 | 
					rsyncParamsRemote r direction key file afile = do
 | 
				
			||||||
	u <- getUUID
 | 
						u <- getUUID
 | 
				
			||||||
 | 
						direct <- isDirect
 | 
				
			||||||
	let fields = (Fields.remoteUUID, fromUUID u)
 | 
						let fields = (Fields.remoteUUID, fromUUID u)
 | 
				
			||||||
 | 
							: (Fields.direct, if direct then "1" else "")
 | 
				
			||||||
		: maybe [] (\f -> [(Fields.associatedFile, f)]) afile
 | 
							: maybe [] (\f -> [(Fields.associatedFile, f)]) afile
 | 
				
			||||||
	Just (shellcmd, shellparams) <- git_annex_shell (repo r)
 | 
						Just (shellcmd, shellparams) <- git_annex_shell (repo r)
 | 
				
			||||||
		(if direction == Download then "sendkey" else "recvkey")
 | 
							(if direction == Download then "sendkey" else "recvkey")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										6
									
								
								debian/changelog
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								debian/changelog
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -1,8 +1,10 @@
 | 
				
			||||||
git-annex (3.20130108) UNRELEASED; urgency=low
 | 
					git-annex (3.20130108) UNRELEASED; urgency=low
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  * Now handles the case where a file that's being transferred to a remote
 | 
				
			||||||
 | 
					    is modified in place, which direct mode allows to happen. When this
 | 
				
			||||||
 | 
					    happens, the transfer now fails, rather than allow possibly corrupt
 | 
				
			||||||
 | 
					    data into the remote.
 | 
				
			||||||
  * fsck: Better checking of file content in direct mode.
 | 
					  * fsck: Better checking of file content in direct mode.
 | 
				
			||||||
  * Special remotes now all rollback storage of keys that get modified
 | 
					 | 
				
			||||||
    during the transfer, which can happen in direct mode.
 | 
					 | 
				
			||||||
  * drop: Suggest using git annex move when numcopies prevents dropping a file.
 | 
					  * drop: Suggest using git annex move when numcopies prevents dropping a file.
 | 
				
			||||||
  * webapp: Repo switcher filters out repos that do not exist any more
 | 
					  * webapp: Repo switcher filters out repos that do not exist any more
 | 
				
			||||||
    (or are on a drive that's not mounted).
 | 
					    (or are on a drive that's not mounted).
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -84,6 +84,32 @@ is converted to a real file when it becomes present.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## TODO
 | 
					## TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* kqueue does not deliver an event when an existing file is modified.
 | 
				
			||||||
 | 
					  This doesn't affect OSX, which uses FSEvents now, but it makes direct
 | 
				
			||||||
 | 
					  mode assistant not 100% on other BSD's.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `git annex sync` updates the key to files mappings for files changed,
 | 
				
			||||||
 | 
					  but needs much other work to handle direct mode:
 | 
				
			||||||
 | 
					  * Generate git commit, without running `git commit`, because it will
 | 
				
			||||||
 | 
					    want to stage the full files. **done**
 | 
				
			||||||
 | 
					  * Update location logs for any files deleted by a commit. **done**
 | 
				
			||||||
 | 
					  * Generate a git merge, without running `git merge` (or possibly running
 | 
				
			||||||
 | 
					    it in a scratch repo?), because it will stumble over the direct files.
 | 
				
			||||||
 | 
					    **done**
 | 
				
			||||||
 | 
					  * Drop contents of files deleted by a merge (including updating the
 | 
				
			||||||
 | 
					    location log), or if we cannot drop,
 | 
				
			||||||
 | 
					    move their contents to `.git/annex/objects/`.  **no**  .. instead, 
 | 
				
			||||||
 | 
					    avoid ever losing file contents in a direct mode merge. If the file is
 | 
				
			||||||
 | 
					    deleted, its content is moved back to .git/annex/objects, if necessary.
 | 
				
			||||||
 | 
					  * When a merge adds a symlink pointing at a key that is present in the
 | 
				
			||||||
 | 
					    repo, replace the symlink with the direct file (either moving out
 | 
				
			||||||
 | 
					    of `.git/annex/objects/` or hard-linking if the same key is present
 | 
				
			||||||
 | 
					    elsewhere in the tree. **done**
 | 
				
			||||||
 | 
					  * handle merge conflicts on direct mode files **done**
 | 
				
			||||||
 | 
					* support direct mode in the assistant (many little fixes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* Deal with files changing as they're being transferred from a direct mode
 | 
					* Deal with files changing as they're being transferred from a direct mode
 | 
				
			||||||
  repository to another git repository. The remote repo currently will 
 | 
					  repository to another git repository. The remote repo currently will 
 | 
				
			||||||
  accept the bad data and update the location log to say it has the key.
 | 
					  accept the bad data and update the location log to say it has the key.
 | 
				
			||||||
| 
						 | 
					@ -113,34 +139,7 @@ is converted to a real file when it becomes present.
 | 
				
			||||||
  the temp file, which is probably corrupt. (Could in future use it as a
 | 
					  the temp file, which is probably corrupt. (Could in future use it as a
 | 
				
			||||||
  basis for transferring the new key..) **done**
 | 
					  basis for transferring the new key..) **done**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  For git remotes, add a flag to `git-annex-shell recvkey` (using a field
 | 
					  For git remotes, added a flag to `git-annex-shell recvkey` (using a field
 | 
				
			||||||
  after the "--" to remain back-compat). With this flag, after receiving
 | 
					  after the "--" to remain back-compat). With this flag, after receiving
 | 
				
			||||||
  the data, the remote should wait for a signal that the data is good
 | 
					  the data, the remote fscks the data. This is not optimal, but avoids
 | 
				
			||||||
  before it updates the location log. The signal could just be a "1"
 | 
					  needing another round-trip, or a protocol change.
 | 
				
			||||||
  sent over the ssh channel. Or another `git-annex-shell` command. **TODO**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
* kqueue does not deliver an event when an existing file is modified.
 | 
					 | 
				
			||||||
  This doesn't affect OSX, which uses FSEvents now, but it makes direct
 | 
					 | 
				
			||||||
  mode assistant not 100% on other BSD's.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## done
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
* `git annex sync` updates the key to files mappings for files changed,
 | 
					 | 
				
			||||||
  but needs much other work to handle direct mode:
 | 
					 | 
				
			||||||
  * Generate git commit, without running `git commit`, because it will
 | 
					 | 
				
			||||||
    want to stage the full files. **done**
 | 
					 | 
				
			||||||
  * Update location logs for any files deleted by a commit. **done**
 | 
					 | 
				
			||||||
  * Generate a git merge, without running `git merge` (or possibly running
 | 
					 | 
				
			||||||
    it in a scratch repo?), because it will stumble over the direct files.
 | 
					 | 
				
			||||||
    **done**
 | 
					 | 
				
			||||||
  * Drop contents of files deleted by a merge (including updating the
 | 
					 | 
				
			||||||
    location log), or if we cannot drop,
 | 
					 | 
				
			||||||
    move their contents to `.git/annex/objects/`.  **no**  .. instead, 
 | 
					 | 
				
			||||||
    avoid ever losing file contents in a direct mode merge. If the file is
 | 
					 | 
				
			||||||
    deleted, its content is moved back to .git/annex/objects, if necessary.
 | 
					 | 
				
			||||||
  * When a merge adds a symlink pointing at a key that is present in the
 | 
					 | 
				
			||||||
    repo, replace the symlink with the direct file (either moving out
 | 
					 | 
				
			||||||
    of `.git/annex/objects/` or hard-linking if the same key is present
 | 
					 | 
				
			||||||
    elsewhere in the tree. **done**
 | 
					 | 
				
			||||||
  * handle merge conflicts on direct mode files **done**
 | 
					 | 
				
			||||||
* support direct mode in the assistant (many little fixes)
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -76,7 +76,8 @@ to git-annex-shell are:
 | 
				
			||||||
  past versions of git-annex-shell (that ignore these, but would choke
 | 
					  past versions of git-annex-shell (that ignore these, but would choke
 | 
				
			||||||
  on new dashed options).
 | 
					  on new dashed options).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Currently used fields include remoteuuid= and associatedfile=
 | 
					  Currently used fields include remoteuuid=, associatedfile=,
 | 
				
			||||||
 | 
					  and direct=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# HOOK
 | 
					# HOOK
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue