fix potential race in updating inode cache
Some uses of linkFromAnnex are inside replaceWorkTreeFile, which was already safe, but others use it directly on the work tree file, which was race-prone. Eg, if the work tree file was first removed, then linkFromAnnex called to populate it, the user could have re-written it in the interim. This came to light during an audit of all calls of addInodeCaches, looking for such races. All the other uses of it seem ok. Sponsored-by: Brett Eisenberg on Patreon
This commit is contained in:
parent
e4b2a067e0
commit
14683da9eb
5 changed files with 22 additions and 6 deletions
|
@ -30,6 +30,7 @@ module Annex.Content (
|
|||
populatePointerFile,
|
||||
linkToAnnex,
|
||||
linkFromAnnex,
|
||||
linkFromAnnex',
|
||||
LinkAnnexResult(..),
|
||||
unlinkAnnex,
|
||||
checkedCopyFile,
|
||||
|
@ -78,6 +79,7 @@ import Annex.Link
|
|||
import Annex.LockPool
|
||||
import Annex.UUID
|
||||
import Annex.InodeSentinal
|
||||
import Annex.ReplaceFile
|
||||
import Annex.AdjustedBranch (adjustedBranchRefresh)
|
||||
import Messages.Progress
|
||||
import Types.Remote (RetrievalSecurityPolicy(..))
|
||||
|
@ -382,9 +384,23 @@ linkToAnnex key src srcic = ifM (checkSecureHashes' key)
|
|||
, return LinkAnnexFailed
|
||||
)
|
||||
|
||||
{- Makes a destination file be a link or copy from the annex object. -}
|
||||
{- Makes a destination file be a link or copy from the annex object.
|
||||
-
|
||||
- linkAnnex stats the file after copying it to add to the inode
|
||||
- cache. But dest may be a file in the working tree, which could
|
||||
- get modified immediately after being populated. To avoid such a
|
||||
- race, call linkAnnex on a temporary file and move it into place
|
||||
- afterwards. Note that a consequence of this is that, if the file
|
||||
- already exists, it will be overwritten.
|
||||
-}
|
||||
linkFromAnnex :: Key -> RawFilePath -> Maybe FileMode -> Annex LinkAnnexResult
|
||||
linkFromAnnex key dest destmode = do
|
||||
linkFromAnnex key dest destmode =
|
||||
replaceFile (const noop) (fromRawFilePath dest) $ \tmp ->
|
||||
linkFromAnnex' key (toRawFilePath tmp) destmode
|
||||
|
||||
{- This is only safe to use when dest is not a worktree file. -}
|
||||
linkFromAnnex' :: Key -> RawFilePath -> Maybe FileMode -> Annex LinkAnnexResult
|
||||
linkFromAnnex' key dest destmode = do
|
||||
src <- calcRepo (gitAnnexLocation key)
|
||||
srcic <- withTSDelta (liftIO . genInodeCache src)
|
||||
linkAnnex From key src srcic dest destmode
|
||||
|
|
|
@ -131,7 +131,7 @@ scanAnnexedFiles initscan = do
|
|||
fileMode <$> R.getFileStatus f
|
||||
ic <- replaceWorkTreeFile (fromRawFilePath f) $ \tmp -> do
|
||||
let tmp' = toRawFilePath tmp
|
||||
linkFromAnnex k tmp' destmode >>= \case
|
||||
linkFromAnnex' k tmp' destmode >>= \case
|
||||
LinkAnnexOk ->
|
||||
withTSDelta (liftIO . genInodeCache tmp')
|
||||
LinkAnnexNoop -> return Nothing
|
||||
|
|
|
@ -85,7 +85,7 @@ makeHardLink :: RawFilePath -> Key -> CommandPerform
|
|||
makeHardLink file key = do
|
||||
replaceWorkTreeFile (fromRawFilePath file) $ \tmp -> do
|
||||
mode <- liftIO $ catchMaybeIO $ fileMode <$> R.getFileStatus file
|
||||
linkFromAnnex key (toRawFilePath tmp) mode >>= \case
|
||||
linkFromAnnex' key (toRawFilePath tmp) mode >>= \case
|
||||
LinkAnnexFailed -> error "unable to make hard link"
|
||||
_ -> noop
|
||||
next $ return True
|
||||
|
|
|
@ -357,7 +357,7 @@ verifyWorkTree key file = do
|
|||
let tmp' = toRawFilePath tmp
|
||||
mode <- liftIO $ catchMaybeIO $ fileMode <$> R.getFileStatus file
|
||||
ifM (annexThin <$> Annex.getGitConfig)
|
||||
( void $ linkFromAnnex key tmp' mode
|
||||
( void $ linkFromAnnex' key tmp' mode
|
||||
, do
|
||||
obj <- calcRepo (gitAnnexLocation key)
|
||||
void $ checkedCopyFile key obj tmp' mode
|
||||
|
|
|
@ -50,7 +50,7 @@ perform dest key = do
|
|||
replaceWorkTreeFile (fromRawFilePath dest) $ \tmp ->
|
||||
ifM (inAnnex key)
|
||||
( do
|
||||
r <- linkFromAnnex key (toRawFilePath tmp) destmode
|
||||
r <- linkFromAnnex' key (toRawFilePath tmp) destmode
|
||||
case r of
|
||||
LinkAnnexOk -> return ()
|
||||
LinkAnnexNoop -> return ()
|
||||
|
|
Loading…
Reference in a new issue