fix potential race in updating inode cache

In Annex.Content, the object file was statted after pointer files were
populated. But if annex.thin is set, once the pointer files are
populated, the object file can potentially be modified via the hard
link. So, it was possible, though seemingly very unlikely, for the inode
of the modified object file to be cached.

Command.Fix and Command.Fsck had similar problems, statting the work
tree files after they were in place. Changed them to stat the temp file
that gets moved into place. This does rely on .git/annex being on the
same filesystem. If it's not, the cached inode will not be the same as
the one that the temp file gets moved to. Result will be that git-annex
will later need to do an expensive verification of the content of the
worktree files. Note that the cross-filesystem move of the temp file
already is a larger amount of extra work, so this seems acceptable.

Sponsored-by: Luke Shumaker on Patreon
This commit is contained in:
Joey Hess 2021-07-27 12:29:10 -04:00
parent 3b5a3e168d
commit e4b2a067e0
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
4 changed files with 8 additions and 9 deletions

View file

@ -346,8 +346,11 @@ moveAnnex key af src = ifM (checkSecureHashes' key)
fs <- map (`fromTopFilePath` g)
<$> Database.Keys.getAssociatedFiles key
unless (null fs) $ do
destic <- withTSDelta $
liftIO . genInodeCache dest
ics <- mapM (populatePointerFile (Restage True) key dest) fs
Database.Keys.storeInodeCaches' key [dest] (catMaybes ics)
Database.Keys.addInodeCaches key
(catMaybes (destic:ics))
)
alreadyhave = liftIO $ R.removeLink src

View file

@ -77,8 +77,8 @@ breakHardLink file key obj = do
unlessM (checkedCopyFile key obj tmp' mode) $
error "unable to break hard link"
thawContent tmp'
Database.Keys.storeInodeCaches key [tmp']
modifyContent obj $ freezeContent obj
Database.Keys.storeInodeCaches key [file]
next $ return True
makeHardLink :: RawFilePath -> Key -> CommandPerform

View file

@ -363,7 +363,7 @@ verifyWorkTree key file = do
void $ checkedCopyFile key obj tmp' mode
thawContent tmp'
)
Database.Keys.storeInodeCaches key [file]
Database.Keys.storeInodeCaches key [tmp']
_ -> return ()
return True

View file

@ -18,7 +18,6 @@ module Database.Keys (
getAssociatedKey,
removeAssociatedFile,
storeInodeCaches,
storeInodeCaches',
addInodeCaches,
getInodeCaches,
removeInodeCaches,
@ -175,11 +174,8 @@ removeAssociatedFile k = runWriterIO . SQL.removeAssociatedFile k
{- Stats the files, and stores their InodeCaches. -}
storeInodeCaches :: Key -> [RawFilePath] -> Annex ()
storeInodeCaches k fs = storeInodeCaches' k fs []
storeInodeCaches' :: Key -> [RawFilePath] -> [InodeCache] -> Annex ()
storeInodeCaches' k fs ics = withTSDelta $ \d ->
addInodeCaches k . (++ ics) . catMaybes
storeInodeCaches k fs = withTSDelta $ \d ->
addInodeCaches k . catMaybes
=<< liftIO (mapM (\f -> genInodeCache f d) fs)
addInodeCaches :: Key -> [InodeCache] -> Annex ()