Direct mode .git/annex/objects directories are no longer left writable
Because that allowed writing to symlinks of files that are not present, which followed the link and put bad content in an object location. fsck: Fix up .git/annex/object directory permissions. This commit was sponsored by an anonymous bitcoin donor.
This commit is contained in:
parent
b0f85b3e22
commit
d48b00ebed
8 changed files with 56 additions and 41 deletions
|
@ -29,7 +29,6 @@ module Annex.Content (
|
||||||
preseedTmp,
|
preseedTmp,
|
||||||
freezeContent,
|
freezeContent,
|
||||||
thawContent,
|
thawContent,
|
||||||
cleanObjectLoc,
|
|
||||||
dirKeys,
|
dirKeys,
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
@ -255,11 +254,9 @@ moveAnnex key src = withObjectLoc key storeobject storedirect
|
||||||
where
|
where
|
||||||
storeobject dest = ifM (liftIO $ doesFileExist dest)
|
storeobject dest = ifM (liftIO $ doesFileExist dest)
|
||||||
( alreadyhave
|
( alreadyhave
|
||||||
, do
|
, modifyContent dest $ do
|
||||||
createContentDir dest
|
|
||||||
liftIO $ moveFile src dest
|
liftIO $ moveFile src dest
|
||||||
freezeContent dest
|
freezeContent dest
|
||||||
freezeContentDir dest
|
|
||||||
)
|
)
|
||||||
storeindirect = storeobject =<< calcRepo (gitAnnexLocation key)
|
storeindirect = storeobject =<< calcRepo (gitAnnexLocation key)
|
||||||
|
|
||||||
|
@ -273,7 +270,6 @@ moveAnnex key src = withObjectLoc key storeobject storedirect
|
||||||
storedirect = storedirect' storeindirect
|
storedirect = storedirect' storeindirect
|
||||||
storedirect' fallback [] = fallback
|
storedirect' fallback [] = fallback
|
||||||
storedirect' fallback (f:fs) = do
|
storedirect' fallback (f:fs) = do
|
||||||
thawContentDir =<< calcRepo (gitAnnexLocation key)
|
|
||||||
thawContent src
|
thawContent src
|
||||||
v <- isAnnexLink f
|
v <- isAnnexLink f
|
||||||
if Just key == v
|
if Just key == v
|
||||||
|
@ -349,11 +345,11 @@ withObjectLoc key indirect direct = ifM isDirect
|
||||||
where
|
where
|
||||||
goindirect = indirect =<< calcRepo (gitAnnexLocation key)
|
goindirect = indirect =<< calcRepo (gitAnnexLocation key)
|
||||||
|
|
||||||
cleanObjectLoc :: Key -> Annex ()
|
cleanObjectLoc :: Key -> Annex () -> Annex ()
|
||||||
cleanObjectLoc key = do
|
cleanObjectLoc key cleaner = do
|
||||||
file <- calcRepo $ gitAnnexLocation key
|
file <- calcRepo $ gitAnnexLocation key
|
||||||
unlessM crippledFileSystem $
|
void $ tryAnnexIO $ thawContentDir file
|
||||||
void $ liftIO $ catchMaybeIO $ allowWrite $ parentDir file
|
cleaner
|
||||||
liftIO $ removeparents file (3 :: Int)
|
liftIO $ removeparents file (3 :: Int)
|
||||||
where
|
where
|
||||||
removeparents _ 0 = noop
|
removeparents _ 0 = noop
|
||||||
|
@ -369,13 +365,10 @@ cleanObjectLoc key = do
|
||||||
removeAnnex :: Key -> Annex ()
|
removeAnnex :: Key -> Annex ()
|
||||||
removeAnnex key = withObjectLoc key remove removedirect
|
removeAnnex key = withObjectLoc key remove removedirect
|
||||||
where
|
where
|
||||||
remove file = do
|
remove file = cleanObjectLoc key $ do
|
||||||
thawContentDir file
|
|
||||||
liftIO $ nukeFile file
|
liftIO $ nukeFile file
|
||||||
removeInodeCache key
|
removeInodeCache key
|
||||||
cleanObjectLoc key
|
|
||||||
removedirect fs = do
|
removedirect fs = do
|
||||||
thawContentDir =<< calcRepo (gitAnnexLocation key)
|
|
||||||
cache <- recordedInodeCache key
|
cache <- recordedInodeCache key
|
||||||
removeInodeCache key
|
removeInodeCache key
|
||||||
mapM_ (resetfile cache) fs
|
mapM_ (resetfile cache) fs
|
||||||
|
@ -389,12 +382,10 @@ removeAnnex key = withObjectLoc key remove removedirect
|
||||||
|
|
||||||
{- Moves a key's file out of .git/annex/objects/ -}
|
{- Moves a key's file out of .git/annex/objects/ -}
|
||||||
fromAnnex :: Key -> FilePath -> Annex ()
|
fromAnnex :: Key -> FilePath -> Annex ()
|
||||||
fromAnnex key dest = do
|
fromAnnex key dest = cleanObjectLoc key $ do
|
||||||
file <- calcRepo $ gitAnnexLocation key
|
file <- calcRepo $ gitAnnexLocation key
|
||||||
thawContentDir file
|
|
||||||
thawContent file
|
thawContent file
|
||||||
liftIO $ moveFile file dest
|
liftIO $ moveFile file dest
|
||||||
cleanObjectLoc key
|
|
||||||
|
|
||||||
{- Moves a key out of .git/annex/objects/ into .git/annex/bad, and
|
{- Moves a key out of .git/annex/objects/ into .git/annex/bad, and
|
||||||
- returns the file it was moved to. -}
|
- returns the file it was moved to. -}
|
||||||
|
@ -404,9 +395,8 @@ moveBad key = do
|
||||||
bad <- fromRepo gitAnnexBadDir
|
bad <- fromRepo gitAnnexBadDir
|
||||||
let dest = bad </> takeFileName src
|
let dest = bad </> takeFileName src
|
||||||
createAnnexDirectory (parentDir dest)
|
createAnnexDirectory (parentDir dest)
|
||||||
thawContentDir src
|
cleanObjectLoc key $
|
||||||
liftIO $ moveFile src dest
|
liftIO $ moveFile src dest
|
||||||
cleanObjectLoc key
|
|
||||||
logStatus key InfoMissing
|
logStatus key InfoMissing
|
||||||
return dest
|
return dest
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ module Annex.Content.Direct (
|
||||||
associatedFilesRelative,
|
associatedFilesRelative,
|
||||||
removeAssociatedFile,
|
removeAssociatedFile,
|
||||||
removeAssociatedFileUnchecked,
|
removeAssociatedFileUnchecked,
|
||||||
|
removeAssociatedFiles,
|
||||||
addAssociatedFile,
|
addAssociatedFile,
|
||||||
goodContent,
|
goodContent,
|
||||||
recordedInodeCache,
|
recordedInodeCache,
|
||||||
|
@ -64,8 +65,8 @@ changeAssociatedFiles key transform = do
|
||||||
files <- associatedFilesRelative key
|
files <- associatedFilesRelative key
|
||||||
let files' = transform files
|
let files' = transform files
|
||||||
when (files /= files') $ do
|
when (files /= files') $ do
|
||||||
createContentDir mapping
|
modifyContent mapping $
|
||||||
liftIO $ viaTmp write mapping $ unlines files'
|
liftIO $ viaTmp write mapping $ unlines files'
|
||||||
top <- fromRepo Git.repoPath
|
top <- fromRepo Git.repoPath
|
||||||
return $ map (top </>) files'
|
return $ map (top </>) files'
|
||||||
where
|
where
|
||||||
|
@ -75,6 +76,13 @@ changeAssociatedFiles key transform = do
|
||||||
hPutStr h content
|
hPutStr h content
|
||||||
hClose h
|
hClose h
|
||||||
|
|
||||||
|
{- Removes the list of associated files. -}
|
||||||
|
removeAssociatedFiles :: Key -> Annex ()
|
||||||
|
removeAssociatedFiles key = do
|
||||||
|
mapping <- calcRepo $ gitAnnexMapping key
|
||||||
|
modifyContent mapping $
|
||||||
|
liftIO $ nukeFile mapping
|
||||||
|
|
||||||
{- Removes an associated file. Returns new associatedFiles value.
|
{- Removes an associated file. Returns new associatedFiles value.
|
||||||
- Checks if this was the last copy of the object, and updates location
|
- Checks if this was the last copy of the object, and updates location
|
||||||
- log. -}
|
- log. -}
|
||||||
|
@ -142,16 +150,16 @@ addInodeCache key cache = do
|
||||||
|
|
||||||
{- Writes inode cache for a key. -}
|
{- Writes inode cache for a key. -}
|
||||||
writeInodeCache :: Key -> [InodeCache] -> Annex ()
|
writeInodeCache :: Key -> [InodeCache] -> Annex ()
|
||||||
writeInodeCache key caches = withInodeCacheFile key $ \f -> do
|
writeInodeCache key caches = withInodeCacheFile key $ \f ->
|
||||||
createContentDir f
|
modifyContent f $
|
||||||
liftIO $ writeFile f $
|
liftIO $ writeFile f $
|
||||||
unlines $ map showInodeCache caches
|
unlines $ map showInodeCache caches
|
||||||
|
|
||||||
{- Removes an inode cache. -}
|
{- Removes an inode cache. -}
|
||||||
removeInodeCache :: Key -> Annex ()
|
removeInodeCache :: Key -> Annex ()
|
||||||
removeInodeCache key = withInodeCacheFile key $ \f -> do
|
removeInodeCache key = withInodeCacheFile key $ \f ->
|
||||||
createContentDir f -- also thaws directory
|
modifyContent f $
|
||||||
liftIO $ nukeFile f
|
liftIO $ nukeFile f
|
||||||
|
|
||||||
withInodeCacheFile :: Key -> (FilePath -> Annex a) -> Annex a
|
withInodeCacheFile :: Key -> (FilePath -> Annex a) -> Annex a
|
||||||
withInodeCacheFile key a = a =<< calcRepo (gitAnnexInodeCache key)
|
withInodeCacheFile key a = a =<< calcRepo (gitAnnexInodeCache key)
|
||||||
|
|
|
@ -210,11 +210,11 @@ toDirectGen k f = do
|
||||||
where
|
where
|
||||||
fromindirect loc = do
|
fromindirect loc = do
|
||||||
{- Move content from annex to direct file. -}
|
{- Move content from annex to direct file. -}
|
||||||
thawContentDir loc
|
|
||||||
updateInodeCache k loc
|
updateInodeCache k loc
|
||||||
void $ addAssociatedFile k f
|
void $ addAssociatedFile k f
|
||||||
thawContent loc
|
modifyContent loc $ do
|
||||||
replaceFile f $ liftIO . moveFile loc
|
thawContent loc
|
||||||
|
replaceFile f $ liftIO . moveFile loc
|
||||||
fromdirect loc = do
|
fromdirect loc = do
|
||||||
replaceFile f $
|
replaceFile f $
|
||||||
liftIO . void . copyFileExternal loc
|
liftIO . void . copyFileExternal loc
|
||||||
|
|
|
@ -13,12 +13,14 @@ module Annex.Perms (
|
||||||
createContentDir,
|
createContentDir,
|
||||||
freezeContentDir,
|
freezeContentDir,
|
||||||
thawContentDir,
|
thawContentDir,
|
||||||
|
modifyContent,
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Common.Annex
|
import Common.Annex
|
||||||
import Utility.FileMode
|
import Utility.FileMode
|
||||||
import Git.SharedRepository
|
import Git.SharedRepository
|
||||||
import qualified Annex
|
import qualified Annex
|
||||||
|
import Annex.Exception
|
||||||
import Config
|
import Config
|
||||||
|
|
||||||
import System.Posix.Types
|
import System.Posix.Types
|
||||||
|
@ -103,3 +105,13 @@ createContentDir dest = do
|
||||||
liftIO $ allowWrite dir
|
liftIO $ allowWrite dir
|
||||||
where
|
where
|
||||||
dir = parentDir dest
|
dir = parentDir dest
|
||||||
|
|
||||||
|
{- Creates the content directory for a file if it doesn't already exist,
|
||||||
|
- or thaws it if it does, then runs an action to modify the file, and
|
||||||
|
- finally, freezes the content directory. -}
|
||||||
|
modifyContent :: FilePath -> Annex a -> Annex a
|
||||||
|
modifyContent f a = do
|
||||||
|
createContentDir f -- also thaws it
|
||||||
|
v <- tryAnnex a
|
||||||
|
freezeContentDir f
|
||||||
|
either throwAnnex return v
|
||||||
|
|
|
@ -218,9 +218,10 @@ verifyLocationLog key desc = do
|
||||||
|
|
||||||
{- Since we're checking that a key's file is present, throw
|
{- Since we're checking that a key's file is present, throw
|
||||||
- in a permission fixup here too. -}
|
- in a permission fixup here too. -}
|
||||||
when (present && not direct) $ do
|
file <- calcRepo $ gitAnnexLocation key
|
||||||
file <- calcRepo $ gitAnnexLocation key
|
when (present && not direct) $
|
||||||
freezeContent file
|
freezeContent file
|
||||||
|
whenM (liftIO $ doesDirectoryExist $ parentDir file) $
|
||||||
freezeContentDir file
|
freezeContentDir file
|
||||||
|
|
||||||
{- In direct mode, modified files will show up as not present,
|
{- In direct mode, modified files will show up as not present,
|
||||||
|
|
|
@ -20,9 +20,9 @@ import Config
|
||||||
import qualified Annex
|
import qualified Annex
|
||||||
import Annex.Direct
|
import Annex.Direct
|
||||||
import Annex.Content
|
import Annex.Content
|
||||||
|
import Annex.Content.Direct
|
||||||
import Annex.CatFile
|
import Annex.CatFile
|
||||||
import Annex.Version
|
import Annex.Version
|
||||||
import Annex.Perms
|
|
||||||
import Annex.Exception
|
import Annex.Exception
|
||||||
import Init
|
import Init
|
||||||
import qualified Command.Add
|
import qualified Command.Add
|
||||||
|
@ -77,7 +77,8 @@ perform = do
|
||||||
Just s
|
Just s
|
||||||
| isSymbolicLink s -> void $ flip whenAnnexed f $
|
| isSymbolicLink s -> void $ flip whenAnnexed f $
|
||||||
\_ (k, _) -> do
|
\_ (k, _) -> do
|
||||||
cleandirect k
|
removeInodeCache k
|
||||||
|
removeAssociatedFiles k
|
||||||
return Nothing
|
return Nothing
|
||||||
| otherwise ->
|
| otherwise ->
|
||||||
maybe noop (fromdirect f)
|
maybe noop (fromdirect f)
|
||||||
|
@ -87,8 +88,8 @@ perform = do
|
||||||
|
|
||||||
fromdirect f k = do
|
fromdirect f k = do
|
||||||
showStart "indirect" f
|
showStart "indirect" f
|
||||||
thawContentDir =<< calcRepo (gitAnnexLocation k)
|
removeInodeCache k
|
||||||
cleandirect k -- clean before content directory gets frozen
|
removeAssociatedFiles k
|
||||||
whenM (liftIO $ not . isSymbolicLink <$> getSymbolicLinkStatus f) $ do
|
whenM (liftIO $ not . isSymbolicLink <$> getSymbolicLinkStatus f) $ do
|
||||||
v <-tryAnnexIO (moveAnnex k f)
|
v <-tryAnnexIO (moveAnnex k f)
|
||||||
case v of
|
case v of
|
||||||
|
@ -103,10 +104,6 @@ perform = do
|
||||||
warnlocked e = do
|
warnlocked e = do
|
||||||
warning $ show e
|
warning $ show e
|
||||||
warning "leaving this file as-is; correct this problem and run git annex add on it"
|
warning "leaving this file as-is; correct this problem and run git annex add on it"
|
||||||
|
|
||||||
cleandirect k = do
|
|
||||||
liftIO . nukeFile =<< calcRepo (gitAnnexInodeCache k)
|
|
||||||
liftIO . nukeFile =<< calcRepo (gitAnnexMapping k)
|
|
||||||
|
|
||||||
cleanup :: CommandCleanup
|
cleanup :: CommandCleanup
|
||||||
cleanup = do
|
cleanup = do
|
||||||
|
|
4
debian/changelog
vendored
4
debian/changelog
vendored
|
@ -31,6 +31,10 @@ git-annex (5.20131102) UNRELEASED; urgency=low
|
||||||
with a directory. An ordering problem caused the directory to not get
|
with a directory. An ordering problem caused the directory to not get
|
||||||
created in this case.
|
created in this case.
|
||||||
Thanks to Tim for the test cases.
|
Thanks to Tim for the test cases.
|
||||||
|
* Direct mode .git/annex/objects directories are no longer left writable,
|
||||||
|
because that allowed writing to symlinks of files that are not present,
|
||||||
|
which followed the link and put bad content in an object location.
|
||||||
|
* fsck: Fix up .git/annex/object directory permissions.
|
||||||
|
|
||||||
-- Joey Hess <joeyh@debian.org> Wed, 06 Nov 2013 16:14:14 -0400
|
-- Joey Hess <joeyh@debian.org> Wed, 06 Nov 2013 16:14:14 -0400
|
||||||
|
|
||||||
|
|
|
@ -43,3 +43,6 @@ remote types: git gcrypt S3 bup directory rsync web webdav glacier hook
|
||||||
|
|
||||||
Linux ceilingcat 3.11.6-1-ARCH #1 SMP PREEMPT Fri Oct 18 23:22:36 CEST 2013 x86_64 GNU/Linux
|
Linux ceilingcat 3.11.6-1-ARCH #1 SMP PREEMPT Fri Oct 18 23:22:36 CEST 2013 x86_64 GNU/Linux
|
||||||
"""]]
|
"""]]
|
||||||
|
|
||||||
|
> [[fixed|done]]; direct mode now freezes the content directory as indirect
|
||||||
|
> mode already did. fsck will fix up the permissions too. --[[Joey]]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue