2012-04-21 20:59:49 +00:00
|
|
|
{- git-annex file permissions
|
|
|
|
-
|
2023-04-26 17:25:29 +00:00
|
|
|
- Copyright 2012-2023 Joey Hess <id@joeyh.name>
|
2012-04-21 20:59:49 +00:00
|
|
|
-
|
2019-03-13 19:48:14 +00:00
|
|
|
- Licensed under the GNU AGPL version 3 or higher.
|
2012-04-21 20:59:49 +00:00
|
|
|
-}
|
|
|
|
|
2022-02-24 18:01:29 +00:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
|
|
|
2012-04-21 20:59:49 +00:00
|
|
|
module Annex.Perms (
|
2018-03-15 17:20:38 +00:00
|
|
|
FileMode,
|
2013-11-18 22:05:37 +00:00
|
|
|
setAnnexFilePerm,
|
|
|
|
setAnnexDirPerm,
|
2020-09-02 18:25:12 +00:00
|
|
|
resetAnnexFilePerm,
|
2012-04-21 20:59:49 +00:00
|
|
|
annexFileMode,
|
|
|
|
createAnnexDirectory,
|
2020-03-06 15:40:20 +00:00
|
|
|
createWorkTreeDirectory,
|
2016-03-09 17:43:22 +00:00
|
|
|
freezeContent,
|
2021-07-12 14:15:49 +00:00
|
|
|
freezeContent',
|
2022-01-13 17:25:10 +00:00
|
|
|
freezeContent'',
|
2021-08-27 18:33:01 +00:00
|
|
|
checkContentWritePerm,
|
2021-09-01 14:27:28 +00:00
|
|
|
checkContentWritePerm',
|
2016-03-09 17:43:22 +00:00
|
|
|
thawContent,
|
2021-07-12 14:15:49 +00:00
|
|
|
thawContent',
|
2013-01-26 09:09:15 +00:00
|
|
|
createContentDir,
|
|
|
|
freezeContentDir,
|
2013-04-30 23:09:36 +00:00
|
|
|
thawContentDir,
|
2022-05-16 16:34:56 +00:00
|
|
|
modifyContentDir,
|
|
|
|
modifyContentDirWhenExists,
|
2015-05-19 19:04:24 +00:00
|
|
|
withShared,
|
2022-02-24 17:28:31 +00:00
|
|
|
hasFreezeHook,
|
2022-02-24 18:10:53 +00:00
|
|
|
hasThawHook,
|
2012-04-21 20:59:49 +00:00
|
|
|
) where
|
|
|
|
|
2016-01-20 20:36:33 +00:00
|
|
|
import Annex.Common
|
2012-04-21 20:59:49 +00:00
|
|
|
import Utility.FileMode
|
2020-03-06 15:40:20 +00:00
|
|
|
import Git
|
2017-02-17 18:04:43 +00:00
|
|
|
import Git.ConfigTypes
|
2012-04-21 23:42:49 +00:00
|
|
|
import qualified Annex
|
2022-01-11 20:36:07 +00:00
|
|
|
import Annex.Version
|
|
|
|
import Types.RepoVersion
|
2013-02-14 18:10:36 +00:00
|
|
|
import Config
|
2020-10-28 21:25:59 +00:00
|
|
|
import Utility.Directory.Create
|
|
|
|
import qualified Utility.RawFilePath as R
|
2012-04-21 20:59:49 +00:00
|
|
|
|
2023-04-26 21:03:16 +00:00
|
|
|
import System.PosixCompat.Files (fileMode, intersectFileModes, nullFileMode, groupWriteMode, ownerWriteMode, ownerReadMode, groupReadMode, otherReadMode, stdFileMode, ownerExecuteMode, groupExecuteMode, otherExecuteMode, setGroupIDMode)
|
2023-03-01 19:55:58 +00:00
|
|
|
|
2012-04-21 23:42:49 +00:00
|
|
|
withShared :: (SharedRepository -> Annex a) -> Annex a
|
2015-05-19 19:04:24 +00:00
|
|
|
withShared a = a =<< coreSharedRepository <$> Annex.getGitConfig
|
2012-04-21 23:42:49 +00:00
|
|
|
|
2020-11-05 22:45:37 +00:00
|
|
|
setAnnexFilePerm :: RawFilePath -> Annex ()
|
2013-11-18 22:05:37 +00:00
|
|
|
setAnnexFilePerm = setAnnexPerm False
|
|
|
|
|
2020-11-05 22:45:37 +00:00
|
|
|
setAnnexDirPerm :: RawFilePath -> Annex ()
|
2013-11-18 22:05:37 +00:00
|
|
|
setAnnexDirPerm = setAnnexPerm True
|
|
|
|
|
2012-04-21 20:59:49 +00:00
|
|
|
{- Sets appropriate file mode for a file or directory in the annex,
|
|
|
|
- other than the content files and content directory. Normally,
|
2020-09-02 18:25:12 +00:00
|
|
|
- don't change the mode, but with core.sharedRepository set,
|
2012-04-21 20:59:49 +00:00
|
|
|
- allow the group to write, etc. -}
|
2020-11-05 22:45:37 +00:00
|
|
|
setAnnexPerm :: Bool -> RawFilePath -> Annex ()
|
2023-04-27 19:57:50 +00:00
|
|
|
setAnnexPerm isdir file = setAnnexPerm' Nothing isdir >>= \go -> liftIO (go file)
|
2020-09-02 18:25:12 +00:00
|
|
|
|
2023-04-27 19:57:50 +00:00
|
|
|
setAnnexPerm' :: Maybe ([FileMode] -> FileMode -> FileMode) -> Bool -> Annex (RawFilePath -> IO ())
|
|
|
|
setAnnexPerm' modef isdir = ifM crippledFileSystem
|
|
|
|
( return (const noop)
|
|
|
|
, withShared $ \s -> return $ \file -> go s file
|
|
|
|
)
|
2012-12-13 04:24:19 +00:00
|
|
|
where
|
2023-04-27 19:57:50 +00:00
|
|
|
go GroupShared file = void $ tryIO $ modifyFileMode file $ modef' $
|
2013-11-18 22:05:37 +00:00
|
|
|
groupSharedModes ++
|
|
|
|
if isdir then [ ownerExecuteMode, groupExecuteMode ] else []
|
2023-04-27 19:57:50 +00:00
|
|
|
go AllShared file = void $ tryIO $ modifyFileMode file $ modef' $
|
2013-11-18 22:05:37 +00:00
|
|
|
readModes ++
|
|
|
|
[ ownerWriteMode, groupWriteMode ] ++
|
|
|
|
if isdir then executeModes else []
|
2023-04-27 19:57:50 +00:00
|
|
|
go UnShared file = case modef of
|
2020-09-02 18:25:12 +00:00
|
|
|
Nothing -> noop
|
2023-04-27 19:57:50 +00:00
|
|
|
Just f -> void $ tryIO $
|
2020-09-02 18:25:12 +00:00
|
|
|
modifyFileMode file $ f []
|
2023-04-27 19:57:50 +00:00
|
|
|
go (UmaskShared n) file = void $ tryIO $ R.setFileMode file $
|
2023-04-26 21:03:16 +00:00
|
|
|
if isdir then umaskSharedDirectory n else n
|
2020-09-02 18:25:12 +00:00
|
|
|
modef' = fromMaybe addModes modef
|
|
|
|
|
2020-11-05 22:45:37 +00:00
|
|
|
resetAnnexFilePerm :: RawFilePath -> Annex ()
|
2020-09-02 18:25:12 +00:00
|
|
|
resetAnnexFilePerm = resetAnnexPerm False
|
|
|
|
|
|
|
|
{- Like setAnnexPerm, but ignores the current mode of the file entirely,
|
|
|
|
- and sets the same mode that the umask would result in when creating a
|
|
|
|
- new file.
|
|
|
|
-
|
|
|
|
- Useful eg, after creating a temporary file with locked down modes,
|
|
|
|
- which is going to be moved to a non-temporary location and needs
|
|
|
|
- usual modes.
|
|
|
|
-}
|
2020-11-05 22:45:37 +00:00
|
|
|
resetAnnexPerm :: Bool -> RawFilePath -> Annex ()
|
2020-09-02 18:25:12 +00:00
|
|
|
resetAnnexPerm isdir file = unlessM crippledFileSystem $ do
|
|
|
|
defmode <- liftIO defaultFileMode
|
|
|
|
let modef moremodes _oldmode = addModes moremodes defmode
|
2023-04-27 19:57:50 +00:00
|
|
|
setAnnexPerm' (Just modef) isdir >>= \go -> liftIO (go file)
|
2012-04-21 20:59:49 +00:00
|
|
|
|
2023-04-27 19:57:50 +00:00
|
|
|
{- Creates a ModeSetter which can be used for creating a file in the annex
|
|
|
|
- (other than content files, which are locked down more). -}
|
|
|
|
annexFileMode :: Annex ModeSetter
|
|
|
|
annexFileMode = do
|
|
|
|
modesetter <- setAnnexPerm' Nothing False
|
|
|
|
withShared (\s -> pure $ mk s modesetter)
|
2012-12-13 04:24:19 +00:00
|
|
|
where
|
2023-04-27 19:57:50 +00:00
|
|
|
mk GroupShared = ModeSetter stdFileMode
|
|
|
|
mk AllShared = ModeSetter stdFileMode
|
|
|
|
mk UnShared = ModeSetter stdFileMode
|
|
|
|
mk (UmaskShared mode) = ModeSetter mode
|
2012-04-21 20:59:49 +00:00
|
|
|
|
2022-08-12 16:56:56 +00:00
|
|
|
{- Creates a directory inside the gitAnnexDir (or possibly the dbdir),
|
|
|
|
- creating any parent directories up to and including the gitAnnexDir.
|
2020-03-05 18:27:45 +00:00
|
|
|
- Makes directories with appropriate permissions. -}
|
2020-10-28 21:25:59 +00:00
|
|
|
createAnnexDirectory :: RawFilePath -> Annex ()
|
2020-03-05 18:27:45 +00:00
|
|
|
createAnnexDirectory dir = do
|
2020-10-28 21:25:59 +00:00
|
|
|
top <- parentDir <$> fromRepo gitAnnexDir
|
2022-08-12 16:56:56 +00:00
|
|
|
tops <- annexDbDir <$> Annex.getGitConfig >>= return . \case
|
|
|
|
Nothing -> [top]
|
2022-08-12 17:18:15 +00:00
|
|
|
Just dbdir -> [top, parentDir (parentDir dbdir)]
|
2022-08-12 16:56:56 +00:00
|
|
|
createDirectoryUnder' tops dir createdir
|
2012-12-13 04:24:19 +00:00
|
|
|
where
|
2020-03-05 18:27:45 +00:00
|
|
|
createdir p = do
|
2020-10-28 21:25:59 +00:00
|
|
|
liftIO $ R.createDirectory p
|
2020-11-05 22:45:37 +00:00
|
|
|
setAnnexDirPerm p
|
2013-01-26 09:09:15 +00:00
|
|
|
|
2020-03-06 15:40:20 +00:00
|
|
|
{- Create a directory in the git work tree, creating any parent
|
|
|
|
- directories up to the top of the work tree.
|
|
|
|
-
|
|
|
|
- Uses default permissions.
|
|
|
|
-}
|
2020-10-28 21:25:59 +00:00
|
|
|
createWorkTreeDirectory :: RawFilePath -> Annex ()
|
2020-03-06 15:40:20 +00:00
|
|
|
createWorkTreeDirectory dir = do
|
|
|
|
fromRepo repoWorkTree >>= liftIO . \case
|
2022-08-12 16:45:46 +00:00
|
|
|
Just wt -> createDirectoryUnder [wt] dir
|
2020-03-06 15:40:20 +00:00
|
|
|
-- Should never happen, but let whatever tries to write
|
|
|
|
-- to the directory be what throws an exception, as that
|
|
|
|
-- will be clearer than an exception from here.
|
|
|
|
Nothing -> noop
|
|
|
|
|
2016-03-09 17:43:22 +00:00
|
|
|
{- Normally, blocks writing to an annexed file, and modifies file
|
|
|
|
- permissions to allow reading it.
|
|
|
|
-
|
2022-01-11 20:36:07 +00:00
|
|
|
- Before v9, when core.sharedRepository is set, the write bits are not
|
|
|
|
- removed from the file, but instead the appropriate group write bits
|
|
|
|
- are set. This is necessary to let other users in the group lock the file.
|
|
|
|
- v9 improved this by using separate lock files, so the content file does
|
|
|
|
- not need to be writable when using it.
|
|
|
|
-
|
|
|
|
- In a shared repository, the current user may not be able to change
|
|
|
|
- a file owned by another user, so failure to change modes is ignored.
|
2021-08-27 18:33:01 +00:00
|
|
|
-
|
|
|
|
- Note that, on Linux, xattrs can sometimes prevent removing
|
|
|
|
- certain permissions from a file with chmod. (Maybe some ACLs too?)
|
|
|
|
- In such a case, this will return with the file still having some mode
|
|
|
|
- it should not normally have. checkContentWritePerm can detect when
|
|
|
|
- that happens with write permissions.
|
2016-03-09 17:43:22 +00:00
|
|
|
-}
|
2020-11-05 22:45:37 +00:00
|
|
|
freezeContent :: RawFilePath -> Annex ()
|
2022-09-25 19:21:24 +00:00
|
|
|
freezeContent file =
|
2021-07-12 14:15:49 +00:00
|
|
|
withShared $ \sr -> freezeContent' sr file
|
|
|
|
|
|
|
|
freezeContent' :: SharedRepository -> RawFilePath -> Annex ()
|
2022-01-13 17:25:10 +00:00
|
|
|
freezeContent' sr file = freezeContent'' sr file =<< getVersion
|
|
|
|
|
|
|
|
freezeContent'' :: SharedRepository -> RawFilePath -> Maybe RepoVersion -> Annex ()
|
|
|
|
freezeContent'' sr file rv = do
|
2022-02-24 18:01:29 +00:00
|
|
|
fastDebug "Annex.Perms" ("freezing content " ++ fromRawFilePath file)
|
2022-09-25 19:21:24 +00:00
|
|
|
unlessM crippledFileSystem $ go sr
|
Added annex.freezecontent-command and annex.thawcontent-command configs
Freeze first sets the file perms, and then runs
freezecontent-command. Thaw runs thawcontent-command before
restoring file permissions. This is in case the freeze command
prevents changing file perms, as eg setting a file immutable does.
Also, changing file perms tends to mess up previously set ACLs.
git-annex init's probe for crippled filesystem uses them, so if file perms
don't work, but freezecontent-command manages to prevent write to a file,
it won't treat the filesystem as crippled.
When the the filesystem has been probed as crippled, the hooks are not
used, because there seems to be no point then; git-annex won't be relying
on locking annex objects down. Also, this avoids them being run when the
file perms have not been changed, in case they somehow rely on
git-annex's setting of the file perms in order to work.
Sponsored-by: Dartmouth College's Datalad project
2021-06-21 18:40:20 +00:00
|
|
|
freezeHook file
|
2016-03-09 17:43:22 +00:00
|
|
|
where
|
2023-04-26 21:03:16 +00:00
|
|
|
go UnShared = liftIO $ nowriteadd [ownerReadMode]
|
2022-01-13 17:25:10 +00:00
|
|
|
go GroupShared = if versionNeedsWritableContentFiles rv
|
|
|
|
then liftIO $ ignoresharederr $ modmode $ addModes
|
2022-01-11 20:36:07 +00:00
|
|
|
[ownerReadMode, groupReadMode, ownerWriteMode, groupWriteMode]
|
2022-01-13 17:25:10 +00:00
|
|
|
else liftIO $ ignoresharederr $
|
2022-01-11 20:36:07 +00:00
|
|
|
nowriteadd [ownerReadMode, groupReadMode]
|
2022-01-13 17:25:10 +00:00
|
|
|
go AllShared = if versionNeedsWritableContentFiles rv
|
|
|
|
then liftIO $ ignoresharederr $ modmode $ addModes
|
2022-01-11 20:36:07 +00:00
|
|
|
(readModes ++ writeModes)
|
2022-01-13 17:25:10 +00:00
|
|
|
else liftIO $ ignoresharederr $
|
2022-01-11 20:36:07 +00:00
|
|
|
nowriteadd readModes
|
2023-04-26 21:03:16 +00:00
|
|
|
go (UmaskShared n) = if versionNeedsWritableContentFiles rv
|
|
|
|
-- Assume that the configured mode includes write bits
|
|
|
|
-- for all users who should be able to lock the file, so
|
|
|
|
-- don't need to add any write modes.
|
|
|
|
then liftIO $ ignoresharederr $ modmode $ const n
|
|
|
|
else liftIO $ ignoresharederr $ modmode $ const $
|
|
|
|
removeModes writeModes n
|
2022-01-11 20:36:07 +00:00
|
|
|
|
|
|
|
ignoresharederr = void . tryIO
|
|
|
|
|
|
|
|
modmode = modifyFileMode file
|
|
|
|
|
|
|
|
nowriteadd readmodes = modmode $
|
2016-03-09 17:43:22 +00:00
|
|
|
removeModes writeModes .
|
2022-01-11 20:36:07 +00:00
|
|
|
addModes readmodes
|
2016-03-09 17:43:22 +00:00
|
|
|
|
2021-08-27 18:33:01 +00:00
|
|
|
{- Checks if the write permissions are as freezeContent should set them.
|
|
|
|
-
|
|
|
|
- When the repository is shared, the user may not be able to change
|
|
|
|
- permissions of a file owned by another user. So if the permissions seem
|
|
|
|
- wrong, but the repository is shared, returns Nothing. If the permissions
|
|
|
|
- are wrong otherwise, returns Just False.
|
2022-02-24 17:28:31 +00:00
|
|
|
-
|
|
|
|
- When there is a freeze hook, it may prevent write in some way other than
|
|
|
|
- permissions. One use of a freeze hook is when the filesystem does not
|
|
|
|
- support removing write permissions, so when there is such a hook
|
|
|
|
- write permissions are ignored.
|
2021-08-27 18:33:01 +00:00
|
|
|
-}
|
|
|
|
checkContentWritePerm :: RawFilePath -> Annex (Maybe Bool)
|
|
|
|
checkContentWritePerm file = ifM crippledFileSystem
|
|
|
|
( return (Just True)
|
2022-01-11 20:36:07 +00:00
|
|
|
, do
|
|
|
|
rv <- getVersion
|
2022-02-24 17:28:31 +00:00
|
|
|
hasfreezehook <- hasFreezeHook
|
2023-04-26 17:25:29 +00:00
|
|
|
withShared $ \sr ->
|
|
|
|
liftIO $ checkContentWritePerm' sr file rv hasfreezehook
|
2016-04-14 19:36:53 +00:00
|
|
|
)
|
2021-08-27 18:33:01 +00:00
|
|
|
|
2022-02-24 17:28:31 +00:00
|
|
|
checkContentWritePerm' :: SharedRepository -> RawFilePath -> Maybe RepoVersion -> Bool -> IO (Maybe Bool)
|
|
|
|
checkContentWritePerm' sr file rv hasfreezehook
|
|
|
|
| hasfreezehook = return (Just True)
|
|
|
|
| otherwise = case sr of
|
2023-04-26 21:03:16 +00:00
|
|
|
UnShared -> want Just (excludemodes writeModes)
|
2022-02-24 17:28:31 +00:00
|
|
|
GroupShared
|
|
|
|
| versionNeedsWritableContentFiles rv -> want sharedret
|
|
|
|
(includemodes [ownerWriteMode, groupWriteMode])
|
|
|
|
| otherwise -> want sharedret (excludemodes writeModes)
|
|
|
|
AllShared
|
|
|
|
| versionNeedsWritableContentFiles rv ->
|
|
|
|
want sharedret (includemodes writeModes)
|
|
|
|
| otherwise -> want sharedret (excludemodes writeModes)
|
2023-04-26 21:03:16 +00:00
|
|
|
UmaskShared n
|
|
|
|
| versionNeedsWritableContentFiles rv -> want sharedret
|
|
|
|
(\havemode -> havemode == n)
|
|
|
|
| otherwise -> want sharedret
|
|
|
|
(\havemode -> havemode == removeModes writeModes n)
|
2021-09-01 14:27:28 +00:00
|
|
|
where
|
|
|
|
want mk f = catchMaybeIO (fileMode <$> R.getFileStatus file)
|
|
|
|
>>= return . \case
|
2021-08-27 18:33:01 +00:00
|
|
|
Just havemode -> mk (f havemode)
|
|
|
|
Nothing -> mk True
|
|
|
|
|
|
|
|
includemodes l havemode = havemode == combineModes (havemode:l)
|
|
|
|
excludemodes l havemode = all (\m -> intersectFileModes m havemode == nullFileMode) l
|
|
|
|
|
|
|
|
sharedret True = Just True
|
|
|
|
sharedret False = Nothing
|
2016-04-14 19:36:53 +00:00
|
|
|
|
2016-03-09 17:43:22 +00:00
|
|
|
{- Allows writing to an annexed file that freezeContent was called on
|
|
|
|
- before. -}
|
2020-11-05 22:45:37 +00:00
|
|
|
thawContent :: RawFilePath -> Annex ()
|
2021-07-12 14:15:49 +00:00
|
|
|
thawContent file = withShared $ \sr -> thawContent' sr file
|
|
|
|
|
|
|
|
thawContent' :: SharedRepository -> RawFilePath -> Annex ()
|
2022-02-24 18:01:29 +00:00
|
|
|
thawContent' sr file = do
|
|
|
|
fastDebug "Annex.Perms" ("thawing content " ++ fromRawFilePath file)
|
|
|
|
thawPerms (go sr) (thawHook file)
|
2016-03-09 17:43:22 +00:00
|
|
|
where
|
2016-04-14 19:36:53 +00:00
|
|
|
go GroupShared = liftIO $ void $ tryIO $ groupWriteRead file
|
|
|
|
go AllShared = liftIO $ void $ tryIO $ groupWriteRead file
|
2023-04-26 17:25:29 +00:00
|
|
|
go UnShared = liftIO $ allowWrite file
|
2023-04-26 21:03:16 +00:00
|
|
|
go (UmaskShared n) = liftIO $ void $ tryIO $ R.setFileMode file n
|
2016-03-09 17:43:22 +00:00
|
|
|
|
|
|
|
{- Runs an action that thaws a file's permissions. This will probably
|
|
|
|
- fail on a crippled filesystem. But, if file modes are supported on a
|
Added annex.freezecontent-command and annex.thawcontent-command configs
Freeze first sets the file perms, and then runs
freezecontent-command. Thaw runs thawcontent-command before
restoring file permissions. This is in case the freeze command
prevents changing file perms, as eg setting a file immutable does.
Also, changing file perms tends to mess up previously set ACLs.
git-annex init's probe for crippled filesystem uses them, so if file perms
don't work, but freezecontent-command manages to prevent write to a file,
it won't treat the filesystem as crippled.
When the the filesystem has been probed as crippled, the hooks are not
used, because there seems to be no point then; git-annex won't be relying
on locking annex objects down. Also, this avoids them being run when the
file perms have not been changed, in case they somehow rely on
git-annex's setting of the file perms in order to work.
Sponsored-by: Dartmouth College's Datalad project
2021-06-21 18:40:20 +00:00
|
|
|
- crippled filesystem, the file may be frozen, so try to thaw its
|
|
|
|
- permissions. -}
|
|
|
|
thawPerms :: Annex () -> Annex () -> Annex ()
|
|
|
|
thawPerms a hook = ifM crippledFileSystem
|
2022-09-25 19:21:24 +00:00
|
|
|
( hook >> void (tryNonAsync a)
|
Added annex.freezecontent-command and annex.thawcontent-command configs
Freeze first sets the file perms, and then runs
freezecontent-command. Thaw runs thawcontent-command before
restoring file permissions. This is in case the freeze command
prevents changing file perms, as eg setting a file immutable does.
Also, changing file perms tends to mess up previously set ACLs.
git-annex init's probe for crippled filesystem uses them, so if file perms
don't work, but freezecontent-command manages to prevent write to a file,
it won't treat the filesystem as crippled.
When the the filesystem has been probed as crippled, the hooks are not
used, because there seems to be no point then; git-annex won't be relying
on locking annex objects down. Also, this avoids them being run when the
file perms have not been changed, in case they somehow rely on
git-annex's setting of the file perms in order to work.
Sponsored-by: Dartmouth College's Datalad project
2021-06-21 18:40:20 +00:00
|
|
|
, hook >> a
|
2016-03-09 17:43:22 +00:00
|
|
|
)
|
|
|
|
|
2013-01-26 09:09:15 +00:00
|
|
|
{- Blocks writing to the directory an annexed file is in, to prevent the
|
2017-02-11 09:38:49 +00:00
|
|
|
- file accidentally being deleted. However, if core.sharedRepository
|
2013-01-26 09:09:15 +00:00
|
|
|
- is set, this is not done, since the group must be allowed to delete the
|
2023-04-26 21:03:16 +00:00
|
|
|
- file without eing able to thaw the directory.
|
2013-01-26 09:09:15 +00:00
|
|
|
-}
|
2020-10-28 21:25:59 +00:00
|
|
|
freezeContentDir :: RawFilePath -> Annex ()
|
2022-09-25 19:21:24 +00:00
|
|
|
freezeContentDir file = do
|
2022-02-24 18:01:29 +00:00
|
|
|
fastDebug "Annex.Perms" ("freezing content directory " ++ fromRawFilePath dir)
|
2022-09-25 19:21:24 +00:00
|
|
|
unlessM crippledFileSystem $ withShared go
|
Added annex.freezecontent-command and annex.thawcontent-command configs
Freeze first sets the file perms, and then runs
freezecontent-command. Thaw runs thawcontent-command before
restoring file permissions. This is in case the freeze command
prevents changing file perms, as eg setting a file immutable does.
Also, changing file perms tends to mess up previously set ACLs.
git-annex init's probe for crippled filesystem uses them, so if file perms
don't work, but freezecontent-command manages to prevent write to a file,
it won't treat the filesystem as crippled.
When the the filesystem has been probed as crippled, the hooks are not
used, because there seems to be no point then; git-annex won't be relying
on locking annex objects down. Also, this avoids them being run when the
file perms have not been changed, in case they somehow rely on
git-annex's setting of the file perms in order to work.
Sponsored-by: Dartmouth College's Datalad project
2021-06-21 18:40:20 +00:00
|
|
|
freezeHook dir
|
2013-01-26 09:09:15 +00:00
|
|
|
where
|
2020-11-05 22:45:37 +00:00
|
|
|
dir = parentDir file
|
2023-04-26 21:03:16 +00:00
|
|
|
go UnShared = liftIO $ preventWrite dir
|
2016-04-14 19:36:53 +00:00
|
|
|
go GroupShared = liftIO $ void $ tryIO $ groupWriteRead dir
|
|
|
|
go AllShared = liftIO $ void $ tryIO $ groupWriteRead dir
|
2023-04-26 21:03:16 +00:00
|
|
|
go (UmaskShared n) = liftIO $ void $ tryIO $ R.setFileMode dir $
|
|
|
|
umaskSharedDirectory $
|
|
|
|
-- If n includes group or other write mode, leave them set
|
|
|
|
-- to allow them to delete the file without being able to
|
|
|
|
-- thaw the directory.
|
|
|
|
removeModes [ownerWriteMode] n
|
2013-01-26 09:09:15 +00:00
|
|
|
|
2020-10-28 21:25:59 +00:00
|
|
|
thawContentDir :: RawFilePath -> Annex ()
|
2022-02-24 18:01:29 +00:00
|
|
|
thawContentDir file = do
|
|
|
|
fastDebug "Annex.Perms" ("thawing content directory " ++ fromRawFilePath dir)
|
2023-04-26 21:03:16 +00:00
|
|
|
thawPerms (withShared (liftIO . go)) (thawHook dir)
|
Added annex.freezecontent-command and annex.thawcontent-command configs
Freeze first sets the file perms, and then runs
freezecontent-command. Thaw runs thawcontent-command before
restoring file permissions. This is in case the freeze command
prevents changing file perms, as eg setting a file immutable does.
Also, changing file perms tends to mess up previously set ACLs.
git-annex init's probe for crippled filesystem uses them, so if file perms
don't work, but freezecontent-command manages to prevent write to a file,
it won't treat the filesystem as crippled.
When the the filesystem has been probed as crippled, the hooks are not
used, because there seems to be no point then; git-annex won't be relying
on locking annex objects down. Also, this avoids them being run when the
file perms have not been changed, in case they somehow rely on
git-annex's setting of the file perms in order to work.
Sponsored-by: Dartmouth College's Datalad project
2021-06-21 18:40:20 +00:00
|
|
|
where
|
|
|
|
dir = parentDir file
|
2023-04-26 21:03:16 +00:00
|
|
|
go UnShared = allowWrite dir
|
|
|
|
go GroupShared = allowWrite dir
|
|
|
|
go AllShared = allowWrite dir
|
|
|
|
go (UmaskShared n) = R.setFileMode dir n
|
2013-04-30 23:09:36 +00:00
|
|
|
|
2013-01-26 09:09:15 +00:00
|
|
|
{- Makes the directory tree to store an annexed file's content,
|
|
|
|
- with appropriate permissions on each level. -}
|
2020-10-28 21:25:59 +00:00
|
|
|
createContentDir :: RawFilePath -> Annex ()
|
2013-01-26 09:09:15 +00:00
|
|
|
createContentDir dest = do
|
2020-10-28 21:25:59 +00:00
|
|
|
unlessM (liftIO $ R.doesPathExist dir) $
|
2013-01-26 09:09:15 +00:00
|
|
|
createAnnexDirectory dir
|
|
|
|
-- might have already existed with restricted perms
|
2022-09-26 17:10:25 +00:00
|
|
|
thawHook dir
|
|
|
|
unlessM crippledFileSystem $ liftIO $ allowWrite dir
|
2013-01-26 09:09:15 +00:00
|
|
|
where
|
2015-01-09 17:11:56 +00:00
|
|
|
dir = parentDir dest
|
2013-11-15 18:52:03 +00:00
|
|
|
|
|
|
|
{- Creates the content directory for a file if it doesn't already exist,
|
2022-05-16 16:34:56 +00:00
|
|
|
- or thaws it if it does, then runs an action to modify a file in the
|
|
|
|
- directory, and finally, freezes the content directory. -}
|
|
|
|
modifyContentDir :: RawFilePath -> Annex a -> Annex a
|
|
|
|
modifyContentDir f a = do
|
2013-11-15 18:52:03 +00:00
|
|
|
createContentDir f -- also thaws it
|
unify exception handling into Utility.Exception
Removed old extensible-exceptions, only needed for very old ghc.
Made webdav use Utility.Exception, to work after some changes in DAV's
exception handling.
Removed Annex.Exception. Mostly this was trivial, but note that
tryAnnex is replaced with tryNonAsync and catchAnnex replaced with
catchNonAsync. In theory that could be a behavior change, since the former
caught all exceptions, and the latter don't catch async exceptions.
However, in practice, nothing in the Annex monad uses async exceptions.
Grepping for throwTo and killThread only find stuff in the assistant,
which does not seem related.
Command.Add.undo is changed to accept a SomeException, and things
that use it for rollback now catch non-async exceptions, rather than
only IOExceptions.
2014-08-08 01:55:44 +00:00
|
|
|
v <- tryNonAsync a
|
2013-11-15 18:52:03 +00:00
|
|
|
freezeContentDir f
|
unify exception handling into Utility.Exception
Removed old extensible-exceptions, only needed for very old ghc.
Made webdav use Utility.Exception, to work after some changes in DAV's
exception handling.
Removed Annex.Exception. Mostly this was trivial, but note that
tryAnnex is replaced with tryNonAsync and catchAnnex replaced with
catchNonAsync. In theory that could be a behavior change, since the former
caught all exceptions, and the latter don't catch async exceptions.
However, in practice, nothing in the Annex monad uses async exceptions.
Grepping for throwTo and killThread only find stuff in the assistant,
which does not seem related.
Command.Add.undo is changed to accept a SomeException, and things
that use it for rollback now catch non-async exceptions, rather than
only IOExceptions.
2014-08-08 01:55:44 +00:00
|
|
|
either throwM return v
|
Added annex.freezecontent-command and annex.thawcontent-command configs
Freeze first sets the file perms, and then runs
freezecontent-command. Thaw runs thawcontent-command before
restoring file permissions. This is in case the freeze command
prevents changing file perms, as eg setting a file immutable does.
Also, changing file perms tends to mess up previously set ACLs.
git-annex init's probe for crippled filesystem uses them, so if file perms
don't work, but freezecontent-command manages to prevent write to a file,
it won't treat the filesystem as crippled.
When the the filesystem has been probed as crippled, the hooks are not
used, because there seems to be no point then; git-annex won't be relying
on locking annex objects down. Also, this avoids them being run when the
file perms have not been changed, in case they somehow rely on
git-annex's setting of the file perms in order to work.
Sponsored-by: Dartmouth College's Datalad project
2021-06-21 18:40:20 +00:00
|
|
|
|
2022-05-16 16:34:56 +00:00
|
|
|
{- Like modifyContentDir, but avoids creating the content directory if it
|
2022-05-23 16:53:55 +00:00
|
|
|
- does not already exist. In that case, the action will probably fail. -}
|
2022-05-16 16:34:56 +00:00
|
|
|
modifyContentDirWhenExists :: RawFilePath -> Annex a -> Annex a
|
|
|
|
modifyContentDirWhenExists f a = do
|
|
|
|
thawContentDir f
|
|
|
|
v <- tryNonAsync a
|
|
|
|
freezeContentDir f
|
|
|
|
either throwM return v
|
|
|
|
|
2022-02-24 17:28:31 +00:00
|
|
|
hasFreezeHook :: Annex Bool
|
|
|
|
hasFreezeHook = isJust . annexFreezeContentCommand <$> Annex.getGitConfig
|
|
|
|
|
2022-02-24 18:10:53 +00:00
|
|
|
hasThawHook :: Annex Bool
|
|
|
|
hasThawHook = isJust . annexThawContentCommand <$> Annex.getGitConfig
|
|
|
|
|
Added annex.freezecontent-command and annex.thawcontent-command configs
Freeze first sets the file perms, and then runs
freezecontent-command. Thaw runs thawcontent-command before
restoring file permissions. This is in case the freeze command
prevents changing file perms, as eg setting a file immutable does.
Also, changing file perms tends to mess up previously set ACLs.
git-annex init's probe for crippled filesystem uses them, so if file perms
don't work, but freezecontent-command manages to prevent write to a file,
it won't treat the filesystem as crippled.
When the the filesystem has been probed as crippled, the hooks are not
used, because there seems to be no point then; git-annex won't be relying
on locking annex objects down. Also, this avoids them being run when the
file perms have not been changed, in case they somehow rely on
git-annex's setting of the file perms in order to work.
Sponsored-by: Dartmouth College's Datalad project
2021-06-21 18:40:20 +00:00
|
|
|
freezeHook :: RawFilePath -> Annex ()
|
|
|
|
freezeHook p = maybe noop go =<< annexFreezeContentCommand <$> Annex.getGitConfig
|
|
|
|
where
|
|
|
|
go basecmd = void $ liftIO $
|
|
|
|
boolSystem "sh" [Param "-c", Param $ gencmd basecmd]
|
|
|
|
gencmd = massReplace [ ("%path", shellEscape (fromRawFilePath p)) ]
|
|
|
|
|
|
|
|
thawHook :: RawFilePath -> Annex ()
|
|
|
|
thawHook p = maybe noop go =<< annexThawContentCommand <$> Annex.getGitConfig
|
|
|
|
where
|
|
|
|
go basecmd = void $ liftIO $
|
|
|
|
boolSystem "sh" [Param "-c", Param $ gencmd basecmd]
|
|
|
|
gencmd = massReplace [ ("%path", shellEscape (fromRawFilePath p)) ]
|
2023-04-26 21:03:16 +00:00
|
|
|
|
|
|
|
{- Calculate mode to use for a directory from the mode to use for a file.
|
|
|
|
-
|
|
|
|
- This corresponds to git's handling of core.sharedRepository=0xxx
|
|
|
|
-}
|
|
|
|
umaskSharedDirectory :: FileMode -> FileMode
|
|
|
|
umaskSharedDirectory n = flip addModes n $ map snd $ filter fst
|
|
|
|
[ (isset ownerReadMode, ownerExecuteMode)
|
|
|
|
, (isset groupReadMode, groupExecuteMode)
|
|
|
|
, (isset otherReadMode, otherExecuteMode)
|
|
|
|
, (isset groupReadMode || isset groupWriteMode, setGroupIDMode)
|
|
|
|
]
|
|
|
|
where
|
|
|
|
isset v = checkMode v n
|