honor core.sharedRepository when making all the other files in the annex
Lock files, directories, etc.
This commit is contained in:
parent
7e45712d19
commit
b98b69e8c6
8 changed files with 119 additions and 33 deletions
|
@ -36,6 +36,7 @@ import qualified Git.UnionMerge
|
||||||
import Git.HashObject
|
import Git.HashObject
|
||||||
import qualified Git.Index
|
import qualified Git.Index
|
||||||
import Annex.CatFile
|
import Annex.CatFile
|
||||||
|
import Annex.Perms
|
||||||
|
|
||||||
{- Name of the branch that is used to store git-annex's information. -}
|
{- Name of the branch that is used to store git-annex's information. -}
|
||||||
name :: Git.Ref
|
name :: Git.Ref
|
||||||
|
@ -308,6 +309,7 @@ setIndexSha :: Git.Ref -> Annex ()
|
||||||
setIndexSha ref = do
|
setIndexSha ref = do
|
||||||
lock <- fromRepo gitAnnexIndexLock
|
lock <- fromRepo gitAnnexIndexLock
|
||||||
liftIO $ writeFile lock $ show ref ++ "\n"
|
liftIO $ writeFile lock $ show ref ++ "\n"
|
||||||
|
setAnnexPerm lock
|
||||||
|
|
||||||
{- Checks if there are uncommitted changes in the branch's index or journal. -}
|
{- Checks if there are uncommitted changes in the branch's index or journal. -}
|
||||||
unCommitted :: Annex Bool
|
unCommitted :: Annex Bool
|
||||||
|
|
|
@ -46,6 +46,7 @@ import Utility.CopyFile
|
||||||
import Config
|
import Config
|
||||||
import Annex.Exception
|
import Annex.Exception
|
||||||
import Git.SharedRepository
|
import Git.SharedRepository
|
||||||
|
import Annex.Perms
|
||||||
|
|
||||||
{- Checks if a given key's content is currently present. -}
|
{- Checks if a given key's content is currently present. -}
|
||||||
inAnnex :: Key -> Annex Bool
|
inAnnex :: Key -> Annex Bool
|
||||||
|
@ -141,7 +142,7 @@ getViaTmp key action = do
|
||||||
prepTmp :: Key -> Annex FilePath
|
prepTmp :: Key -> Annex FilePath
|
||||||
prepTmp key = do
|
prepTmp key = do
|
||||||
tmp <- fromRepo $ gitAnnexTmpLocation key
|
tmp <- fromRepo $ gitAnnexTmpLocation key
|
||||||
liftIO $ createDirectoryIfMissing True (parentDir tmp)
|
createAnnexDirectory (parentDir tmp)
|
||||||
return tmp
|
return tmp
|
||||||
|
|
||||||
{- Like getViaTmp, but does not check that there is enough disk space
|
{- Like getViaTmp, but does not check that there is enough disk space
|
||||||
|
@ -216,14 +217,11 @@ checkDiskSpace destination key alreadythere = do
|
||||||
moveAnnex :: Key -> FilePath -> Annex ()
|
moveAnnex :: Key -> FilePath -> Annex ()
|
||||||
moveAnnex key src = do
|
moveAnnex key src = do
|
||||||
dest <- inRepo $ gitAnnexLocation key
|
dest <- inRepo $ gitAnnexLocation key
|
||||||
let dir = parentDir dest
|
|
||||||
ifM (liftIO $ doesFileExist dest)
|
ifM (liftIO $ doesFileExist dest)
|
||||||
( liftIO $ removeFile src
|
( liftIO $ removeFile src
|
||||||
, do
|
, do
|
||||||
liftIO $ do
|
createContentDir dest
|
||||||
createDirectoryIfMissing True dir
|
liftIO $ moveFile src dest
|
||||||
allowWrite dir -- in case the directory already exists
|
|
||||||
moveFile src dest
|
|
||||||
freezeContent dest
|
freezeContent dest
|
||||||
freezeContentDir dest
|
freezeContentDir dest
|
||||||
)
|
)
|
||||||
|
@ -268,8 +266,8 @@ moveBad key = do
|
||||||
src <- inRepo $ gitAnnexLocation key
|
src <- inRepo $ gitAnnexLocation key
|
||||||
bad <- fromRepo gitAnnexBadDir
|
bad <- fromRepo gitAnnexBadDir
|
||||||
let dest = bad </> takeFileName src
|
let dest = bad </> takeFileName src
|
||||||
|
createAnnexDirectory (parentDir dest)
|
||||||
liftIO $ do
|
liftIO $ do
|
||||||
createDirectoryIfMissing True (parentDir dest)
|
|
||||||
allowWrite (parentDir src)
|
allowWrite (parentDir src)
|
||||||
moveFile src dest
|
moveFile src dest
|
||||||
cleanObjectLoc key
|
cleanObjectLoc key
|
||||||
|
@ -367,3 +365,13 @@ freezeContentDir file = liftIO . go =<< fromRepo getSharedRepository
|
||||||
go AllShared = groupWriteRead dir
|
go AllShared = groupWriteRead dir
|
||||||
go _ = preventWrite dir
|
go _ = preventWrite dir
|
||||||
|
|
||||||
|
{- Makes the directory tree to store an annexed file's content,
|
||||||
|
- with appropriate permissions on each level. -}
|
||||||
|
createContentDir :: FilePath -> Annex ()
|
||||||
|
createContentDir dest = do
|
||||||
|
unlessM (liftIO $ doesDirectoryExist dir) $
|
||||||
|
createAnnexDirectory dir
|
||||||
|
-- might have already existed with restricted perms
|
||||||
|
liftIO $ allowWrite dir
|
||||||
|
where
|
||||||
|
dir = parentDir dest
|
||||||
|
|
|
@ -16,6 +16,7 @@ import System.IO.Binary
|
||||||
import Common.Annex
|
import Common.Annex
|
||||||
import Annex.Exception
|
import Annex.Exception
|
||||||
import qualified Git
|
import qualified Git
|
||||||
|
import Annex.Perms
|
||||||
|
|
||||||
{- Records content for a file in the branch to the journal.
|
{- Records content for a file in the branch to the journal.
|
||||||
-
|
-
|
||||||
|
@ -23,22 +24,20 @@ import qualified Git
|
||||||
- avoids git needing to rewrite the index after every change. -}
|
- avoids git needing to rewrite the index after every change. -}
|
||||||
setJournalFile :: FilePath -> String -> Annex ()
|
setJournalFile :: FilePath -> String -> Annex ()
|
||||||
setJournalFile file content = do
|
setJournalFile file content = do
|
||||||
g <- gitRepo
|
createAnnexDirectory =<< fromRepo gitAnnexJournalDir
|
||||||
liftIO $ doRedo (write g) $ do
|
createAnnexDirectory =<< fromRepo gitAnnexTmpDir
|
||||||
createDirectoryIfMissing True $ gitAnnexJournalDir g
|
-- journal file is written atomically
|
||||||
createDirectoryIfMissing True $ gitAnnexTmpDir g
|
jfile <- fromRepo $ journalFile file
|
||||||
where
|
tmp <- fromRepo gitAnnexTmpDir
|
||||||
-- journal file is written atomically
|
let tmpfile = tmp </> takeFileName jfile
|
||||||
write g = do
|
liftIO $ do
|
||||||
let jfile = journalFile g file
|
writeBinaryFile tmpfile content
|
||||||
let tmpfile = gitAnnexTmpDir g </> takeFileName jfile
|
moveFile tmpfile jfile
|
||||||
writeBinaryFile tmpfile content
|
|
||||||
moveFile tmpfile jfile
|
|
||||||
|
|
||||||
{- Gets any journalled content for a file in the branch. -}
|
{- Gets any journalled content for a file in the branch. -}
|
||||||
getJournalFile :: FilePath -> Annex (Maybe String)
|
getJournalFile :: FilePath -> Annex (Maybe String)
|
||||||
getJournalFile file = inRepo $ \g -> catchMaybeIO $
|
getJournalFile file = inRepo $ \g -> catchMaybeIO $
|
||||||
readFileStrict $ journalFile g file
|
readFileStrict $ journalFile file g
|
||||||
|
|
||||||
{- List of files that have updated content in the journal. -}
|
{- List of files that have updated content in the journal. -}
|
||||||
getJournalledFiles :: Annex [FilePath]
|
getJournalledFiles :: Annex [FilePath]
|
||||||
|
@ -62,8 +61,8 @@ journalDirty = not . null <$> getJournalFiles
|
||||||
- used in the branch is not necessary, and all the files are put directly
|
- used in the branch is not necessary, and all the files are put directly
|
||||||
- in the journal directory.
|
- in the journal directory.
|
||||||
-}
|
-}
|
||||||
journalFile :: Git.Repo -> FilePath -> FilePath
|
journalFile :: FilePath -> Git.Repo -> FilePath
|
||||||
journalFile repo file = gitAnnexJournalDir repo </> concatMap mangle file
|
journalFile file repo = gitAnnexJournalDir repo </> concatMap mangle file
|
||||||
where
|
where
|
||||||
mangle '/' = "_"
|
mangle '/' = "_"
|
||||||
mangle '_' = "__"
|
mangle '_' = "__"
|
||||||
|
@ -79,16 +78,12 @@ fileJournal = replace "//" "_" . replace "_" "/"
|
||||||
lockJournal :: Annex a -> Annex a
|
lockJournal :: Annex a -> Annex a
|
||||||
lockJournal a = do
|
lockJournal a = do
|
||||||
file <- fromRepo gitAnnexJournalLock
|
file <- fromRepo gitAnnexJournalLock
|
||||||
bracketIO (lock file) unlock a
|
createAnnexDirectory $ takeDirectory file
|
||||||
|
mode <- annexFileMode
|
||||||
|
bracketIO (lock file mode) unlock a
|
||||||
where
|
where
|
||||||
lock file = do
|
lock file mode = do
|
||||||
l <- doRedo (createFile file stdFileMode) $
|
l <- noUmask mode $ createFile file mode
|
||||||
createDirectoryIfMissing True $ takeDirectory file
|
|
||||||
waitToSetLock l (WriteLock, AbsoluteSeek, 0, 0)
|
waitToSetLock l (WriteLock, AbsoluteSeek, 0, 0)
|
||||||
return l
|
return l
|
||||||
unlock = closeFd
|
unlock = closeFd
|
||||||
|
|
||||||
{- Runs an action, catching failure and running something to fix it up, and
|
|
||||||
- retrying if necessary. -}
|
|
||||||
doRedo :: IO a -> IO b -> IO a
|
|
||||||
doRedo a b = catchIO a $ const $ b >> a
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ import System.Posix.Types (Fd)
|
||||||
|
|
||||||
import Common.Annex
|
import Common.Annex
|
||||||
import Annex
|
import Annex
|
||||||
|
import Annex.Perms
|
||||||
|
|
||||||
{- Create a specified lock file, and takes a shared lock. -}
|
{- Create a specified lock file, and takes a shared lock. -}
|
||||||
lockFile :: FilePath -> Annex ()
|
lockFile :: FilePath -> Annex ()
|
||||||
|
@ -19,7 +20,9 @@ lockFile file = go =<< fromPool file
|
||||||
where
|
where
|
||||||
go (Just _) = return () -- already locked
|
go (Just _) = return () -- already locked
|
||||||
go Nothing = do
|
go Nothing = do
|
||||||
fd <- liftIO $ openFd file ReadOnly (Just stdFileMode) defaultFileFlags
|
mode <- annexFileMode
|
||||||
|
fd <- liftIO $ noUmask mode $
|
||||||
|
openFd file ReadOnly (Just mode) defaultFileFlags
|
||||||
liftIO $ waitToSetLock fd (ReadLock, AbsoluteSeek, 0, 0)
|
liftIO $ waitToSetLock fd (ReadLock, AbsoluteSeek, 0, 0)
|
||||||
changePool $ M.insert file fd
|
changePool $ M.insert file fd
|
||||||
|
|
||||||
|
|
61
Annex/Perms.hs
Normal file
61
Annex/Perms.hs
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
{- git-annex file permissions
|
||||||
|
-
|
||||||
|
- Copyright 2012 Joey Hess <joey@kitenet.net>
|
||||||
|
-
|
||||||
|
- Licensed under the GNU GPL version 3 or higher.
|
||||||
|
-}
|
||||||
|
|
||||||
|
module Annex.Perms (
|
||||||
|
setAnnexPerm,
|
||||||
|
annexFileMode,
|
||||||
|
createAnnexDirectory,
|
||||||
|
noUmask,
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Common.Annex
|
||||||
|
import Utility.FileMode
|
||||||
|
import Git.SharedRepository
|
||||||
|
|
||||||
|
import System.Posix.Types
|
||||||
|
|
||||||
|
{- Sets appropriate file mode for a file or directory in the annex,
|
||||||
|
- other than the content files and content directory. Normally,
|
||||||
|
- use the default mode, but with core.sharedRepository set,
|
||||||
|
- allow the group to write, etc. -}
|
||||||
|
setAnnexPerm :: FilePath -> Annex ()
|
||||||
|
setAnnexPerm file = liftIO . go =<< fromRepo getSharedRepository
|
||||||
|
where
|
||||||
|
go GroupShared = groupWriteRead file
|
||||||
|
go AllShared = modifyFileMode file $ addModes $
|
||||||
|
[ ownerWriteMode, groupWriteMode ] ++ readModes
|
||||||
|
go _ = return ()
|
||||||
|
|
||||||
|
{- Gets the appropriate mode to use for creating a file in the annex
|
||||||
|
- (other than content files, which are locked down more). -}
|
||||||
|
annexFileMode :: Annex FileMode
|
||||||
|
annexFileMode = go <$> fromRepo getSharedRepository
|
||||||
|
where
|
||||||
|
go GroupShared = sharedmode
|
||||||
|
go AllShared = combineModes (sharedmode:readModes)
|
||||||
|
go _ = stdFileMode
|
||||||
|
sharedmode = combineModes
|
||||||
|
[ ownerWriteMode, groupWriteMode
|
||||||
|
, ownerReadMode, groupReadMode
|
||||||
|
]
|
||||||
|
|
||||||
|
{- Creates a directory inside the gitAnnexDir, including any parent
|
||||||
|
- directories. Makes directories with appropriate permissions. -}
|
||||||
|
createAnnexDirectory :: FilePath -> Annex ()
|
||||||
|
createAnnexDirectory dir = traverse dir [] =<< top
|
||||||
|
where
|
||||||
|
top = parentDir <$> fromRepo gitAnnexDir
|
||||||
|
traverse d below stop
|
||||||
|
| d `equalFilePath` stop = done
|
||||||
|
| otherwise = ifM (liftIO $ doesDirectoryExist d)
|
||||||
|
( done
|
||||||
|
, traverse (parentDir d) (d:below) stop
|
||||||
|
)
|
||||||
|
where
|
||||||
|
done = forM_ below $ \p -> do
|
||||||
|
liftIO $ createDirectory p
|
||||||
|
setAnnexPerm p
|
|
@ -17,6 +17,7 @@ import Annex.LockPool
|
||||||
import qualified Git
|
import qualified Git
|
||||||
import Config
|
import Config
|
||||||
import qualified Build.SysConfig as SysConfig
|
import qualified Build.SysConfig as SysConfig
|
||||||
|
import Annex.Perms
|
||||||
|
|
||||||
{- Generates parameters to ssh to a given host (or user@host) on a given
|
{- Generates parameters to ssh to a given host (or user@host) on a given
|
||||||
- port, with connection caching. -}
|
- port, with connection caching. -}
|
||||||
|
@ -74,7 +75,9 @@ sshCleanup = do
|
||||||
-- be stopped.
|
-- be stopped.
|
||||||
let lockfile = socket2lock socketfile
|
let lockfile = socket2lock socketfile
|
||||||
unlockFile lockfile
|
unlockFile lockfile
|
||||||
fd <- liftIO $ openFd lockfile ReadWrite (Just stdFileMode) defaultFileFlags
|
mode <- annexFileMode
|
||||||
|
fd <- liftIO $ noUmask mode $
|
||||||
|
openFd lockfile ReadWrite (Just mode) defaultFileFlags
|
||||||
v <- liftIO $ tryIO $
|
v <- liftIO $ tryIO $
|
||||||
setLock fd (WriteLock, AbsoluteSeek, 0, 0)
|
setLock fd (WriteLock, AbsoluteSeek, 0, 0)
|
||||||
case v of
|
case v of
|
||||||
|
|
|
@ -14,6 +14,7 @@ import Types.Remote
|
||||||
import qualified Annex
|
import qualified Annex
|
||||||
import Annex.LockPool
|
import Annex.LockPool
|
||||||
import Config
|
import Config
|
||||||
|
import Annex.Perms
|
||||||
|
|
||||||
{- Modifies a remote's access functions to first run the
|
{- Modifies a remote's access functions to first run the
|
||||||
- annex-start-command hook, and trigger annex-stop-command on shutdown.
|
- annex-start-command hook, and trigger annex-stop-command on shutdown.
|
||||||
|
@ -75,7 +76,9 @@ runHooks r starthook stophook a = do
|
||||||
-- succeeds, we're the only process using this remote,
|
-- succeeds, we're the only process using this remote,
|
||||||
-- so can stop it.
|
-- so can stop it.
|
||||||
unlockFile lck
|
unlockFile lck
|
||||||
fd <- liftIO $ openFd lck ReadWrite (Just stdFileMode) defaultFileFlags
|
mode <- annexFileMode
|
||||||
|
fd <- liftIO $ noUmask mode $
|
||||||
|
openFd lck ReadWrite (Just mode) defaultFileFlags
|
||||||
v <- liftIO $ tryIO $
|
v <- liftIO $ tryIO $
|
||||||
setLock fd (WriteLock, AbsoluteSeek, 0, 0)
|
setLock fd (WriteLock, AbsoluteSeek, 0, 0)
|
||||||
case v of
|
case v of
|
||||||
|
|
|
@ -75,6 +75,17 @@ isExecutable mode = combineModes ebits `intersectFileModes` mode /= 0
|
||||||
where
|
where
|
||||||
ebits = [ownerExecuteMode, groupExecuteMode, otherExecuteMode]
|
ebits = [ownerExecuteMode, groupExecuteMode, otherExecuteMode]
|
||||||
|
|
||||||
|
{- Runs an action without that pesky umask influencing it, unless the
|
||||||
|
- passed FileMode is the standard one. -}
|
||||||
|
noUmask :: FileMode -> IO a -> IO a
|
||||||
|
noUmask mode a
|
||||||
|
| mode == stdFileMode = a
|
||||||
|
| otherwise = bracket setup cleanup go
|
||||||
|
where
|
||||||
|
setup = setFileCreationMask nullFileMode
|
||||||
|
cleanup = setFileCreationMask
|
||||||
|
go _ = a
|
||||||
|
|
||||||
combineModes :: [FileMode] -> FileMode
|
combineModes :: [FileMode] -> FileMode
|
||||||
combineModes [] = undefined
|
combineModes [] = undefined
|
||||||
combineModes [m] = m
|
combineModes [m] = m
|
||||||
|
|
Loading…
Reference in a new issue