crippled filesystem support, probing and initial support
git annex init probes for crippled filesystems, and sets direct mode, as well as `annex.crippledfilesystem`. Avoid manipulating permissions of files on crippled filesystems. That would likely cause an exception to be thrown. Very basic support in Command.Add for cripped filesystems; avoids the lock down entirely since doing it needs both permissions and hard links. Will make this better soon.
This commit is contained in:
parent
35b7b1a406
commit
47477b2807
15 changed files with 122 additions and 52 deletions
|
@ -335,12 +335,12 @@ withObjectLoc key indirect direct = ifM isDirect
|
|||
cleanObjectLoc :: Key -> Annex ()
|
||||
cleanObjectLoc key = do
|
||||
file <- inRepo $ gitAnnexLocation key
|
||||
liftIO $ do
|
||||
let dir = parentDir file
|
||||
void $ catchMaybeIO $ do
|
||||
allowWrite dir
|
||||
unlessM crippledFileSystem $
|
||||
void $ liftIO $ catchMaybeIO $ allowWrite dir
|
||||
void $ liftIO $ catchMaybeIO $ do
|
||||
removeDirectoryRecursive dir
|
||||
removeparents dir (2 :: Int)
|
||||
liftIO $ removeparents dir (2 :: Int)
|
||||
where
|
||||
removeparents _ 0 = noop
|
||||
removeparents file n = do
|
||||
|
@ -356,9 +356,9 @@ removeAnnex :: Key -> Annex ()
|
|||
removeAnnex key = withObjectLoc key remove removedirect
|
||||
where
|
||||
remove file = do
|
||||
liftIO $ do
|
||||
allowWrite $ parentDir file
|
||||
removeFile file
|
||||
unlessM crippledFileSystem $
|
||||
liftIO $ allowWrite $ parentDir file
|
||||
liftIO $ removeFile file
|
||||
cleanObjectLoc key
|
||||
removedirect fs = do
|
||||
cache <- recordedCache key
|
||||
|
@ -377,6 +377,7 @@ removeAnnex key = withObjectLoc key remove removedirect
|
|||
fromAnnex :: Key -> FilePath -> Annex ()
|
||||
fromAnnex key dest = do
|
||||
file <- inRepo $ gitAnnexLocation key
|
||||
unlessM crippledFileSystem $
|
||||
liftIO $ allowWrite $ parentDir file
|
||||
thawContent file
|
||||
liftIO $ moveFile file dest
|
||||
|
@ -390,9 +391,9 @@ moveBad key = do
|
|||
bad <- fromRepo gitAnnexBadDir
|
||||
let dest = bad </> takeFileName src
|
||||
createAnnexDirectory (parentDir dest)
|
||||
liftIO $ do
|
||||
allowWrite (parentDir src)
|
||||
moveFile src dest
|
||||
unlessM crippledFileSystem $
|
||||
liftIO $ allowWrite (parentDir src)
|
||||
liftIO $ moveFile src dest
|
||||
cleanObjectLoc key
|
||||
logStatus key InfoMissing
|
||||
return dest
|
||||
|
@ -454,7 +455,8 @@ preseedTmp key file = go =<< inAnnex key
|
|||
- to avoid accidental edits. core.sharedRepository may change
|
||||
- who can read it. -}
|
||||
freezeContent :: FilePath -> Annex ()
|
||||
freezeContent file = liftIO . go =<< fromRepo getSharedRepository
|
||||
freezeContent file = unlessM crippledFileSystem $
|
||||
liftIO . go =<< fromRepo getSharedRepository
|
||||
where
|
||||
go GroupShared = modifyFileMode file $
|
||||
removeModes writeModes .
|
||||
|
@ -467,7 +469,8 @@ freezeContent file = liftIO . go =<< fromRepo getSharedRepository
|
|||
{- Allows writing to an annexed file that freezeContent was called on
|
||||
- before. -}
|
||||
thawContent :: FilePath -> Annex ()
|
||||
thawContent file = liftIO . go =<< fromRepo getSharedRepository
|
||||
thawContent file = unlessM crippledFileSystem $
|
||||
liftIO . go =<< fromRepo getSharedRepository
|
||||
where
|
||||
go GroupShared = groupWriteRead file
|
||||
go AllShared = groupWriteRead file
|
||||
|
|
|
@ -143,7 +143,7 @@ mergeDirectCleanup d oldsha newsha = do
|
|||
- Empty work tree directories are removed, per git behavior. -}
|
||||
moveout_raw f = liftIO $ do
|
||||
nukeFile f
|
||||
void $ catchMaybeIO $ removeDirectory $ parentDir f
|
||||
void $ tryIO $ removeDirectory $ parentDir f
|
||||
|
||||
{- The symlink is created from the key, rather than moving in the
|
||||
- symlink created in the temp directory by the merge. This because
|
||||
|
@ -161,7 +161,7 @@ mergeDirectCleanup d oldsha newsha = do
|
|||
- directory by the merge, and are moved to the real work tree. -}
|
||||
movein_raw f = liftIO $ do
|
||||
createDirectoryIfMissing True $ parentDir f
|
||||
void $ catchMaybeIO $ rename (d </> f) f
|
||||
void $ tryIO $ rename (d </> f) f
|
||||
|
||||
{- If possible, converts a symlink in the working tree into a direct
|
||||
- mode file. -}
|
||||
|
@ -203,7 +203,7 @@ removeDirect k f = do
|
|||
_ -> noop
|
||||
liftIO $ do
|
||||
nukeFile f
|
||||
void $ catchMaybeIO $ removeDirectory $ parentDir f
|
||||
void $ tryIO $ removeDirectory $ parentDir f
|
||||
|
||||
{- Called when a direct mode file has been changed. Its old content may be
|
||||
- lost. -}
|
||||
|
|
|
@ -18,6 +18,7 @@ import Common.Annex
|
|||
import Utility.FileMode
|
||||
import Git.SharedRepository
|
||||
import qualified Annex
|
||||
import Config
|
||||
|
||||
import System.Posix.Types
|
||||
|
||||
|
@ -34,7 +35,8 @@ withShared a = maybe startup a =<< Annex.getState Annex.shared
|
|||
- use the default mode, but with core.sharedRepository set,
|
||||
- allow the group to write, etc. -}
|
||||
setAnnexPerm :: FilePath -> Annex ()
|
||||
setAnnexPerm file = withShared $ liftIO . go
|
||||
setAnnexPerm file = unlessM crippledFileSystem $
|
||||
withShared $ liftIO . go
|
||||
where
|
||||
go GroupShared = groupWriteRead file
|
||||
go AllShared = modifyFileMode file $ addModes $
|
||||
|
@ -77,7 +79,8 @@ createAnnexDirectory dir = traverse dir [] =<< top
|
|||
- file.
|
||||
-}
|
||||
freezeContentDir :: FilePath -> Annex ()
|
||||
freezeContentDir file = liftIO . go =<< fromRepo getSharedRepository
|
||||
freezeContentDir file = unlessM crippledFileSystem $
|
||||
liftIO . go =<< fromRepo getSharedRepository
|
||||
where
|
||||
dir = parentDir file
|
||||
go GroupShared = groupWriteRead dir
|
||||
|
@ -91,6 +94,7 @@ createContentDir dest = do
|
|||
unlessM (liftIO $ doesDirectoryExist dir) $
|
||||
createAnnexDirectory dir
|
||||
-- might have already existed with restricted perms
|
||||
unlessM crippledFileSystem $
|
||||
liftIO $ allowWrite dir
|
||||
where
|
||||
dir = parentDir dest
|
||||
|
|
|
@ -60,7 +60,7 @@ multicastPairMsg repeats secret pairdata stage = go M.empty repeats
|
|||
go cache' $ pred <$> n
|
||||
{- The multicast library currently chokes on ipv6 addresses. -}
|
||||
sendinterface _ (IPv6Addr _) = noop
|
||||
sendinterface cache i = void $ catchMaybeIO $
|
||||
sendinterface cache i = void $ tryIO $
|
||||
withSocketsDo $ bracket setup cleanup use
|
||||
where
|
||||
setup = multicastSender (multicastAddress i) pairingPort
|
||||
|
|
|
@ -233,6 +233,7 @@ handleAdds delayadd cs = returnWhen (null incomplete) $ do
|
|||
then a
|
||||
else do
|
||||
-- remove the hard link
|
||||
when (contentLocation keysource /= keyFilename keysource) $
|
||||
void $ liftIO $ tryIO $ removeFile $ contentLocation keysource
|
||||
return Nothing
|
||||
|
||||
|
@ -278,6 +279,7 @@ safeToAdd delayadd pending inprocess = do
|
|||
warning $ keyFilename ks
|
||||
++ " still has writers, not adding"
|
||||
-- remove the hard link
|
||||
when (contentLocation ks /= keyFilename ks) $
|
||||
void $ liftIO $ tryIO $ removeFile $ contentLocation ks
|
||||
canceladd _ = noop
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@ cancelTransfer pause t = do
|
|||
| otherwise = killThread tid
|
||||
{- In order to stop helper processes like rsync,
|
||||
- kill the whole process group of the process running the transfer. -}
|
||||
killproc pid = void $ catchMaybeIO $ do
|
||||
killproc pid = void $ tryIO $ do
|
||||
g <- getProcessGroupIDOf pid
|
||||
void $ tryIO $ signalProcessGroup sigTERM g
|
||||
threadDelay 50000 -- 0.05 second grace period
|
||||
|
|
|
@ -67,7 +67,10 @@ start file = ifAnnexed file fixup add
|
|||
- Lockdown can fail if a file gets deleted, and Nothing will be returned.
|
||||
-}
|
||||
lockDown :: FilePath -> Annex (Maybe KeySource)
|
||||
lockDown file = do
|
||||
lockDown file = ifM (crippledFileSystem)
|
||||
( return $ Just $
|
||||
KeySource { keyFilename = file, contentLocation = file }
|
||||
, do
|
||||
tmp <- fromRepo gitAnnexTmpDir
|
||||
createAnnexDirectory tmp
|
||||
liftIO $ catchMaybeIO $ do
|
||||
|
@ -77,8 +80,9 @@ lockDown file = do
|
|||
nukeFile tmpfile
|
||||
createLink file tmpfile
|
||||
return $ KeySource { keyFilename = file , contentLocation = tmpfile }
|
||||
)
|
||||
|
||||
{- Moves a locked down file into the annex.
|
||||
{- Ingests a locked down file into the annex.
|
||||
-
|
||||
- In direct mode, leaves the file alone, and just updates bookkeeping
|
||||
- information.
|
||||
|
@ -107,7 +111,9 @@ ingest (Just source) = do
|
|||
( do
|
||||
writeCache key cache
|
||||
void $ addAssociatedFile key $ keyFilename source
|
||||
unlessM crippledFileSystem $
|
||||
liftIO $ allowWrite $ keyFilename source
|
||||
when (contentLocation source /= keyFilename source) $
|
||||
liftIO $ nukeFile $ contentLocation source
|
||||
return $ Just key
|
||||
, failure
|
||||
|
@ -115,6 +121,7 @@ ingest (Just source) = do
|
|||
godirect _ _ = failure
|
||||
|
||||
failure = do
|
||||
when (contentLocation source /= keyFilename source) $
|
||||
liftIO $ nukeFile $ contentLocation source
|
||||
return Nothing
|
||||
|
||||
|
|
|
@ -203,6 +203,7 @@ fixLink key file = do
|
|||
showNote "fixing content location"
|
||||
dir <- liftIO $ parentDir <$> absPath file
|
||||
let content = absPathFrom dir have
|
||||
unlessM crippledFileSystem $
|
||||
liftIO $ allowWrite (parentDir content)
|
||||
moveAnnex key content
|
||||
|
||||
|
|
|
@ -86,6 +86,14 @@ setDirect b = do
|
|||
setConfig (annexConfig "direct") (Git.Config.boolConfig b)
|
||||
Annex.changeGitConfig $ \c -> c { annexDirect = b }
|
||||
|
||||
crippledFileSystem :: Annex Bool
|
||||
crippledFileSystem = annexCrippledFileSystem <$> Annex.getGitConfig
|
||||
|
||||
setCrippledFileSystem :: Bool -> Annex ()
|
||||
setCrippledFileSystem b = do
|
||||
setConfig (annexConfig "crippledfilesystem") (Git.Config.boolConfig b)
|
||||
Annex.changeGitConfig $ \c -> c { annexCrippledFileSystem = b }
|
||||
|
||||
{- Gets the http headers to use. -}
|
||||
getHttpHeaders :: Annex [String]
|
||||
getHttpHeaders = do
|
||||
|
|
27
Init.hs
27
Init.hs
|
@ -22,6 +22,8 @@ import Annex.Version
|
|||
import Annex.UUID
|
||||
import Utility.UserInfo
|
||||
import Utility.Shell
|
||||
import Utility.FileMode
|
||||
import Config
|
||||
|
||||
genDescription :: Maybe String -> Annex String
|
||||
genDescription (Just d) = return d
|
||||
|
@ -35,6 +37,7 @@ genDescription Nothing = do
|
|||
initialize :: Maybe String -> Annex ()
|
||||
initialize mdescription = do
|
||||
prepUUID
|
||||
probeCrippledFileSystem
|
||||
Annex.Branch.create
|
||||
setVersion
|
||||
gitPreCommitHookWrite
|
||||
|
@ -98,3 +101,27 @@ preCommitScript = unlines
|
|||
, "# automatically configured by git-annex"
|
||||
, "git annex pre-commit ."
|
||||
]
|
||||
|
||||
probeCrippledFileSystem :: Annex ()
|
||||
probeCrippledFileSystem = do
|
||||
tmp <- fromRepo gitAnnexTmpDir
|
||||
let f = tmp </> "init-probe"
|
||||
liftIO $ do
|
||||
createDirectoryIfMissing True tmp
|
||||
writeFile f ""
|
||||
whenM (liftIO $ not <$> probe f) $ do
|
||||
warning "Detected a crippled filesystem. Enabling direct mode."
|
||||
setDirect True
|
||||
setCrippledFileSystem True
|
||||
liftIO $ removeFile f
|
||||
where
|
||||
probe f = catchBoolIO $ do
|
||||
let f2 = f ++ "2"
|
||||
nukeFile f2
|
||||
createLink f f2
|
||||
nukeFile f2
|
||||
createSymbolicLink f f2
|
||||
nukeFile f2
|
||||
preventWrite f
|
||||
allowWrite f
|
||||
return True
|
||||
|
|
|
@ -183,12 +183,14 @@ storeHelper d chunksize key storer = check <&&> go
|
|||
void $ tryIO $ removeDirectoryRecursive dest -- or not exist
|
||||
createDirectoryIfMissing True (parentDir dest)
|
||||
renameDirectory tmp dest
|
||||
-- may fail on some filesystems
|
||||
void $ tryIO $ do
|
||||
mapM_ preventWrite =<< dirContents dest
|
||||
preventWrite dest
|
||||
recorder f s = do
|
||||
void $ tryIO $ allowWrite f
|
||||
writeFile f s
|
||||
preventWrite f
|
||||
void $ tryIO $ preventWrite f
|
||||
|
||||
retrieve :: FilePath -> ChunkSize -> Key -> AssociatedFile -> FilePath -> Annex Bool
|
||||
retrieve d chunksize k _ f = metered Nothing k $ \meterupdate ->
|
||||
|
@ -215,8 +217,9 @@ retrieveCheap d _ k f = liftIO $ withStoredFiles Nothing d k go
|
|||
go _files = return False
|
||||
|
||||
remove :: FilePath -> Key -> Annex Bool
|
||||
remove d k = liftIO $ catchBoolIO $ do
|
||||
allowWrite dir
|
||||
remove d k = liftIO $ do
|
||||
void $ tryIO $ allowWrite dir
|
||||
catchBoolIO $ do
|
||||
removeDirectoryRecursive dir
|
||||
return True
|
||||
where
|
||||
|
|
|
@ -35,6 +35,7 @@ data GitConfig = GitConfig
|
|||
, annexHttpHeadersCommand :: Maybe String
|
||||
, annexAutoCommit :: Bool
|
||||
, annexWebOptions :: [String]
|
||||
, annexCrippledFileSystem :: Bool
|
||||
}
|
||||
|
||||
extractGitConfig :: Git.Repo -> GitConfig
|
||||
|
@ -55,6 +56,7 @@ extractGitConfig r = GitConfig
|
|||
, annexHttpHeadersCommand = getmaybe "http-headers-command"
|
||||
, annexAutoCommit = getbool "autocommit" True
|
||||
, annexWebOptions = getwords "web-options"
|
||||
, annexCrippledFileSystem = getbool "crippledfilesystem" False
|
||||
}
|
||||
where
|
||||
get k def = fromMaybe def $ getmayberead k
|
||||
|
|
|
@ -12,9 +12,12 @@ module Types.KeySource where
|
|||
-
|
||||
- The contentLocation may be different from the filename
|
||||
- associated with the key. For example, the add command
|
||||
- temporarily puts the content into a lockdown directory
|
||||
- may temporarily hard link the content into a lockdown directory
|
||||
- for checking. The migrate command uses the content
|
||||
- of a different Key. -}
|
||||
- of a different Key.
|
||||
-
|
||||
-
|
||||
-}
|
||||
data KeySource = KeySource
|
||||
{ keyFilename :: FilePath
|
||||
, contentLocation :: FilePath
|
||||
|
|
4
debian/changelog
vendored
4
debian/changelog
vendored
|
@ -4,6 +4,10 @@ git-annex (3.20130208) UNRELEASED; urgency=low
|
|||
* Now uses the Haskell Glob library, rather than pcre-light, avoiding
|
||||
the need to install libpcre. Currently done only for Cabal or when
|
||||
the Makefile is made to use -DWITH_GLOB
|
||||
* init: Detect when the repository is on a filesystem that does not
|
||||
support hard links, or symlinks, or unix permissions, and set
|
||||
annex.crippledfilesystem, as well as annex.direct. This allows
|
||||
use of git-annex repositories on FAT and even worse filesystems.
|
||||
|
||||
-- Joey Hess <joeyh@debian.org> Sun, 10 Feb 2013 14:52:01 -0400
|
||||
|
||||
|
|
|
@ -796,16 +796,22 @@ Here are all the supported configuration settings.
|
|||
to close it. On Mac OSX, when not using direct mode this defaults to
|
||||
1 second, to work around a bad interaction with software there.
|
||||
|
||||
* `annex.autocommit`
|
||||
|
||||
Set to false to prevent the git-annex assistant from automatically
|
||||
committing changes to files in the repository.
|
||||
|
||||
* `annex.direct`
|
||||
|
||||
Set to true to enable an (experimental) mode where files in the repository
|
||||
are accessed directly, rather than through symlinks. Note that many git
|
||||
and git-annex commands will not work with such a repository.
|
||||
|
||||
* `annex.autocommit`
|
||||
* `annex.crippledfilesystem`
|
||||
|
||||
Set to false to prevent the git-annex assistant from automatically
|
||||
committing changes to files in the repository.
|
||||
Set to true if the repository is on a crippled filesystem, such as FAT,
|
||||
which does not support symbolic links, or hard links, or unix permissions.
|
||||
This is automatically probed by "git annex init".
|
||||
|
||||
* `remote.<name>.annex-cost`
|
||||
|
||||
|
|
Loading…
Reference in a new issue