summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Joey Hess <joey@kitenet.net>2010-11-08 19:26:37 -0400
committerGravatar Joey Hess <joey@kitenet.net>2010-11-08 19:26:37 -0400
commit1d32d902c95a49c53c46951641852c209476cb3d (patch)
tree56b7ae1ebb6da1b3924e4abbbe608aabf95aa172
parent8dd9f8e49eae081e7503facff6d5a53285194c09 (diff)
Annexed file contents are now made unwritable and put in unwriteable directories, to avoid them accidentially being removed or modified. (Thanks Josh Triplett for the idea.)
-rw-r--r--Command/Add.hs9
-rw-r--r--Command/Drop.hs17
-rw-r--r--Command/DropKey.hs8
-rw-r--r--Command/SetKey.hs22
-rw-r--r--Command/Unannex.hs9
-rw-r--r--Core.hs53
-rw-r--r--debian/changelog3
-rw-r--r--doc/todo/immutable_annexed_files.mdwn2
8 files changed, 74 insertions, 49 deletions
diff --git a/Command/Add.hs b/Command/Add.hs
index 3cc681f69..6c5d24f84 100644
--- a/Command/Add.hs
+++ b/Command/Add.hs
@@ -9,12 +9,9 @@ module Command.Add where
import Control.Monad.State (liftIO)
import System.Posix.Files
-import System.Directory
import Command
import qualified Annex
-import Utility
-import Locations
import qualified Backend
import LocationLog
import Types
@@ -42,11 +39,9 @@ perform (file, backend) = do
cleanup :: FilePath -> Key -> SubCmdCleanup
cleanup file key = do
+ moveAnnex key file
logStatus key ValuePresent
- g <- Annex.gitRepo
- let dest = annexLocation g key
- liftIO $ createDirectoryIfMissing True (parentDir dest)
- liftIO $ renameFile file dest
+
link <- calcGitLink file key
liftIO $ createSymbolicLink link file
Annex.queue "add" [] file
diff --git a/Command/Drop.hs b/Command/Drop.hs
index d1ebd7f64..48433b14c 100644
--- a/Command/Drop.hs
+++ b/Command/Drop.hs
@@ -7,12 +7,9 @@
module Command.Drop where
-import Control.Monad.State (liftIO)
-import System.Directory
+import Control.Monad (when)
import Command
-import qualified Annex
-import Locations
import qualified Backend
import LocationLog
import Types
@@ -39,13 +36,7 @@ perform key backend = do
cleanup :: Key -> SubCmdCleanup
cleanup key = do
- logStatus key ValueMissing
inannex <- inAnnex key
- if (inannex)
- then do
- g <- Annex.gitRepo
- let loc = annexLocation g key
- liftIO $ removeFile loc
- return True
- else return True
-
+ when (inannex) $ removeAnnex key
+ logStatus key ValueMissing
+ return True
diff --git a/Command/DropKey.hs b/Command/DropKey.hs
index 8076e6fd3..e0b20918c 100644
--- a/Command/DropKey.hs
+++ b/Command/DropKey.hs
@@ -7,12 +7,8 @@
module Command.DropKey where
-import Control.Monad.State (liftIO)
-import System.Directory
-
import Command
import qualified Annex
-import Locations
import qualified Backend
import LocationLog
import Types
@@ -36,9 +32,7 @@ start keyname = do
perform :: Key -> SubCmdPerform
perform key = do
- g <- Annex.gitRepo
- let loc = annexLocation g key
- liftIO $ removeFile loc
+ removeAnnex key
return $ Just $ cleanup key
cleanup :: Key -> SubCmdCleanup
diff --git a/Command/SetKey.hs b/Command/SetKey.hs
index 9286e740b..50e9a590b 100644
--- a/Command/SetKey.hs
+++ b/Command/SetKey.hs
@@ -13,7 +13,6 @@ import Control.Monad (when)
import Command
import qualified Annex
import Utility
-import Locations
import qualified Backend
import LocationLog
import Types
@@ -22,21 +21,22 @@ import Messages
{- Sets cached content for a key. -}
start :: SubCmdStartString
-start tmpfile = do
+start file = do
keyname <- Annex.flagGet "key"
when (null keyname) $ error "please specify the key with --key"
backends <- Backend.list
let key = genKey (backends !! 0) keyname
- showStart "setkey" tmpfile
- return $ Just $ perform tmpfile key
+ showStart "setkey" file
+ return $ Just $ perform file key
perform :: FilePath -> Key -> SubCmdPerform
-perform tmpfile key = do
- g <- Annex.gitRepo
- let loc = annexLocation g key
- ok <- liftIO $ boolSystem "mv" [tmpfile, loc]
- if (not ok)
- then error "mv failed!"
- else return $ Just $ cleanup key
+perform file key = do
+ -- the file might be on a different filesystem, so mv is used
+ -- rather than simply calling moveToObjectDir key file
+ ok <- getViaTmp key $ \dest -> liftIO $ boolSystem "mv" [file, dest]
+ if ok
+ then return $ Just $ cleanup key
+ else error "mv failed!"
+
cleanup :: Key -> SubCmdCleanup
cleanup key = do
logStatus key ValuePresent
diff --git a/Command/Unannex.hs b/Command/Unannex.hs
index e0848cd4a..a9c18f765 100644
--- a/Command/Unannex.hs
+++ b/Command/Unannex.hs
@@ -13,7 +13,6 @@ import System.Directory
import Command
import qualified Annex
import Utility
-import Locations
import qualified Backend
import LocationLog
import Types
@@ -38,12 +37,14 @@ perform file key backend = do
cleanup :: FilePath -> Key -> SubCmdCleanup
cleanup file key = do
- logStatus key ValueMissing
g <- Annex.gitRepo
- let src = annexLocation g key
+
liftIO $ removeFile file
liftIO $ Git.run g ["rm", "--quiet", file]
-- git rm deletes empty directories; put them back
liftIO $ createDirectoryIfMissing True (parentDir file)
- liftIO $ renameFile src file
+
+ fromAnnex key file
+ logStatus key ValueMissing
+
return True
diff --git a/Core.hs b/Core.hs
index 90af62eb6..f04a3dfac 100644
--- a/Core.hs
+++ b/Core.hs
@@ -144,7 +144,7 @@ getViaTmp key action = do
success <- action tmp
if (success)
then do
- moveToObjectDir key tmp
+ moveAnnex key tmp
logStatus key ValuePresent
return True
else do
@@ -152,14 +152,53 @@ getViaTmp key action = do
-- to resume its transfer
return False
+{- Removes the write bits from a file. -}
+preventWrite :: FilePath -> IO ()
+preventWrite f = unsetFileMode f writebits
+ where
+ writebits = foldl unionFileModes ownerWriteMode
+ [groupWriteMode, otherWriteMode]
+
+{- Turns a file's write bit back on. -}
+allowWrite :: FilePath -> IO ()
+allowWrite f = do
+ s <- getFileStatus f
+ setFileMode f $ (fileMode s) `unionFileModes` ownerWriteMode
+
{- Moves a file into .git/annex/objects/ -}
-moveToObjectDir :: Key -> FilePath -> Annex ()
-moveToObjectDir key src = do
+moveAnnex :: Key -> FilePath -> Annex ()
+moveAnnex key src = do
g <- Annex.gitRepo
let dest = annexLocation g key
- liftIO $ createDirectoryIfMissing True (parentDir dest)
- liftIO $ renameFile src dest
- -- TODO directory and file mode tweaks
+ let dir = parentDir dest
+ liftIO $ do
+ createDirectoryIfMissing True dir
+ renameFile src dest
+ preventWrite dest
+ preventWrite dir
+
+{- Removes a key's file from .git/annex/objects/ -}
+removeAnnex :: Key -> Annex ()
+removeAnnex key = do
+ g <- Annex.gitRepo
+ let file = annexLocation g key
+ let dir = parentDir file
+ liftIO $ do
+ allowWrite dir
+ removeFile file
+ removeDirectory dir
+
+{- Moves a key's file out of .git/annex/objects/ -}
+fromAnnex :: Key -> FilePath -> Annex ()
+fromAnnex key dest = do
+ g <- Annex.gitRepo
+ let file = annexLocation g key
+ let dir = parentDir file
+ liftIO $ do
+ allowWrite dir
+ allowWrite file
+ renameFile file dest
+ removeDirectory dir
{- List of keys whose content exists in .git/annex/objects/ -}
getKeysPresent :: Annex [Key]
@@ -202,7 +241,7 @@ upgradeFrom0 = do
-- do the reorganisation of the files
let olddir = annexDir g
keys <- getKeysPresent' olddir
- _ <- mapM (\k -> moveToObjectDir k $ olddir ++ "/" ++ keyFile k) keys
+ _ <- mapM (\k -> moveAnnex k $ olddir ++ "/" ++ keyFile k) keys
-- update the symlinks to the files
files <- liftIO $ Git.inRepo g $ Git.workTree g
diff --git a/debian/changelog b/debian/changelog
index dc9dcedc2..1ce6a2deb 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -8,6 +8,9 @@ git-annex (0.04) UNRELEASED; urgency=low
git-annex is used in a repository with the old layout.
* Note that git-annex 0.04 cannot transfer content from old repositories
that have not yet been upgraded.
+ * Annexed file contents are now made unwritable and put in unwriteable
+ directories, to avoid them accidentially being removed or modified.
+ (Thanks Josh Triplett for the idea.)
-- Joey Hess <joeyh@debian.org> Mon, 08 Nov 2010 12:36:39 -0400
diff --git a/doc/todo/immutable_annexed_files.mdwn b/doc/todo/immutable_annexed_files.mdwn
index e5207dc16..b26838e95 100644
--- a/doc/todo/immutable_annexed_files.mdwn
+++ b/doc/todo/immutable_annexed_files.mdwn
@@ -4,3 +4,5 @@
> josh: Oh, I just thought of another slightly crazy but handy idea.
> josh: I'd hate to run into a program which somehow followed the symlink and then did an unlink to replace the file.
> josh: To break that, you could create a new directory under annex's internal directory for each file, and make the directory have no write permission.
+
+[[done]] and done --[[Joey]]