git-annex/Remote/Directory.hs

143 lines
4.2 KiB
Haskell
Raw Normal View History

{- A "remote" that is just a filesystem directory.
2011-03-30 17:18:46 +00:00
-
- Copyright 2011 Joey Hess <joey@kitenet.net>
-
- Licensed under the GNU GPL version 3 or higher.
-}
module Remote.Directory (remote) where
import qualified Data.ByteString.Lazy.Char8 as L
2011-03-30 17:18:46 +00:00
import qualified Data.Map as M
2011-10-05 20:02:51 +00:00
import Common.Annex
import Utility.CopyFile
import Types.Remote
import qualified Git
import Config
2011-09-23 22:13:24 +00:00
import Utility.FileMode
2011-08-17 00:49:54 +00:00
import Remote.Helper.Special
import Remote.Helper.Encryptable
import Crypto
2011-03-30 17:18:46 +00:00
remote :: RemoteType Annex
remote = RemoteType {
typename = "directory",
2011-03-30 18:00:54 +00:00
enumerate = findSpecialRemotes "directory",
2011-03-30 17:18:46 +00:00
generate = gen,
2011-03-30 18:00:54 +00:00
setup = directorySetup
2011-03-30 17:18:46 +00:00
}
2011-04-15 19:09:36 +00:00
gen :: Git.Repo -> UUID -> Maybe RemoteConfig -> Annex (Remote Annex)
gen r u c = do
dir <- getConfig r "directory" (error "missing directory")
2011-03-30 19:15:46 +00:00
cst <- remoteCost r cheapRemoteCost
2011-04-17 04:40:23 +00:00
return $ encryptableRemote c
2011-04-17 01:41:14 +00:00
(storeEncrypted dir)
(retrieveEncrypted dir)
Remote {
uuid = u,
cost = cst,
name = Git.repoDescribe r,
storeKey = store dir,
retrieveKeyFile = retrieve dir,
removeKey = remove dir,
hasKey = checkPresent dir,
hasKeyCheap = True,
config = Nothing,
repo = r
2011-04-17 01:41:14 +00:00
}
2011-03-30 17:18:46 +00:00
2011-04-15 19:09:36 +00:00
directorySetup :: UUID -> RemoteConfig -> Annex RemoteConfig
2011-03-30 18:00:54 +00:00
directorySetup u c = do
2011-03-30 17:18:46 +00:00
-- verify configuration is sane
2011-07-15 16:47:14 +00:00
let dir = fromMaybe (error "Specify directory=") $
2011-05-15 06:49:43 +00:00
M.lookup "directory" c
liftIO $ doesDirectoryExist dir
>>! error $ "Directory does not exist: " ++ dir
c' <- encryptionSetup c
2011-03-30 17:18:46 +00:00
-- The directory is stored in git config, not in this remote's
-- persistant state, so it can vary between hosts.
gitConfigSpecialRemote u c' "directory" dir
return $ M.delete "directory" c'
2011-03-30 17:18:46 +00:00
{- Where to store a given Key in the Directory.
-
- There are two possible locations to try; this had to be done because
- on Linux, vfat filesystem mounted with shortname=mixed have a
- variant of case insensativity that causes miserable failure when
- hashDirMixed produces eg, "xx" and "XX". The first directory to be
- created wins the namespace, and the second one cannot then be created.
- But unlike behavior with shortname=lower, "XX/foo" won't look in
- "xx/foo".
-}
locations :: FilePath -> Key -> [FilePath]
locations d k = [using hashDirMixed, using hashDirLower]
where
using h = d </> h k </> f </> f
f = keyFile k
2011-03-30 17:18:46 +00:00
withCheckedFile :: (FilePath -> IO Bool) -> FilePath -> Key -> (FilePath -> IO Bool) -> IO Bool
withCheckedFile _ [] _ _ = return False
withCheckedFile check d k a = go $ locations d k
where
go [] = return False
go (f:fs) = do
use <- check f
if use
then a f
else go fs
withStoredFile :: FilePath -> Key -> (FilePath -> IO Bool) -> IO Bool
withStoredFile = withCheckedFile doesFileExist
2011-04-17 01:41:14 +00:00
store :: FilePath -> Key -> Annex Bool
store d k = do
src <- fromRepo $ gitAnnexLocation k
liftIO $ catchBoolIO $ storeHelper d k $ copyFileExternal src
2011-04-17 01:41:14 +00:00
storeEncrypted :: FilePath -> (Cipher, Key) -> Key -> Annex Bool
storeEncrypted d (cipher, enck) k = do
src <- fromRepo $ gitAnnexLocation k
liftIO $ catchBoolIO $ storeHelper d enck $ encrypt src
where
2011-04-17 01:41:14 +00:00
encrypt src dest = do
withEncryptedContent cipher (L.readFile src) $ L.writeFile dest
2011-04-17 01:41:14 +00:00
return True
2011-03-30 17:18:46 +00:00
storeHelper :: FilePath -> Key -> (FilePath -> IO Bool) -> IO Bool
storeHelper d key a = withCheckedFile check d key go
where
check dest = isJust <$> mkdir (parentDir dest)
mkdir = catchMaybeIO . createDirectoryIfMissing True
go dest = do
let dir = parentDir dest
allowWrite dir
ok <- a dest
when ok $ do
preventWrite dest
preventWrite dir
return ok
2011-04-17 01:41:14 +00:00
retrieve :: FilePath -> Key -> FilePath -> Annex Bool
retrieve d k f = liftIO $ withStoredFile d k $ \file -> copyFileExternal file f
2011-04-17 01:41:14 +00:00
retrieveEncrypted :: FilePath -> (Cipher, Key) -> FilePath -> Annex Bool
retrieveEncrypted d (cipher, enck) f =
liftIO $ withStoredFile d enck $ \file -> catchBoolIO $ do
withDecryptedContent cipher (L.readFile file) $ L.writeFile f
2011-04-17 04:57:29 +00:00
return True
2011-03-30 17:18:46 +00:00
remove :: FilePath -> Key -> Annex Bool
remove d k = liftIO $ withStoredFile d k $ \file -> catchBoolIO $ do
let dir = parentDir file
2011-04-17 04:57:29 +00:00
allowWrite dir
removeFile file
removeDirectory dir
return True
2011-03-30 17:18:46 +00:00
checkPresent :: FilePath -> Key -> Annex (Either String Bool)
checkPresent d k = liftIO $ catchMsgIO $ withStoredFile d k $
const $ return True -- withStoredFile checked that it exists