summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Joey Hess <joey@kitenet.net>2013-02-14 14:10:36 -0400
committerGravatar Joey Hess <joey@kitenet.net>2013-02-14 14:15:26 -0400
commit177245deb6ee3271eb44d77c2b0cd722755b2c3f (patch)
tree876c4844937c831470192d367123f581fb6cc3d8
parent4e2d50d2e4c9b4d3487c24042b733d02c2f4dd46 (diff)
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.
-rw-r--r--Annex/Content.hs33
-rw-r--r--Annex/Direct.hs6
-rw-r--r--Annex/Perms.hs10
-rw-r--r--Assistant/Pairing/Network.hs2
-rw-r--r--Assistant/Threads/Committer.hs6
-rw-r--r--Command/Add.hs37
-rw-r--r--Command/Fsck.hs3
-rw-r--r--Config.hs8
-rw-r--r--Init.hs27
-rw-r--r--Remote/Directory.hs17
-rw-r--r--Types/GitConfig.hs2
-rw-r--r--Types/KeySource.hs7
-rw-r--r--debian/changelog4
-rw-r--r--doc/git-annex.mdwn12
14 files changed, 122 insertions, 52 deletions
diff --git a/Annex/Content.hs b/Annex/Content.hs
index 8be2cf008..0a66d9912 100644
--- a/Annex/Content.hs
+++ b/Annex/Content.hs
@@ -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
- removeDirectoryRecursive dir
- removeparents dir (2 :: Int)
+ let dir = parentDir file
+ unlessM crippledFileSystem $
+ void $ liftIO $ catchMaybeIO $ allowWrite dir
+ void $ liftIO $ catchMaybeIO $ do
+ removeDirectoryRecursive dir
+ 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,7 +377,8 @@ removeAnnex key = withObjectLoc key remove removedirect
fromAnnex :: Key -> FilePath -> Annex ()
fromAnnex key dest = do
file <- inRepo $ gitAnnexLocation key
- liftIO $ allowWrite $ parentDir file
+ unlessM crippledFileSystem $
+ liftIO $ allowWrite $ parentDir file
thawContent file
liftIO $ moveFile file dest
cleanObjectLoc key
@@ -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
diff --git a/Annex/Direct.hs b/Annex/Direct.hs
index 648bb7518..b33fef8bc 100644
--- a/Annex/Direct.hs
+++ b/Annex/Direct.hs
@@ -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. -}
diff --git a/Annex/Perms.hs b/Annex/Perms.hs
index 27804ad3d..b1bac5e23 100644
--- a/Annex/Perms.hs
+++ b/Annex/Perms.hs
@@ -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
- liftIO $ allowWrite dir
+ unlessM crippledFileSystem $
+ liftIO $ allowWrite dir
where
dir = parentDir dest
diff --git a/Assistant/Pairing/Network.hs b/Assistant/Pairing/Network.hs
index 44a63df36..6c625f881 100644
--- a/Assistant/Pairing/Network.hs
+++ b/Assistant/Pairing/Network.hs
@@ -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
diff --git a/Assistant/Threads/Committer.hs b/Assistant/Threads/Committer.hs
index ce39735f9..463c2965c 100644
--- a/Assistant/Threads/Committer.hs
+++ b/Assistant/Threads/Committer.hs
@@ -233,7 +233,8 @@ handleAdds delayadd cs = returnWhen (null incomplete) $ do
then a
else do
-- remove the hard link
- void $ liftIO $ tryIO $ removeFile $ contentLocation keysource
+ when (contentLocation keysource /= keyFilename keysource) $
+ void $ liftIO $ tryIO $ removeFile $ contentLocation keysource
return Nothing
{- Files can Either be Right to be added now,
@@ -278,7 +279,8 @@ safeToAdd delayadd pending inprocess = do
warning $ keyFilename ks
++ " still has writers, not adding"
-- remove the hard link
- void $ liftIO $ tryIO $ removeFile $ contentLocation ks
+ when (contentLocation ks /= keyFilename ks) $
+ void $ liftIO $ tryIO $ removeFile $ contentLocation ks
canceladd _ = noop
openwrite (_file, mode, _pid)
diff --git a/Command/Add.hs b/Command/Add.hs
index bfab33099..f6b43034c 100644
--- a/Command/Add.hs
+++ b/Command/Add.hs
@@ -67,18 +67,22 @@ 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
- tmp <- fromRepo gitAnnexTmpDir
- createAnnexDirectory tmp
- liftIO $ catchMaybeIO $ do
- preventWrite file
- (tmpfile, h) <- openTempFile tmp (takeFileName file)
- hClose h
- nukeFile tmpfile
- createLink file tmpfile
- return $ KeySource { keyFilename = file , contentLocation = tmpfile }
-
-{- Moves a locked down file into the annex.
+lockDown file = ifM (crippledFileSystem)
+ ( return $ Just $
+ KeySource { keyFilename = file, contentLocation = file }
+ , do
+ tmp <- fromRepo gitAnnexTmpDir
+ createAnnexDirectory tmp
+ liftIO $ catchMaybeIO $ do
+ preventWrite file
+ (tmpfile, h) <- openTempFile tmp (takeFileName file)
+ hClose h
+ nukeFile tmpfile
+ createLink file tmpfile
+ return $ KeySource { keyFilename = file , contentLocation = tmpfile }
+ )
+
+{- Ingests a locked down file into the annex.
-
- In direct mode, leaves the file alone, and just updates bookkeeping
- information.
@@ -107,15 +111,18 @@ ingest (Just source) = do
( do
writeCache key cache
void $ addAssociatedFile key $ keyFilename source
- liftIO $ allowWrite $ keyFilename source
- liftIO $ nukeFile $ contentLocation source
+ unlessM crippledFileSystem $
+ liftIO $ allowWrite $ keyFilename source
+ when (contentLocation source /= keyFilename source) $
+ liftIO $ nukeFile $ contentLocation source
return $ Just key
, failure
)
godirect _ _ = failure
failure = do
- liftIO $ nukeFile $ contentLocation source
+ when (contentLocation source /= keyFilename source) $
+ liftIO $ nukeFile $ contentLocation source
return Nothing
perform :: FilePath -> CommandPerform
diff --git a/Command/Fsck.hs b/Command/Fsck.hs
index 8f33493b5..666245517 100644
--- a/Command/Fsck.hs
+++ b/Command/Fsck.hs
@@ -203,7 +203,8 @@ fixLink key file = do
showNote "fixing content location"
dir <- liftIO $ parentDir <$> absPath file
let content = absPathFrom dir have
- liftIO $ allowWrite (parentDir content)
+ unlessM crippledFileSystem $
+ liftIO $ allowWrite (parentDir content)
moveAnnex key content
showNote "fixing link"
diff --git a/Config.hs b/Config.hs
index ad67a9a0d..d37989e66 100644
--- a/Config.hs
+++ b/Config.hs
@@ -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
diff --git a/Init.hs b/Init.hs
index a6f4fa935..77b36b6dd 100644
--- a/Init.hs
+++ b/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
diff --git a/Remote/Directory.hs b/Remote/Directory.hs
index 922742099..3070a530b 100644
--- a/Remote/Directory.hs
+++ b/Remote/Directory.hs
@@ -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
- mapM_ preventWrite =<< dirContents dest
- preventWrite 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,10 +217,11 @@ 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
- removeDirectoryRecursive dir
- return True
+remove d k = liftIO $ do
+ void $ tryIO $ allowWrite dir
+ catchBoolIO $ do
+ removeDirectoryRecursive dir
+ return True
where
dir = storeDir d k
diff --git a/Types/GitConfig.hs b/Types/GitConfig.hs
index 86bfd39b6..014a409e1 100644
--- a/Types/GitConfig.hs
+++ b/Types/GitConfig.hs
@@ -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
diff --git a/Types/KeySource.hs b/Types/KeySource.hs
index f4885767a..628954c33 100644
--- a/Types/KeySource.hs
+++ b/Types/KeySource.hs
@@ -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
diff --git a/debian/changelog b/debian/changelog
index e2c0dcb4a..0359dc5c0 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -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
diff --git a/doc/git-annex.mdwn b/doc/git-annex.mdwn
index e55f97fc2..a06ac3802 100644
--- a/doc/git-annex.mdwn
+++ b/doc/git-annex.mdwn
@@ -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`