summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Joey Hess <joey@kitenet.net>2012-06-05 20:28:34 -0400
committerGravatar Joey Hess <joey@kitenet.net>2012-06-05 20:28:34 -0400
commitc981ccc0773a02ca60eb6456f04de14cd758ee7b (patch)
treea34aa1cb4104803d1e5ca45d45f6d96aee79be88
parent5809f33f8b3c2aa3cb8207bc775339c533a914ab (diff)
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)
-rw-r--r--Command/Add.hs29
-rw-r--r--debian/changelog7
2 files changed, 30 insertions, 6 deletions
diff --git a/Command/Add.hs b/Command/Add.hs
index 7029a9c16..2c671eea2 100644
--- a/Command/Add.hs
+++ b/Command/Add.hs
@@ -15,7 +15,9 @@ import qualified Annex.Queue
import Backend
import Logs.Location
import Annex.Content
+import Annex.Perms
import Utility.Touch
+import Utility.FileMode
def :: [Command]
def = [command "add" paramPaths seek "add files to annex"]
@@ -44,23 +46,38 @@ start file = notBareRepo $ ifAnnexed file fixup add
liftIO $ removeFile file
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 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
- genKey source backend >>= go
+ genKey source backend >>= go tmpfile
where
- go Nothing = stop
- go (Just (key, _)) = do
- handle (undo file key) $ moveAnnex key file
+ go _ Nothing = stop
+ go tmpfile (Just (key, _)) = do
+ handle (undo file key) $ moveAnnex key tmpfile
+ nuke file
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.
- This can be called before or after the symlink is in place. -}
undo :: FilePath -> Key -> IOException -> Annex a
undo file key e = do
whenM (inAnnex key) $ do
- liftIO $ whenM (doesFileExist file) $ removeFile file
+ nuke file
handle tryharder $ fromAnnex key file
logStatus key InfoMissing
throw e
diff --git a/debian/changelog b/debian/changelog
index fd4f7b98b..9a010327d 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -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
* sync: Show a nicer message if a user tries to sync to a special remote.