add: Prevent (most) modifications from being made to a file while it is being added to the annex.

Anything that tries to open the file for write, or delete the file,
or replace it with something else, will not affect the add.

Only if a process has the file open for write before add starts
can it still change it while (or after) it's added to the annex.
(fsck will catch this later of course)
This commit is contained in:
Joey Hess 2012-06-05 20:28:34 -04:00
parent 5809f33f8b
commit c981ccc077
2 changed files with 30 additions and 6 deletions

View file

@ -15,7 +15,9 @@ import qualified Annex.Queue
import Backend import Backend
import Logs.Location import Logs.Location
import Annex.Content import Annex.Content
import Annex.Perms
import Utility.Touch import Utility.Touch
import Utility.FileMode
def :: [Command] def :: [Command]
def = [command "add" paramPaths seek "add files to annex"] def = [command "add" paramPaths seek "add files to annex"]
@ -44,23 +46,38 @@ start file = notBareRepo $ ifAnnexed file fixup add
liftIO $ removeFile file liftIO $ removeFile file
next $ next $ cleanup file key =<< inAnnex key next $ next $ cleanup file key =<< inAnnex key
{- The file that's being added is locked down before a key is generated,
- to prevent it from being modified in between. It's hard linked into a
- temporary location, and its writable bits are removed. It could still be
- written to by a process that already has it open for writing. -}
perform :: FilePath -> CommandPerform perform :: FilePath -> CommandPerform
perform file = do perform file = do
let source = KeySource { keyFilename = file, contentLocation = file} liftIO $ preventWrite file
tmp <- fromRepo gitAnnexTmpDir
createAnnexDirectory tmp
pid <- liftIO getProcessID
let tmpfile = tmp </> "add" ++ show pid ++ "." ++ takeFileName file
nuke tmpfile
liftIO $ createLink file tmpfile
let source = KeySource { keyFilename = file, contentLocation = tmpfile }
backend <- chooseBackend file backend <- chooseBackend file
genKey source backend >>= go genKey source backend >>= go tmpfile
where where
go Nothing = stop go _ Nothing = stop
go (Just (key, _)) = do go tmpfile (Just (key, _)) = do
handle (undo file key) $ moveAnnex key file handle (undo file key) $ moveAnnex key tmpfile
nuke file
next $ cleanup file key True next $ cleanup file key True
nuke :: FilePath -> Annex ()
nuke file = liftIO $ whenM (doesFileExist file) $ removeFile file
{- On error, put the file back so it doesn't seem to have vanished. {- On error, put the file back so it doesn't seem to have vanished.
- This can be called before or after the symlink is in place. -} - This can be called before or after the symlink is in place. -}
undo :: FilePath -> Key -> IOException -> Annex a undo :: FilePath -> Key -> IOException -> Annex a
undo file key e = do undo file key e = do
whenM (inAnnex key) $ do whenM (inAnnex key) $ do
liftIO $ whenM (doesFileExist file) $ removeFile file nuke file
handle tryharder $ fromAnnex key file handle tryharder $ fromAnnex key file
logStatus key InfoMissing logStatus key InfoMissing
throw e throw e

7
debian/changelog vendored
View file

@ -1,3 +1,10 @@
git-annex (3.20120606) UNRELEASED; urgency=low
* add: Prevent (most) modifications from being made to a file while it
is being added to the annex.
-- Joey Hess <joeyh@debian.org> Tue, 05 Jun 2012 20:25:51 -0400
git-annex (3.20120605) unstable; urgency=low git-annex (3.20120605) unstable; urgency=low
* sync: Show a nicer message if a user tries to sync to a special remote. * sync: Show a nicer message if a user tries to sync to a special remote.