diff options
author | 2016-01-07 14:51:28 -0400 | |
---|---|---|
committer | 2016-01-07 15:14:15 -0400 | |
commit | de92739546ba6fd82963e9932d622b891f8ff096 (patch) | |
tree | b60fc4d87f9ac341c3babf68fe020eeaacb52a18 /Command/ReKey.hs | |
parent | 3729ee0549993ccb648b7f798c9c400661350cdf (diff) |
migrate and rekey v6 unlocked file support
Diffstat (limited to 'Command/ReKey.hs')
-rw-r--r-- | Command/ReKey.hs | 80 |
1 files changed, 61 insertions, 19 deletions
diff --git a/Command/ReKey.hs b/Command/ReKey.hs index 9fb8515c0..468d0dfe6 100644 --- a/Command/ReKey.hs +++ b/Command/ReKey.hs @@ -1,6 +1,6 @@ {- git-annex command - - - Copyright 2012 Joey Hess <id@joeyh.name> + - Copyright 2012-2016 Joey Hess <id@joeyh.name> - - Licensed under the GNU GPL version 3 or higher. -} @@ -13,10 +13,16 @@ import qualified Annex import Types.Key import Annex.Content import Annex.Ingest +import Annex.Link +import Annex.Perms +import Annex.ReplaceFile import Logs.Web import Logs.Location -import Utility.CopyFile +import Git.FilePath import qualified Remote +import qualified Database.Keys +import Annex.InodeSentinal +import Utility.InodeCache cmd :: Command cmd = notDirect $ @@ -40,24 +46,50 @@ start (file, keyname) = ifAnnexed file go stop perform :: FilePath -> Key -> Key -> CommandPerform perform file oldkey newkey = do - present <- inAnnex oldkey - _ <- if present - then linkKey oldkey newkey - else do - unlessM (Annex.getState Annex.force) $ - error $ file ++ " is not available (use --force to override)" - return True + ifM (inAnnex oldkey) + ( unlessM (linkKey file oldkey newkey) $ + error "failed" + , unlessM (Annex.getState Annex.force) $ + error $ file ++ " is not available (use --force to override)" + ) next $ cleanup file oldkey newkey {- Make a hard link to the old key content (when supported), - to avoid wasting disk space. -} -linkKey :: Key -> Key -> Annex Bool -linkKey oldkey newkey = getViaTmp' DefaultVerify newkey $ \tmp -> unVerified $ do - src <- calcRepo $ gitAnnexLocation oldkey - liftIO $ ifM (doesFileExist tmp) - ( return True - , createLinkOrCopy src tmp - ) +linkKey :: FilePath -> Key -> Key -> Annex Bool +linkKey file oldkey newkey = ifM (isJust <$> isAnnexLink file) + {- If the object file is already hardlinked to elsewhere, a hard + - link won't be made by getViaTmp', but a copy instead. + - This avoids hard linking to content linked to an + - unlocked file, which would leave the new key unlocked + - and vulnerable to corruption. -} + ( getViaTmp' DefaultVerify newkey $ \tmp -> unVerified $ do + oldobj <- calcRepo (gitAnnexLocation oldkey) + linkOrCopy' (return True) newkey oldobj tmp + , do + ic <- withTSDelta (liftIO . genInodeCache file) + {- The file being rekeyed is itself an unlocked file, so if + - it's linked to the old key, that link must be broken. -} + oldobj <- calcRepo (gitAnnexLocation oldkey) + v <- tryNonAsync $ modifyContent oldobj $ do + replaceFile oldobj $ \tmp -> + unlessM (checkedCopyFile oldkey file tmp) $ + error "can't lock old key" + freezeContent oldobj + oldic <- withTSDelta (liftIO . genInodeCache oldobj) + whenM (isUnmodified oldkey oldobj) $ + Database.Keys.addInodeCaches oldkey (catMaybes [oldic]) + case v of + Left e -> do + warning (show e) + return False + Right () -> do + r <- linkToAnnex newkey file ic + return $ case r of + LinkAnnexFailed -> False + LinkAnnexOk -> True + LinkAnnexNoop -> True + ) cleanup :: FilePath -> Key -> Key -> CommandCleanup cleanup file oldkey newkey = do @@ -68,8 +100,18 @@ cleanup file oldkey newkey = do r <- Remote.claimingUrl url setUrlPresent (Remote.uuid r) newkey url - -- Update symlink to use the new key. - liftIO $ removeFile file - addLink file newkey Nothing + ifM (isJust <$> isAnnexLink file) + ( do + -- Update symlink to use the new key. + liftIO $ removeFile file + addLink file newkey Nothing + , do + liftIO $ whenM (isJust <$> isPointerFile file) $ + writeFile file (formatPointer newkey) + stagePointerFile file =<< hashPointerFile newkey + Database.Keys.removeAssociatedFile oldkey + =<< inRepo (toTopFilePath file) + ) + logStatus newkey InfoPresent return True |